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 CHANGED
@@ -1078,8 +1078,8 @@ var useSidebar = () => React3.useContext(SidebarContext);
1078
1078
  function Sidebar({
1079
1079
  collapsed = false,
1080
1080
  glass = true,
1081
- width = "210px",
1082
- collapsedWidth = "52px",
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-2.5 px-3 py-3", collapsed && "justify-center px-0", className),
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-[12px] font-semibold tracking-[-0.01em] text-[#1C1C1E]", children: title }),
1151
- subtitle && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "truncate text-[10px] text-[#8E8E93]", children: subtitle })
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-2 my-0.5 h-px bg-[#E5E5EA]", className) });
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-1.5 py-1.5 avt-scroll space-y-px", className), ...props });
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-0.5", className), ...props, children: [
1166
- label && !collapsed && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mb-0.5 px-2.5 text-[9px] font-semibold uppercase tracking-widest text-[#C7C7CC]", children: label }),
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-lg transition-all duration-150",
1189
- "text-[12px] font-medium select-none outline-none",
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
- collapsed ? "justify-center px-0 mx-auto w-8 h-8 min-h-[36px] min-w-[36px]" : "px-2.5 py-1.5 min-h-[30px]",
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-4 min-w-4 items-center justify-center rounded-full px-1",
1204
- "text-[9px] font-bold",
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-2", className), ...props });
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-7 w-7 flex-shrink-0 items-center justify-center rounded-full",
1357
- `bg-gradient-to-br ${avatarColor} text-white text-[10px] font-semibold`
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-lg bg-[#F2F2F7] p-2", className), ...props, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
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-[11px] font-semibold text-[#1C1C1E]", children: name }),
1369
- subtitle && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "truncate text-[10px] text-[#8E8E93]", children: subtitle })
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-6 w-6 items-center justify-center rounded-md",
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-3.5 w-3.5 transition-transform duration-200", collapsed && "rotate-180"),
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;