avt-rct-lib 1.0.4 → 1.0.5
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/index.cjs +954 -148
- package/dist/index.d.cts +181 -21
- package/dist/index.d.ts +181 -21
- package/dist/index.js +944 -148
- package/package.json +1 -1
- package/src/styles/base.css +84 -23
package/dist/index.cjs
CHANGED
|
@@ -1078,8 +1078,8 @@ var useSidebar = () => React3.useContext(SidebarContext);
|
|
|
1078
1078
|
function Sidebar({
|
|
1079
1079
|
collapsed = false,
|
|
1080
1080
|
glass = true,
|
|
1081
|
-
width = "
|
|
1082
|
-
collapsedWidth = "
|
|
1081
|
+
width = "240px",
|
|
1082
|
+
collapsedWidth = "64px",
|
|
1083
1083
|
overlay = false,
|
|
1084
1084
|
onOverlayClose,
|
|
1085
1085
|
className,
|
|
@@ -1142,28 +1142,28 @@ function SidebarBrand({ logo, title, subtitle, className, ...props }) {
|
|
|
1142
1142
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1143
1143
|
"div",
|
|
1144
1144
|
{
|
|
1145
|
-
className: cn("flex items-center gap-
|
|
1145
|
+
className: cn("flex items-center gap-3 px-4 py-5", collapsed && "justify-center px-0", className),
|
|
1146
1146
|
...props,
|
|
1147
1147
|
children: [
|
|
1148
1148
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-shrink-0", children: logo }),
|
|
1149
1149
|
!collapsed && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 overflow-hidden", children: [
|
|
1150
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "truncate text-[
|
|
1151
|
-
subtitle && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "truncate text-[
|
|
1150
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "truncate text-[13px] font-semibold tracking-[-0.01em] text-[#1C1C1E]", children: title }),
|
|
1151
|
+
subtitle && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "truncate text-[11px] text-[#8E8E93]", children: subtitle })
|
|
1152
1152
|
] })
|
|
1153
1153
|
]
|
|
1154
1154
|
}
|
|
1155
1155
|
);
|
|
1156
1156
|
}
|
|
1157
1157
|
function SidebarDivider({ className }) {
|
|
1158
|
-
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("mx-
|
|
1158
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("mx-3 my-1 h-px bg-[#E5E5EA]", className) });
|
|
1159
1159
|
}
|
|
1160
1160
|
function SidebarContent({ className, ...props }) {
|
|
1161
|
-
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("flex-1 overflow-y-auto px-
|
|
1161
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("flex-1 overflow-y-auto px-2 py-2 avt-scroll space-y-0.5", className), ...props });
|
|
1162
1162
|
}
|
|
1163
1163
|
function SidebarGroup({ label, className, children, ...props }) {
|
|
1164
1164
|
const { collapsed } = useSidebar();
|
|
1165
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("mb-
|
|
1166
|
-
label && !collapsed && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mb-
|
|
1165
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("mb-1", className), ...props, children: [
|
|
1166
|
+
label && !collapsed && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mb-1 px-3 text-[10px] font-semibold uppercase tracking-widest text-[#C7C7CC]", children: label }),
|
|
1167
1167
|
children
|
|
1168
1168
|
] });
|
|
1169
1169
|
}
|
|
@@ -1185,10 +1185,11 @@ function SidebarItem({
|
|
|
1185
1185
|
...tagProps,
|
|
1186
1186
|
title: collapsed ? label : void 0,
|
|
1187
1187
|
className: cn(
|
|
1188
|
-
"flex w-full items-center gap-2 rounded-
|
|
1189
|
-
"text-[
|
|
1188
|
+
"flex w-full items-center gap-2.5 rounded-xl transition-all duration-150",
|
|
1189
|
+
"text-[13px] font-medium select-none outline-none",
|
|
1190
1190
|
"focus-visible:ring-2 focus-visible:ring-[#007AFF]/30",
|
|
1191
|
-
|
|
1191
|
+
// Mobile-friendly touch target
|
|
1192
|
+
collapsed ? "justify-center px-0 mx-auto w-10 h-10 min-h-[44px] min-w-[44px]" : "px-3 py-2.5 min-h-[44px]",
|
|
1192
1193
|
active ? "bg-[#007AFF] text-white shadow-[0_2px_8px_rgba(0,122,255,0.28)]" : "text-[#3C3C43] hover:bg-[#007AFF]/8 hover:text-[#007AFF]",
|
|
1193
1194
|
className
|
|
1194
1195
|
),
|
|
@@ -1200,8 +1201,8 @@ function SidebarItem({
|
|
|
1200
1201
|
"span",
|
|
1201
1202
|
{
|
|
1202
1203
|
className: cn(
|
|
1203
|
-
"ml-auto flex h-
|
|
1204
|
-
"text-[
|
|
1204
|
+
"ml-auto flex h-5 min-w-5 items-center justify-center rounded-full px-1.5",
|
|
1205
|
+
"text-[10px] font-bold",
|
|
1205
1206
|
active ? "bg-white/20 text-white" : "bg-[#E5E5EA] text-[#8E8E93]"
|
|
1206
1207
|
),
|
|
1207
1208
|
children: badge
|
|
@@ -1211,132 +1212,8 @@ function SidebarItem({
|
|
|
1211
1212
|
}
|
|
1212
1213
|
);
|
|
1213
1214
|
}
|
|
1214
|
-
function SidebarSubMenu({
|
|
1215
|
-
icon,
|
|
1216
|
-
label,
|
|
1217
|
-
badge,
|
|
1218
|
-
defaultOpen = false,
|
|
1219
|
-
open: controlledOpen,
|
|
1220
|
-
onOpenChange,
|
|
1221
|
-
activeChild = false,
|
|
1222
|
-
children,
|
|
1223
|
-
className
|
|
1224
|
-
}) {
|
|
1225
|
-
const { collapsed } = useSidebar();
|
|
1226
|
-
const [internalOpen, setInternalOpen] = React3.useState(defaultOpen);
|
|
1227
|
-
const isOpen = controlledOpen ?? internalOpen;
|
|
1228
|
-
const toggle = () => {
|
|
1229
|
-
const next = !isOpen;
|
|
1230
|
-
setInternalOpen(next);
|
|
1231
|
-
onOpenChange?.(next);
|
|
1232
|
-
};
|
|
1233
|
-
if (collapsed) {
|
|
1234
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1235
|
-
"button",
|
|
1236
|
-
{
|
|
1237
|
-
type: "button",
|
|
1238
|
-
title: label,
|
|
1239
|
-
onClick: toggle,
|
|
1240
|
-
className: cn(
|
|
1241
|
-
"mx-auto flex h-8 w-8 min-h-[36px] min-w-[36px] items-center justify-center rounded-lg",
|
|
1242
|
-
"select-none outline-none transition-all duration-150",
|
|
1243
|
-
"focus-visible:ring-2 focus-visible:ring-[#007AFF]/30",
|
|
1244
|
-
activeChild ? "bg-[#007AFF] text-white shadow-[0_2px_8px_rgba(0,122,255,0.28)]" : "text-[#3C3C43] hover:bg-[#007AFF]/8 hover:text-[#007AFF]",
|
|
1245
|
-
className
|
|
1246
|
-
),
|
|
1247
|
-
children: icon && /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("flex-shrink-0", !activeChild && "text-[#8E8E93]"), children: icon })
|
|
1248
|
-
}
|
|
1249
|
-
);
|
|
1250
|
-
}
|
|
1251
|
-
const triggerActive = activeChild && !isOpen;
|
|
1252
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("space-y-px", className), children: [
|
|
1253
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1254
|
-
"button",
|
|
1255
|
-
{
|
|
1256
|
-
type: "button",
|
|
1257
|
-
onClick: toggle,
|
|
1258
|
-
className: cn(
|
|
1259
|
-
"flex w-full items-center gap-2 rounded-lg px-2.5 py-1.5 min-h-[30px]",
|
|
1260
|
-
"text-[12px] font-medium select-none outline-none transition-all duration-150",
|
|
1261
|
-
"focus-visible:ring-2 focus-visible:ring-[#007AFF]/30",
|
|
1262
|
-
triggerActive ? "bg-[#007AFF] text-white shadow-[0_2px_8px_rgba(0,122,255,0.28)]" : "text-[#3C3C43] hover:bg-[#007AFF]/8 hover:text-[#007AFF]"
|
|
1263
|
-
),
|
|
1264
|
-
children: [
|
|
1265
|
-
icon && /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("flex-shrink-0", !triggerActive && "text-[#8E8E93]"), children: icon }),
|
|
1266
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1 truncate text-left", children: label }),
|
|
1267
|
-
badge !== void 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1268
|
-
"span",
|
|
1269
|
-
{
|
|
1270
|
-
className: cn(
|
|
1271
|
-
"flex h-4 min-w-4 items-center justify-center rounded-full px-1 text-[9px] font-bold",
|
|
1272
|
-
triggerActive ? "bg-white/20 text-white" : "bg-[#E5E5EA] text-[#8E8E93]"
|
|
1273
|
-
),
|
|
1274
|
-
children: badge
|
|
1275
|
-
}
|
|
1276
|
-
),
|
|
1277
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1278
|
-
"svg",
|
|
1279
|
-
{
|
|
1280
|
-
className: cn(
|
|
1281
|
-
"h-3 w-3 flex-shrink-0 transition-transform duration-200",
|
|
1282
|
-
triggerActive ? "text-white/60" : "text-[#C7C7CC]",
|
|
1283
|
-
isOpen && "rotate-90"
|
|
1284
|
-
),
|
|
1285
|
-
viewBox: "0 0 24 24",
|
|
1286
|
-
fill: "none",
|
|
1287
|
-
stroke: "currentColor",
|
|
1288
|
-
strokeWidth: "2.5",
|
|
1289
|
-
strokeLinecap: "round",
|
|
1290
|
-
strokeLinejoin: "round",
|
|
1291
|
-
children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M9 18l6-6-6-6" })
|
|
1292
|
-
}
|
|
1293
|
-
)
|
|
1294
|
-
]
|
|
1295
|
-
}
|
|
1296
|
-
),
|
|
1297
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1298
|
-
"div",
|
|
1299
|
-
{
|
|
1300
|
-
className: cn(
|
|
1301
|
-
"overflow-hidden transition-all duration-200 ease-[cubic-bezier(0.16,1,0.3,1)]",
|
|
1302
|
-
isOpen ? "max-h-96 opacity-100" : "max-h-0 opacity-0 pointer-events-none"
|
|
1303
|
-
),
|
|
1304
|
-
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "ml-2.5 space-y-px border-l border-[#E5E5EA] py-0.5 pl-1.5", children })
|
|
1305
|
-
}
|
|
1306
|
-
)
|
|
1307
|
-
] });
|
|
1308
|
-
}
|
|
1309
|
-
function SidebarSubMenuItem({
|
|
1310
|
-
icon,
|
|
1311
|
-
label,
|
|
1312
|
-
active = false,
|
|
1313
|
-
href,
|
|
1314
|
-
as: Tag = "button",
|
|
1315
|
-
className,
|
|
1316
|
-
...props
|
|
1317
|
-
}) {
|
|
1318
|
-
const tagProps = href ? { href } : { type: "button" };
|
|
1319
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1320
|
-
Tag,
|
|
1321
|
-
{
|
|
1322
|
-
...tagProps,
|
|
1323
|
-
className: cn(
|
|
1324
|
-
"flex w-full items-center gap-1.5 rounded-md px-2 py-1 min-h-[26px]",
|
|
1325
|
-
"text-[11px] font-medium select-none outline-none transition-all duration-150",
|
|
1326
|
-
"focus-visible:ring-2 focus-visible:ring-[#007AFF]/30",
|
|
1327
|
-
active ? "bg-[#007AFF] text-white shadow-[0_1px_4px_rgba(0,122,255,0.20)]" : "text-[#3C3C43] hover:bg-[#007AFF]/8 hover:text-[#007AFF]",
|
|
1328
|
-
className
|
|
1329
|
-
),
|
|
1330
|
-
...props,
|
|
1331
|
-
children: [
|
|
1332
|
-
icon && /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("flex-shrink-0", !active && "text-[#8E8E93]"), children: icon }),
|
|
1333
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1 truncate text-left", children: label })
|
|
1334
|
-
]
|
|
1335
|
-
}
|
|
1336
|
-
);
|
|
1337
|
-
}
|
|
1338
1215
|
function SidebarFooter({ className, ...props }) {
|
|
1339
|
-
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("flex-shrink-0 p-
|
|
1216
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("flex-shrink-0 p-3", className), ...props });
|
|
1340
1217
|
}
|
|
1341
1218
|
function SidebarUser({
|
|
1342
1219
|
name,
|
|
@@ -1353,8 +1230,8 @@ function SidebarUser({
|
|
|
1353
1230
|
"div",
|
|
1354
1231
|
{
|
|
1355
1232
|
className: cn(
|
|
1356
|
-
"flex h-
|
|
1357
|
-
`bg-gradient-to-br ${avatarColor} text-white text-
|
|
1233
|
+
"flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-full",
|
|
1234
|
+
`bg-gradient-to-br ${avatarColor} text-white text-xs font-semibold`
|
|
1358
1235
|
),
|
|
1359
1236
|
children: avatarFallback ?? name.charAt(0).toUpperCase()
|
|
1360
1237
|
}
|
|
@@ -1362,11 +1239,11 @@ function SidebarUser({
|
|
|
1362
1239
|
if (collapsed) {
|
|
1363
1240
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("flex justify-center", className), ...props, children: avatarNode });
|
|
1364
1241
|
}
|
|
1365
|
-
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("rounded-
|
|
1242
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("rounded-xl bg-[#F2F2F7] p-3", className), ...props, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2.5", children: [
|
|
1366
1243
|
avatarNode,
|
|
1367
1244
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
1368
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "truncate text-[
|
|
1369
|
-
subtitle && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "truncate text-[
|
|
1245
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "truncate text-[12px] font-semibold text-[#1C1C1E]", children: name }),
|
|
1246
|
+
subtitle && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "truncate text-[11px] text-[#8E8E93]", children: subtitle })
|
|
1370
1247
|
] }),
|
|
1371
1248
|
actions && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-shrink-0", children: actions })
|
|
1372
1249
|
] }) });
|
|
@@ -1377,7 +1254,7 @@ function SidebarToggle({ collapsed, className, ...props }) {
|
|
|
1377
1254
|
{
|
|
1378
1255
|
type: "button",
|
|
1379
1256
|
className: cn(
|
|
1380
|
-
"flex h-
|
|
1257
|
+
"flex h-7 w-7 items-center justify-center rounded-lg",
|
|
1381
1258
|
"text-[#8E8E93] hover:bg-[#F2F2F7] hover:text-[#3C3C43]",
|
|
1382
1259
|
"transition-colors duration-150",
|
|
1383
1260
|
className
|
|
@@ -1387,7 +1264,7 @@ function SidebarToggle({ collapsed, className, ...props }) {
|
|
|
1387
1264
|
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1388
1265
|
"svg",
|
|
1389
1266
|
{
|
|
1390
|
-
className: cn("h-
|
|
1267
|
+
className: cn("h-4 w-4 transition-transform duration-200", collapsed && "rotate-180"),
|
|
1391
1268
|
viewBox: "0 0 24 24",
|
|
1392
1269
|
fill: "none",
|
|
1393
1270
|
stroke: "currentColor",
|
|
@@ -1400,6 +1277,925 @@ function SidebarToggle({ collapsed, className, ...props }) {
|
|
|
1400
1277
|
}
|
|
1401
1278
|
);
|
|
1402
1279
|
}
|
|
1280
|
+
function useAnchoredPosition(anchorRef, open, {
|
|
1281
|
+
align = "start",
|
|
1282
|
+
sideOffset = 6,
|
|
1283
|
+
minWidth = 180,
|
|
1284
|
+
matchWidth = true,
|
|
1285
|
+
maxHeight = 280,
|
|
1286
|
+
viewportPadding = 8
|
|
1287
|
+
} = {}) {
|
|
1288
|
+
const [pos, setPos] = React3.useState(null);
|
|
1289
|
+
const update = React3.useCallback(() => {
|
|
1290
|
+
const el = anchorRef.current;
|
|
1291
|
+
if (!el) return;
|
|
1292
|
+
const rect = el.getBoundingClientRect();
|
|
1293
|
+
const vw = window.innerWidth;
|
|
1294
|
+
const vh = window.innerHeight;
|
|
1295
|
+
const width = matchWidth ? Math.max(minWidth, rect.width) : minWidth;
|
|
1296
|
+
let left;
|
|
1297
|
+
if (align === "end") left = rect.right - width;
|
|
1298
|
+
else if (align === "center") left = rect.left + rect.width / 2 - width / 2;
|
|
1299
|
+
else left = rect.left;
|
|
1300
|
+
left = Math.max(viewportPadding, Math.min(left, vw - width - viewportPadding));
|
|
1301
|
+
const spaceBelow = vh - rect.bottom - sideOffset - viewportPadding;
|
|
1302
|
+
const spaceAbove = rect.top - sideOffset - viewportPadding;
|
|
1303
|
+
const flipUp = spaceBelow < Math.min(maxHeight, 180) && spaceAbove > spaceBelow;
|
|
1304
|
+
const available = Math.max(120, flipUp ? spaceAbove : spaceBelow);
|
|
1305
|
+
const height = Math.min(maxHeight, available);
|
|
1306
|
+
const top = flipUp ? rect.top - sideOffset - height : rect.bottom + sideOffset;
|
|
1307
|
+
setPos({
|
|
1308
|
+
top,
|
|
1309
|
+
left,
|
|
1310
|
+
width,
|
|
1311
|
+
maxHeight: height,
|
|
1312
|
+
placement: flipUp ? "top" : "bottom"
|
|
1313
|
+
});
|
|
1314
|
+
}, [anchorRef, align, sideOffset, minWidth, matchWidth, maxHeight, viewportPadding]);
|
|
1315
|
+
React3.useEffect(() => {
|
|
1316
|
+
if (!open) {
|
|
1317
|
+
setPos(null);
|
|
1318
|
+
return;
|
|
1319
|
+
}
|
|
1320
|
+
update();
|
|
1321
|
+
window.addEventListener("scroll", update, true);
|
|
1322
|
+
window.addEventListener("resize", update);
|
|
1323
|
+
return () => {
|
|
1324
|
+
window.removeEventListener("scroll", update, true);
|
|
1325
|
+
window.removeEventListener("resize", update);
|
|
1326
|
+
};
|
|
1327
|
+
}, [open, update]);
|
|
1328
|
+
return pos;
|
|
1329
|
+
}
|
|
1330
|
+
var stack = [];
|
|
1331
|
+
var bound = false;
|
|
1332
|
+
function onGlobalKeydown(e) {
|
|
1333
|
+
if (e.key !== "Escape") return;
|
|
1334
|
+
const top = stack[stack.length - 1];
|
|
1335
|
+
if (!top) return;
|
|
1336
|
+
e.stopPropagation();
|
|
1337
|
+
top();
|
|
1338
|
+
}
|
|
1339
|
+
function bind() {
|
|
1340
|
+
if (bound || typeof document === "undefined") return;
|
|
1341
|
+
document.addEventListener("keydown", onGlobalKeydown, true);
|
|
1342
|
+
bound = true;
|
|
1343
|
+
}
|
|
1344
|
+
function unbind() {
|
|
1345
|
+
if (!bound || typeof document === "undefined") return;
|
|
1346
|
+
document.removeEventListener("keydown", onGlobalKeydown, true);
|
|
1347
|
+
bound = false;
|
|
1348
|
+
}
|
|
1349
|
+
function useEscapeDismiss(enabled, onDismiss) {
|
|
1350
|
+
const handlerRef = React3.useRef(onDismiss);
|
|
1351
|
+
handlerRef.current = onDismiss;
|
|
1352
|
+
React3.useEffect(() => {
|
|
1353
|
+
if (!enabled) return;
|
|
1354
|
+
const entry = () => handlerRef.current();
|
|
1355
|
+
stack.push(entry);
|
|
1356
|
+
bind();
|
|
1357
|
+
return () => {
|
|
1358
|
+
const i = stack.lastIndexOf(entry);
|
|
1359
|
+
if (i >= 0) stack.splice(i, 1);
|
|
1360
|
+
if (stack.length === 0) unbind();
|
|
1361
|
+
};
|
|
1362
|
+
}, [enabled]);
|
|
1363
|
+
}
|
|
1364
|
+
var triggerBase = [
|
|
1365
|
+
"flex w-full items-center gap-2 rounded-xl bg-[#F2F2F7] text-left",
|
|
1366
|
+
"border-0 outline-none select-none text-[#1C1C1E]",
|
|
1367
|
+
"transition-all duration-150",
|
|
1368
|
+
"focus-visible:bg-white focus-visible:shadow-[0_0_0_2px_rgba(0,122,255,0.22)]",
|
|
1369
|
+
"disabled:cursor-not-allowed disabled:opacity-50"
|
|
1370
|
+
].join(" ");
|
|
1371
|
+
var triggerSizes = {
|
|
1372
|
+
sm: "h-9 px-3 text-[13px]",
|
|
1373
|
+
md: "h-11 px-4 text-sm",
|
|
1374
|
+
lg: "h-12 px-5 text-[15px]"
|
|
1375
|
+
};
|
|
1376
|
+
var panelBase = [
|
|
1377
|
+
"fixed z-[9999] flex flex-col overflow-hidden avt-animate-slide-up",
|
|
1378
|
+
"rounded-xl border border-[#E5E5EA]/60 bg-white/95 backdrop-blur-2xl",
|
|
1379
|
+
"shadow-[0_8px_24px_rgba(0,0,0,0.10),_0_0_1px_rgba(0,0,0,0.06)]"
|
|
1380
|
+
].join(" ");
|
|
1381
|
+
function optionRowClass(state, className) {
|
|
1382
|
+
return cn(
|
|
1383
|
+
"flex w-full items-center gap-2.5 px-3.5 py-2.5 text-[13px] font-medium",
|
|
1384
|
+
"cursor-pointer select-none text-left outline-none",
|
|
1385
|
+
"transition-colors duration-100",
|
|
1386
|
+
// Mobile: jaga target sentuh minimal
|
|
1387
|
+
"min-h-[44px] sm:min-h-0",
|
|
1388
|
+
state.disabled ? "pointer-events-none opacity-40" : state.active ? "bg-[#F2F2F7]" : "hover:bg-[#F2F2F7]",
|
|
1389
|
+
state.selected ? "text-[#007AFF]" : "text-[#1C1C1E]",
|
|
1390
|
+
className
|
|
1391
|
+
);
|
|
1392
|
+
}
|
|
1393
|
+
var groupLabelClass = "px-3.5 pb-1 pt-2 text-[11px] font-semibold uppercase tracking-wider text-[#8E8E93]";
|
|
1394
|
+
var ChevronDownIcon = ({ className }) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1395
|
+
"svg",
|
|
1396
|
+
{
|
|
1397
|
+
className,
|
|
1398
|
+
viewBox: "0 0 24 24",
|
|
1399
|
+
fill: "none",
|
|
1400
|
+
stroke: "currentColor",
|
|
1401
|
+
strokeWidth: "2.5",
|
|
1402
|
+
strokeLinecap: "round",
|
|
1403
|
+
strokeLinejoin: "round",
|
|
1404
|
+
"aria-hidden": "true",
|
|
1405
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M6 9l6 6 6-6" })
|
|
1406
|
+
}
|
|
1407
|
+
);
|
|
1408
|
+
var CheckIcon = ({ className }) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1409
|
+
"svg",
|
|
1410
|
+
{
|
|
1411
|
+
className,
|
|
1412
|
+
viewBox: "0 0 24 24",
|
|
1413
|
+
fill: "none",
|
|
1414
|
+
stroke: "currentColor",
|
|
1415
|
+
strokeWidth: "3",
|
|
1416
|
+
strokeLinecap: "round",
|
|
1417
|
+
strokeLinejoin: "round",
|
|
1418
|
+
"aria-hidden": "true",
|
|
1419
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M20 6L9 17l-5-5" })
|
|
1420
|
+
}
|
|
1421
|
+
);
|
|
1422
|
+
var SearchIcon2 = ({ className }) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1423
|
+
"svg",
|
|
1424
|
+
{
|
|
1425
|
+
className,
|
|
1426
|
+
viewBox: "0 0 24 24",
|
|
1427
|
+
fill: "none",
|
|
1428
|
+
stroke: "currentColor",
|
|
1429
|
+
strokeWidth: "2.5",
|
|
1430
|
+
strokeLinecap: "round",
|
|
1431
|
+
"aria-hidden": "true",
|
|
1432
|
+
children: [
|
|
1433
|
+
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "11", cy: "11", r: "7" }),
|
|
1434
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M20 20l-3.5-3.5" })
|
|
1435
|
+
]
|
|
1436
|
+
}
|
|
1437
|
+
);
|
|
1438
|
+
var ClearIcon = ({ className }) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1439
|
+
"svg",
|
|
1440
|
+
{
|
|
1441
|
+
className,
|
|
1442
|
+
viewBox: "0 0 24 24",
|
|
1443
|
+
fill: "none",
|
|
1444
|
+
stroke: "currentColor",
|
|
1445
|
+
strokeWidth: "2.5",
|
|
1446
|
+
strokeLinecap: "round",
|
|
1447
|
+
"aria-hidden": "true",
|
|
1448
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M18 6L6 18M6 6l12 12" })
|
|
1449
|
+
}
|
|
1450
|
+
);
|
|
1451
|
+
var SpinnerIcon = ({ className }) => /* @__PURE__ */ jsxRuntime.jsxs("svg", { className: cn("animate-spin", className), viewBox: "0 0 24 24", fill: "none", "aria-hidden": "true", children: [
|
|
1452
|
+
/* @__PURE__ */ jsxRuntime.jsx("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "3" }),
|
|
1453
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { className: "opacity-75", fill: "currentColor", d: "M4 12a8 8 0 018-8v4a4 4 0 00-4 4H4z" })
|
|
1454
|
+
] });
|
|
1455
|
+
function groupOptions(options) {
|
|
1456
|
+
const groups = [];
|
|
1457
|
+
const byName = /* @__PURE__ */ new Map();
|
|
1458
|
+
for (const option of options) {
|
|
1459
|
+
const key = option.group ?? "";
|
|
1460
|
+
let bucket = byName.get(key);
|
|
1461
|
+
if (!bucket) {
|
|
1462
|
+
bucket = { group: option.group, items: [], offset: 0 };
|
|
1463
|
+
byName.set(key, bucket);
|
|
1464
|
+
groups.push(bucket);
|
|
1465
|
+
}
|
|
1466
|
+
bucket.items.push(option);
|
|
1467
|
+
}
|
|
1468
|
+
let offset = 0;
|
|
1469
|
+
for (const bucket of groups) {
|
|
1470
|
+
bucket.offset = offset;
|
|
1471
|
+
offset += bucket.items.length;
|
|
1472
|
+
}
|
|
1473
|
+
return groups;
|
|
1474
|
+
}
|
|
1475
|
+
function nextEnabledIndex(options, from, dir) {
|
|
1476
|
+
const n = options.length;
|
|
1477
|
+
if (n === 0) return -1;
|
|
1478
|
+
let i = from < 0 ? dir === 1 ? -1 : 0 : from;
|
|
1479
|
+
for (let step = 0; step < n; step++) {
|
|
1480
|
+
i = (i + dir + n) % n;
|
|
1481
|
+
if (!options[i].disabled) return i;
|
|
1482
|
+
}
|
|
1483
|
+
return -1;
|
|
1484
|
+
}
|
|
1485
|
+
function defaultFilter(option, query) {
|
|
1486
|
+
const q = query.trim().toLowerCase();
|
|
1487
|
+
if (!q) return true;
|
|
1488
|
+
return option.label.toLowerCase().includes(q) || (option.description?.toLowerCase().includes(q) ?? false) || String(option.value).toLowerCase().includes(q);
|
|
1489
|
+
}
|
|
1490
|
+
var Select = React3__default.default.forwardRef(function Select2({
|
|
1491
|
+
options,
|
|
1492
|
+
value: controlledValue,
|
|
1493
|
+
defaultValue = null,
|
|
1494
|
+
onChange,
|
|
1495
|
+
placeholder = "Pilih\u2026",
|
|
1496
|
+
label,
|
|
1497
|
+
hint,
|
|
1498
|
+
error,
|
|
1499
|
+
size = "md",
|
|
1500
|
+
disabled = false,
|
|
1501
|
+
clearable = false,
|
|
1502
|
+
name,
|
|
1503
|
+
align = "start",
|
|
1504
|
+
maxHeight = 280,
|
|
1505
|
+
emptyText = "Tidak ada pilihan",
|
|
1506
|
+
containerClassName,
|
|
1507
|
+
panelClassName,
|
|
1508
|
+
onOpenChange,
|
|
1509
|
+
renderOption,
|
|
1510
|
+
searchable = false,
|
|
1511
|
+
searchPlaceholder = "Cari\u2026",
|
|
1512
|
+
filter = defaultFilter,
|
|
1513
|
+
onSearchChange,
|
|
1514
|
+
manualFilter = false,
|
|
1515
|
+
loading = false,
|
|
1516
|
+
loadingText = "Memuat\u2026",
|
|
1517
|
+
className,
|
|
1518
|
+
id,
|
|
1519
|
+
...props
|
|
1520
|
+
}, ref) {
|
|
1521
|
+
const reactId = React3__default.default.useId();
|
|
1522
|
+
const uid = id ?? `avt-select-${reactId}`;
|
|
1523
|
+
const listboxId = `${uid}-listbox`;
|
|
1524
|
+
const labelId = `${uid}-label`;
|
|
1525
|
+
const [open, setOpen] = React3.useState(false);
|
|
1526
|
+
const [query, setQuery] = React3.useState("");
|
|
1527
|
+
const [activeIndex, setActiveIndex] = React3.useState(-1);
|
|
1528
|
+
const [internalValue, setInternalValue] = React3.useState(defaultValue);
|
|
1529
|
+
const triggerRef = React3.useRef(null);
|
|
1530
|
+
const panelRef = React3.useRef(null);
|
|
1531
|
+
const listRef = React3.useRef(null);
|
|
1532
|
+
const typeahead = React3.useRef({ text: "", at: 0 });
|
|
1533
|
+
const focusOnMount = React3.useCallback((el) => {
|
|
1534
|
+
el?.focus();
|
|
1535
|
+
}, []);
|
|
1536
|
+
React3__default.default.useImperativeHandle(ref, () => triggerRef.current, []);
|
|
1537
|
+
const isControlled = controlledValue !== void 0;
|
|
1538
|
+
const value = isControlled ? controlledValue : internalValue;
|
|
1539
|
+
const selected = React3.useMemo(
|
|
1540
|
+
() => value == null ? null : options.find((o) => o.value === value) ?? null,
|
|
1541
|
+
[options, value]
|
|
1542
|
+
);
|
|
1543
|
+
const visible = React3.useMemo(() => {
|
|
1544
|
+
if (!searchable || manualFilter || !query.trim()) return options;
|
|
1545
|
+
return options.filter((o) => filter(o, query));
|
|
1546
|
+
}, [options, searchable, manualFilter, query, filter]);
|
|
1547
|
+
const groups = React3.useMemo(() => groupOptions(visible), [visible]);
|
|
1548
|
+
const flat = React3.useMemo(() => groups.flatMap((g) => g.items), [groups]);
|
|
1549
|
+
const changeOpen = React3.useCallback(
|
|
1550
|
+
(next) => {
|
|
1551
|
+
setOpen(next);
|
|
1552
|
+
onOpenChange?.(next);
|
|
1553
|
+
},
|
|
1554
|
+
[onOpenChange]
|
|
1555
|
+
);
|
|
1556
|
+
const dismiss = React3.useCallback(() => {
|
|
1557
|
+
changeOpen(false);
|
|
1558
|
+
triggerRef.current?.focus();
|
|
1559
|
+
}, [changeOpen]);
|
|
1560
|
+
useEscapeDismiss(open, dismiss);
|
|
1561
|
+
React3.useEffect(() => {
|
|
1562
|
+
if (!open) return;
|
|
1563
|
+
const handler = (e) => {
|
|
1564
|
+
const target = e.target;
|
|
1565
|
+
if (triggerRef.current?.contains(target)) return;
|
|
1566
|
+
if (panelRef.current?.contains(target)) return;
|
|
1567
|
+
changeOpen(false);
|
|
1568
|
+
};
|
|
1569
|
+
document.addEventListener("mousedown", handler, true);
|
|
1570
|
+
document.addEventListener("touchstart", handler, true);
|
|
1571
|
+
return () => {
|
|
1572
|
+
document.removeEventListener("mousedown", handler, true);
|
|
1573
|
+
document.removeEventListener("touchstart", handler, true);
|
|
1574
|
+
};
|
|
1575
|
+
}, [open, changeOpen]);
|
|
1576
|
+
React3.useEffect(() => {
|
|
1577
|
+
if (!open) setQuery("");
|
|
1578
|
+
}, [open]);
|
|
1579
|
+
React3.useEffect(() => {
|
|
1580
|
+
if (!open) {
|
|
1581
|
+
setActiveIndex(-1);
|
|
1582
|
+
return;
|
|
1583
|
+
}
|
|
1584
|
+
const pick = flat.findIndex((o) => value != null && o.value === value && !o.disabled);
|
|
1585
|
+
setActiveIndex(pick >= 0 ? pick : nextEnabledIndex(flat, -1, 1));
|
|
1586
|
+
}, [open, query]);
|
|
1587
|
+
React3.useEffect(() => {
|
|
1588
|
+
if (!open || activeIndex < 0) return;
|
|
1589
|
+
listRef.current?.querySelector(`[data-index="${activeIndex}"]`)?.scrollIntoView({ block: "nearest" });
|
|
1590
|
+
}, [open, activeIndex]);
|
|
1591
|
+
const commit = React3.useCallback(
|
|
1592
|
+
(option) => {
|
|
1593
|
+
if (option.disabled) return;
|
|
1594
|
+
if (!isControlled) setInternalValue(option.value);
|
|
1595
|
+
onChange?.(option.value, option);
|
|
1596
|
+
changeOpen(false);
|
|
1597
|
+
triggerRef.current?.focus();
|
|
1598
|
+
},
|
|
1599
|
+
[isControlled, onChange, changeOpen]
|
|
1600
|
+
);
|
|
1601
|
+
const clear = React3.useCallback(
|
|
1602
|
+
(e) => {
|
|
1603
|
+
e.stopPropagation();
|
|
1604
|
+
if (!isControlled) setInternalValue(null);
|
|
1605
|
+
onChange?.(null, null);
|
|
1606
|
+
},
|
|
1607
|
+
[isControlled, onChange]
|
|
1608
|
+
);
|
|
1609
|
+
const move = React3.useCallback(
|
|
1610
|
+
(dir) => setActiveIndex((i) => nextEnabledIndex(flat, i, dir)),
|
|
1611
|
+
[flat]
|
|
1612
|
+
);
|
|
1613
|
+
const runTypeahead = React3.useCallback(
|
|
1614
|
+
(char) => {
|
|
1615
|
+
const now = Date.now();
|
|
1616
|
+
const text = now - typeahead.current.at > 600 ? char : typeahead.current.text + char;
|
|
1617
|
+
typeahead.current = { text, at: now };
|
|
1618
|
+
const q = text.toLowerCase();
|
|
1619
|
+
const hit = flat.findIndex((o) => !o.disabled && o.label.toLowerCase().startsWith(q));
|
|
1620
|
+
if (hit >= 0) setActiveIndex(hit);
|
|
1621
|
+
},
|
|
1622
|
+
[flat]
|
|
1623
|
+
);
|
|
1624
|
+
const onNavKeyDown = React3.useCallback(
|
|
1625
|
+
(e) => {
|
|
1626
|
+
switch (e.key) {
|
|
1627
|
+
case "ArrowDown":
|
|
1628
|
+
e.preventDefault();
|
|
1629
|
+
move(1);
|
|
1630
|
+
return;
|
|
1631
|
+
case "ArrowUp":
|
|
1632
|
+
e.preventDefault();
|
|
1633
|
+
move(-1);
|
|
1634
|
+
return;
|
|
1635
|
+
case "Home":
|
|
1636
|
+
e.preventDefault();
|
|
1637
|
+
setActiveIndex(nextEnabledIndex(flat, -1, 1));
|
|
1638
|
+
return;
|
|
1639
|
+
case "End":
|
|
1640
|
+
e.preventDefault();
|
|
1641
|
+
setActiveIndex(nextEnabledIndex(flat, 0, -1));
|
|
1642
|
+
return;
|
|
1643
|
+
case "Enter":
|
|
1644
|
+
e.preventDefault();
|
|
1645
|
+
if (activeIndex >= 0 && flat[activeIndex]) commit(flat[activeIndex]);
|
|
1646
|
+
return;
|
|
1647
|
+
case "Tab":
|
|
1648
|
+
changeOpen(false);
|
|
1649
|
+
return;
|
|
1650
|
+
}
|
|
1651
|
+
},
|
|
1652
|
+
[move, flat, activeIndex, commit, changeOpen]
|
|
1653
|
+
);
|
|
1654
|
+
const onTriggerKeyDown = (e) => {
|
|
1655
|
+
if (disabled) return;
|
|
1656
|
+
if (!open) {
|
|
1657
|
+
if (e.key === "ArrowDown" || e.key === "ArrowUp" || e.key === "Enter" || e.key === " ") {
|
|
1658
|
+
e.preventDefault();
|
|
1659
|
+
changeOpen(true);
|
|
1660
|
+
}
|
|
1661
|
+
return;
|
|
1662
|
+
}
|
|
1663
|
+
if (e.key === " " && !searchable) {
|
|
1664
|
+
e.preventDefault();
|
|
1665
|
+
if (activeIndex >= 0 && flat[activeIndex]) commit(flat[activeIndex]);
|
|
1666
|
+
return;
|
|
1667
|
+
}
|
|
1668
|
+
onNavKeyDown(e);
|
|
1669
|
+
if (!searchable && e.key.length === 1 && !e.metaKey && !e.ctrlKey && !e.altKey) {
|
|
1670
|
+
runTypeahead(e.key);
|
|
1671
|
+
}
|
|
1672
|
+
};
|
|
1673
|
+
const showClear = clearable && selected != null && !disabled;
|
|
1674
|
+
const activeId = open && activeIndex >= 0 ? `${uid}-opt-${activeIndex}` : void 0;
|
|
1675
|
+
const comboProps = searchable ? { "aria-haspopup": "listbox" } : {
|
|
1676
|
+
role: "combobox",
|
|
1677
|
+
"aria-controls": open ? listboxId : void 0,
|
|
1678
|
+
"aria-activedescendant": activeId,
|
|
1679
|
+
"aria-haspopup": "listbox"
|
|
1680
|
+
};
|
|
1681
|
+
const pos = useAnchoredPosition(triggerRef, open, {
|
|
1682
|
+
align,
|
|
1683
|
+
matchWidth: true,
|
|
1684
|
+
maxHeight
|
|
1685
|
+
});
|
|
1686
|
+
const panel = open && pos && typeof document !== "undefined" ? reactDom.createPortal(
|
|
1687
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1688
|
+
"div",
|
|
1689
|
+
{
|
|
1690
|
+
ref: panelRef,
|
|
1691
|
+
className: cn(panelBase, panelClassName),
|
|
1692
|
+
style: {
|
|
1693
|
+
top: pos.top,
|
|
1694
|
+
left: pos.left,
|
|
1695
|
+
width: pos.width,
|
|
1696
|
+
maxHeight: pos.maxHeight
|
|
1697
|
+
},
|
|
1698
|
+
children: [
|
|
1699
|
+
searchable && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex items-center border-b border-[#F2F2F7] px-3", children: [
|
|
1700
|
+
/* @__PURE__ */ jsxRuntime.jsx(SearchIcon2, { className: "pointer-events-none absolute left-3 h-3.5 w-3.5 text-[#8E8E93]" }),
|
|
1701
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1702
|
+
"input",
|
|
1703
|
+
{
|
|
1704
|
+
ref: focusOnMount,
|
|
1705
|
+
type: "text",
|
|
1706
|
+
role: "combobox",
|
|
1707
|
+
"aria-expanded": true,
|
|
1708
|
+
"aria-controls": listboxId,
|
|
1709
|
+
"aria-activedescendant": activeId,
|
|
1710
|
+
"aria-autocomplete": "list",
|
|
1711
|
+
"aria-label": searchPlaceholder,
|
|
1712
|
+
autoComplete: "off",
|
|
1713
|
+
spellCheck: false,
|
|
1714
|
+
value: query,
|
|
1715
|
+
placeholder: searchPlaceholder,
|
|
1716
|
+
onChange: (e) => {
|
|
1717
|
+
setQuery(e.target.value);
|
|
1718
|
+
onSearchChange?.(e.target.value);
|
|
1719
|
+
},
|
|
1720
|
+
onKeyDown: onNavKeyDown,
|
|
1721
|
+
className: cn(
|
|
1722
|
+
"h-10 w-full border-0 bg-transparent pl-6 pr-2 text-[13px] text-[#1C1C1E]",
|
|
1723
|
+
"outline-none placeholder:text-[#8E8E93]"
|
|
1724
|
+
)
|
|
1725
|
+
}
|
|
1726
|
+
),
|
|
1727
|
+
loading && /* @__PURE__ */ jsxRuntime.jsx(SpinnerIcon, { className: "absolute right-3 h-3.5 w-3.5 text-[#8E8E93]" })
|
|
1728
|
+
] }),
|
|
1729
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1730
|
+
"div",
|
|
1731
|
+
{
|
|
1732
|
+
ref: listRef,
|
|
1733
|
+
id: listboxId,
|
|
1734
|
+
role: "listbox",
|
|
1735
|
+
"aria-labelledby": label ? labelId : void 0,
|
|
1736
|
+
className: "avt-scroll min-h-0 flex-1 overflow-y-auto py-1.5",
|
|
1737
|
+
children: flat.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-3.5 py-6 text-center text-[13px] text-[#8E8E93]", children: loading ? loadingText : emptyText }) : groups.map((group) => /* @__PURE__ */ jsxRuntime.jsxs("div", { role: "group", "aria-label": group.group, children: [
|
|
1738
|
+
group.group && /* @__PURE__ */ jsxRuntime.jsx("div", { className: groupLabelClass, children: group.group }),
|
|
1739
|
+
group.items.map((option, i) => {
|
|
1740
|
+
const index = group.offset + i;
|
|
1741
|
+
const state = {
|
|
1742
|
+
selected: value != null && option.value === value,
|
|
1743
|
+
active: index === activeIndex
|
|
1744
|
+
};
|
|
1745
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1746
|
+
"div",
|
|
1747
|
+
{
|
|
1748
|
+
id: `${uid}-opt-${index}`,
|
|
1749
|
+
"data-index": index,
|
|
1750
|
+
role: "option",
|
|
1751
|
+
"aria-selected": state.selected,
|
|
1752
|
+
"aria-disabled": option.disabled || void 0,
|
|
1753
|
+
className: optionRowClass({
|
|
1754
|
+
...state,
|
|
1755
|
+
disabled: option.disabled
|
|
1756
|
+
}),
|
|
1757
|
+
onMouseEnter: () => !option.disabled && setActiveIndex(index),
|
|
1758
|
+
onClick: () => commit(option),
|
|
1759
|
+
children: renderOption ? renderOption(option, state) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1760
|
+
option.icon && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-shrink-0 text-[#8E8E93]", children: option.icon }),
|
|
1761
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "min-w-0 flex-1", children: [
|
|
1762
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "block truncate", children: option.label }),
|
|
1763
|
+
option.description && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "block truncate text-[11px] font-normal text-[#8E8E93]", children: option.description })
|
|
1764
|
+
] }),
|
|
1765
|
+
state.selected && /* @__PURE__ */ jsxRuntime.jsx(CheckIcon, { className: "h-4 w-4 flex-shrink-0 text-[#007AFF]" })
|
|
1766
|
+
] })
|
|
1767
|
+
},
|
|
1768
|
+
option.value
|
|
1769
|
+
);
|
|
1770
|
+
})
|
|
1771
|
+
] }, group.group ?? "__default"))
|
|
1772
|
+
}
|
|
1773
|
+
)
|
|
1774
|
+
]
|
|
1775
|
+
}
|
|
1776
|
+
),
|
|
1777
|
+
document.body
|
|
1778
|
+
) : null;
|
|
1779
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex flex-col gap-1.5", containerClassName), ...props, children: [
|
|
1780
|
+
label && /* @__PURE__ */ jsxRuntime.jsx("label", { id: labelId, htmlFor: uid, className: "text-[13px] font-medium text-[#3C3C43]", children: label }),
|
|
1781
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
|
|
1782
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1783
|
+
"button",
|
|
1784
|
+
{
|
|
1785
|
+
ref: triggerRef,
|
|
1786
|
+
id: uid,
|
|
1787
|
+
type: "button",
|
|
1788
|
+
disabled,
|
|
1789
|
+
"aria-expanded": open,
|
|
1790
|
+
"aria-invalid": error ? true : void 0,
|
|
1791
|
+
className: cn(
|
|
1792
|
+
triggerBase,
|
|
1793
|
+
triggerSizes[size],
|
|
1794
|
+
"pr-9",
|
|
1795
|
+
showClear && "pr-14",
|
|
1796
|
+
error && "bg-[#FF3B30]/6 focus-visible:shadow-[0_0_0_2px_rgba(255,59,48,0.22)]",
|
|
1797
|
+
open && "bg-white shadow-[0_0_0_2px_rgba(0,122,255,0.22)]",
|
|
1798
|
+
className
|
|
1799
|
+
),
|
|
1800
|
+
onClick: () => changeOpen(!open),
|
|
1801
|
+
onKeyDown: onTriggerKeyDown,
|
|
1802
|
+
...comboProps,
|
|
1803
|
+
children: [
|
|
1804
|
+
selected?.icon && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-shrink-0 text-[#8E8E93]", children: selected.icon }),
|
|
1805
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("flex-1 truncate", !selected && "text-[#8E8E93]"), children: selected ? selected.label : placeholder }),
|
|
1806
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1807
|
+
ChevronDownIcon,
|
|
1808
|
+
{
|
|
1809
|
+
className: cn(
|
|
1810
|
+
"absolute right-3.5 h-4 w-4 flex-shrink-0 text-[#8E8E93]",
|
|
1811
|
+
"transition-transform duration-150",
|
|
1812
|
+
open && "rotate-180"
|
|
1813
|
+
)
|
|
1814
|
+
}
|
|
1815
|
+
)
|
|
1816
|
+
]
|
|
1817
|
+
}
|
|
1818
|
+
),
|
|
1819
|
+
showClear && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1820
|
+
"button",
|
|
1821
|
+
{
|
|
1822
|
+
type: "button",
|
|
1823
|
+
tabIndex: -1,
|
|
1824
|
+
"aria-label": "Hapus pilihan",
|
|
1825
|
+
onClick: clear,
|
|
1826
|
+
className: cn(
|
|
1827
|
+
"absolute right-8 top-1/2 flex h-5 w-5 -translate-y-1/2 items-center justify-center",
|
|
1828
|
+
"rounded-full bg-[#E5E5EA] text-[#8E8E93] transition-colors duration-150",
|
|
1829
|
+
"hover:bg-[#D1D1D6] hover:text-[#1C1C1E]"
|
|
1830
|
+
),
|
|
1831
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(ClearIcon, { className: "h-2.5 w-2.5" })
|
|
1832
|
+
}
|
|
1833
|
+
)
|
|
1834
|
+
] }),
|
|
1835
|
+
name && /* @__PURE__ */ jsxRuntime.jsx("input", { type: "hidden", name, value: value ?? "", readOnly: true }),
|
|
1836
|
+
error ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-[#FF3B30]", children: error }) : hint ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-[#8E8E93]", children: hint }) : null,
|
|
1837
|
+
panel
|
|
1838
|
+
] });
|
|
1839
|
+
});
|
|
1840
|
+
Select.displayName = "Select";
|
|
1841
|
+
var SelectSearch = React3__default.default.forwardRef(
|
|
1842
|
+
function SelectSearch2(props, ref) {
|
|
1843
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Select, { ref, searchable: true, ...props });
|
|
1844
|
+
}
|
|
1845
|
+
);
|
|
1846
|
+
SelectSearch.displayName = "SelectSearch";
|
|
1847
|
+
var FOCUSABLE = [
|
|
1848
|
+
"a[href]",
|
|
1849
|
+
"button:not([disabled])",
|
|
1850
|
+
"input:not([disabled])",
|
|
1851
|
+
"select:not([disabled])",
|
|
1852
|
+
"textarea:not([disabled])",
|
|
1853
|
+
'[tabindex]:not([tabindex="-1"])'
|
|
1854
|
+
].join(",");
|
|
1855
|
+
function useFocusTrap(containerRef, enabled = true, initialFocusRef) {
|
|
1856
|
+
React3.useEffect(() => {
|
|
1857
|
+
if (!enabled) return;
|
|
1858
|
+
const container = containerRef.current;
|
|
1859
|
+
if (!container) return;
|
|
1860
|
+
const previouslyFocused = document.activeElement;
|
|
1861
|
+
const focusables = () => Array.from(container.querySelectorAll(FOCUSABLE)).filter(
|
|
1862
|
+
(el) => el.getClientRects().length > 0
|
|
1863
|
+
);
|
|
1864
|
+
const raf = requestAnimationFrame(() => {
|
|
1865
|
+
const target = initialFocusRef?.current ?? focusables()[0] ?? container;
|
|
1866
|
+
target.focus();
|
|
1867
|
+
});
|
|
1868
|
+
const onKeyDown = (e) => {
|
|
1869
|
+
if (e.key !== "Tab") return;
|
|
1870
|
+
const items = focusables();
|
|
1871
|
+
if (items.length === 0) {
|
|
1872
|
+
e.preventDefault();
|
|
1873
|
+
return;
|
|
1874
|
+
}
|
|
1875
|
+
const first = items[0];
|
|
1876
|
+
const last = items[items.length - 1];
|
|
1877
|
+
const active = document.activeElement;
|
|
1878
|
+
const inside = container.contains(active);
|
|
1879
|
+
if (e.shiftKey) {
|
|
1880
|
+
if (active === first || !inside) {
|
|
1881
|
+
e.preventDefault();
|
|
1882
|
+
last.focus();
|
|
1883
|
+
}
|
|
1884
|
+
} else if (active === last || !inside) {
|
|
1885
|
+
e.preventDefault();
|
|
1886
|
+
first.focus();
|
|
1887
|
+
}
|
|
1888
|
+
};
|
|
1889
|
+
document.addEventListener("keydown", onKeyDown);
|
|
1890
|
+
return () => {
|
|
1891
|
+
cancelAnimationFrame(raf);
|
|
1892
|
+
document.removeEventListener("keydown", onKeyDown);
|
|
1893
|
+
previouslyFocused?.focus?.();
|
|
1894
|
+
};
|
|
1895
|
+
}, [containerRef, enabled, initialFocusRef]);
|
|
1896
|
+
}
|
|
1897
|
+
var sizes2 = {
|
|
1898
|
+
sm: "max-w-sm",
|
|
1899
|
+
md: "max-w-md",
|
|
1900
|
+
lg: "max-w-lg",
|
|
1901
|
+
xl: "max-w-2xl",
|
|
1902
|
+
full: "max-w-[calc(100vw-2rem)]"
|
|
1903
|
+
};
|
|
1904
|
+
var lockCount = 0;
|
|
1905
|
+
var previousOverflow = "";
|
|
1906
|
+
function useBodyScrollLock(enabled) {
|
|
1907
|
+
React3.useEffect(() => {
|
|
1908
|
+
if (!enabled) return;
|
|
1909
|
+
if (lockCount === 0) {
|
|
1910
|
+
previousOverflow = document.body.style.overflow;
|
|
1911
|
+
document.body.style.overflow = "hidden";
|
|
1912
|
+
}
|
|
1913
|
+
lockCount++;
|
|
1914
|
+
return () => {
|
|
1915
|
+
lockCount--;
|
|
1916
|
+
if (lockCount === 0) document.body.style.overflow = previousOverflow;
|
|
1917
|
+
};
|
|
1918
|
+
}, [enabled]);
|
|
1919
|
+
}
|
|
1920
|
+
function Modal({
|
|
1921
|
+
open,
|
|
1922
|
+
onClose,
|
|
1923
|
+
title,
|
|
1924
|
+
description,
|
|
1925
|
+
footer,
|
|
1926
|
+
size = "md",
|
|
1927
|
+
closeOnOverlay = true,
|
|
1928
|
+
closeOnEscape = true,
|
|
1929
|
+
showClose = true,
|
|
1930
|
+
initialFocusRef,
|
|
1931
|
+
overlayClassName,
|
|
1932
|
+
bodyClassName,
|
|
1933
|
+
role = "dialog",
|
|
1934
|
+
className,
|
|
1935
|
+
children,
|
|
1936
|
+
...props
|
|
1937
|
+
}) {
|
|
1938
|
+
const reactId = React3__default.default.useId();
|
|
1939
|
+
const titleId = `avt-modal-${reactId}-title`;
|
|
1940
|
+
const descId = `avt-modal-${reactId}-desc`;
|
|
1941
|
+
const panelRef = React3.useRef(null);
|
|
1942
|
+
useEscapeDismiss(open && closeOnEscape, onClose);
|
|
1943
|
+
useBodyScrollLock(open);
|
|
1944
|
+
useFocusTrap(panelRef, open, initialFocusRef);
|
|
1945
|
+
if (!open || typeof document === "undefined") return null;
|
|
1946
|
+
const hasHeader = Boolean(title || description || showClose);
|
|
1947
|
+
return reactDom.createPortal(
|
|
1948
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "fixed inset-0 z-[1000] flex items-center justify-center p-4 sm:p-6", children: [
|
|
1949
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1950
|
+
"div",
|
|
1951
|
+
{
|
|
1952
|
+
className: cn(
|
|
1953
|
+
"avt-animate-fade-in absolute inset-0 bg-black/30 backdrop-blur-[2px]",
|
|
1954
|
+
overlayClassName
|
|
1955
|
+
),
|
|
1956
|
+
onClick: closeOnOverlay ? onClose : void 0,
|
|
1957
|
+
"aria-hidden": "true"
|
|
1958
|
+
}
|
|
1959
|
+
),
|
|
1960
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1961
|
+
"div",
|
|
1962
|
+
{
|
|
1963
|
+
ref: panelRef,
|
|
1964
|
+
role,
|
|
1965
|
+
"aria-modal": "true",
|
|
1966
|
+
"aria-labelledby": title ? titleId : void 0,
|
|
1967
|
+
"aria-describedby": description ? descId : void 0,
|
|
1968
|
+
tabIndex: -1,
|
|
1969
|
+
className: cn(
|
|
1970
|
+
"avt-animate-modal relative z-10 flex w-full flex-col overflow-hidden outline-none",
|
|
1971
|
+
"rounded-2xl bg-white/95 backdrop-blur-2xl",
|
|
1972
|
+
"border border-[#E5E5EA]/60 shadow-[0_16px_48px_rgba(0,0,0,0.16)]",
|
|
1973
|
+
"max-h-[calc(100vh-2rem)]",
|
|
1974
|
+
sizes2[size],
|
|
1975
|
+
className
|
|
1976
|
+
),
|
|
1977
|
+
...props,
|
|
1978
|
+
children: [
|
|
1979
|
+
hasHeader && /* @__PURE__ */ jsxRuntime.jsxs(ModalHeader, { showClose, onClose, children: [
|
|
1980
|
+
title && /* @__PURE__ */ jsxRuntime.jsx(ModalTitle, { id: titleId, children: title }),
|
|
1981
|
+
description && /* @__PURE__ */ jsxRuntime.jsx(ModalDescription, { id: descId, children: description })
|
|
1982
|
+
] }),
|
|
1983
|
+
/* @__PURE__ */ jsxRuntime.jsx(ModalBody, { className: bodyClassName, children }),
|
|
1984
|
+
footer && /* @__PURE__ */ jsxRuntime.jsx(ModalFooter, { children: footer })
|
|
1985
|
+
]
|
|
1986
|
+
}
|
|
1987
|
+
)
|
|
1988
|
+
] }),
|
|
1989
|
+
document.body
|
|
1990
|
+
);
|
|
1991
|
+
}
|
|
1992
|
+
function ModalHeader({
|
|
1993
|
+
showClose,
|
|
1994
|
+
onClose,
|
|
1995
|
+
className,
|
|
1996
|
+
children,
|
|
1997
|
+
...props
|
|
1998
|
+
}) {
|
|
1999
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2000
|
+
"div",
|
|
2001
|
+
{
|
|
2002
|
+
className: cn(
|
|
2003
|
+
"flex items-start justify-between border-b border-[#F2F2F7] px-6 pb-4 pt-6",
|
|
2004
|
+
className
|
|
2005
|
+
),
|
|
2006
|
+
...props,
|
|
2007
|
+
children: [
|
|
2008
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-w-0 flex-1 pr-3", children }),
|
|
2009
|
+
showClose && onClose && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2010
|
+
"button",
|
|
2011
|
+
{
|
|
2012
|
+
type: "button",
|
|
2013
|
+
onClick: onClose,
|
|
2014
|
+
"aria-label": "Tutup",
|
|
2015
|
+
className: cn(
|
|
2016
|
+
"flex h-7 w-7 flex-shrink-0 items-center justify-center rounded-full",
|
|
2017
|
+
"bg-[#F2F2F7] text-[#8E8E93] hover:bg-[#E5E5EA] hover:text-[#1C1C1E]",
|
|
2018
|
+
"transition-colors duration-150",
|
|
2019
|
+
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[#007AFF]/40"
|
|
2020
|
+
),
|
|
2021
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2022
|
+
"svg",
|
|
2023
|
+
{
|
|
2024
|
+
className: "h-3.5 w-3.5",
|
|
2025
|
+
viewBox: "0 0 24 24",
|
|
2026
|
+
fill: "none",
|
|
2027
|
+
stroke: "currentColor",
|
|
2028
|
+
strokeWidth: "2.5",
|
|
2029
|
+
strokeLinecap: "round",
|
|
2030
|
+
"aria-hidden": "true",
|
|
2031
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M18 6L6 18M6 6l12 12" })
|
|
2032
|
+
}
|
|
2033
|
+
)
|
|
2034
|
+
}
|
|
2035
|
+
)
|
|
2036
|
+
]
|
|
2037
|
+
}
|
|
2038
|
+
);
|
|
2039
|
+
}
|
|
2040
|
+
function ModalTitle({ className, ...props }) {
|
|
2041
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2042
|
+
"h2",
|
|
2043
|
+
{
|
|
2044
|
+
className: cn("text-[15px] font-semibold tracking-[-0.01em] text-[#1C1C1E]", className),
|
|
2045
|
+
...props
|
|
2046
|
+
}
|
|
2047
|
+
);
|
|
2048
|
+
}
|
|
2049
|
+
function ModalDescription({
|
|
2050
|
+
className,
|
|
2051
|
+
...props
|
|
2052
|
+
}) {
|
|
2053
|
+
return /* @__PURE__ */ jsxRuntime.jsx("p", { className: cn("mt-0.5 text-[13px] text-[#8E8E93]", className), ...props });
|
|
2054
|
+
}
|
|
2055
|
+
function ModalBody({ className, ...props }) {
|
|
2056
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("avt-scroll flex-1 overflow-y-auto px-6 py-5", className), ...props });
|
|
2057
|
+
}
|
|
2058
|
+
function ModalFooter({ className, ...props }) {
|
|
2059
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2060
|
+
"div",
|
|
2061
|
+
{
|
|
2062
|
+
className: cn(
|
|
2063
|
+
"flex items-center justify-end gap-2 px-6 py-4",
|
|
2064
|
+
"border-t border-[#F2F2F7] bg-[#FAFAFA]",
|
|
2065
|
+
className
|
|
2066
|
+
),
|
|
2067
|
+
...props
|
|
2068
|
+
}
|
|
2069
|
+
);
|
|
2070
|
+
}
|
|
2071
|
+
var accents = {
|
|
2072
|
+
info: { bg: "bg-[#007AFF]/10", fg: "text-[#007AFF]", confirm: "primary" },
|
|
2073
|
+
success: { bg: "bg-[#34C759]/10", fg: "text-[#34C759]", confirm: "primary" },
|
|
2074
|
+
warning: { bg: "bg-[#FF9500]/10", fg: "text-[#FF9500]", confirm: "primary" },
|
|
2075
|
+
danger: {
|
|
2076
|
+
bg: "bg-[#FF3B30]/10",
|
|
2077
|
+
fg: "text-[#FF3B30]",
|
|
2078
|
+
confirm: "destructive"
|
|
2079
|
+
},
|
|
2080
|
+
question: { bg: "bg-[#5856D6]/10", fg: "text-[#5856D6]", confirm: "primary" }
|
|
2081
|
+
};
|
|
2082
|
+
var iconProps = {
|
|
2083
|
+
className: "h-5 w-5",
|
|
2084
|
+
viewBox: "0 0 24 24",
|
|
2085
|
+
fill: "none",
|
|
2086
|
+
stroke: "currentColor",
|
|
2087
|
+
strokeWidth: "2.2",
|
|
2088
|
+
strokeLinecap: "round",
|
|
2089
|
+
strokeLinejoin: "round",
|
|
2090
|
+
"aria-hidden": true
|
|
2091
|
+
};
|
|
2092
|
+
var icons = {
|
|
2093
|
+
info: /* @__PURE__ */ jsxRuntime.jsxs("svg", { ...iconProps, children: [
|
|
2094
|
+
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "12", cy: "12", r: "9" }),
|
|
2095
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 11v5M12 8h.01" })
|
|
2096
|
+
] }),
|
|
2097
|
+
success: /* @__PURE__ */ jsxRuntime.jsxs("svg", { ...iconProps, children: [
|
|
2098
|
+
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "12", cy: "12", r: "9" }),
|
|
2099
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M8.5 12.5l2.5 2.5 4.5-5" })
|
|
2100
|
+
] }),
|
|
2101
|
+
warning: /* @__PURE__ */ jsxRuntime.jsxs("svg", { ...iconProps, children: [
|
|
2102
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M10.3 4.3L2.6 17.6A2 2 0 004.3 20.6h15.4a2 2 0 001.7-3L13.7 4.3a2 2 0 00-3.4 0z" }),
|
|
2103
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 9v4M12 17h.01" })
|
|
2104
|
+
] }),
|
|
2105
|
+
danger: /* @__PURE__ */ jsxRuntime.jsxs("svg", { ...iconProps, children: [
|
|
2106
|
+
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "12", cy: "12", r: "9" }),
|
|
2107
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M15 9l-6 6M9 9l6 6" })
|
|
2108
|
+
] }),
|
|
2109
|
+
question: /* @__PURE__ */ jsxRuntime.jsxs("svg", { ...iconProps, children: [
|
|
2110
|
+
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "12", cy: "12", r: "9" }),
|
|
2111
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M9.5 9.5a2.5 2.5 0 113.4 2.3c-.6.2-.9.8-.9 1.4v.3M12 17h.01" })
|
|
2112
|
+
] })
|
|
2113
|
+
};
|
|
2114
|
+
function Dialog({
|
|
2115
|
+
open,
|
|
2116
|
+
onClose,
|
|
2117
|
+
variant = "question",
|
|
2118
|
+
title,
|
|
2119
|
+
description,
|
|
2120
|
+
confirmText = "Konfirmasi",
|
|
2121
|
+
cancelText = "Batal",
|
|
2122
|
+
onConfirm,
|
|
2123
|
+
onCancel,
|
|
2124
|
+
loading = false,
|
|
2125
|
+
closeOnConfirm = true,
|
|
2126
|
+
hideCancel = false,
|
|
2127
|
+
closeOnOverlay = true,
|
|
2128
|
+
closeOnEscape = true,
|
|
2129
|
+
size = "sm",
|
|
2130
|
+
icon,
|
|
2131
|
+
children,
|
|
2132
|
+
className
|
|
2133
|
+
}) {
|
|
2134
|
+
const reactId = React3__default.default.useId();
|
|
2135
|
+
const titleId = `avt-dialog-${reactId}-title`;
|
|
2136
|
+
const descId = `avt-dialog-${reactId}-desc`;
|
|
2137
|
+
const [busy, setBusy] = React3.useState(false);
|
|
2138
|
+
const isBusy = loading || busy;
|
|
2139
|
+
const accent = accents[variant];
|
|
2140
|
+
const handleCancel = React3.useCallback(() => {
|
|
2141
|
+
if (isBusy) return;
|
|
2142
|
+
onCancel?.();
|
|
2143
|
+
onClose();
|
|
2144
|
+
}, [isBusy, onCancel, onClose]);
|
|
2145
|
+
const handleConfirm = React3.useCallback(async () => {
|
|
2146
|
+
if (isBusy) return;
|
|
2147
|
+
if (!onConfirm) {
|
|
2148
|
+
if (closeOnConfirm) onClose();
|
|
2149
|
+
return;
|
|
2150
|
+
}
|
|
2151
|
+
setBusy(true);
|
|
2152
|
+
try {
|
|
2153
|
+
await onConfirm();
|
|
2154
|
+
if (closeOnConfirm) onClose();
|
|
2155
|
+
} catch {
|
|
2156
|
+
} finally {
|
|
2157
|
+
setBusy(false);
|
|
2158
|
+
}
|
|
2159
|
+
}, [isBusy, onConfirm, closeOnConfirm, onClose]);
|
|
2160
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2161
|
+
Modal,
|
|
2162
|
+
{
|
|
2163
|
+
open,
|
|
2164
|
+
onClose: handleCancel,
|
|
2165
|
+
role: "alertdialog",
|
|
2166
|
+
size,
|
|
2167
|
+
showClose: false,
|
|
2168
|
+
closeOnOverlay: closeOnOverlay && !isBusy,
|
|
2169
|
+
closeOnEscape: closeOnEscape && !isBusy,
|
|
2170
|
+
"aria-labelledby": titleId,
|
|
2171
|
+
"aria-describedby": description ? descId : void 0,
|
|
2172
|
+
bodyClassName: "px-6 pb-2 pt-6",
|
|
2173
|
+
className,
|
|
2174
|
+
footer: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
2175
|
+
!hideCancel && /* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "secondary", onClick: handleCancel, disabled: isBusy, children: cancelText }),
|
|
2176
|
+
/* @__PURE__ */ jsxRuntime.jsx(Button, { variant: accent.confirm, onClick: handleConfirm, loading: isBusy, children: confirmText })
|
|
2177
|
+
] }),
|
|
2178
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-4", children: [
|
|
2179
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2180
|
+
"div",
|
|
2181
|
+
{
|
|
2182
|
+
className: cn(
|
|
2183
|
+
"flex h-10 w-10 flex-shrink-0 items-center justify-center rounded-full",
|
|
2184
|
+
accent.bg,
|
|
2185
|
+
accent.fg
|
|
2186
|
+
),
|
|
2187
|
+
children: icon ?? icons[variant]
|
|
2188
|
+
}
|
|
2189
|
+
),
|
|
2190
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1 pt-0.5", children: [
|
|
2191
|
+
/* @__PURE__ */ jsxRuntime.jsx("h2", { id: titleId, className: "text-[15px] font-semibold tracking-[-0.01em] text-[#1C1C1E]", children: title }),
|
|
2192
|
+
description && /* @__PURE__ */ jsxRuntime.jsx("p", { id: descId, className: "mt-1 text-[13px] leading-relaxed text-[#8E8E93]", children: description }),
|
|
2193
|
+
children && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-3.5", children })
|
|
2194
|
+
] })
|
|
2195
|
+
] })
|
|
2196
|
+
}
|
|
2197
|
+
);
|
|
2198
|
+
}
|
|
1403
2199
|
function useClickOutside(ref, handler, enabled = true) {
|
|
1404
2200
|
React3.useEffect(() => {
|
|
1405
2201
|
if (!enabled) return;
|
|
@@ -1426,6 +2222,7 @@ exports.CardFooter = CardFooter;
|
|
|
1426
2222
|
exports.CardHeader = CardHeader;
|
|
1427
2223
|
exports.CardTitle = CardTitle;
|
|
1428
2224
|
exports.DataTable = DataTable;
|
|
2225
|
+
exports.Dialog = Dialog;
|
|
1429
2226
|
exports.Drawer = Drawer;
|
|
1430
2227
|
exports.Input = Input;
|
|
1431
2228
|
exports.Menu = MenuRoot;
|
|
@@ -1437,6 +2234,12 @@ exports.MenuLabel = MenuLabel;
|
|
|
1437
2234
|
exports.MenuRoot = MenuRoot;
|
|
1438
2235
|
exports.MenuSeparator = MenuSeparator;
|
|
1439
2236
|
exports.MenuTrigger = MenuTrigger;
|
|
2237
|
+
exports.Modal = Modal;
|
|
2238
|
+
exports.ModalBody = ModalBody;
|
|
2239
|
+
exports.ModalDescription = ModalDescription;
|
|
2240
|
+
exports.ModalFooter = ModalFooter;
|
|
2241
|
+
exports.ModalHeader = ModalHeader;
|
|
2242
|
+
exports.ModalTitle = ModalTitle;
|
|
1440
2243
|
exports.Navbar = Navbar;
|
|
1441
2244
|
exports.NavbarBrand = NavbarBrand;
|
|
1442
2245
|
exports.NavbarCenter = NavbarCenter;
|
|
@@ -1446,6 +2249,8 @@ exports.NavbarLeft = NavbarLeft;
|
|
|
1446
2249
|
exports.NavbarRight = NavbarRight;
|
|
1447
2250
|
exports.NavbarSearch = NavbarSearch;
|
|
1448
2251
|
exports.Scrollbar = Scrollbar;
|
|
2252
|
+
exports.Select = Select;
|
|
2253
|
+
exports.SelectSearch = SelectSearch;
|
|
1449
2254
|
exports.Sheet = Sheet;
|
|
1450
2255
|
exports.SheetContent = SheetContent;
|
|
1451
2256
|
exports.SheetDescription = SheetDescription;
|
|
@@ -1460,8 +2265,6 @@ exports.SidebarFooter = SidebarFooter;
|
|
|
1460
2265
|
exports.SidebarGroup = SidebarGroup;
|
|
1461
2266
|
exports.SidebarHeader = SidebarHeader;
|
|
1462
2267
|
exports.SidebarItem = SidebarItem;
|
|
1463
|
-
exports.SidebarSubMenu = SidebarSubMenu;
|
|
1464
|
-
exports.SidebarSubMenuItem = SidebarSubMenuItem;
|
|
1465
2268
|
exports.SidebarToggle = SidebarToggle;
|
|
1466
2269
|
exports.SidebarUser = SidebarUser;
|
|
1467
2270
|
exports.Table = Table;
|
|
@@ -1485,7 +2288,10 @@ exports.colors = colors;
|
|
|
1485
2288
|
exports.dismissToast = dismissToast;
|
|
1486
2289
|
exports.generateId = generateId;
|
|
1487
2290
|
exports.toast = toast;
|
|
2291
|
+
exports.useAnchoredPosition = useAnchoredPosition;
|
|
1488
2292
|
exports.useClickOutside = useClickOutside;
|
|
2293
|
+
exports.useEscapeDismiss = useEscapeDismiss;
|
|
2294
|
+
exports.useFocusTrap = useFocusTrap;
|
|
1489
2295
|
exports.useKeydown = useKeydown;
|
|
1490
2296
|
exports.useToast = useToast;
|
|
1491
2297
|
exports.withScrollbar = withScrollbar;
|