@a13y/react 0.1.1 → 0.1.3

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.
@@ -1,4 +1,4 @@
1
- import { useState, useRef, useEffect, useCallback, useId } from 'react';
1
+ import React4, { useState, useRef, useEffect, cloneElement, useCallback, useId } from 'react';
2
2
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
3
3
 
4
4
  var useAccessibleButton = (props) => {
@@ -843,7 +843,2823 @@ var AccessibleTabs = (props) => {
843
843
  )
844
844
  ] });
845
845
  };
846
+ var idCounter = 0;
847
+ function useId2(prefix = "a13y") {
848
+ const idRef = useRef(void 0);
849
+ if (!idRef.current) {
850
+ idRef.current = `${prefix}-${++idCounter}`;
851
+ }
852
+ return idRef.current;
853
+ }
854
+ var AccessibleTooltip = ({
855
+ content,
856
+ placement = "top",
857
+ delay = 300,
858
+ trigger = "both",
859
+ children,
860
+ className = "",
861
+ style = {}
862
+ }) => {
863
+ const tooltipId = useId2("tooltip");
864
+ const [isVisible, setIsVisible] = useState(false);
865
+ const timeoutRef = useRef(void 0);
866
+ const triggerRef = useRef(null);
867
+ const showTooltip = () => {
868
+ if (timeoutRef.current) {
869
+ clearTimeout(timeoutRef.current);
870
+ }
871
+ timeoutRef.current = setTimeout(() => {
872
+ setIsVisible(true);
873
+ }, delay);
874
+ };
875
+ const hideTooltip = () => {
876
+ if (timeoutRef.current) {
877
+ clearTimeout(timeoutRef.current);
878
+ }
879
+ setIsVisible(false);
880
+ };
881
+ useEffect(() => {
882
+ return () => {
883
+ if (timeoutRef.current) {
884
+ clearTimeout(timeoutRef.current);
885
+ }
886
+ };
887
+ }, []);
888
+ useEffect(() => {
889
+ if (!isVisible) return;
890
+ const handleEscape = (event) => {
891
+ if (event.key === "Escape") {
892
+ hideTooltip();
893
+ }
894
+ };
895
+ document.addEventListener("keydown", handleEscape);
896
+ return () => document.removeEventListener("keydown", handleEscape);
897
+ }, [isVisible]);
898
+ const shouldTriggerOnHover = trigger === "hover" || trigger === "both";
899
+ const shouldTriggerOnFocus = trigger === "focus" || trigger === "both";
900
+ const childProps = {
901
+ ref: triggerRef,
902
+ "aria-describedby": isVisible ? tooltipId : void 0
903
+ };
904
+ if (shouldTriggerOnHover) {
905
+ childProps.onMouseEnter = () => showTooltip();
906
+ childProps.onMouseLeave = () => hideTooltip();
907
+ }
908
+ if (shouldTriggerOnFocus) {
909
+ childProps.onFocus = () => showTooltip();
910
+ childProps.onBlur = () => hideTooltip();
911
+ }
912
+ const getTooltipPosition = () => {
913
+ const baseStyles = {
914
+ position: "absolute",
915
+ zIndex: 1e3,
916
+ padding: "8px 12px",
917
+ backgroundColor: "#333",
918
+ color: "#fff",
919
+ borderRadius: "4px",
920
+ fontSize: "14px",
921
+ whiteSpace: "nowrap",
922
+ pointerEvents: "none"
923
+ };
924
+ switch (placement) {
925
+ case "top":
926
+ return { ...baseStyles, bottom: "100%", left: "50%", transform: "translateX(-50%)", marginBottom: "8px" };
927
+ case "bottom":
928
+ return { ...baseStyles, top: "100%", left: "50%", transform: "translateX(-50%)", marginTop: "8px" };
929
+ case "left":
930
+ return { ...baseStyles, right: "100%", top: "50%", transform: "translateY(-50%)", marginRight: "8px" };
931
+ case "right":
932
+ return { ...baseStyles, left: "100%", top: "50%", transform: "translateY(-50%)", marginLeft: "8px" };
933
+ default:
934
+ return baseStyles;
935
+ }
936
+ };
937
+ return /* @__PURE__ */ jsxs("span", { style: { position: "relative", display: "inline-block" }, children: [
938
+ cloneElement(children, childProps),
939
+ isVisible && /* @__PURE__ */ jsx(
940
+ "span",
941
+ {
942
+ role: "tooltip",
943
+ id: tooltipId,
944
+ className,
945
+ style: { ...getTooltipPosition(), ...style },
946
+ children: content
947
+ }
948
+ )
949
+ ] });
950
+ };
951
+ var AccessibleToggle = ({
952
+ checked,
953
+ onChange,
954
+ label,
955
+ description,
956
+ disabled = false,
957
+ className = "",
958
+ switchClassName = "",
959
+ style = {}
960
+ }) => {
961
+ const toggleId = useId2("toggle");
962
+ const descriptionId = useId2("toggle-description");
963
+ const handleKeyDown = (event) => {
964
+ if (event.key === " " || event.key === "Enter") {
965
+ event.preventDefault();
966
+ if (!disabled) {
967
+ onChange(!checked);
968
+ }
969
+ }
970
+ };
971
+ const handleClick = () => {
972
+ if (!disabled) {
973
+ onChange(!checked);
974
+ }
975
+ };
976
+ const containerStyles = {
977
+ display: "inline-flex",
978
+ alignItems: "center",
979
+ gap: "12px",
980
+ cursor: disabled ? "not-allowed" : "pointer",
981
+ opacity: disabled ? 0.6 : 1,
982
+ ...style
983
+ };
984
+ const switchStyles = {
985
+ position: "relative",
986
+ width: "44px",
987
+ height: "24px",
988
+ backgroundColor: checked ? "#007bff" : "#ccc",
989
+ borderRadius: "12px",
990
+ transition: "background-color 0.2s",
991
+ flexShrink: 0
992
+ };
993
+ const thumbStyles = {
994
+ position: "absolute",
995
+ top: "2px",
996
+ left: checked ? "22px" : "2px",
997
+ width: "20px",
998
+ height: "20px",
999
+ backgroundColor: "#fff",
1000
+ borderRadius: "50%",
1001
+ transition: "left 0.2s"
1002
+ };
1003
+ const labelStyles = {
1004
+ display: "flex",
1005
+ flexDirection: "column",
1006
+ gap: "4px"
1007
+ };
1008
+ const descriptionStyles = {
1009
+ fontSize: "0.875rem",
1010
+ color: "#666"
1011
+ };
1012
+ return /* @__PURE__ */ jsxs(
1013
+ "div",
1014
+ {
1015
+ className,
1016
+ style: containerStyles,
1017
+ onClick: handleClick,
1018
+ children: [
1019
+ /* @__PURE__ */ jsx(
1020
+ "div",
1021
+ {
1022
+ role: "switch",
1023
+ "aria-checked": checked,
1024
+ "aria-labelledby": toggleId,
1025
+ "aria-describedby": description ? descriptionId : void 0,
1026
+ "aria-disabled": disabled,
1027
+ tabIndex: disabled ? -1 : 0,
1028
+ onKeyDown: handleKeyDown,
1029
+ className: switchClassName,
1030
+ style: switchStyles,
1031
+ children: /* @__PURE__ */ jsx("div", { style: thumbStyles })
1032
+ }
1033
+ ),
1034
+ /* @__PURE__ */ jsxs("div", { style: labelStyles, children: [
1035
+ /* @__PURE__ */ jsx(
1036
+ "label",
1037
+ {
1038
+ id: toggleId,
1039
+ htmlFor: toggleId,
1040
+ style: { fontWeight: 500, cursor: disabled ? "not-allowed" : "pointer" },
1041
+ children: label
1042
+ }
1043
+ ),
1044
+ description && /* @__PURE__ */ jsx("span", { id: descriptionId, style: descriptionStyles, children: description })
1045
+ ] })
1046
+ ]
1047
+ }
1048
+ );
1049
+ };
1050
+ var AccessibleToast = ({
1051
+ message,
1052
+ type = "info",
1053
+ duration = 5e3,
1054
+ position = "top-right",
1055
+ action,
1056
+ isOpen,
1057
+ onClose,
1058
+ className = "",
1059
+ style = {}
1060
+ }) => {
1061
+ const toastId = useId2("toast");
1062
+ const [isVisible, setIsVisible] = useState(isOpen);
1063
+ useEffect(() => {
1064
+ setIsVisible(isOpen);
1065
+ }, [isOpen]);
1066
+ useEffect(() => {
1067
+ if (!isVisible || duration === 0) return;
1068
+ const timer = setTimeout(() => {
1069
+ setIsVisible(false);
1070
+ onClose();
1071
+ }, duration);
1072
+ return () => clearTimeout(timer);
1073
+ }, [isVisible, duration, onClose]);
1074
+ const handleKeyDown = (event) => {
1075
+ if (event.key === "Escape") {
1076
+ setIsVisible(false);
1077
+ onClose();
1078
+ }
1079
+ };
1080
+ if (!isVisible) return null;
1081
+ const getAriaRole = () => {
1082
+ return type === "error" ? "alert" : "status";
1083
+ };
1084
+ const getAriaPoliteness = () => {
1085
+ return type === "error" ? "assertive" : "polite";
1086
+ };
1087
+ const getPositionStyles = () => {
1088
+ const base = {
1089
+ position: "fixed",
1090
+ zIndex: 9999
1091
+ };
1092
+ switch (position) {
1093
+ case "top-right":
1094
+ return { ...base, top: "16px", right: "16px" };
1095
+ case "top-left":
1096
+ return { ...base, top: "16px", left: "16px" };
1097
+ case "bottom-right":
1098
+ return { ...base, bottom: "16px", right: "16px" };
1099
+ case "bottom-left":
1100
+ return { ...base, bottom: "16px", left: "16px" };
1101
+ case "top-center":
1102
+ return { ...base, top: "16px", left: "50%", transform: "translateX(-50%)" };
1103
+ case "bottom-center":
1104
+ return { ...base, bottom: "16px", left: "50%", transform: "translateX(-50%)" };
1105
+ default:
1106
+ return base;
1107
+ }
1108
+ };
1109
+ const getTypeStyles = () => {
1110
+ const baseTypeStyles = {
1111
+ success: { backgroundColor: "#10b981", color: "#fff" },
1112
+ error: { backgroundColor: "#ef4444", color: "#fff" },
1113
+ warning: { backgroundColor: "#f59e0b", color: "#fff" },
1114
+ info: { backgroundColor: "#3b82f6", color: "#fff" }
1115
+ };
1116
+ return baseTypeStyles[type];
1117
+ };
1118
+ const toastStyles = {
1119
+ ...getPositionStyles(),
1120
+ ...getTypeStyles(),
1121
+ minWidth: "300px",
1122
+ maxWidth: "500px",
1123
+ padding: "16px",
1124
+ borderRadius: "8px",
1125
+ boxShadow: "0 4px 6px rgba(0, 0, 0, 0.1)",
1126
+ display: "flex",
1127
+ alignItems: "center",
1128
+ gap: "12px",
1129
+ animation: "slideIn 0.3s ease-out",
1130
+ ...style
1131
+ };
1132
+ const messageStyles = {
1133
+ flex: 1,
1134
+ fontSize: "14px",
1135
+ lineHeight: "1.5"
1136
+ };
1137
+ const buttonStyles = {
1138
+ background: "transparent",
1139
+ border: "1px solid currentColor",
1140
+ color: "inherit",
1141
+ padding: "4px 12px",
1142
+ borderRadius: "4px",
1143
+ fontSize: "14px",
1144
+ cursor: "pointer",
1145
+ transition: "opacity 0.2s"
1146
+ };
1147
+ const closeButtonStyles = {
1148
+ ...buttonStyles,
1149
+ border: "none",
1150
+ padding: "4px 8px",
1151
+ fontSize: "18px",
1152
+ lineHeight: "1"
1153
+ };
1154
+ return /* @__PURE__ */ jsxs(
1155
+ "div",
1156
+ {
1157
+ id: toastId,
1158
+ role: getAriaRole(),
1159
+ "aria-live": getAriaPoliteness(),
1160
+ "aria-atomic": "true",
1161
+ className,
1162
+ style: toastStyles,
1163
+ onKeyDown: handleKeyDown,
1164
+ tabIndex: -1,
1165
+ children: [
1166
+ /* @__PURE__ */ jsx("div", { style: messageStyles, children: message }),
1167
+ action && /* @__PURE__ */ jsx(
1168
+ "button",
1169
+ {
1170
+ type: "button",
1171
+ onClick: () => {
1172
+ action.onClick();
1173
+ setIsVisible(false);
1174
+ onClose();
1175
+ },
1176
+ style: buttonStyles,
1177
+ onMouseEnter: (e) => e.currentTarget.style.opacity = "0.8",
1178
+ onMouseLeave: (e) => e.currentTarget.style.opacity = "1",
1179
+ children: action.label
1180
+ }
1181
+ ),
1182
+ /* @__PURE__ */ jsx(
1183
+ "button",
1184
+ {
1185
+ type: "button",
1186
+ onClick: () => {
1187
+ setIsVisible(false);
1188
+ onClose();
1189
+ },
1190
+ "aria-label": "Close notification",
1191
+ style: closeButtonStyles,
1192
+ onMouseEnter: (e) => e.currentTarget.style.opacity = "0.8",
1193
+ onMouseLeave: (e) => e.currentTarget.style.opacity = "1",
1194
+ children: "\xD7"
1195
+ }
1196
+ )
1197
+ ]
1198
+ }
1199
+ );
1200
+ };
1201
+ var ToastContainer = ({
1202
+ toasts,
1203
+ onRemove,
1204
+ position = "top-right"
1205
+ }) => {
1206
+ return /* @__PURE__ */ jsx(Fragment, { children: toasts.map((toast) => /* @__PURE__ */ jsx(
1207
+ AccessibleToast,
1208
+ {
1209
+ message: toast.message,
1210
+ type: toast.type,
1211
+ duration: toast.duration,
1212
+ position,
1213
+ action: toast.action,
1214
+ isOpen: true,
1215
+ onClose: () => onRemove(toast.id)
1216
+ },
1217
+ toast.id
1218
+ )) });
1219
+ };
1220
+ var AccessibleAccordion = ({
1221
+ items,
1222
+ allowMultiple = false,
1223
+ defaultOpenItems = [],
1224
+ onToggle,
1225
+ className = "",
1226
+ itemClassName = "",
1227
+ headerClassName = "",
1228
+ contentClassName = "",
1229
+ style = {}
1230
+ }) => {
1231
+ const [openItems, setOpenItems] = useState(
1232
+ new Set(defaultOpenItems)
1233
+ );
1234
+ const toggleItem = (itemId) => {
1235
+ setOpenItems((prev) => {
1236
+ const newOpenItems = new Set(prev);
1237
+ if (newOpenItems.has(itemId)) {
1238
+ newOpenItems.delete(itemId);
1239
+ onToggle?.(itemId, false);
1240
+ } else {
1241
+ if (!allowMultiple) {
1242
+ newOpenItems.clear();
1243
+ }
1244
+ newOpenItems.add(itemId);
1245
+ onToggle?.(itemId, true);
1246
+ }
1247
+ return newOpenItems;
1248
+ });
1249
+ };
1250
+ const handleKeyDown = (event, itemId, index) => {
1251
+ const item = items.find((i) => i.id === itemId);
1252
+ if (item?.disabled) return;
1253
+ switch (event.key) {
1254
+ case "Enter":
1255
+ case " ":
1256
+ event.preventDefault();
1257
+ toggleItem(itemId);
1258
+ break;
1259
+ case "ArrowDown":
1260
+ event.preventDefault();
1261
+ focusNextItem(index);
1262
+ break;
1263
+ case "ArrowUp":
1264
+ event.preventDefault();
1265
+ focusPreviousItem(index);
1266
+ break;
1267
+ case "Home":
1268
+ event.preventDefault();
1269
+ focusFirstItem();
1270
+ break;
1271
+ case "End":
1272
+ event.preventDefault();
1273
+ focusLastItem();
1274
+ break;
1275
+ }
1276
+ };
1277
+ const focusNextItem = (currentIndex) => {
1278
+ const nextIndex = (currentIndex + 1) % items.length;
1279
+ focusItemByIndex(nextIndex);
1280
+ };
1281
+ const focusPreviousItem = (currentIndex) => {
1282
+ const prevIndex = currentIndex === 0 ? items.length - 1 : currentIndex - 1;
1283
+ focusItemByIndex(prevIndex);
1284
+ };
1285
+ const focusFirstItem = () => {
1286
+ focusItemByIndex(0);
1287
+ };
1288
+ const focusLastItem = () => {
1289
+ focusItemByIndex(items.length - 1);
1290
+ };
1291
+ const focusItemByIndex = (index) => {
1292
+ const button = document.querySelector(
1293
+ `[data-accordion-button][data-index="${index}"]`
1294
+ );
1295
+ button?.focus();
1296
+ };
1297
+ const containerStyles = {
1298
+ border: "1px solid #e5e7eb",
1299
+ borderRadius: "8px",
1300
+ overflow: "hidden",
1301
+ ...style
1302
+ };
1303
+ const itemStyles = {
1304
+ borderBottom: "1px solid #e5e7eb"
1305
+ };
1306
+ const headerStyles = {
1307
+ width: "100%",
1308
+ padding: "16px",
1309
+ backgroundColor: "#fff",
1310
+ border: "none",
1311
+ textAlign: "left",
1312
+ fontSize: "16px",
1313
+ fontWeight: 500,
1314
+ cursor: "pointer",
1315
+ display: "flex",
1316
+ justifyContent: "space-between",
1317
+ alignItems: "center",
1318
+ transition: "background-color 0.2s"
1319
+ };
1320
+ const contentStyles = {
1321
+ padding: "16px",
1322
+ backgroundColor: "#f9fafb"
1323
+ };
1324
+ const iconStyles = (isOpen) => ({
1325
+ transition: "transform 0.2s",
1326
+ transform: isOpen ? "rotate(180deg)" : "rotate(0deg)"
1327
+ });
1328
+ return /* @__PURE__ */ jsx("div", { className, style: containerStyles, children: items.map((item, index) => {
1329
+ const isOpen = openItems.has(item.id);
1330
+ const buttonId = useId2(`accordion-button-${item.id}`);
1331
+ const panelId = useId2(`accordion-panel-${item.id}`);
1332
+ return /* @__PURE__ */ jsxs(
1333
+ "div",
1334
+ {
1335
+ className: itemClassName,
1336
+ style: { ...itemStyles, borderBottom: index === items.length - 1 ? "none" : itemStyles.borderBottom },
1337
+ children: [
1338
+ /* @__PURE__ */ jsx("h3", { style: { margin: 0 }, children: /* @__PURE__ */ jsxs(
1339
+ "button",
1340
+ {
1341
+ id: buttonId,
1342
+ type: "button",
1343
+ "aria-expanded": isOpen,
1344
+ "aria-controls": panelId,
1345
+ "aria-disabled": item.disabled,
1346
+ disabled: item.disabled,
1347
+ onClick: () => !item.disabled && toggleItem(item.id),
1348
+ onKeyDown: (e) => handleKeyDown(e, item.id, index),
1349
+ className: headerClassName,
1350
+ style: {
1351
+ ...headerStyles,
1352
+ cursor: item.disabled ? "not-allowed" : "pointer",
1353
+ opacity: item.disabled ? 0.6 : 1
1354
+ },
1355
+ "data-accordion-button": true,
1356
+ "data-index": index,
1357
+ onMouseEnter: (e) => !item.disabled && (e.currentTarget.style.backgroundColor = "#f9fafb"),
1358
+ onMouseLeave: (e) => e.currentTarget.style.backgroundColor = "#fff",
1359
+ children: [
1360
+ /* @__PURE__ */ jsx("span", { children: item.title }),
1361
+ /* @__PURE__ */ jsx("span", { "aria-hidden": "true", style: iconStyles(isOpen), children: "\u25BC" })
1362
+ ]
1363
+ }
1364
+ ) }),
1365
+ isOpen && /* @__PURE__ */ jsx(
1366
+ "div",
1367
+ {
1368
+ id: panelId,
1369
+ role: "region",
1370
+ "aria-labelledby": buttonId,
1371
+ className: contentClassName,
1372
+ style: contentStyles,
1373
+ children: item.content
1374
+ }
1375
+ )
1376
+ ]
1377
+ },
1378
+ item.id
1379
+ );
1380
+ }) });
1381
+ };
1382
+ var AccessibleBreadcrumb = ({
1383
+ items,
1384
+ separator = "/",
1385
+ ariaLabel = "Breadcrumb",
1386
+ className = "",
1387
+ itemClassName = "",
1388
+ style = {}
1389
+ }) => {
1390
+ if (items.length === 0) return null;
1391
+ const navStyles = {
1392
+ ...style
1393
+ };
1394
+ const listStyles = {
1395
+ display: "flex",
1396
+ alignItems: "center",
1397
+ gap: "8px",
1398
+ listStyle: "none",
1399
+ margin: 0,
1400
+ padding: 0,
1401
+ flexWrap: "wrap"
1402
+ };
1403
+ const itemStyles = {
1404
+ display: "flex",
1405
+ alignItems: "center",
1406
+ gap: "8px"
1407
+ };
1408
+ const linkStyles = {
1409
+ color: "#3b82f6",
1410
+ textDecoration: "none",
1411
+ transition: "color 0.2s"
1412
+ };
1413
+ const currentStyles = {
1414
+ color: "#6b7280",
1415
+ fontWeight: 500
1416
+ };
1417
+ const separatorStyles = {
1418
+ color: "#9ca3af",
1419
+ userSelect: "none"
1420
+ };
1421
+ return /* @__PURE__ */ jsx("nav", { "aria-label": ariaLabel, className, style: navStyles, children: /* @__PURE__ */ jsx("ol", { style: listStyles, children: items.map((item, index) => {
1422
+ const isLast = index === items.length - 1;
1423
+ const isCurrent = isLast;
1424
+ return /* @__PURE__ */ jsxs("li", { className: itemClassName, style: itemStyles, children: [
1425
+ isCurrent ? /* @__PURE__ */ jsx("span", { "aria-current": "page", style: currentStyles, children: item.label }) : item.href ? /* @__PURE__ */ jsx(
1426
+ "a",
1427
+ {
1428
+ href: item.href,
1429
+ style: linkStyles,
1430
+ onMouseEnter: (e) => e.currentTarget.style.color = "#2563eb",
1431
+ onMouseLeave: (e) => e.currentTarget.style.color = "#3b82f6",
1432
+ children: item.label
1433
+ }
1434
+ ) : item.onClick ? /* @__PURE__ */ jsx(
1435
+ "button",
1436
+ {
1437
+ type: "button",
1438
+ onClick: item.onClick,
1439
+ style: {
1440
+ ...linkStyles,
1441
+ background: "transparent",
1442
+ border: "none",
1443
+ padding: 0,
1444
+ cursor: "pointer",
1445
+ font: "inherit"
1446
+ },
1447
+ onMouseEnter: (e) => e.currentTarget.style.color = "#2563eb",
1448
+ onMouseLeave: (e) => e.currentTarget.style.color = "#3b82f6",
1449
+ children: item.label
1450
+ }
1451
+ ) : /* @__PURE__ */ jsx("span", { style: currentStyles, children: item.label }),
1452
+ !isLast && /* @__PURE__ */ jsx("span", { "aria-hidden": "true", style: separatorStyles, children: separator })
1453
+ ] }, index);
1454
+ }) }) });
1455
+ };
1456
+ var AccessibleCheckboxGroup = ({
1457
+ options,
1458
+ value,
1459
+ onChange,
1460
+ label,
1461
+ description,
1462
+ required = false,
1463
+ disabled = false,
1464
+ error,
1465
+ className = "",
1466
+ style = {}
1467
+ }) => {
1468
+ const descriptionId = useId2("checkbox-description");
1469
+ const errorId = useId2("checkbox-error");
1470
+ const handleChange = (optionValue, checked) => {
1471
+ if (disabled) return;
1472
+ const newValue = checked ? [...value, optionValue] : value.filter((v) => v !== optionValue);
1473
+ onChange(newValue);
1474
+ };
1475
+ const fieldsetStyles = {
1476
+ border: "1px solid #e5e7eb",
1477
+ borderRadius: "8px",
1478
+ padding: "16px",
1479
+ margin: 0,
1480
+ ...style
1481
+ };
1482
+ const legendStyles = {
1483
+ fontWeight: 600,
1484
+ fontSize: "16px",
1485
+ marginBottom: "8px",
1486
+ padding: "0 4px"
1487
+ };
1488
+ const descriptionStyles = {
1489
+ fontSize: "14px",
1490
+ color: "#6b7280",
1491
+ marginBottom: "12px"
1492
+ };
1493
+ const optionContainerStyles = {
1494
+ display: "flex",
1495
+ flexDirection: "column",
1496
+ gap: "12px"
1497
+ };
1498
+ const optionStyles = {
1499
+ display: "flex",
1500
+ alignItems: "flex-start",
1501
+ gap: "8px"
1502
+ };
1503
+ const checkboxStyles = {
1504
+ width: "18px",
1505
+ height: "18px",
1506
+ marginTop: "2px",
1507
+ cursor: disabled ? "not-allowed" : "pointer"
1508
+ };
1509
+ const labelStyles = {
1510
+ display: "flex",
1511
+ flexDirection: "column",
1512
+ gap: "2px",
1513
+ cursor: disabled ? "not-allowed" : "pointer",
1514
+ flex: 1
1515
+ };
1516
+ const optionDescriptionStyles = {
1517
+ fontSize: "13px",
1518
+ color: "#9ca3af"
1519
+ };
1520
+ const errorStyles = {
1521
+ color: "#ef4444",
1522
+ fontSize: "14px",
1523
+ marginTop: "8px"
1524
+ };
1525
+ return /* @__PURE__ */ jsxs(
1526
+ "fieldset",
1527
+ {
1528
+ className,
1529
+ style: fieldsetStyles,
1530
+ "aria-describedby": [description && descriptionId, error && errorId].filter(Boolean).join(" ") || void 0,
1531
+ disabled,
1532
+ children: [
1533
+ /* @__PURE__ */ jsxs("legend", { style: legendStyles, children: [
1534
+ label,
1535
+ required && /* @__PURE__ */ jsxs("span", { "aria-label": "required", style: { color: "#ef4444" }, children: [
1536
+ " ",
1537
+ "*"
1538
+ ] })
1539
+ ] }),
1540
+ description && /* @__PURE__ */ jsx("div", { id: descriptionId, style: descriptionStyles, children: description }),
1541
+ /* @__PURE__ */ jsx("div", { style: optionContainerStyles, role: "group", children: options.map((option) => {
1542
+ const checkboxId = useId2(`checkbox-${option.value}`);
1543
+ const optionDescId = option.description ? useId2(`checkbox-desc-${option.value}`) : void 0;
1544
+ const isChecked = value.includes(option.value);
1545
+ const isDisabled = disabled || option.disabled;
1546
+ return /* @__PURE__ */ jsxs("div", { style: optionStyles, children: [
1547
+ /* @__PURE__ */ jsx(
1548
+ "input",
1549
+ {
1550
+ type: "checkbox",
1551
+ id: checkboxId,
1552
+ checked: isChecked,
1553
+ onChange: (e) => handleChange(option.value, e.target.checked),
1554
+ disabled: isDisabled,
1555
+ "aria-describedby": optionDescId,
1556
+ style: checkboxStyles
1557
+ }
1558
+ ),
1559
+ /* @__PURE__ */ jsxs("label", { htmlFor: checkboxId, style: { ...labelStyles, opacity: isDisabled ? 0.6 : 1 }, children: [
1560
+ /* @__PURE__ */ jsx("span", { style: { fontWeight: 500 }, children: option.label }),
1561
+ option.description && /* @__PURE__ */ jsx("span", { id: optionDescId, style: optionDescriptionStyles, children: option.description })
1562
+ ] })
1563
+ ] }, option.value);
1564
+ }) }),
1565
+ error && /* @__PURE__ */ jsx("div", { id: errorId, role: "alert", style: errorStyles, children: error })
1566
+ ]
1567
+ }
1568
+ );
1569
+ };
1570
+ var AccessibleRadioGroup = ({
1571
+ options,
1572
+ value,
1573
+ onChange,
1574
+ name,
1575
+ label,
1576
+ description,
1577
+ required = false,
1578
+ disabled = false,
1579
+ error,
1580
+ className = "",
1581
+ style = {}
1582
+ }) => {
1583
+ const groupId = useId2("radio-group");
1584
+ const descriptionId = useId2("radio-description");
1585
+ const errorId = useId2("radio-error");
1586
+ const handleKeyDown = (event, currentIndex) => {
1587
+ let nextIndex = currentIndex;
1588
+ switch (event.key) {
1589
+ case "ArrowDown":
1590
+ case "ArrowRight":
1591
+ event.preventDefault();
1592
+ nextIndex = (currentIndex + 1) % options.length;
1593
+ break;
1594
+ case "ArrowUp":
1595
+ case "ArrowLeft":
1596
+ event.preventDefault();
1597
+ nextIndex = currentIndex === 0 ? options.length - 1 : currentIndex - 1;
1598
+ break;
1599
+ default:
1600
+ return;
1601
+ }
1602
+ while (options[nextIndex]?.disabled && nextIndex !== currentIndex) {
1603
+ if (event.key === "ArrowDown" || event.key === "ArrowRight") {
1604
+ nextIndex = (nextIndex + 1) % options.length;
1605
+ } else {
1606
+ nextIndex = nextIndex === 0 ? options.length - 1 : nextIndex - 1;
1607
+ }
1608
+ }
1609
+ if (!options[nextIndex]?.disabled) {
1610
+ onChange(options[nextIndex].value);
1611
+ const nextRadio = document.getElementById(`${groupId}-${options[nextIndex].value}`);
1612
+ nextRadio?.focus();
1613
+ }
1614
+ };
1615
+ const fieldsetStyles = {
1616
+ border: "1px solid #e5e7eb",
1617
+ borderRadius: "8px",
1618
+ padding: "16px",
1619
+ margin: 0,
1620
+ ...style
1621
+ };
1622
+ const legendStyles = {
1623
+ fontWeight: 600,
1624
+ fontSize: "16px",
1625
+ marginBottom: "8px",
1626
+ padding: "0 4px"
1627
+ };
1628
+ const descriptionStyles = {
1629
+ fontSize: "14px",
1630
+ color: "#6b7280",
1631
+ marginBottom: "12px"
1632
+ };
1633
+ const optionContainerStyles = {
1634
+ display: "flex",
1635
+ flexDirection: "column",
1636
+ gap: "12px"
1637
+ };
1638
+ const optionStyles = {
1639
+ display: "flex",
1640
+ alignItems: "flex-start",
1641
+ gap: "8px"
1642
+ };
1643
+ const radioStyles = {
1644
+ width: "18px",
1645
+ height: "18px",
1646
+ marginTop: "2px",
1647
+ cursor: disabled ? "not-allowed" : "pointer"
1648
+ };
1649
+ const labelStyles = {
1650
+ display: "flex",
1651
+ flexDirection: "column",
1652
+ gap: "2px",
1653
+ cursor: disabled ? "not-allowed" : "pointer",
1654
+ flex: 1
1655
+ };
1656
+ const optionDescriptionStyles = {
1657
+ fontSize: "13px",
1658
+ color: "#9ca3af"
1659
+ };
1660
+ const errorStyles = {
1661
+ color: "#ef4444",
1662
+ fontSize: "14px",
1663
+ marginTop: "8px"
1664
+ };
1665
+ return /* @__PURE__ */ jsxs(
1666
+ "fieldset",
1667
+ {
1668
+ className,
1669
+ style: fieldsetStyles,
1670
+ "aria-describedby": [description && descriptionId, error && errorId].filter(Boolean).join(" ") || void 0,
1671
+ disabled,
1672
+ children: [
1673
+ /* @__PURE__ */ jsxs("legend", { style: legendStyles, children: [
1674
+ label,
1675
+ required && /* @__PURE__ */ jsxs("span", { "aria-label": "required", style: { color: "#ef4444" }, children: [
1676
+ " ",
1677
+ "*"
1678
+ ] })
1679
+ ] }),
1680
+ description && /* @__PURE__ */ jsx("div", { id: descriptionId, style: descriptionStyles, children: description }),
1681
+ /* @__PURE__ */ jsx("div", { style: optionContainerStyles, role: "radiogroup", "aria-labelledby": groupId, children: options.map((option, index) => {
1682
+ const radioId = `${groupId}-${option.value}`;
1683
+ const optionDescId = option.description ? useId2(`radio-desc-${option.value}`) : void 0;
1684
+ const isChecked = value === option.value;
1685
+ const isDisabled = disabled || option.disabled;
1686
+ return /* @__PURE__ */ jsxs("div", { style: optionStyles, children: [
1687
+ /* @__PURE__ */ jsx(
1688
+ "input",
1689
+ {
1690
+ type: "radio",
1691
+ id: radioId,
1692
+ name,
1693
+ value: option.value,
1694
+ checked: isChecked,
1695
+ onChange: (e) => onChange(e.target.value),
1696
+ onKeyDown: (e) => handleKeyDown(e, index),
1697
+ disabled: isDisabled,
1698
+ "aria-describedby": optionDescId,
1699
+ style: radioStyles,
1700
+ tabIndex: isChecked ? 0 : -1
1701
+ }
1702
+ ),
1703
+ /* @__PURE__ */ jsxs("label", { htmlFor: radioId, style: { ...labelStyles, opacity: isDisabled ? 0.6 : 1 }, children: [
1704
+ /* @__PURE__ */ jsx("span", { style: { fontWeight: 500 }, children: option.label }),
1705
+ option.description && /* @__PURE__ */ jsx("span", { id: optionDescId, style: optionDescriptionStyles, children: option.description })
1706
+ ] })
1707
+ ] }, option.value);
1708
+ }) }),
1709
+ error && /* @__PURE__ */ jsx("div", { id: errorId, role: "alert", style: errorStyles, children: error })
1710
+ ]
1711
+ }
1712
+ );
1713
+ };
1714
+ function useAriaLive(politeness = "polite") {
1715
+ const [message, setMessage] = useState("");
1716
+ const timeoutRef = useRef(void 0);
1717
+ const clearMessage = () => {
1718
+ setMessage("");
1719
+ if (timeoutRef.current) {
1720
+ clearTimeout(timeoutRef.current);
1721
+ }
1722
+ };
1723
+ const setMessageWithClear = (newMessage) => {
1724
+ setMessage(newMessage);
1725
+ if (timeoutRef.current) {
1726
+ clearTimeout(timeoutRef.current);
1727
+ }
1728
+ timeoutRef.current = setTimeout(() => {
1729
+ setMessage("");
1730
+ }, 5e3);
1731
+ };
1732
+ useEffect(() => {
1733
+ return () => {
1734
+ if (timeoutRef.current) {
1735
+ clearTimeout(timeoutRef.current);
1736
+ }
1737
+ };
1738
+ }, []);
1739
+ return {
1740
+ setMessage: setMessageWithClear,
1741
+ clearMessage,
1742
+ message,
1743
+ liveRegionProps: {
1744
+ role: politeness === "assertive" ? "alert" : "status",
1745
+ "aria-live": politeness,
1746
+ "aria-atomic": "true",
1747
+ "aria-relevant": "additions text"
1748
+ }
1749
+ };
1750
+ }
1751
+ var AccessibleProgress = ({
1752
+ value,
1753
+ max = 100,
1754
+ min = 0,
1755
+ label,
1756
+ variant = "linear",
1757
+ showValue = false,
1758
+ announceChanges = false,
1759
+ className = "",
1760
+ style = {}
1761
+ }) => {
1762
+ const progressId = useId2("progress");
1763
+ const labelId = useId2("progress-label");
1764
+ const { setMessage, liveRegionProps, message } = useAriaLive("polite");
1765
+ const isIndeterminate = value === void 0;
1766
+ const percentage = isIndeterminate ? 0 : Math.round((value - min) / (max - min) * 100);
1767
+ React4.useEffect(() => {
1768
+ if (announceChanges && !isIndeterminate && value !== void 0) {
1769
+ const milestones = [25, 50, 75, 100];
1770
+ if (milestones.includes(percentage)) {
1771
+ setMessage(`${label}: ${percentage}% complete`);
1772
+ }
1773
+ }
1774
+ }, [percentage, announceChanges, isIndeterminate, value, label, setMessage]);
1775
+ const containerStyles = {
1776
+ display: "inline-flex",
1777
+ flexDirection: variant === "linear" ? "column" : "row",
1778
+ alignItems: variant === "linear" ? "stretch" : "center",
1779
+ gap: variant === "linear" ? "8px" : "12px",
1780
+ width: variant === "linear" ? "100%" : "auto",
1781
+ ...style
1782
+ };
1783
+ const labelContainerStyles = {
1784
+ display: "flex",
1785
+ justifyContent: "space-between",
1786
+ alignItems: "center",
1787
+ fontSize: "14px",
1788
+ fontWeight: 500
1789
+ };
1790
+ const renderLinearProgress = () => {
1791
+ const trackStyles = {
1792
+ width: "100%",
1793
+ height: "8px",
1794
+ backgroundColor: "#e5e7eb",
1795
+ borderRadius: "4px",
1796
+ overflow: "hidden",
1797
+ position: "relative"
1798
+ };
1799
+ const barStyles = {
1800
+ height: "100%",
1801
+ backgroundColor: "#3b82f6",
1802
+ transition: isIndeterminate ? "none" : "width 0.3s ease",
1803
+ width: isIndeterminate ? "30%" : `${percentage}%`,
1804
+ animation: isIndeterminate ? "indeterminateLinear 1.5s infinite ease-in-out" : "none"
1805
+ };
1806
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
1807
+ /* @__PURE__ */ jsx("style", { children: `
1808
+ @keyframes indeterminateLinear {
1809
+ 0% { transform: translateX(-100%); }
1810
+ 100% { transform: translateX(400%); }
1811
+ }
1812
+ ` }),
1813
+ /* @__PURE__ */ jsxs("div", { style: labelContainerStyles, children: [
1814
+ /* @__PURE__ */ jsx("span", { id: labelId, children: label }),
1815
+ showValue && !isIndeterminate && /* @__PURE__ */ jsxs("span", { children: [
1816
+ percentage,
1817
+ "%"
1818
+ ] })
1819
+ ] }),
1820
+ /* @__PURE__ */ jsx("div", { style: trackStyles, children: /* @__PURE__ */ jsx("div", { style: barStyles }) })
1821
+ ] });
1822
+ };
1823
+ const renderCircularProgress = () => {
1824
+ const size = 48;
1825
+ const strokeWidth = 4;
1826
+ const radius = (size - strokeWidth) / 2;
1827
+ const circumference = 2 * Math.PI * radius;
1828
+ const offset = isIndeterminate ? circumference * 0.25 : circumference - percentage / 100 * circumference;
1829
+ const svgStyles = {
1830
+ transform: "rotate(-90deg)",
1831
+ animation: isIndeterminate ? "spin 1s linear infinite" : "none"
1832
+ };
1833
+ const circleStyles = {
1834
+ transition: isIndeterminate ? "none" : "stroke-dashoffset 0.3s ease"
1835
+ };
1836
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
1837
+ /* @__PURE__ */ jsx("style", { children: `
1838
+ @keyframes spin {
1839
+ from { transform: rotate(-90deg); }
1840
+ to { transform: rotate(270deg); }
1841
+ }
1842
+ ` }),
1843
+ /* @__PURE__ */ jsxs("svg", { width: size, height: size, style: svgStyles, children: [
1844
+ /* @__PURE__ */ jsx(
1845
+ "circle",
1846
+ {
1847
+ cx: size / 2,
1848
+ cy: size / 2,
1849
+ r: radius,
1850
+ fill: "none",
1851
+ stroke: "#e5e7eb",
1852
+ strokeWidth
1853
+ }
1854
+ ),
1855
+ /* @__PURE__ */ jsx(
1856
+ "circle",
1857
+ {
1858
+ cx: size / 2,
1859
+ cy: size / 2,
1860
+ r: radius,
1861
+ fill: "none",
1862
+ stroke: "#3b82f6",
1863
+ strokeWidth,
1864
+ strokeDasharray: circumference,
1865
+ strokeDashoffset: offset,
1866
+ strokeLinecap: "round",
1867
+ style: circleStyles
1868
+ }
1869
+ )
1870
+ ] }),
1871
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "4px" }, children: [
1872
+ /* @__PURE__ */ jsx("span", { id: labelId, style: { fontSize: "14px", fontWeight: 500 }, children: label }),
1873
+ showValue && !isIndeterminate && /* @__PURE__ */ jsxs("span", { style: { fontSize: "12px", color: "#6b7280" }, children: [
1874
+ percentage,
1875
+ "%"
1876
+ ] })
1877
+ ] })
1878
+ ] });
1879
+ };
1880
+ return /* @__PURE__ */ jsxs("div", { className, style: containerStyles, children: [
1881
+ /* @__PURE__ */ jsx(
1882
+ "div",
1883
+ {
1884
+ id: progressId,
1885
+ role: "progressbar",
1886
+ "aria-labelledby": labelId,
1887
+ "aria-valuenow": isIndeterminate ? void 0 : value,
1888
+ "aria-valuemin": min,
1889
+ "aria-valuemax": max,
1890
+ "aria-valuetext": isIndeterminate ? "Loading..." : `${percentage}%`,
1891
+ children: variant === "linear" ? renderLinearProgress() : renderCircularProgress()
1892
+ }
1893
+ ),
1894
+ announceChanges && /* @__PURE__ */ jsx("div", { ...liveRegionProps, style: { position: "absolute", left: "-10000px", width: "1px", height: "1px", overflow: "hidden" }, children: message })
1895
+ ] });
1896
+ };
1897
+ var SkipLinks = ({
1898
+ links,
1899
+ className = "",
1900
+ style = {},
1901
+ linkStyle = {}
1902
+ }) => {
1903
+ if (links.length === 0) return null;
1904
+ const containerStyles = {
1905
+ position: "fixed",
1906
+ top: 0,
1907
+ left: 0,
1908
+ zIndex: 1e4,
1909
+ ...style
1910
+ };
1911
+ const listStyles = {
1912
+ listStyle: "none",
1913
+ margin: 0,
1914
+ padding: 0,
1915
+ display: "flex",
1916
+ flexDirection: "column",
1917
+ gap: "4px"
1918
+ };
1919
+ const defaultLinkStyles = {
1920
+ position: "absolute",
1921
+ left: "-10000px",
1922
+ top: "auto",
1923
+ width: "1px",
1924
+ height: "1px",
1925
+ overflow: "hidden",
1926
+ display: "block",
1927
+ padding: "12px 24px",
1928
+ backgroundColor: "#000",
1929
+ color: "#fff",
1930
+ textDecoration: "none",
1931
+ fontWeight: 600,
1932
+ fontSize: "14px",
1933
+ borderRadius: "0 0 4px 0",
1934
+ transition: "none",
1935
+ ...linkStyle
1936
+ };
1937
+ const focusStyles = {
1938
+ position: "static",
1939
+ width: "auto",
1940
+ height: "auto",
1941
+ overflow: "visible",
1942
+ left: "auto"
1943
+ };
1944
+ const handleClick = (e, href) => {
1945
+ e.preventDefault();
1946
+ const target = document.getElementById(href);
1947
+ if (target) {
1948
+ target.scrollIntoView({ behavior: "smooth", block: "start" });
1949
+ const originalTabIndex = target.getAttribute("tabindex");
1950
+ if (!target.hasAttribute("tabindex")) {
1951
+ target.setAttribute("tabindex", "-1");
1952
+ }
1953
+ target.focus();
1954
+ if (originalTabIndex === null) {
1955
+ setTimeout(() => {
1956
+ target.removeAttribute("tabindex");
1957
+ }, 100);
1958
+ }
1959
+ }
1960
+ };
1961
+ return /* @__PURE__ */ jsx(
1962
+ "nav",
1963
+ {
1964
+ "aria-label": "Skip navigation",
1965
+ className,
1966
+ style: containerStyles,
1967
+ children: /* @__PURE__ */ jsx("ul", { style: listStyles, children: links.map((link, index) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(
1968
+ "a",
1969
+ {
1970
+ href: `#${link.href}`,
1971
+ onClick: (e) => handleClick(e, link.href),
1972
+ style: defaultLinkStyles,
1973
+ onFocus: (e) => {
1974
+ Object.assign(e.currentTarget.style, focusStyles);
1975
+ },
1976
+ onBlur: (e) => {
1977
+ Object.assign(e.currentTarget.style, defaultLinkStyles);
1978
+ },
1979
+ children: link.label
1980
+ }
1981
+ ) }, index)) })
1982
+ }
1983
+ );
1984
+ };
1985
+ var AccessiblePagination = ({
1986
+ currentPage,
1987
+ totalPages,
1988
+ onPageChange,
1989
+ siblingCount = 1,
1990
+ showFirstLast = false,
1991
+ ariaLabel = "Pagination",
1992
+ className = "",
1993
+ style = {}
1994
+ }) => {
1995
+ if (totalPages <= 1) return null;
1996
+ const generatePageNumbers = () => {
1997
+ const pages2 = [];
1998
+ pages2.push(1);
1999
+ const leftSiblingIndex = Math.max(currentPage - siblingCount, 2);
2000
+ const rightSiblingIndex = Math.min(currentPage + siblingCount, totalPages - 1);
2001
+ if (leftSiblingIndex > 2) {
2002
+ pages2.push("...");
2003
+ }
2004
+ for (let i = leftSiblingIndex; i <= rightSiblingIndex; i++) {
2005
+ pages2.push(i);
2006
+ }
2007
+ if (rightSiblingIndex < totalPages - 1) {
2008
+ pages2.push("...");
2009
+ }
2010
+ if (totalPages > 1) {
2011
+ pages2.push(totalPages);
2012
+ }
2013
+ return pages2;
2014
+ };
2015
+ const pages = generatePageNumbers();
2016
+ const navStyles = {
2017
+ ...style
2018
+ };
2019
+ const listStyles = {
2020
+ display: "flex",
2021
+ alignItems: "center",
2022
+ gap: "4px",
2023
+ listStyle: "none",
2024
+ margin: 0,
2025
+ padding: 0
2026
+ };
2027
+ const buttonBaseStyles = {
2028
+ minWidth: "40px",
2029
+ height: "40px",
2030
+ padding: "8px 12px",
2031
+ border: "1px solid #e5e7eb",
2032
+ backgroundColor: "#fff",
2033
+ borderRadius: "6px",
2034
+ fontSize: "14px",
2035
+ fontWeight: 500,
2036
+ cursor: "pointer",
2037
+ transition: "all 0.2s",
2038
+ display: "flex",
2039
+ alignItems: "center",
2040
+ justifyContent: "center"
2041
+ };
2042
+ const activeButtonStyles = {
2043
+ ...buttonBaseStyles,
2044
+ backgroundColor: "#3b82f6",
2045
+ color: "#fff",
2046
+ borderColor: "#3b82f6"
2047
+ };
2048
+ const disabledButtonStyles = {
2049
+ ...buttonBaseStyles,
2050
+ opacity: 0.5,
2051
+ cursor: "not-allowed"
2052
+ };
2053
+ const ellipsisStyles = {
2054
+ minWidth: "40px",
2055
+ height: "40px",
2056
+ display: "flex",
2057
+ alignItems: "center",
2058
+ justifyContent: "center",
2059
+ color: "#9ca3af"
2060
+ };
2061
+ const handlePageChange = (page) => {
2062
+ if (page >= 1 && page <= totalPages && page !== currentPage) {
2063
+ onPageChange(page);
2064
+ }
2065
+ };
2066
+ return /* @__PURE__ */ jsx("nav", { "aria-label": ariaLabel, className, style: navStyles, children: /* @__PURE__ */ jsxs("ul", { style: listStyles, children: [
2067
+ showFirstLast && /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(
2068
+ "button",
2069
+ {
2070
+ type: "button",
2071
+ onClick: () => handlePageChange(1),
2072
+ disabled: currentPage === 1,
2073
+ "aria-label": "Go to first page",
2074
+ style: currentPage === 1 ? disabledButtonStyles : buttonBaseStyles,
2075
+ onMouseEnter: (e) => {
2076
+ if (currentPage !== 1) {
2077
+ e.currentTarget.style.backgroundColor = "#f3f4f6";
2078
+ }
2079
+ },
2080
+ onMouseLeave: (e) => {
2081
+ if (currentPage !== 1) {
2082
+ e.currentTarget.style.backgroundColor = "#fff";
2083
+ }
2084
+ },
2085
+ children: "\xAB\xAB"
2086
+ }
2087
+ ) }),
2088
+ /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(
2089
+ "button",
2090
+ {
2091
+ type: "button",
2092
+ onClick: () => handlePageChange(currentPage - 1),
2093
+ disabled: currentPage === 1,
2094
+ "aria-label": "Go to previous page",
2095
+ style: currentPage === 1 ? disabledButtonStyles : buttonBaseStyles,
2096
+ onMouseEnter: (e) => {
2097
+ if (currentPage !== 1) {
2098
+ e.currentTarget.style.backgroundColor = "#f3f4f6";
2099
+ }
2100
+ },
2101
+ onMouseLeave: (e) => {
2102
+ if (currentPage !== 1) {
2103
+ e.currentTarget.style.backgroundColor = "#fff";
2104
+ }
2105
+ },
2106
+ children: "\xAB"
2107
+ }
2108
+ ) }),
2109
+ pages.map((page, index) => {
2110
+ if (page === "...") {
2111
+ return /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx("span", { style: ellipsisStyles, "aria-hidden": "true", children: "\u2026" }) }, `ellipsis-${index}`);
2112
+ }
2113
+ const pageNumber = page;
2114
+ const isActive = pageNumber === currentPage;
2115
+ return /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(
2116
+ "button",
2117
+ {
2118
+ type: "button",
2119
+ onClick: () => handlePageChange(pageNumber),
2120
+ "aria-label": `Go to page ${pageNumber}`,
2121
+ "aria-current": isActive ? "page" : void 0,
2122
+ style: isActive ? activeButtonStyles : buttonBaseStyles,
2123
+ onMouseEnter: (e) => {
2124
+ if (!isActive) {
2125
+ e.currentTarget.style.backgroundColor = "#f3f4f6";
2126
+ }
2127
+ },
2128
+ onMouseLeave: (e) => {
2129
+ if (!isActive) {
2130
+ e.currentTarget.style.backgroundColor = "#fff";
2131
+ }
2132
+ },
2133
+ children: pageNumber
2134
+ }
2135
+ ) }, pageNumber);
2136
+ }),
2137
+ /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(
2138
+ "button",
2139
+ {
2140
+ type: "button",
2141
+ onClick: () => handlePageChange(currentPage + 1),
2142
+ disabled: currentPage === totalPages,
2143
+ "aria-label": "Go to next page",
2144
+ style: currentPage === totalPages ? disabledButtonStyles : buttonBaseStyles,
2145
+ onMouseEnter: (e) => {
2146
+ if (currentPage !== totalPages) {
2147
+ e.currentTarget.style.backgroundColor = "#f3f4f6";
2148
+ }
2149
+ },
2150
+ onMouseLeave: (e) => {
2151
+ if (currentPage !== totalPages) {
2152
+ e.currentTarget.style.backgroundColor = "#fff";
2153
+ }
2154
+ },
2155
+ children: "\xBB"
2156
+ }
2157
+ ) }),
2158
+ showFirstLast && /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(
2159
+ "button",
2160
+ {
2161
+ type: "button",
2162
+ onClick: () => handlePageChange(totalPages),
2163
+ disabled: currentPage === totalPages,
2164
+ "aria-label": "Go to last page",
2165
+ style: currentPage === totalPages ? disabledButtonStyles : buttonBaseStyles,
2166
+ onMouseEnter: (e) => {
2167
+ if (currentPage !== totalPages) {
2168
+ e.currentTarget.style.backgroundColor = "#f3f4f6";
2169
+ }
2170
+ },
2171
+ onMouseLeave: (e) => {
2172
+ if (currentPage !== totalPages) {
2173
+ e.currentTarget.style.backgroundColor = "#fff";
2174
+ }
2175
+ },
2176
+ children: "\xBB\xBB"
2177
+ }
2178
+ ) })
2179
+ ] }) });
2180
+ };
2181
+ function useClickOutside(ref, handler, enabled = true) {
2182
+ useEffect(() => {
2183
+ if (!enabled) return;
2184
+ const handleClickOutside = (event) => {
2185
+ if (!ref.current || ref.current.contains(event.target)) {
2186
+ return;
2187
+ }
2188
+ handler(event);
2189
+ };
2190
+ document.addEventListener("mousedown", handleClickOutside);
2191
+ document.addEventListener("touchstart", handleClickOutside);
2192
+ return () => {
2193
+ document.removeEventListener("mousedown", handleClickOutside);
2194
+ document.removeEventListener("touchstart", handleClickOutside);
2195
+ };
2196
+ }, [ref, handler, enabled]);
2197
+ }
2198
+ function AccessibleCombobox({
2199
+ options,
2200
+ value,
2201
+ onChange,
2202
+ label,
2203
+ placeholder = "Select an option",
2204
+ searchable = false,
2205
+ required = false,
2206
+ disabled = false,
2207
+ error,
2208
+ className = "",
2209
+ style = {}
2210
+ }) {
2211
+ const [isOpen, setIsOpen] = useState(false);
2212
+ const [searchQuery, setSearchQuery] = useState("");
2213
+ const [highlightedIndex, setHighlightedIndex] = useState(0);
2214
+ const comboboxId = useId2("combobox");
2215
+ const labelId = useId2("combobox-label");
2216
+ const listboxId = useId2("combobox-listbox");
2217
+ const errorId = useId2("combobox-error");
2218
+ const containerRef = useRef(null);
2219
+ const inputRef = useRef(null);
2220
+ const listboxRef = useRef(null);
2221
+ useClickOutside(containerRef, () => setIsOpen(false), isOpen);
2222
+ const filteredOptions = searchable ? options.filter(
2223
+ (option) => option.label.toLowerCase().includes(searchQuery.toLowerCase())
2224
+ ) : options;
2225
+ const selectedOption = options.find((opt) => opt.value === value);
2226
+ useEffect(() => {
2227
+ if (isOpen && listboxRef.current) {
2228
+ const highlightedElement = listboxRef.current.querySelector(
2229
+ `[data-index="${highlightedIndex}"]`
2230
+ );
2231
+ highlightedElement?.scrollIntoView({ block: "nearest" });
2232
+ }
2233
+ }, [highlightedIndex, isOpen]);
2234
+ const handleToggle = () => {
2235
+ if (disabled) return;
2236
+ setIsOpen(!isOpen);
2237
+ if (!isOpen) {
2238
+ setSearchQuery("");
2239
+ setHighlightedIndex(0);
2240
+ setTimeout(() => inputRef.current?.focus(), 0);
2241
+ }
2242
+ };
2243
+ const handleSelect = (option) => {
2244
+ if (option.disabled) return;
2245
+ onChange(option.value);
2246
+ setIsOpen(false);
2247
+ setSearchQuery("");
2248
+ inputRef.current?.blur();
2249
+ };
2250
+ const handleKeyDown = (event) => {
2251
+ if (disabled) return;
2252
+ switch (event.key) {
2253
+ case "Enter":
2254
+ event.preventDefault();
2255
+ if (isOpen && filteredOptions[highlightedIndex]) {
2256
+ handleSelect(filteredOptions[highlightedIndex]);
2257
+ } else {
2258
+ setIsOpen(!isOpen);
2259
+ }
2260
+ break;
2261
+ case " ":
2262
+ if (!searchable || !isOpen) {
2263
+ event.preventDefault();
2264
+ setIsOpen(!isOpen);
2265
+ }
2266
+ break;
2267
+ case "Escape":
2268
+ event.preventDefault();
2269
+ setIsOpen(false);
2270
+ setSearchQuery("");
2271
+ break;
2272
+ case "ArrowDown":
2273
+ event.preventDefault();
2274
+ if (!isOpen) {
2275
+ setIsOpen(true);
2276
+ } else {
2277
+ setHighlightedIndex(
2278
+ (prev) => prev < filteredOptions.length - 1 ? prev + 1 : prev
2279
+ );
2280
+ }
2281
+ break;
2282
+ case "ArrowUp":
2283
+ event.preventDefault();
2284
+ if (isOpen) {
2285
+ setHighlightedIndex((prev) => prev > 0 ? prev - 1 : prev);
2286
+ }
2287
+ break;
2288
+ case "Home":
2289
+ if (isOpen) {
2290
+ event.preventDefault();
2291
+ setHighlightedIndex(0);
2292
+ }
2293
+ break;
2294
+ case "End":
2295
+ if (isOpen) {
2296
+ event.preventDefault();
2297
+ setHighlightedIndex(filteredOptions.length - 1);
2298
+ }
2299
+ break;
2300
+ }
2301
+ };
2302
+ const containerStyles = {
2303
+ position: "relative",
2304
+ width: "100%",
2305
+ ...style
2306
+ };
2307
+ const labelStyles = {
2308
+ display: "block",
2309
+ fontWeight: 600,
2310
+ fontSize: "14px",
2311
+ marginBottom: "6px"
2312
+ };
2313
+ const inputContainerStyles = {
2314
+ position: "relative",
2315
+ width: "100%"
2316
+ };
2317
+ const inputStyles = {
2318
+ width: "100%",
2319
+ padding: "10px 36px 10px 12px",
2320
+ border: `1px solid ${error ? "#ef4444" : "#e5e7eb"}`,
2321
+ borderRadius: "6px",
2322
+ fontSize: "14px",
2323
+ backgroundColor: disabled ? "#f9fafb" : "#fff",
2324
+ cursor: disabled ? "not-allowed" : "pointer",
2325
+ outline: "none"
2326
+ };
2327
+ const iconStyles = {
2328
+ position: "absolute",
2329
+ right: "12px",
2330
+ top: "50%",
2331
+ transform: "translateY(-50%)",
2332
+ pointerEvents: "none",
2333
+ transition: "transform 0.2s"
2334
+ };
2335
+ const listboxStyles = {
2336
+ position: "absolute",
2337
+ top: "100%",
2338
+ left: 0,
2339
+ right: 0,
2340
+ marginTop: "4px",
2341
+ maxHeight: "240px",
2342
+ overflowY: "auto",
2343
+ backgroundColor: "#fff",
2344
+ border: "1px solid #e5e7eb",
2345
+ borderRadius: "6px",
2346
+ boxShadow: "0 4px 6px rgba(0, 0, 0, 0.1)",
2347
+ zIndex: 1e3,
2348
+ listStyle: "none",
2349
+ margin: 0,
2350
+ padding: "4px"
2351
+ };
2352
+ const optionStyles = (isHighlighted, isSelected, isDisabled) => ({
2353
+ padding: "10px 12px",
2354
+ cursor: isDisabled ? "not-allowed" : "pointer",
2355
+ backgroundColor: isHighlighted ? "#f3f4f6" : isSelected ? "#e5e7eb" : "transparent",
2356
+ borderRadius: "4px",
2357
+ fontSize: "14px",
2358
+ opacity: isDisabled ? 0.5 : 1
2359
+ });
2360
+ const errorStyles = {
2361
+ marginTop: "6px",
2362
+ fontSize: "13px",
2363
+ color: "#ef4444"
2364
+ };
2365
+ return /* @__PURE__ */ jsxs("div", { ref: containerRef, className, style: containerStyles, children: [
2366
+ /* @__PURE__ */ jsxs("label", { id: labelId, htmlFor: comboboxId, style: labelStyles, children: [
2367
+ label,
2368
+ required && /* @__PURE__ */ jsxs("span", { "aria-label": "required", style: { color: "#ef4444" }, children: [
2369
+ " ",
2370
+ "*"
2371
+ ] })
2372
+ ] }),
2373
+ /* @__PURE__ */ jsxs("div", { style: inputContainerStyles, children: [
2374
+ /* @__PURE__ */ jsx(
2375
+ "input",
2376
+ {
2377
+ ref: inputRef,
2378
+ id: comboboxId,
2379
+ type: "text",
2380
+ role: "combobox",
2381
+ "aria-labelledby": labelId,
2382
+ "aria-controls": listboxId,
2383
+ "aria-expanded": isOpen,
2384
+ "aria-autocomplete": searchable ? "list" : "none",
2385
+ "aria-activedescendant": isOpen && filteredOptions[highlightedIndex] ? `${listboxId}-option-${highlightedIndex}` : void 0,
2386
+ "aria-describedby": error ? errorId : void 0,
2387
+ "aria-required": required,
2388
+ "aria-invalid": !!error,
2389
+ disabled,
2390
+ value: searchable && isOpen ? searchQuery : selectedOption?.label || "",
2391
+ onChange: (e) => {
2392
+ if (searchable) {
2393
+ setSearchQuery(e.target.value);
2394
+ setHighlightedIndex(0);
2395
+ if (!isOpen) setIsOpen(true);
2396
+ }
2397
+ },
2398
+ onKeyDown: handleKeyDown,
2399
+ onClick: handleToggle,
2400
+ placeholder,
2401
+ style: inputStyles,
2402
+ readOnly: !searchable
2403
+ }
2404
+ ),
2405
+ /* @__PURE__ */ jsx(
2406
+ "span",
2407
+ {
2408
+ "aria-hidden": "true",
2409
+ style: {
2410
+ ...iconStyles,
2411
+ transform: `translateY(-50%) rotate(${isOpen ? "180deg" : "0deg"})`
2412
+ },
2413
+ children: "\u25BC"
2414
+ }
2415
+ )
2416
+ ] }),
2417
+ isOpen && /* @__PURE__ */ jsx(
2418
+ "ul",
2419
+ {
2420
+ ref: listboxRef,
2421
+ id: listboxId,
2422
+ role: "listbox",
2423
+ "aria-labelledby": labelId,
2424
+ style: listboxStyles,
2425
+ children: filteredOptions.length === 0 ? /* @__PURE__ */ jsx("li", { role: "option", "aria-disabled": "true", style: { padding: "10px 12px", color: "#9ca3af" }, children: "No options found" }) : filteredOptions.map((option, index) => {
2426
+ const isHighlighted = index === highlightedIndex;
2427
+ const isSelected = option.value === value;
2428
+ return /* @__PURE__ */ jsx(
2429
+ "li",
2430
+ {
2431
+ id: `${listboxId}-option-${index}`,
2432
+ role: "option",
2433
+ "aria-selected": isSelected,
2434
+ "aria-disabled": option.disabled,
2435
+ "data-index": index,
2436
+ onClick: () => handleSelect(option),
2437
+ onMouseEnter: () => setHighlightedIndex(index),
2438
+ style: optionStyles(isHighlighted, isSelected, !!option.disabled),
2439
+ children: option.label
2440
+ },
2441
+ String(option.value)
2442
+ );
2443
+ })
2444
+ }
2445
+ ),
2446
+ error && /* @__PURE__ */ jsx("div", { id: errorId, role: "alert", style: errorStyles, children: error })
2447
+ ] });
2448
+ }
2449
+ var AccessibleDatePicker = ({
2450
+ value,
2451
+ onChange,
2452
+ label,
2453
+ minDate,
2454
+ maxDate,
2455
+ disabledDates = [],
2456
+ required = false,
2457
+ disabled = false,
2458
+ error,
2459
+ dateFormat = "MM/DD/YYYY",
2460
+ className = "",
2461
+ style = {}
2462
+ }) => {
2463
+ const [isOpen, setIsOpen] = useState(false);
2464
+ const [viewDate, setViewDate] = useState(value || /* @__PURE__ */ new Date());
2465
+ const [focusedDate, setFocusedDate] = useState(null);
2466
+ const pickerId = useId2("datepicker");
2467
+ const labelId = useId2("datepicker-label");
2468
+ const calendarId = useId2("datepicker-calendar");
2469
+ const errorId = useId2("datepicker-error");
2470
+ const containerRef = useRef(null);
2471
+ const buttonRef = useRef(null);
2472
+ useClickOutside(containerRef, () => setIsOpen(false), isOpen);
2473
+ const formatDate = (date) => {
2474
+ if (!date) return "";
2475
+ const day = String(date.getDate()).padStart(2, "0");
2476
+ const month = String(date.getMonth() + 1).padStart(2, "0");
2477
+ const year = date.getFullYear();
2478
+ switch (dateFormat) {
2479
+ case "DD/MM/YYYY":
2480
+ return `${day}/${month}/${year}`;
2481
+ case "YYYY-MM-DD":
2482
+ return `${year}-${month}-${day}`;
2483
+ case "MM/DD/YYYY":
2484
+ default:
2485
+ return `${month}/${day}/${year}`;
2486
+ }
2487
+ };
2488
+ const isSameDay = (date1, date2) => {
2489
+ return date1.getDate() === date2.getDate() && date1.getMonth() === date2.getMonth() && date1.getFullYear() === date2.getFullYear();
2490
+ };
2491
+ const isDateDisabled = (date) => {
2492
+ if (minDate && date < minDate) return true;
2493
+ if (maxDate && date > maxDate) return true;
2494
+ return disabledDates.some((disabledDate) => isSameDay(date, disabledDate));
2495
+ };
2496
+ const getDaysInMonth = (date) => {
2497
+ const year = date.getFullYear();
2498
+ const month = date.getMonth();
2499
+ const firstDay = new Date(year, month, 1);
2500
+ const lastDay = new Date(year, month + 1, 0);
2501
+ const days2 = [];
2502
+ const startDayOfWeek = firstDay.getDay();
2503
+ for (let i = 0; i < startDayOfWeek; i++) {
2504
+ days2.push(new Date(year, month, -startDayOfWeek + i + 1));
2505
+ }
2506
+ for (let day = 1; day <= lastDay.getDate(); day++) {
2507
+ days2.push(new Date(year, month, day));
2508
+ }
2509
+ return days2;
2510
+ };
2511
+ const handlePreviousMonth = () => {
2512
+ setViewDate(new Date(viewDate.getFullYear(), viewDate.getMonth() - 1, 1));
2513
+ };
2514
+ const handleNextMonth = () => {
2515
+ setViewDate(new Date(viewDate.getFullYear(), viewDate.getMonth() + 1, 1));
2516
+ };
2517
+ const handleDateSelect = (date) => {
2518
+ if (isDateDisabled(date)) return;
2519
+ onChange(date);
2520
+ setIsOpen(false);
2521
+ buttonRef.current?.focus();
2522
+ };
2523
+ const handleKeyDown = (event, date) => {
2524
+ let nextDate = null;
2525
+ switch (event.key) {
2526
+ case "Enter":
2527
+ case " ":
2528
+ event.preventDefault();
2529
+ handleDateSelect(date);
2530
+ return;
2531
+ case "Escape":
2532
+ event.preventDefault();
2533
+ setIsOpen(false);
2534
+ buttonRef.current?.focus();
2535
+ return;
2536
+ case "ArrowLeft":
2537
+ event.preventDefault();
2538
+ nextDate = new Date(date);
2539
+ nextDate.setDate(date.getDate() - 1);
2540
+ break;
2541
+ case "ArrowRight":
2542
+ event.preventDefault();
2543
+ nextDate = new Date(date);
2544
+ nextDate.setDate(date.getDate() + 1);
2545
+ break;
2546
+ case "ArrowUp":
2547
+ event.preventDefault();
2548
+ nextDate = new Date(date);
2549
+ nextDate.setDate(date.getDate() - 7);
2550
+ break;
2551
+ case "ArrowDown":
2552
+ event.preventDefault();
2553
+ nextDate = new Date(date);
2554
+ nextDate.setDate(date.getDate() + 7);
2555
+ break;
2556
+ case "Home":
2557
+ event.preventDefault();
2558
+ nextDate = new Date(date.getFullYear(), date.getMonth(), 1);
2559
+ break;
2560
+ case "End":
2561
+ event.preventDefault();
2562
+ nextDate = new Date(date.getFullYear(), date.getMonth() + 1, 0);
2563
+ break;
2564
+ case "PageUp":
2565
+ event.preventDefault();
2566
+ nextDate = new Date(date.getFullYear(), date.getMonth() - 1, date.getDate());
2567
+ break;
2568
+ case "PageDown":
2569
+ event.preventDefault();
2570
+ nextDate = new Date(date.getFullYear(), date.getMonth() + 1, date.getDate());
2571
+ break;
2572
+ }
2573
+ if (nextDate) {
2574
+ setFocusedDate(nextDate);
2575
+ if (nextDate.getMonth() !== viewDate.getMonth()) {
2576
+ setViewDate(new Date(nextDate.getFullYear(), nextDate.getMonth(), 1));
2577
+ }
2578
+ }
2579
+ };
2580
+ const days = getDaysInMonth(viewDate);
2581
+ const monthNames = [
2582
+ "January",
2583
+ "February",
2584
+ "March",
2585
+ "April",
2586
+ "May",
2587
+ "June",
2588
+ "July",
2589
+ "August",
2590
+ "September",
2591
+ "October",
2592
+ "November",
2593
+ "December"
2594
+ ];
2595
+ const dayNames = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
2596
+ const containerStyles = {
2597
+ position: "relative",
2598
+ width: "100%",
2599
+ ...style
2600
+ };
2601
+ const labelStyles = {
2602
+ display: "block",
2603
+ fontWeight: 600,
2604
+ fontSize: "14px",
2605
+ marginBottom: "6px"
2606
+ };
2607
+ const buttonStyles = {
2608
+ width: "100%",
2609
+ padding: "10px 36px 10px 12px",
2610
+ border: `1px solid ${error ? "#ef4444" : "#e5e7eb"}`,
2611
+ borderRadius: "6px",
2612
+ fontSize: "14px",
2613
+ backgroundColor: disabled ? "#f9fafb" : "#fff",
2614
+ cursor: disabled ? "not-allowed" : "pointer",
2615
+ textAlign: "left",
2616
+ position: "relative"
2617
+ };
2618
+ const calendarStyles = {
2619
+ position: "absolute",
2620
+ top: "100%",
2621
+ left: 0,
2622
+ marginTop: "4px",
2623
+ backgroundColor: "#fff",
2624
+ border: "1px solid #e5e7eb",
2625
+ borderRadius: "8px",
2626
+ boxShadow: "0 4px 6px rgba(0, 0, 0, 0.1)",
2627
+ padding: "16px",
2628
+ zIndex: 1e3,
2629
+ minWidth: "280px"
2630
+ };
2631
+ const headerStyles = {
2632
+ display: "flex",
2633
+ justifyContent: "space-between",
2634
+ alignItems: "center",
2635
+ marginBottom: "12px"
2636
+ };
2637
+ const navButtonStyles = {
2638
+ padding: "6px 12px",
2639
+ border: "1px solid #e5e7eb",
2640
+ borderRadius: "4px",
2641
+ backgroundColor: "#fff",
2642
+ cursor: "pointer",
2643
+ fontSize: "14px"
2644
+ };
2645
+ const gridStyles = {
2646
+ display: "grid",
2647
+ gridTemplateColumns: "repeat(7, 1fr)",
2648
+ gap: "4px"
2649
+ };
2650
+ const dayHeaderStyles = {
2651
+ textAlign: "center",
2652
+ fontWeight: 600,
2653
+ fontSize: "12px",
2654
+ padding: "8px 0",
2655
+ color: "#6b7280"
2656
+ };
2657
+ const dayCellStyles = (_date, isCurrentMonth, isSelected, isToday, isDisabled) => ({
2658
+ padding: "8px",
2659
+ border: "none",
2660
+ borderRadius: "4px",
2661
+ fontSize: "14px",
2662
+ cursor: isDisabled ? "not-allowed" : "pointer",
2663
+ backgroundColor: isSelected ? "#3b82f6" : isToday ? "#e5e7eb" : "transparent",
2664
+ color: isSelected ? "#fff" : !isCurrentMonth ? "#9ca3af" : isDisabled ? "#d1d5db" : "#1f2937",
2665
+ fontWeight: isSelected || isToday ? 600 : 400,
2666
+ opacity: isDisabled ? 0.5 : 1
2667
+ });
2668
+ const errorStyles = {
2669
+ marginTop: "6px",
2670
+ fontSize: "13px",
2671
+ color: "#ef4444"
2672
+ };
2673
+ return /* @__PURE__ */ jsxs("div", { ref: containerRef, className, style: containerStyles, children: [
2674
+ /* @__PURE__ */ jsxs("label", { id: labelId, htmlFor: pickerId, style: labelStyles, children: [
2675
+ label,
2676
+ required && /* @__PURE__ */ jsxs("span", { "aria-label": "required", style: { color: "#ef4444" }, children: [
2677
+ " ",
2678
+ "*"
2679
+ ] })
2680
+ ] }),
2681
+ /* @__PURE__ */ jsxs(
2682
+ "button",
2683
+ {
2684
+ ref: buttonRef,
2685
+ id: pickerId,
2686
+ type: "button",
2687
+ "aria-labelledby": labelId,
2688
+ "aria-expanded": isOpen,
2689
+ "aria-controls": calendarId,
2690
+ "aria-describedby": error ? errorId : void 0,
2691
+ "aria-required": required,
2692
+ "aria-invalid": !!error,
2693
+ disabled,
2694
+ onClick: () => !disabled && setIsOpen(!isOpen),
2695
+ style: buttonStyles,
2696
+ children: [
2697
+ value ? formatDate(value) : "Select date",
2698
+ /* @__PURE__ */ jsx(
2699
+ "span",
2700
+ {
2701
+ "aria-hidden": "true",
2702
+ style: {
2703
+ position: "absolute",
2704
+ right: "12px",
2705
+ top: "50%",
2706
+ transform: "translateY(-50%)"
2707
+ },
2708
+ children: "\u{1F4C5}"
2709
+ }
2710
+ )
2711
+ ]
2712
+ }
2713
+ ),
2714
+ isOpen && /* @__PURE__ */ jsxs("div", { id: calendarId, role: "dialog", "aria-modal": "false", "aria-label": "Calendar", style: calendarStyles, children: [
2715
+ /* @__PURE__ */ jsxs("div", { style: headerStyles, children: [
2716
+ /* @__PURE__ */ jsx(
2717
+ "button",
2718
+ {
2719
+ type: "button",
2720
+ onClick: handlePreviousMonth,
2721
+ "aria-label": "Previous month",
2722
+ style: navButtonStyles,
2723
+ children: "\u2039"
2724
+ }
2725
+ ),
2726
+ /* @__PURE__ */ jsxs("span", { style: { fontWeight: 600 }, children: [
2727
+ monthNames[viewDate.getMonth()],
2728
+ " ",
2729
+ viewDate.getFullYear()
2730
+ ] }),
2731
+ /* @__PURE__ */ jsx(
2732
+ "button",
2733
+ {
2734
+ type: "button",
2735
+ onClick: handleNextMonth,
2736
+ "aria-label": "Next month",
2737
+ style: navButtonStyles,
2738
+ children: "\u203A"
2739
+ }
2740
+ )
2741
+ ] }),
2742
+ /* @__PURE__ */ jsxs("div", { role: "grid", "aria-labelledby": labelId, style: gridStyles, children: [
2743
+ dayNames.map((day) => /* @__PURE__ */ jsx("div", { role: "columnheader", style: dayHeaderStyles, children: day }, day)),
2744
+ days.map((cellDate, index) => {
2745
+ const isCurrentMonth = cellDate.getMonth() === viewDate.getMonth();
2746
+ const isSelected = value ? isSameDay(cellDate, value) : false;
2747
+ const isToday = isSameDay(cellDate, /* @__PURE__ */ new Date());
2748
+ const isDisabled = isDateDisabled(cellDate);
2749
+ const isFocused = focusedDate ? isSameDay(cellDate, focusedDate) : false;
2750
+ return /* @__PURE__ */ jsx(
2751
+ "button",
2752
+ {
2753
+ type: "button",
2754
+ role: "gridcell",
2755
+ "aria-label": formatDate(cellDate),
2756
+ "aria-selected": isSelected,
2757
+ "aria-disabled": isDisabled,
2758
+ disabled: isDisabled,
2759
+ tabIndex: isFocused || isSelected && !focusedDate ? 0 : -1,
2760
+ onClick: () => handleDateSelect(cellDate),
2761
+ onKeyDown: (e) => handleKeyDown(e, cellDate),
2762
+ style: dayCellStyles(cellDate, isCurrentMonth, isSelected, isToday, isDisabled),
2763
+ onMouseEnter: (e) => {
2764
+ if (!isDisabled && !isSelected) {
2765
+ e.currentTarget.style.backgroundColor = "#f3f4f6";
2766
+ }
2767
+ },
2768
+ onMouseLeave: (e) => {
2769
+ if (!isDisabled && !isSelected) {
2770
+ e.currentTarget.style.backgroundColor = "transparent";
2771
+ }
2772
+ },
2773
+ children: cellDate.getDate()
2774
+ },
2775
+ index
2776
+ );
2777
+ })
2778
+ ] })
2779
+ ] }),
2780
+ error && /* @__PURE__ */ jsx("div", { id: errorId, role: "alert", style: errorStyles, children: error })
2781
+ ] });
2782
+ };
2783
+ function AccessibleTreeView({
2784
+ data,
2785
+ onSelect,
2786
+ expandedNodes: controlledExpanded,
2787
+ onToggle,
2788
+ multiSelect = false,
2789
+ selectedNodes: controlledSelected = [],
2790
+ ariaLabel = "Tree navigation",
2791
+ className = "",
2792
+ style = {}
2793
+ }) {
2794
+ const [internalExpanded, setInternalExpanded] = useState(/* @__PURE__ */ new Set());
2795
+ const [internalSelected, setInternalSelected] = useState(/* @__PURE__ */ new Set());
2796
+ const treeId = useId2("tree");
2797
+ const expandedSet = controlledExpanded ? new Set(controlledExpanded) : internalExpanded;
2798
+ const selectedSet = new Set(controlledSelected.length > 0 ? controlledSelected : Array.from(internalSelected));
2799
+ const toggleNode = (nodeId) => {
2800
+ const isExpanded = expandedSet.has(nodeId);
2801
+ if (controlledExpanded) {
2802
+ onToggle?.(nodeId, !isExpanded);
2803
+ } else {
2804
+ setInternalExpanded((prev) => {
2805
+ const next = new Set(prev);
2806
+ if (isExpanded) {
2807
+ next.delete(nodeId);
2808
+ } else {
2809
+ next.add(nodeId);
2810
+ }
2811
+ return next;
2812
+ });
2813
+ }
2814
+ };
2815
+ const selectNode = (node) => {
2816
+ if (node.disabled) return;
2817
+ if (multiSelect) {
2818
+ setInternalSelected((prev) => {
2819
+ const next = new Set(prev);
2820
+ if (next.has(node.id)) {
2821
+ next.delete(node.id);
2822
+ } else {
2823
+ next.add(node.id);
2824
+ }
2825
+ return next;
2826
+ });
2827
+ } else {
2828
+ setInternalSelected(/* @__PURE__ */ new Set([node.id]));
2829
+ }
2830
+ onSelect?.(node);
2831
+ };
2832
+ const getAllNodes = (nodes) => {
2833
+ const result = [];
2834
+ const traverse = (nodeList) => {
2835
+ for (const node of nodeList) {
2836
+ result.push(node);
2837
+ if (node.children && expandedSet.has(node.id)) {
2838
+ traverse(node.children);
2839
+ }
2840
+ }
2841
+ };
2842
+ traverse(nodes);
2843
+ return result;
2844
+ };
2845
+ const handleKeyDown = (event, node, allNodes2) => {
2846
+ const currentIndex = allNodes2.findIndex((n) => n.id === node.id);
2847
+ switch (event.key) {
2848
+ case "Enter":
2849
+ case " ":
2850
+ event.preventDefault();
2851
+ selectNode(node);
2852
+ break;
2853
+ case "ArrowDown":
2854
+ event.preventDefault();
2855
+ if (currentIndex < allNodes2.length - 1) {
2856
+ const nextNode = allNodes2[currentIndex + 1];
2857
+ document.getElementById(`${treeId}-${nextNode.id}`)?.focus();
2858
+ }
2859
+ break;
2860
+ case "ArrowUp":
2861
+ event.preventDefault();
2862
+ if (currentIndex > 0) {
2863
+ const prevNode = allNodes2[currentIndex - 1];
2864
+ document.getElementById(`${treeId}-${prevNode.id}`)?.focus();
2865
+ }
2866
+ break;
2867
+ case "ArrowRight":
2868
+ event.preventDefault();
2869
+ if (node.children && node.children.length > 0) {
2870
+ if (!expandedSet.has(node.id)) {
2871
+ toggleNode(node.id);
2872
+ } else if (node.children[0]) {
2873
+ document.getElementById(`${treeId}-${node.children[0].id}`)?.focus();
2874
+ }
2875
+ }
2876
+ break;
2877
+ case "ArrowLeft":
2878
+ event.preventDefault();
2879
+ if (node.children && expandedSet.has(node.id)) {
2880
+ toggleNode(node.id);
2881
+ }
2882
+ break;
2883
+ case "Home":
2884
+ event.preventDefault();
2885
+ if (allNodes2[0]) {
2886
+ document.getElementById(`${treeId}-${allNodes2[0].id}`)?.focus();
2887
+ }
2888
+ break;
2889
+ case "End":
2890
+ event.preventDefault();
2891
+ if (allNodes2[allNodes2.length - 1]) {
2892
+ document.getElementById(`${treeId}-${allNodes2[allNodes2.length - 1].id}`)?.focus();
2893
+ }
2894
+ break;
2895
+ }
2896
+ };
2897
+ const renderNode = (node, level, allNodes2) => {
2898
+ const hasChildren = node.children && node.children.length > 0;
2899
+ const isExpanded = expandedSet.has(node.id);
2900
+ const isSelected = selectedSet.has(node.id);
2901
+ const nodeStyles = {
2902
+ display: "flex",
2903
+ alignItems: "center",
2904
+ gap: "8px",
2905
+ padding: "8px 12px",
2906
+ paddingLeft: `${12 + level * 24}px`,
2907
+ cursor: node.disabled ? "not-allowed" : "pointer",
2908
+ backgroundColor: isSelected ? "#e5e7eb" : "transparent",
2909
+ borderRadius: "4px",
2910
+ opacity: node.disabled ? 0.5 : 1
2911
+ };
2912
+ const iconStyles = {
2913
+ width: "16px",
2914
+ textAlign: "center",
2915
+ transition: "transform 0.2s",
2916
+ transform: isExpanded ? "rotate(90deg)" : "rotate(0deg)"
2917
+ };
2918
+ return /* @__PURE__ */ jsxs(React4.Fragment, { children: [
2919
+ /* @__PURE__ */ jsxs(
2920
+ "div",
2921
+ {
2922
+ id: `${treeId}-${node.id}`,
2923
+ role: "treeitem",
2924
+ "aria-expanded": hasChildren ? isExpanded : void 0,
2925
+ "aria-selected": isSelected,
2926
+ "aria-level": level + 1,
2927
+ "aria-disabled": node.disabled,
2928
+ tabIndex: isSelected ? 0 : -1,
2929
+ onClick: () => {
2930
+ if (!node.disabled) {
2931
+ if (hasChildren) {
2932
+ toggleNode(node.id);
2933
+ }
2934
+ selectNode(node);
2935
+ }
2936
+ },
2937
+ onKeyDown: (e) => handleKeyDown(e, node, allNodes2),
2938
+ style: nodeStyles,
2939
+ onMouseEnter: (e) => {
2940
+ if (!node.disabled && !isSelected) {
2941
+ e.currentTarget.style.backgroundColor = "#f3f4f6";
2942
+ }
2943
+ },
2944
+ onMouseLeave: (e) => {
2945
+ if (!node.disabled && !isSelected) {
2946
+ e.currentTarget.style.backgroundColor = "transparent";
2947
+ }
2948
+ },
2949
+ children: [
2950
+ hasChildren ? /* @__PURE__ */ jsx("span", { "aria-hidden": "true", style: iconStyles, children: "\u25B6" }) : /* @__PURE__ */ jsx("span", { style: { width: "16px" } }),
2951
+ /* @__PURE__ */ jsx("span", { children: node.label })
2952
+ ]
2953
+ }
2954
+ ),
2955
+ hasChildren && isExpanded && /* @__PURE__ */ jsx("div", { role: "group", children: node.children.map((child) => renderNode(child, level + 1, allNodes2)) })
2956
+ ] }, node.id);
2957
+ };
2958
+ const allNodes = getAllNodes(data);
2959
+ const containerStyles = {
2960
+ ...style
2961
+ };
2962
+ return /* @__PURE__ */ jsx(
2963
+ "div",
2964
+ {
2965
+ id: treeId,
2966
+ role: "tree",
2967
+ "aria-label": ariaLabel,
2968
+ "aria-multiselectable": multiSelect,
2969
+ className,
2970
+ style: containerStyles,
2971
+ children: data.map((node) => renderNode(node, 0, allNodes))
2972
+ }
2973
+ );
2974
+ }
2975
+ function AccessibleTable({
2976
+ data,
2977
+ columns,
2978
+ caption,
2979
+ selectable = false,
2980
+ selectedRows: controlledSelected = [],
2981
+ onSelectionChange,
2982
+ getRowKey = (_, index) => String(index),
2983
+ sortable = false,
2984
+ sortColumn: controlledSortColumn,
2985
+ sortDirection: controlledSortDirection,
2986
+ onSort,
2987
+ className = "",
2988
+ style = {}
2989
+ }) {
2990
+ const [internalSelected, setInternalSelected] = useState(/* @__PURE__ */ new Set());
2991
+ const [internalSortColumn, setInternalSortColumn] = useState(null);
2992
+ const [internalSortDirection, setInternalSortDirection] = useState(null);
2993
+ const tableId = useId2("table");
2994
+ const selectedSet = new Set(controlledSelected.length > 0 ? controlledSelected : Array.from(internalSelected));
2995
+ const sortColumn = controlledSortColumn !== void 0 ? controlledSortColumn : internalSortColumn;
2996
+ const sortDirection = controlledSortDirection !== void 0 ? controlledSortDirection : internalSortDirection;
2997
+ const handleSelectAll = (checked) => {
2998
+ if (checked) {
2999
+ const allIndices = data.map((_, index) => index);
3000
+ setInternalSelected(new Set(allIndices));
3001
+ onSelectionChange?.(allIndices);
3002
+ } else {
3003
+ setInternalSelected(/* @__PURE__ */ new Set());
3004
+ onSelectionChange?.([]);
3005
+ }
3006
+ };
3007
+ const handleSelectRow = (index, checked) => {
3008
+ const newSelected = new Set(selectedSet);
3009
+ if (checked) {
3010
+ newSelected.add(index);
3011
+ } else {
3012
+ newSelected.delete(index);
3013
+ }
3014
+ setInternalSelected(newSelected);
3015
+ onSelectionChange?.(Array.from(newSelected));
3016
+ };
3017
+ const handleSort = (column) => {
3018
+ const col = columns.find((c) => c.key === column);
3019
+ if (!col?.sortable && !sortable) return;
3020
+ let newDirection = "asc";
3021
+ if (sortColumn === column) {
3022
+ if (sortDirection === "asc") {
3023
+ newDirection = "desc";
3024
+ } else if (sortDirection === "desc") {
3025
+ newDirection = null;
3026
+ }
3027
+ }
3028
+ if (onSort) {
3029
+ onSort(column, newDirection);
3030
+ } else {
3031
+ setInternalSortColumn(newDirection ? column : null);
3032
+ setInternalSortDirection(newDirection);
3033
+ }
3034
+ };
3035
+ const isAllSelected = data.length > 0 && selectedSet.size === data.length;
3036
+ const isSomeSelected = selectedSet.size > 0 && selectedSet.size < data.length;
3037
+ const tableStyles = {
3038
+ width: "100%",
3039
+ borderCollapse: "collapse",
3040
+ fontSize: "14px",
3041
+ ...style
3042
+ };
3043
+ const thStyles = {
3044
+ padding: "12px",
3045
+ textAlign: "left",
3046
+ borderBottom: "2px solid #e5e7eb",
3047
+ fontWeight: 600,
3048
+ backgroundColor: "#f9fafb"
3049
+ };
3050
+ const sortButtonStyles = {
3051
+ background: "none",
3052
+ border: "none",
3053
+ cursor: "pointer",
3054
+ display: "flex",
3055
+ alignItems: "center",
3056
+ gap: "8px",
3057
+ font: "inherit",
3058
+ fontWeight: 600,
3059
+ padding: 0,
3060
+ width: "100%"
3061
+ };
3062
+ const tdStyles = {
3063
+ padding: "12px",
3064
+ borderBottom: "1px solid #e5e7eb"
3065
+ };
3066
+ const rowStyles = (isSelected) => ({
3067
+ backgroundColor: isSelected ? "#eff6ff" : "transparent"
3068
+ });
3069
+ const getSortIcon = (column) => {
3070
+ if (sortColumn !== column) return "\u21C5";
3071
+ if (sortDirection === "asc") return "\u2191";
3072
+ if (sortDirection === "desc") return "\u2193";
3073
+ return "\u21C5";
3074
+ };
3075
+ return /* @__PURE__ */ jsxs(
3076
+ "table",
3077
+ {
3078
+ id: tableId,
3079
+ className,
3080
+ style: tableStyles,
3081
+ role: "table",
3082
+ "aria-label": caption,
3083
+ children: [
3084
+ /* @__PURE__ */ jsx("caption", { style: { padding: "12px", textAlign: "left", fontWeight: 600, fontSize: "16px" }, children: caption }),
3085
+ /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { children: [
3086
+ selectable && /* @__PURE__ */ jsx("th", { scope: "col", style: { ...thStyles, width: "50px" }, children: /* @__PURE__ */ jsx(
3087
+ "input",
3088
+ {
3089
+ type: "checkbox",
3090
+ checked: isAllSelected,
3091
+ ref: (el) => {
3092
+ if (el) {
3093
+ el.indeterminate = isSomeSelected;
3094
+ }
3095
+ },
3096
+ onChange: (e) => handleSelectAll(e.target.checked),
3097
+ "aria-label": "Select all rows"
3098
+ }
3099
+ ) }),
3100
+ columns.map((column) => {
3101
+ const isSortable = column.sortable || sortable;
3102
+ return /* @__PURE__ */ jsx(
3103
+ "th",
3104
+ {
3105
+ scope: "col",
3106
+ style: { ...thStyles, width: column.width },
3107
+ "aria-sort": sortColumn === column.key ? sortDirection === "asc" ? "ascending" : sortDirection === "desc" ? "descending" : "none" : void 0,
3108
+ children: isSortable ? /* @__PURE__ */ jsxs(
3109
+ "button",
3110
+ {
3111
+ type: "button",
3112
+ onClick: () => handleSort(column.key),
3113
+ style: sortButtonStyles,
3114
+ "aria-label": `Sort by ${column.label}`,
3115
+ children: [
3116
+ /* @__PURE__ */ jsx("span", { children: column.label }),
3117
+ /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: getSortIcon(column.key) })
3118
+ ]
3119
+ }
3120
+ ) : column.label
3121
+ },
3122
+ column.key
3123
+ );
3124
+ })
3125
+ ] }) }),
3126
+ /* @__PURE__ */ jsx("tbody", { children: data.length === 0 ? /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx(
3127
+ "td",
3128
+ {
3129
+ colSpan: columns.length + (selectable ? 1 : 0),
3130
+ style: { ...tdStyles, textAlign: "center", color: "#9ca3af" },
3131
+ children: "No data available"
3132
+ }
3133
+ ) }) : data.map((item, index) => {
3134
+ const isSelected = selectedSet.has(index);
3135
+ const rowKey = getRowKey(item, index);
3136
+ return /* @__PURE__ */ jsxs("tr", { style: rowStyles(isSelected), children: [
3137
+ selectable && /* @__PURE__ */ jsx("td", { style: tdStyles, children: /* @__PURE__ */ jsx(
3138
+ "input",
3139
+ {
3140
+ type: "checkbox",
3141
+ checked: isSelected,
3142
+ onChange: (e) => handleSelectRow(index, e.target.checked),
3143
+ "aria-label": `Select row ${index + 1}`
3144
+ }
3145
+ ) }),
3146
+ columns.map((column) => /* @__PURE__ */ jsx("td", { style: tdStyles, children: column.render ? column.render(item, index) : String(item[column.key] ?? "") }, column.key))
3147
+ ] }, rowKey);
3148
+ }) })
3149
+ ]
3150
+ }
3151
+ );
3152
+ }
3153
+ function useReducedMotion() {
3154
+ const [prefersReducedMotion, setPrefersReducedMotion] = useState(() => {
3155
+ if (typeof window === "undefined") return false;
3156
+ const mediaQuery = window.matchMedia("(prefers-reduced-motion: reduce)");
3157
+ return mediaQuery.matches;
3158
+ });
3159
+ useEffect(() => {
3160
+ if (typeof window === "undefined") return;
3161
+ const mediaQuery = window.matchMedia("(prefers-reduced-motion: reduce)");
3162
+ const handleChange = (event) => {
3163
+ setPrefersReducedMotion(event.matches);
3164
+ };
3165
+ if (mediaQuery.addEventListener) {
3166
+ mediaQuery.addEventListener("change", handleChange);
3167
+ return () => mediaQuery.removeEventListener("change", handleChange);
3168
+ }
3169
+ mediaQuery.addListener(handleChange);
3170
+ return () => mediaQuery.removeListener(handleChange);
3171
+ }, []);
3172
+ return prefersReducedMotion;
3173
+ }
3174
+ function useAnnounce() {
3175
+ const regionRef = useRef(null);
3176
+ useEffect(() => {
3177
+ if (!regionRef.current) {
3178
+ const region = document.createElement("div");
3179
+ region.setAttribute("role", "status");
3180
+ region.setAttribute("aria-live", "polite");
3181
+ region.setAttribute("aria-atomic", "true");
3182
+ region.style.position = "absolute";
3183
+ region.style.left = "-10000px";
3184
+ region.style.width = "1px";
3185
+ region.style.height = "1px";
3186
+ region.style.overflow = "hidden";
3187
+ document.body.appendChild(region);
3188
+ regionRef.current = region;
3189
+ }
3190
+ return () => {
3191
+ if (regionRef.current) {
3192
+ document.body.removeChild(regionRef.current);
3193
+ regionRef.current = null;
3194
+ }
3195
+ };
3196
+ }, []);
3197
+ const announce = useCallback(
3198
+ (message, politeness = "polite") => {
3199
+ if (!regionRef.current) return;
3200
+ regionRef.current.setAttribute("aria-live", politeness);
3201
+ regionRef.current.textContent = "";
3202
+ setTimeout(() => {
3203
+ if (regionRef.current) {
3204
+ regionRef.current.textContent = message;
3205
+ }
3206
+ }, 100);
3207
+ setTimeout(() => {
3208
+ if (regionRef.current) {
3209
+ regionRef.current.textContent = "";
3210
+ }
3211
+ }, 5100);
3212
+ },
3213
+ []
3214
+ );
3215
+ return announce;
3216
+ }
3217
+ var AccessibleCarousel = ({
3218
+ items,
3219
+ autoPlay = false,
3220
+ interval = 5e3,
3221
+ controls = true,
3222
+ indicators = true,
3223
+ loop = true,
3224
+ ariaLabel = "Carousel",
3225
+ className = "",
3226
+ style = {}
3227
+ }) => {
3228
+ const [currentIndex, setCurrentIndex] = useState(0);
3229
+ const [isPlaying, setIsPlaying] = useState(autoPlay);
3230
+ const [isPaused, setIsPaused] = useState(false);
3231
+ const carouselId = useId2("carousel");
3232
+ const regionRef = useRef(null);
3233
+ const intervalRef = useRef(void 0);
3234
+ const prefersReducedMotion = useReducedMotion();
3235
+ const announce = useAnnounce();
3236
+ const totalSlides = items.length;
3237
+ useEffect(() => {
3238
+ if (isPlaying && !isPaused && !prefersReducedMotion) {
3239
+ intervalRef.current = setInterval(() => {
3240
+ handleNext();
3241
+ }, interval);
3242
+ }
3243
+ return () => {
3244
+ if (intervalRef.current) {
3245
+ clearInterval(intervalRef.current);
3246
+ }
3247
+ };
3248
+ }, [isPlaying, isPaused, currentIndex, interval, prefersReducedMotion]);
3249
+ const handlePrevious = () => {
3250
+ const newIndex = currentIndex === 0 ? loop ? totalSlides - 1 : 0 : currentIndex - 1;
3251
+ setCurrentIndex(newIndex);
3252
+ announce(`Slide ${newIndex + 1} of ${totalSlides}`, "polite");
3253
+ };
3254
+ const handleNext = () => {
3255
+ const newIndex = currentIndex === totalSlides - 1 ? loop ? 0 : totalSlides - 1 : currentIndex + 1;
3256
+ setCurrentIndex(newIndex);
3257
+ announce(`Slide ${newIndex + 1} of ${totalSlides}`, "polite");
3258
+ };
3259
+ const handleGoToSlide = (index) => {
3260
+ setCurrentIndex(index);
3261
+ announce(`Slide ${index + 1} of ${totalSlides}`, "polite");
3262
+ };
3263
+ const handlePlayPause = () => {
3264
+ setIsPlaying(!isPlaying);
3265
+ announce(isPlaying ? "Carousel paused" : "Carousel playing", "polite");
3266
+ };
3267
+ const handleKeyDown = (event) => {
3268
+ switch (event.key) {
3269
+ case "ArrowLeft":
3270
+ event.preventDefault();
3271
+ handlePrevious();
3272
+ break;
3273
+ case "ArrowRight":
3274
+ event.preventDefault();
3275
+ handleNext();
3276
+ break;
3277
+ case "Home":
3278
+ event.preventDefault();
3279
+ handleGoToSlide(0);
3280
+ break;
3281
+ case "End":
3282
+ event.preventDefault();
3283
+ handleGoToSlide(totalSlides - 1);
3284
+ break;
3285
+ }
3286
+ };
3287
+ const containerStyles = {
3288
+ position: "relative",
3289
+ overflow: "hidden",
3290
+ width: "100%",
3291
+ ...style
3292
+ };
3293
+ const slidesContainerStyles = {
3294
+ display: "flex",
3295
+ transition: prefersReducedMotion ? "none" : "transform 0.5s ease-in-out",
3296
+ transform: `translateX(-${currentIndex * 100}%)`
3297
+ };
3298
+ const slideStyles = {
3299
+ minWidth: "100%",
3300
+ flex: "0 0 auto"
3301
+ };
3302
+ const controlsContainerStyles = {
3303
+ position: "absolute",
3304
+ top: "50%",
3305
+ left: 0,
3306
+ right: 0,
3307
+ transform: "translateY(-50%)",
3308
+ display: "flex",
3309
+ justifyContent: "space-between",
3310
+ padding: "0 16px",
3311
+ pointerEvents: "none"
3312
+ };
3313
+ const controlButtonStyles = {
3314
+ pointerEvents: "auto",
3315
+ width: "48px",
3316
+ height: "48px",
3317
+ borderRadius: "50%",
3318
+ border: "none",
3319
+ backgroundColor: "rgba(0, 0, 0, 0.5)",
3320
+ color: "#fff",
3321
+ fontSize: "20px",
3322
+ cursor: "pointer",
3323
+ display: "flex",
3324
+ alignItems: "center",
3325
+ justifyContent: "center",
3326
+ transition: "background-color 0.2s"
3327
+ };
3328
+ const indicatorsStyles = {
3329
+ display: "flex",
3330
+ justifyContent: "center",
3331
+ gap: "8px",
3332
+ marginTop: "16px"
3333
+ };
3334
+ const indicatorButtonStyles = (isActive) => ({
3335
+ width: "12px",
3336
+ height: "12px",
3337
+ borderRadius: "50%",
3338
+ border: "none",
3339
+ backgroundColor: isActive ? "#3b82f6" : "#d1d5db",
3340
+ cursor: "pointer",
3341
+ padding: 0,
3342
+ transition: "background-color 0.2s"
3343
+ });
3344
+ const playPauseButtonStyles = {
3345
+ position: "absolute",
3346
+ bottom: "16px",
3347
+ right: "16px",
3348
+ padding: "8px 16px",
3349
+ borderRadius: "4px",
3350
+ border: "none",
3351
+ backgroundColor: "rgba(0, 0, 0, 0.7)",
3352
+ color: "#fff",
3353
+ fontSize: "14px",
3354
+ cursor: "pointer",
3355
+ display: "flex",
3356
+ alignItems: "center",
3357
+ gap: "6px"
3358
+ };
3359
+ return /* @__PURE__ */ jsxs(
3360
+ "section",
3361
+ {
3362
+ ref: regionRef,
3363
+ "aria-roledescription": "carousel",
3364
+ "aria-label": ariaLabel,
3365
+ className,
3366
+ onMouseEnter: () => setIsPaused(true),
3367
+ onMouseLeave: () => setIsPaused(false),
3368
+ onFocus: () => setIsPaused(true),
3369
+ onBlur: () => setIsPaused(false),
3370
+ onKeyDown: handleKeyDown,
3371
+ tabIndex: 0,
3372
+ children: [
3373
+ /* @__PURE__ */ jsxs("div", { style: containerStyles, children: [
3374
+ /* @__PURE__ */ jsx(
3375
+ "div",
3376
+ {
3377
+ id: `${carouselId}-slides`,
3378
+ style: slidesContainerStyles,
3379
+ "aria-live": "polite",
3380
+ "aria-atomic": "false",
3381
+ children: items.map((item, index) => /* @__PURE__ */ jsx(
3382
+ "div",
3383
+ {
3384
+ role: "group",
3385
+ "aria-roledescription": "slide",
3386
+ "aria-label": `Slide ${index + 1} of ${totalSlides}`,
3387
+ "aria-hidden": index !== currentIndex,
3388
+ style: slideStyles,
3389
+ children: item
3390
+ },
3391
+ index
3392
+ ))
3393
+ }
3394
+ ),
3395
+ controls && /* @__PURE__ */ jsxs("div", { style: controlsContainerStyles, children: [
3396
+ /* @__PURE__ */ jsx(
3397
+ "button",
3398
+ {
3399
+ type: "button",
3400
+ onClick: handlePrevious,
3401
+ "aria-label": "Previous slide",
3402
+ "aria-controls": `${carouselId}-slides`,
3403
+ disabled: !loop && currentIndex === 0,
3404
+ style: {
3405
+ ...controlButtonStyles,
3406
+ opacity: !loop && currentIndex === 0 ? 0.5 : 1,
3407
+ cursor: !loop && currentIndex === 0 ? "not-allowed" : "pointer"
3408
+ },
3409
+ onMouseEnter: (e) => {
3410
+ if (loop || currentIndex !== 0) {
3411
+ e.currentTarget.style.backgroundColor = "rgba(0, 0, 0, 0.7)";
3412
+ }
3413
+ },
3414
+ onMouseLeave: (e) => {
3415
+ e.currentTarget.style.backgroundColor = "rgba(0, 0, 0, 0.5)";
3416
+ },
3417
+ children: "\u2039"
3418
+ }
3419
+ ),
3420
+ /* @__PURE__ */ jsx(
3421
+ "button",
3422
+ {
3423
+ type: "button",
3424
+ onClick: handleNext,
3425
+ "aria-label": "Next slide",
3426
+ "aria-controls": `${carouselId}-slides`,
3427
+ disabled: !loop && currentIndex === totalSlides - 1,
3428
+ style: {
3429
+ ...controlButtonStyles,
3430
+ opacity: !loop && currentIndex === totalSlides - 1 ? 0.5 : 1,
3431
+ cursor: !loop && currentIndex === totalSlides - 1 ? "not-allowed" : "pointer"
3432
+ },
3433
+ onMouseEnter: (e) => {
3434
+ if (loop || currentIndex !== totalSlides - 1) {
3435
+ e.currentTarget.style.backgroundColor = "rgba(0, 0, 0, 0.7)";
3436
+ }
3437
+ },
3438
+ onMouseLeave: (e) => {
3439
+ e.currentTarget.style.backgroundColor = "rgba(0, 0, 0, 0.5)";
3440
+ },
3441
+ children: "\u203A"
3442
+ }
3443
+ )
3444
+ ] }),
3445
+ autoPlay && /* @__PURE__ */ jsxs(
3446
+ "button",
3447
+ {
3448
+ type: "button",
3449
+ onClick: handlePlayPause,
3450
+ "aria-label": isPlaying ? "Pause carousel" : "Play carousel",
3451
+ style: playPauseButtonStyles,
3452
+ onMouseEnter: (e) => {
3453
+ e.currentTarget.style.backgroundColor = "rgba(0, 0, 0, 0.9)";
3454
+ },
3455
+ onMouseLeave: (e) => {
3456
+ e.currentTarget.style.backgroundColor = "rgba(0, 0, 0, 0.7)";
3457
+ },
3458
+ children: [
3459
+ isPlaying ? "\u23F8" : "\u25B6",
3460
+ " ",
3461
+ isPlaying ? "Pause" : "Play"
3462
+ ]
3463
+ }
3464
+ )
3465
+ ] }),
3466
+ indicators && /* @__PURE__ */ jsx("div", { role: "group", "aria-label": "Slide indicators", style: indicatorsStyles, children: items.map((_, index) => /* @__PURE__ */ jsx(
3467
+ "button",
3468
+ {
3469
+ type: "button",
3470
+ onClick: () => handleGoToSlide(index),
3471
+ "aria-label": `Go to slide ${index + 1}`,
3472
+ "aria-current": index === currentIndex ? "true" : "false",
3473
+ style: indicatorButtonStyles(index === currentIndex),
3474
+ onMouseEnter: (e) => {
3475
+ if (index !== currentIndex) {
3476
+ e.currentTarget.style.backgroundColor = "#9ca3af";
3477
+ }
3478
+ },
3479
+ onMouseLeave: (e) => {
3480
+ if (index !== currentIndex) {
3481
+ e.currentTarget.style.backgroundColor = "#d1d5db";
3482
+ }
3483
+ }
3484
+ },
3485
+ index
3486
+ )) })
3487
+ ]
3488
+ }
3489
+ );
3490
+ };
3491
+ var AccessibleDrawer = ({
3492
+ isOpen,
3493
+ onClose,
3494
+ side = "right",
3495
+ modal = true,
3496
+ title,
3497
+ children,
3498
+ className = "",
3499
+ backdropClassName = "",
3500
+ style = {}
3501
+ }) => {
3502
+ const drawerId = useId2("drawer");
3503
+ const titleId = useId2("drawer-title");
3504
+ const { trapRef } = useFocusTrap({
3505
+ isActive: isOpen && modal,
3506
+ onEscape: onClose
3507
+ });
3508
+ const prefersReducedMotion = useReducedMotion();
3509
+ useEffect(() => {
3510
+ if (isOpen && modal) {
3511
+ const originalOverflow = document.body.style.overflow;
3512
+ document.body.style.overflow = "hidden";
3513
+ return () => {
3514
+ document.body.style.overflow = originalOverflow;
3515
+ };
3516
+ }
3517
+ }, [isOpen, modal]);
3518
+ if (!isOpen) return null;
3519
+ const getDrawerPosition = () => {
3520
+ const baseStyles = {
3521
+ position: "fixed",
3522
+ zIndex: 1e3,
3523
+ backgroundColor: "#fff",
3524
+ boxShadow: "0 4px 6px rgba(0, 0, 0, 0.1)",
3525
+ transition: prefersReducedMotion ? "none" : "transform 0.3s ease-in-out"
3526
+ };
3527
+ switch (side) {
3528
+ case "left":
3529
+ return {
3530
+ ...baseStyles,
3531
+ top: 0,
3532
+ left: 0,
3533
+ bottom: 0,
3534
+ width: "320px",
3535
+ maxWidth: "80vw"
3536
+ };
3537
+ case "right":
3538
+ return {
3539
+ ...baseStyles,
3540
+ top: 0,
3541
+ right: 0,
3542
+ bottom: 0,
3543
+ width: "320px",
3544
+ maxWidth: "80vw"
3545
+ };
3546
+ case "top":
3547
+ return {
3548
+ ...baseStyles,
3549
+ top: 0,
3550
+ left: 0,
3551
+ right: 0,
3552
+ height: "320px",
3553
+ maxHeight: "80vh"
3554
+ };
3555
+ case "bottom":
3556
+ return {
3557
+ ...baseStyles,
3558
+ bottom: 0,
3559
+ left: 0,
3560
+ right: 0,
3561
+ height: "320px",
3562
+ maxHeight: "80vh"
3563
+ };
3564
+ default:
3565
+ return baseStyles;
3566
+ }
3567
+ };
3568
+ const backdropStyles = {
3569
+ position: "fixed",
3570
+ top: 0,
3571
+ left: 0,
3572
+ right: 0,
3573
+ bottom: 0,
3574
+ backgroundColor: "rgba(0, 0, 0, 0.5)",
3575
+ zIndex: 999,
3576
+ opacity: isOpen ? 1 : 0,
3577
+ transition: prefersReducedMotion ? "none" : "opacity 0.3s ease-in-out"
3578
+ };
3579
+ const drawerStyles = {
3580
+ ...getDrawerPosition(),
3581
+ display: "flex",
3582
+ flexDirection: "column",
3583
+ overflowY: "auto",
3584
+ ...style
3585
+ };
3586
+ const headerStyles = {
3587
+ display: "flex",
3588
+ justifyContent: "space-between",
3589
+ alignItems: "center",
3590
+ padding: "16px 20px",
3591
+ borderBottom: "1px solid #e5e7eb"
3592
+ };
3593
+ const titleStyles = {
3594
+ fontSize: "18px",
3595
+ fontWeight: 600,
3596
+ margin: 0
3597
+ };
3598
+ const closeButtonStyles = {
3599
+ width: "32px",
3600
+ height: "32px",
3601
+ borderRadius: "4px",
3602
+ border: "none",
3603
+ backgroundColor: "transparent",
3604
+ cursor: "pointer",
3605
+ display: "flex",
3606
+ alignItems: "center",
3607
+ justifyContent: "center",
3608
+ fontSize: "20px",
3609
+ transition: "background-color 0.2s"
3610
+ };
3611
+ const contentStyles = {
3612
+ flex: 1,
3613
+ padding: "20px",
3614
+ overflowY: "auto"
3615
+ };
3616
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
3617
+ modal && /* @__PURE__ */ jsx(
3618
+ "div",
3619
+ {
3620
+ className: backdropClassName,
3621
+ style: backdropStyles,
3622
+ onClick: onClose,
3623
+ "aria-hidden": "true"
3624
+ }
3625
+ ),
3626
+ /* @__PURE__ */ jsxs(
3627
+ "div",
3628
+ {
3629
+ ref: modal ? trapRef : null,
3630
+ id: drawerId,
3631
+ role: "dialog",
3632
+ "aria-modal": modal,
3633
+ "aria-labelledby": title ? titleId : void 0,
3634
+ className,
3635
+ style: drawerStyles,
3636
+ children: [
3637
+ /* @__PURE__ */ jsxs("div", { style: headerStyles, children: [
3638
+ title && /* @__PURE__ */ jsx("h2", { id: titleId, style: titleStyles, children: title }),
3639
+ /* @__PURE__ */ jsx(
3640
+ "button",
3641
+ {
3642
+ type: "button",
3643
+ onClick: onClose,
3644
+ "aria-label": "Close drawer",
3645
+ style: closeButtonStyles,
3646
+ onMouseEnter: (e) => {
3647
+ e.currentTarget.style.backgroundColor = "#f3f4f6";
3648
+ },
3649
+ onMouseLeave: (e) => {
3650
+ e.currentTarget.style.backgroundColor = "transparent";
3651
+ },
3652
+ children: "\xD7"
3653
+ }
3654
+ )
3655
+ ] }),
3656
+ /* @__PURE__ */ jsx("div", { style: contentStyles, children })
3657
+ ]
3658
+ }
3659
+ )
3660
+ ] });
3661
+ };
846
3662
 
847
- export { AccessibleButton, AccessibleDialog, AccessibleMenu, AccessibleModal, AccessibleTabs };
3663
+ export { AccessibleAccordion, AccessibleBreadcrumb, AccessibleButton, AccessibleCarousel, AccessibleCheckboxGroup, AccessibleCombobox, AccessibleDatePicker, AccessibleDialog, AccessibleDrawer, AccessibleMenu, AccessibleModal, AccessiblePagination, AccessibleProgress, AccessibleRadioGroup, AccessibleTable, AccessibleTabs, AccessibleToast, AccessibleToggle, AccessibleTooltip, AccessibleTreeView, SkipLinks, ToastContainer };
848
3664
  //# sourceMappingURL=index.js.map
849
3665
  //# sourceMappingURL=index.js.map