se-design 1.0.79 → 1.0.81-dev1

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.
Files changed (379) hide show
  1. package/dist/assets/icons/envelope.svg +4 -0
  2. package/dist/assets/icons/views.svg +7 -0
  3. package/dist/assets/style.css +1 -1
  4. package/dist/components/Checkbox/index.d.ts +4 -0
  5. package/dist/components/DatePicker/useDatePickerA11y.d.ts +1 -4
  6. package/dist/components/Dropdown/index.d.ts +4 -0
  7. package/dist/components/LabelChip/index.d.ts +1 -0
  8. package/dist/components/Popover/index.d.ts +9 -1
  9. package/dist/components/Radio/index.d.ts +4 -0
  10. package/dist/components/Toggle/index.d.ts +4 -0
  11. package/dist/index100.js +1 -1
  12. package/dist/index100.js.map +1 -1
  13. package/dist/index101.js +1 -1
  14. package/dist/index101.js.map +1 -1
  15. package/dist/index102.js +1 -1
  16. package/dist/index102.js.map +1 -1
  17. package/dist/index103.js +1 -1
  18. package/dist/index103.js.map +1 -1
  19. package/dist/index104.js +1 -1
  20. package/dist/index104.js.map +1 -1
  21. package/dist/index105.js +1 -1
  22. package/dist/index105.js.map +1 -1
  23. package/dist/index106.js +1 -1
  24. package/dist/index106.js.map +1 -1
  25. package/dist/index107.js +1 -1
  26. package/dist/index107.js.map +1 -1
  27. package/dist/index108.js +1 -1
  28. package/dist/index108.js.map +1 -1
  29. package/dist/index109.js +2 -2
  30. package/dist/index109.js.map +1 -1
  31. package/dist/index11.js +44 -43
  32. package/dist/index11.js.map +1 -1
  33. package/dist/index110.js +2 -2
  34. package/dist/index110.js.map +1 -1
  35. package/dist/index111.js +1 -1
  36. package/dist/index111.js.map +1 -1
  37. package/dist/index112.js +1 -1
  38. package/dist/index112.js.map +1 -1
  39. package/dist/index113.js +1 -1
  40. package/dist/index113.js.map +1 -1
  41. package/dist/index114.js +2 -2
  42. package/dist/index114.js.map +1 -1
  43. package/dist/index115.js +2 -2
  44. package/dist/index115.js.map +1 -1
  45. package/dist/index116.js +2 -2
  46. package/dist/index116.js.map +1 -1
  47. package/dist/index117.js +2 -2
  48. package/dist/index117.js.map +1 -1
  49. package/dist/index118.js +1 -1
  50. package/dist/index118.js.map +1 -1
  51. package/dist/index119.js +1 -1
  52. package/dist/index119.js.map +1 -1
  53. package/dist/index12.js +38 -31
  54. package/dist/index12.js.map +1 -1
  55. package/dist/index120.js +2 -2
  56. package/dist/index120.js.map +1 -1
  57. package/dist/index121.js +2 -2
  58. package/dist/index121.js.map +1 -1
  59. package/dist/index122.js +1 -1
  60. package/dist/index122.js.map +1 -1
  61. package/dist/index123.js +1 -1
  62. package/dist/index123.js.map +1 -1
  63. package/dist/index124.js +1 -1
  64. package/dist/index124.js.map +1 -1
  65. package/dist/index125.js +2 -2
  66. package/dist/index125.js.map +1 -1
  67. package/dist/index126.js +1 -1
  68. package/dist/index126.js.map +1 -1
  69. package/dist/index127.js +1 -1
  70. package/dist/index127.js.map +1 -1
  71. package/dist/index128.js +2 -2
  72. package/dist/index128.js.map +1 -1
  73. package/dist/index129.js +2 -2
  74. package/dist/index129.js.map +1 -1
  75. package/dist/index13.js +20 -19
  76. package/dist/index13.js.map +1 -1
  77. package/dist/index130.js +2 -2
  78. package/dist/index130.js.map +1 -1
  79. package/dist/index131.js +2 -2
  80. package/dist/index131.js.map +1 -1
  81. package/dist/index132.js +1 -1
  82. package/dist/index132.js.map +1 -1
  83. package/dist/index133.js +2 -2
  84. package/dist/index133.js.map +1 -1
  85. package/dist/index134.js +1 -1
  86. package/dist/index134.js.map +1 -1
  87. package/dist/index135.js +1 -1
  88. package/dist/index135.js.map +1 -1
  89. package/dist/index136.js +1 -1
  90. package/dist/index136.js.map +1 -1
  91. package/dist/index137.js +1 -1
  92. package/dist/index137.js.map +1 -1
  93. package/dist/index138.js +2 -2
  94. package/dist/index138.js.map +1 -1
  95. package/dist/index139.js +2 -2
  96. package/dist/index139.js.map +1 -1
  97. package/dist/index140.js +1 -1
  98. package/dist/index140.js.map +1 -1
  99. package/dist/index141.js +2 -2
  100. package/dist/index141.js.map +1 -1
  101. package/dist/index142.js +1 -1
  102. package/dist/index142.js.map +1 -1
  103. package/dist/index143.js +1 -1
  104. package/dist/index143.js.map +1 -1
  105. package/dist/index144.js +1 -1
  106. package/dist/index144.js.map +1 -1
  107. package/dist/index145.js +1 -1
  108. package/dist/index145.js.map +1 -1
  109. package/dist/index146.js +1 -1
  110. package/dist/index146.js.map +1 -1
  111. package/dist/index147.js +1 -1
  112. package/dist/index147.js.map +1 -1
  113. package/dist/index148.js +1 -1
  114. package/dist/index148.js.map +1 -1
  115. package/dist/index149.js +2 -2
  116. package/dist/index149.js.map +1 -1
  117. package/dist/index150.js +2 -2
  118. package/dist/index150.js.map +1 -1
  119. package/dist/index151.js +2 -2
  120. package/dist/index151.js.map +1 -1
  121. package/dist/index152.js +1 -1
  122. package/dist/index152.js.map +1 -1
  123. package/dist/index153.js +2 -2
  124. package/dist/index153.js.map +1 -1
  125. package/dist/index154.js +2 -2
  126. package/dist/index154.js.map +1 -1
  127. package/dist/index155.js +1 -1
  128. package/dist/index155.js.map +1 -1
  129. package/dist/index156.js +1 -1
  130. package/dist/index156.js.map +1 -1
  131. package/dist/index157.js +1 -1
  132. package/dist/index157.js.map +1 -1
  133. package/dist/index158.js +2 -2
  134. package/dist/index158.js.map +1 -1
  135. package/dist/index159.js +2 -2
  136. package/dist/index159.js.map +1 -1
  137. package/dist/index16.js +1 -1
  138. package/dist/index160.js +1 -1
  139. package/dist/index160.js.map +1 -1
  140. package/dist/index161.js +2 -2
  141. package/dist/index161.js.map +1 -1
  142. package/dist/index162.js +2 -2
  143. package/dist/index162.js.map +1 -1
  144. package/dist/index163.js +1 -1
  145. package/dist/index163.js.map +1 -1
  146. package/dist/index164.js +1 -1
  147. package/dist/index164.js.map +1 -1
  148. package/dist/index165.js +1 -1
  149. package/dist/index165.js.map +1 -1
  150. package/dist/index166.js +1 -1
  151. package/dist/index166.js.map +1 -1
  152. package/dist/index167.js +1 -1
  153. package/dist/index167.js.map +1 -1
  154. package/dist/index168.js +1 -1
  155. package/dist/index168.js.map +1 -1
  156. package/dist/index169.js +1 -1
  157. package/dist/index169.js.map +1 -1
  158. package/dist/index170.js +1 -1
  159. package/dist/index170.js.map +1 -1
  160. package/dist/index171.js +1 -1
  161. package/dist/index171.js.map +1 -1
  162. package/dist/index172.js +1 -1
  163. package/dist/index172.js.map +1 -1
  164. package/dist/index173.js +1 -1
  165. package/dist/index173.js.map +1 -1
  166. package/dist/index174.js +1 -1
  167. package/dist/index174.js.map +1 -1
  168. package/dist/index175.js +1 -1
  169. package/dist/index175.js.map +1 -1
  170. package/dist/index176.js +1 -1
  171. package/dist/index176.js.map +1 -1
  172. package/dist/index177.js +1 -1
  173. package/dist/index177.js.map +1 -1
  174. package/dist/index178.js +1 -1
  175. package/dist/index178.js.map +1 -1
  176. package/dist/index179.js +1 -1
  177. package/dist/index179.js.map +1 -1
  178. package/dist/index180.js +2 -2
  179. package/dist/index180.js.map +1 -1
  180. package/dist/index181.js +1 -1
  181. package/dist/index181.js.map +1 -1
  182. package/dist/index182.js +1 -1
  183. package/dist/index182.js.map +1 -1
  184. package/dist/index183.js +1 -1
  185. package/dist/index183.js.map +1 -1
  186. package/dist/index184.js +2 -2
  187. package/dist/index184.js.map +1 -1
  188. package/dist/index185.js +1 -1
  189. package/dist/index185.js.map +1 -1
  190. package/dist/index186.js +1 -1
  191. package/dist/index186.js.map +1 -1
  192. package/dist/index187.js +1 -1
  193. package/dist/index187.js.map +1 -1
  194. package/dist/index188.js +2 -2
  195. package/dist/index188.js.map +1 -1
  196. package/dist/index189.js +1 -1
  197. package/dist/index189.js.map +1 -1
  198. package/dist/index19.js +185 -163
  199. package/dist/index19.js.map +1 -1
  200. package/dist/index190.js +1 -1
  201. package/dist/index190.js.map +1 -1
  202. package/dist/index191.js +1 -1
  203. package/dist/index191.js.map +1 -1
  204. package/dist/index192.js +2 -2
  205. package/dist/index192.js.map +1 -1
  206. package/dist/index193.js +1 -1
  207. package/dist/index193.js.map +1 -1
  208. package/dist/index194.js +2 -2
  209. package/dist/index194.js.map +1 -1
  210. package/dist/index195.js +1 -1
  211. package/dist/index195.js.map +1 -1
  212. package/dist/index196.js +2 -2
  213. package/dist/index196.js.map +1 -1
  214. package/dist/index197.js +2 -149
  215. package/dist/index197.js.map +1 -1
  216. package/dist/index198.js +2 -9
  217. package/dist/index198.js.map +1 -1
  218. package/dist/index199.js +2 -6
  219. package/dist/index199.js.map +1 -1
  220. package/dist/index200.js +2 -5
  221. package/dist/index200.js.map +1 -1
  222. package/dist/index201.js +2 -40
  223. package/dist/index201.js.map +1 -1
  224. package/dist/index202.js +5 -0
  225. package/dist/index202.js.map +1 -0
  226. package/dist/index203.js +5 -0
  227. package/dist/index203.js.map +1 -0
  228. package/dist/index204.js +5 -0
  229. package/dist/index204.js.map +1 -0
  230. package/dist/index205.js +5 -0
  231. package/dist/index205.js.map +1 -0
  232. package/dist/index206.js +152 -0
  233. package/dist/index206.js.map +1 -0
  234. package/dist/index207.js +8 -0
  235. package/dist/index207.js.map +1 -0
  236. package/dist/{index217.js → index221.js} +1 -1
  237. package/dist/{index217.js.map → index221.js.map} +1 -1
  238. package/dist/{index225.js → index229.js} +1 -1
  239. package/dist/{index225.js.map → index229.js.map} +1 -1
  240. package/dist/index23.js +30 -28
  241. package/dist/index23.js.map +1 -1
  242. package/dist/{index228.js → index232.js} +1 -1
  243. package/dist/{index228.js.map → index232.js.map} +1 -1
  244. package/dist/index241.js +168 -8
  245. package/dist/index241.js.map +1 -1
  246. package/dist/index242.js +3 -9
  247. package/dist/index242.js.map +1 -1
  248. package/dist/index244.js +9 -169
  249. package/dist/index244.js.map +1 -1
  250. package/dist/index245.js +10 -11
  251. package/dist/index245.js.map +1 -1
  252. package/dist/index246.js +4 -5
  253. package/dist/index246.js.map +1 -1
  254. package/dist/index247.js +170 -6
  255. package/dist/index247.js.map +1 -1
  256. package/dist/index248.js +11 -38
  257. package/dist/index248.js.map +1 -1
  258. package/dist/index249.js +6 -2
  259. package/dist/index249.js.map +1 -1
  260. package/dist/index25.js +259 -236
  261. package/dist/index25.js.map +1 -1
  262. package/dist/index250.js +5 -7
  263. package/dist/index250.js.map +1 -1
  264. package/dist/index251.js +36 -325
  265. package/dist/index251.js.map +1 -1
  266. package/dist/index252.js +2 -50
  267. package/dist/index252.js.map +1 -1
  268. package/dist/index253.js +8 -2
  269. package/dist/index253.js.map +1 -1
  270. package/dist/index254.js +323 -72
  271. package/dist/index254.js.map +1 -1
  272. package/dist/index255.js +47 -90
  273. package/dist/index255.js.map +1 -1
  274. package/dist/index256.js +2 -52
  275. package/dist/index256.js.map +1 -1
  276. package/dist/index257.js +75 -7
  277. package/dist/index257.js.map +1 -1
  278. package/dist/index258.js +92 -4
  279. package/dist/index258.js.map +1 -1
  280. package/dist/index259.js +48 -48
  281. package/dist/index259.js.map +1 -1
  282. package/dist/index260.js +8 -2
  283. package/dist/index260.js.map +1 -1
  284. package/dist/index261.js +5 -2
  285. package/dist/index261.js.map +1 -1
  286. package/dist/index262.js +55 -0
  287. package/dist/index262.js.map +1 -0
  288. package/dist/index263.js +5 -0
  289. package/dist/index263.js.map +1 -0
  290. package/dist/index264.js +5 -0
  291. package/dist/index264.js.map +1 -0
  292. package/dist/index28.js +3 -3
  293. package/dist/index28.js.map +1 -1
  294. package/dist/index29.js +43 -41
  295. package/dist/index29.js.map +1 -1
  296. package/dist/index30.js +81 -79
  297. package/dist/index30.js.map +1 -1
  298. package/dist/index33.js +18 -16
  299. package/dist/index33.js.map +1 -1
  300. package/dist/index35.js +1 -1
  301. package/dist/index36.js +1 -1
  302. package/dist/index38.js +1 -1
  303. package/dist/index39.js +2 -2
  304. package/dist/index40.js +1 -1
  305. package/dist/index44.js +3 -3
  306. package/dist/index44.js.map +1 -1
  307. package/dist/index45.js +1 -1
  308. package/dist/index46.js +2 -2
  309. package/dist/index49.js +1 -1
  310. package/dist/index51.js +177 -169
  311. package/dist/index51.js.map +1 -1
  312. package/dist/index52.js +1 -1
  313. package/dist/index53.js +1 -1
  314. package/dist/index57.js +1 -1
  315. package/dist/index6.js +211 -207
  316. package/dist/index6.js.map +1 -1
  317. package/dist/index63.js +1 -1
  318. package/dist/index65.js +1 -1
  319. package/dist/index7.js +1 -1
  320. package/dist/index72.js +66 -60
  321. package/dist/index72.js.map +1 -1
  322. package/dist/index76.js +28 -25
  323. package/dist/index76.js.map +1 -1
  324. package/dist/{index208.js → index79.js} +1 -1
  325. package/dist/index79.js.map +1 -0
  326. package/dist/index80.js +19 -2
  327. package/dist/index80.js.map +1 -1
  328. package/dist/index81.js +9 -2
  329. package/dist/index81.js.map +1 -1
  330. package/dist/index82.js +42 -2
  331. package/dist/index82.js.map +1 -1
  332. package/dist/index83.js +6 -2
  333. package/dist/index83.js.map +1 -1
  334. package/dist/index84.js +68 -2
  335. package/dist/index84.js.map +1 -1
  336. package/dist/index85.js +21 -2
  337. package/dist/index85.js.map +1 -1
  338. package/dist/index87.js +2 -2
  339. package/dist/index87.js.map +1 -1
  340. package/dist/index88.js +2 -2
  341. package/dist/index88.js.map +1 -1
  342. package/dist/index89.js +1 -1
  343. package/dist/index89.js.map +1 -1
  344. package/dist/index9.js +28 -26
  345. package/dist/index9.js.map +1 -1
  346. package/dist/index90.js +2 -2
  347. package/dist/index90.js.map +1 -1
  348. package/dist/index91.js +1 -1
  349. package/dist/index91.js.map +1 -1
  350. package/dist/index92.js +1 -1
  351. package/dist/index92.js.map +1 -1
  352. package/dist/index93.js +1 -1
  353. package/dist/index93.js.map +1 -1
  354. package/dist/index94.js +1 -1
  355. package/dist/index94.js.map +1 -1
  356. package/dist/index95.js +1 -1
  357. package/dist/index95.js.map +1 -1
  358. package/dist/index96.js +1 -1
  359. package/dist/index96.js.map +1 -1
  360. package/dist/index97.js +1 -1
  361. package/dist/index97.js.map +1 -1
  362. package/dist/index98.js +1 -1
  363. package/dist/index98.js.map +1 -1
  364. package/dist/index99.js +1 -1
  365. package/dist/index99.js.map +1 -1
  366. package/package.json +1 -1
  367. package/dist/index208.js.map +0 -1
  368. package/dist/index209.js +0 -71
  369. package/dist/index209.js.map +0 -1
  370. package/dist/index237.js +0 -176
  371. package/dist/index237.js.map +0 -1
  372. package/dist/index238.js +0 -7
  373. package/dist/index238.js.map +0 -1
  374. package/dist/index240.js +0 -22
  375. package/dist/index240.js.map +0 -1
  376. package/dist/index243.js +0 -8
  377. package/dist/index243.js.map +0 -1
  378. package/dist/index86.js +0 -5
  379. package/dist/index86.js.map +0 -1
package/dist/index72.js CHANGED
@@ -1,105 +1,111 @@
1
- import { useRef as h, useLayoutEffect as a } from "react";
2
- import { getFirstFocusableElement as p, getFocusableElements as A } from "./index71.js";
1
+ import { useRef as p, useLayoutEffect as a } from "react";
2
+ import { getFirstFocusableElement as A, getFocusableElements as L } from "./index71.js";
3
3
  let f = null;
4
- function L(e) {
4
+ function F(e) {
5
5
  const n = e.composedPath();
6
- for (const c of n)
7
- if (c instanceof HTMLElement && c.tabIndex >= 0) {
8
- f = c;
6
+ for (const s of n)
7
+ if (s instanceof HTMLElement && s.tabIndex >= 0) {
8
+ f = s;
9
9
  return;
10
10
  }
11
11
  }
12
12
  function k(e) {
13
13
  (e.key === "Enter" || e.key === " ") && (f = document.activeElement);
14
14
  }
15
- typeof document < "u" && (document.addEventListener("pointerdown", L, !0), document.addEventListener("keydown", k, !0));
16
- function q() {
15
+ typeof document < "u" && (document.addEventListener("pointerdown", F, !0), document.addEventListener("keydown", k, !0));
16
+ function T() {
17
17
  const e = f;
18
18
  return f = null, e;
19
19
  }
20
- let i = null, l = null;
21
- function T(e) {
22
- l !== null && cancelAnimationFrame(l), i = e, l = requestAnimationFrame(() => {
23
- i = null, l = null;
20
+ let m = null, l = null;
21
+ function _(e) {
22
+ l !== null && cancelAnimationFrame(l), m = e, l = requestAnimationFrame(() => {
23
+ m = null, l = null;
24
24
  });
25
25
  }
26
- function w() {
26
+ function I() {
27
27
  l !== null && (cancelAnimationFrame(l), l = null);
28
- const e = i;
29
- return i = null, e;
28
+ const e = m;
29
+ return m = null, e;
30
30
  }
31
- function F(e, n) {
32
- return n === "none" ? null : n === "first" ? p({
31
+ function w(e, n) {
32
+ return n === "none" ? null : n === "first" ? A({
33
33
  container: e
34
34
  }) || e : n === "container" ? e : typeof n == "string" ? e.querySelector(n) : n instanceof HTMLElement ? n : null;
35
35
  }
36
- function _({
36
+ function C({
37
37
  enabled: e,
38
38
  containerRef: n,
39
- restoreFocus: c = !0,
39
+ restoreFocus: s = !0,
40
40
  initialFocus: d = "first",
41
- returnFocusRef: g
41
+ returnFocusRef: g,
42
+ portalContainerRefs: h
42
43
  }) {
43
- const u = h(null), E = h(null);
44
+ const u = p(null), E = p(null);
44
45
  return a(() => {
45
46
  if (!e) {
46
- if (c && u.current) {
47
- const r = u.current;
47
+ if (s && u.current) {
48
+ const t = u.current;
48
49
  u.current = null, requestAnimationFrame(() => {
49
- r.isConnected && r.focus();
50
+ t.isConnected && t.focus();
50
51
  });
51
52
  }
52
53
  return;
53
54
  }
54
- const t = n.current;
55
- if (t)
56
- return u.current = g?.current ?? w() ?? f ?? document.activeElement, f = null, t.contains(document.activeElement) || requestAnimationFrame(() => {
57
- F(t, d)?.focus();
58
- }), () => {
59
- if (c && u.current) {
60
- const r = u.current;
61
- u.current = null, requestAnimationFrame(() => {
62
- r.isConnected && r.focus();
63
- });
64
- }
65
- };
66
- }, [e, n, c, d]), a(() => {
55
+ const r = n.current;
56
+ if (!r) return;
57
+ const c = g?.current ?? I() ?? f ?? document.activeElement;
58
+ if (f = null, c?.tagName === "IFRAME") {
59
+ u.current = null;
60
+ return;
61
+ }
62
+ return u.current = c, r.contains(document.activeElement) || requestAnimationFrame(() => {
63
+ w(r, d)?.focus();
64
+ }), () => {
65
+ if (s && u.current) {
66
+ const t = u.current;
67
+ u.current = null, requestAnimationFrame(() => {
68
+ t.isConnected && t.focus();
69
+ });
70
+ }
71
+ };
72
+ }, [e, n, s, d]), a(() => {
67
73
  if (!e) return;
68
- const t = n.current;
69
- if (!t) return;
70
- const r = (o) => {
71
- if (o.key === "Tab") {
72
- const s = A({
73
- container: t
74
+ const r = n.current;
75
+ if (!r) return;
76
+ const c = (t) => {
77
+ if (t.key === "Tab") {
78
+ const o = L({
79
+ container: r
74
80
  });
75
- if (s.length === 0) {
76
- o.preventDefault(), t.focus();
81
+ if (o.length === 0) {
82
+ t.preventDefault(), r.focus();
77
83
  return;
78
84
  }
79
- const m = s[0], v = s[s.length - 1], y = document.activeElement;
80
- o.shiftKey && y === m ? (o.preventDefault(), v.focus()) : !o.shiftKey && y === v && (o.preventDefault(), m.focus());
85
+ const i = o[0], v = o[o.length - 1], y = document.activeElement;
86
+ t.shiftKey && y === i ? (t.preventDefault(), v.focus()) : !t.shiftKey && y === v && (t.preventDefault(), i.focus());
81
87
  }
82
88
  };
83
- return document.addEventListener("keydown", r, !0), () => document.removeEventListener("keydown", r, !0);
89
+ return document.addEventListener("keydown", c, !0), () => document.removeEventListener("keydown", c, !0);
84
90
  }, [e, n]), a(() => {
85
91
  if (!e) return;
86
- const t = n.current;
87
- if (!t) return;
88
- const r = (o) => {
89
- const s = o.target;
90
- t.contains(s) ? E.current = s : (E.current || p({
91
- container: t
92
- }) || t).focus();
92
+ const r = n.current;
93
+ if (!r) return;
94
+ const c = (t) => {
95
+ const o = t.target;
96
+ o?.tagName !== "IFRAME" && (r.contains(o) ? E.current = o : h?.current?.some((i) => i.current?.contains(o)) || (E.current || A({
97
+ container: r
98
+ }) || r).focus());
93
99
  };
94
- return document.addEventListener("focusin", r, !0), () => document.removeEventListener("focusin", r, !0);
100
+ return document.addEventListener("focusin", c, !0), () => document.removeEventListener("focusin", c, !0);
95
101
  }, [e, n]), {
96
102
  triggerRef: u
97
103
  };
98
104
  }
99
105
  export {
100
- w as consumeFocusAnchor,
101
- q as consumeLastInteractedElement,
102
- T as setFocusAnchor,
103
- _ as useFocusTrap
106
+ I as consumeFocusAnchor,
107
+ T as consumeLastInteractedElement,
108
+ _ as setFocusAnchor,
109
+ C as useFocusTrap
104
110
  };
105
111
  //# sourceMappingURL=index72.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index72.js","sources":["../src/utils/a11y/useFocusTrap.ts"],"sourcesContent":["import { useLayoutEffect, useRef } from 'react';\nimport { getFocusableElements, getFirstFocusableElement } from './focusableElements';\n\nexport interface UseFocusTrapOptions<T extends HTMLElement = HTMLElement> {\n /**\n * Whether the focus trap is active.\n */\n enabled: boolean;\n /**\n * Container element ref to trap focus within.\n */\n containerRef: React.RefObject<T | null>;\n /**\n * Whether to restore focus to the element that had focus before trap activated.\n * Default: true\n */\n restoreFocus?: boolean;\n /**\n * Initial focus target when trap activates.\n * - 'first': Focus first focusable element (default)\n * - 'container': Focus the container itself\n * - 'none': Skip initial focus — browser handles it (e.g. autofocus attribute)\n * - CSS selector: Focus element matching selector\n * - HTMLElement: Focus this specific element\n */\n initialFocus?: 'first' | 'container' | 'none' | string | HTMLElement;\n /**\n * Explicit element to restore focus to when the trap deactivates.\n * Overrides the automatic trigger capture (_lastInteractedElement / document.activeElement).\n * Use when the opener is known at call-site (e.g. a ref on the toggle button).\n */\n returnFocusRef?: React.RefObject<HTMLElement | null>;\n}\n\nexport interface UseFocusTrapReturn {\n /**\n * Ref to the element that had focus before trap activated.\n * Useful for manual focus restoration if needed.\n */\n triggerRef: React.MutableRefObject<HTMLElement | null>;\n}\n\n// Module-level trigger tracking: React's commit phase is bottom-up, so by the\n// time useFocusTrap's useLayoutEffect runs, document.activeElement may already\n// be the autoFocus element inside the modal rather than the opener button.\n// We capture the last interacted element via pointerdown/keydown listeners\n// (which fire before any React state update commits) to work around this.\nlet _lastInteractedElement: HTMLElement | null = null;\n\nfunction _onPointerDown(e: PointerEvent): void {\n // Walk composedPath to find the nearest focusable element being pressed.\n const path = e.composedPath();\n for (const node of path) {\n if (node instanceof HTMLElement && node.tabIndex >= 0) {\n _lastInteractedElement = node;\n return;\n }\n }\n}\n\nfunction _onKeyDown(e: KeyboardEvent): void {\n // Enter/Space on a focused button will synthesise a click — capture before that.\n if (e.key === 'Enter' || e.key === ' ') {\n _lastInteractedElement = document.activeElement as HTMLElement;\n }\n}\n\nif (typeof document !== 'undefined') {\n document.addEventListener('pointerdown', _onPointerDown, true);\n document.addEventListener('keydown', _onKeyDown, true);\n}\n\n/**\n * Returns (and clears) the last element interacted with before a React commit.\n * Used by SidebarOverlay complementary mode to seed its trigger ref without\n * relying on document.activeElement timing.\n */\nexport function consumeLastInteractedElement(): HTMLElement | null {\n const el = _lastInteractedElement;\n _lastInteractedElement = null;\n return el;\n}\n\n// Focus anchor — explicit stable return-focus target, higher priority than\n// _lastInteractedElement. Auto-clears via setTimeout(0) to prevent a stale\n// anchor leaking to an unrelated open.\nlet _focusAnchor: HTMLElement | null = null;\nlet _focusAnchorClearFrame: ReturnType<typeof requestAnimationFrame> | null = null;\n\n/**\n * Sets an explicit focus-return anchor element.\n * Call this before dispatching an action that will open a modal or sidebar,\n * when the natural last-interacted element is not the right return target\n * (e.g. a popover menu item that will be unmounted when the popover closes).\n */\nexport function setFocusAnchor(el: HTMLElement | null): void {\n if (_focusAnchorClearFrame !== null) cancelAnimationFrame(_focusAnchorClearFrame);\n _focusAnchor = el;\n // Auto-clear if not consumed — prevents stale anchor leaking to unrelated opens.\n // rAF fires after React has committed and painted, giving useFocusTrap time to\n // consume the anchor before it is discarded.\n _focusAnchorClearFrame = requestAnimationFrame(() => {\n _focusAnchor = null;\n _focusAnchorClearFrame = null;\n });\n}\n\n/**\n * Returns (and clears) the focus anchor if one was set, otherwise null.\n * Used internally by useFocusTrap and SidebarOverlay.\n */\nexport function consumeFocusAnchor(): HTMLElement | null {\n if (_focusAnchorClearFrame !== null) {\n cancelAnimationFrame(_focusAnchorClearFrame);\n _focusAnchorClearFrame = null;\n }\n const el = _focusAnchor;\n _focusAnchor = null;\n return el;\n}\n\n/**\n * Resolve the initial focus target based on the initialFocus option.\n */\nfunction resolveInitialFocusTarget(\n container: HTMLElement,\n initialFocus: 'first' | 'container' | 'none' | string | HTMLElement\n): HTMLElement | null {\n if (initialFocus === 'none') return null;\n if (initialFocus === 'first') {\n return getFirstFocusableElement({ container }) || container;\n }\n if (initialFocus === 'container') {\n return container;\n }\n if (typeof initialFocus === 'string') {\n return container.querySelector<HTMLElement>(initialFocus);\n }\n if (initialFocus instanceof HTMLElement) {\n return initialFocus;\n }\n return null;\n}\n\n/**\n * Hook to trap focus within a container (for modals, dialogs, drawers).\n *\n * Implements WCAG 2.1 focus trap pattern:\n * - Moves focus into container on activation\n * - Wraps Tab/Shift+Tab navigation within container\n * - Restores focus to trigger element on deactivation\n * - Safety net: catches focus escaping via other means\n * - Handles autoFocus content: captures trigger before autoFocus fires\n * - Handles {isOpen && <Modal>} pattern: restores focus on unmount\n *\n * Note: For Escape key handling, use `useDismissOnEscape` hook separately.\n * This keeps focus trap (accessibility) separate from Escape handling (UX).\n *\n * @example\n * ```tsx\n * const MyModal = ({ isOpen, onClose }) => {\n * const containerRef = useRef<HTMLDivElement>(null);\n *\n * // Escape handling (UX)\n * useDismissOnEscape({\n * containerRef,\n * onDismiss: onClose,\n * enabled: isOpen\n * });\n *\n * // Focus trap (accessibility)\n * const { triggerRef } = useFocusTrap({\n * enabled: isOpen,\n * containerRef,\n * restoreFocus: true\n * });\n *\n * return (\n * <div ref={containerRef}>\n * <button>First</button>\n * <button>Second</button>\n * </div>\n * );\n * };\n * ```\n */\nexport function useFocusTrap<T extends HTMLElement = HTMLElement>({\n enabled,\n containerRef,\n restoreFocus = true,\n initialFocus = 'first',\n returnFocusRef,\n}: UseFocusTrapOptions<T>): UseFocusTrapReturn {\n const triggerRef = useRef<HTMLElement | null>(null);\n const lastFocusedInContainer = useRef<HTMLElement | null>(null);\n\n // Focus management: save trigger, move focus into container on activate, restore on deactivate\n useLayoutEffect(() => {\n if (!enabled) {\n // Restore focus to trigger when trap deactivates\n if (restoreFocus && triggerRef.current) {\n const el = triggerRef.current;\n triggerRef.current = null;\n requestAnimationFrame(() => {\n if (el.isConnected) el.focus();\n });\n }\n return;\n }\n\n const container = containerRef.current;\n if (!container) return;\n\n // Resolve trigger: explicit returnFocusRef wins, then focusAnchor (explicitly set\n // by caller for two-step flows like popover menu → modal), then the pre-commit\n // interaction record, then document.activeElement as final fallback.\n triggerRef.current = returnFocusRef?.current ?? consumeFocusAnchor() ?? _lastInteractedElement ?? (document.activeElement as HTMLElement);\n _lastInteractedElement = null;\n\n // Only move initial focus if autoFocus hasn't already placed it inside the container.\n if (!container.contains(document.activeElement)) {\n requestAnimationFrame(() => {\n resolveInitialFocusTarget(container, initialFocus)?.focus();\n });\n }\n\n // Restore focus on unmount while enabled (covers {isOpen && <Modal>} pattern\n // where the component unmounts before enabled can transition true → false)\n return () => {\n if (restoreFocus && triggerRef.current) {\n const el = triggerRef.current;\n triggerRef.current = null;\n requestAnimationFrame(() => {\n if (el.isConnected) el.focus();\n });\n }\n };\n }, [enabled, containerRef, restoreFocus, initialFocus]);\n\n // Focus trap: Tab wrapping (only when enabled)\n useLayoutEffect(() => {\n if (!enabled) return;\n\n const container = containerRef.current;\n if (!container) return;\n\n const handleKeyDown = (e: KeyboardEvent) => {\n // Tab wrapping\n if (e.key === 'Tab') {\n const focusables = getFocusableElements({ container });\n\n if (focusables.length === 0) {\n e.preventDefault();\n container.focus();\n return;\n }\n\n const first = focusables[0];\n const last = focusables[focusables.length - 1];\n const activeElement = document.activeElement;\n\n if (e.shiftKey && activeElement === first) {\n e.preventDefault();\n last.focus();\n } else if (!e.shiftKey && activeElement === last) {\n e.preventDefault();\n first.focus();\n }\n }\n };\n\n document.addEventListener('keydown', handleKeyDown, true);\n return () => document.removeEventListener('keydown', handleKeyDown, true);\n }, [enabled, containerRef]);\n\n // Focus trap safety net: catch focus escaping\n useLayoutEffect(() => {\n if (!enabled) return;\n\n const container = containerRef.current;\n if (!container) return;\n\n const handleFocusIn = (e: FocusEvent) => {\n const target = e.target as Node;\n\n if (container.contains(target)) {\n lastFocusedInContainer.current = target as HTMLElement;\n } else {\n // Focus escaped - redirect back\n const fallback = lastFocusedInContainer.current\n || getFirstFocusableElement({ container })\n || container;\n fallback.focus();\n }\n };\n\n document.addEventListener('focusin', handleFocusIn, true);\n return () => document.removeEventListener('focusin', handleFocusIn, true);\n }, [enabled, containerRef]);\n\n return { triggerRef };\n}\n"],"names":["_lastInteractedElement","_onPointerDown","e","path","composedPath","node","HTMLElement","tabIndex","_onKeyDown","key","document","activeElement","addEventListener","consumeLastInteractedElement","el","_focusAnchor","_focusAnchorClearFrame","setFocusAnchor","cancelAnimationFrame","requestAnimationFrame","consumeFocusAnchor","resolveInitialFocusTarget","container","initialFocus","getFirstFocusableElement","querySelector","useFocusTrap","enabled","containerRef","restoreFocus","returnFocusRef","triggerRef","useRef","lastFocusedInContainer","useLayoutEffect","current","isConnected","focus","contains","handleKeyDown","focusables","getFocusableElements","length","preventDefault","first","last","shiftKey","removeEventListener","handleFocusIn","target"],"mappings":"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"}
1
+ {"version":3,"file":"index72.js","sources":["../src/utils/a11y/useFocusTrap.ts"],"sourcesContent":["import { useLayoutEffect, useRef } from 'react';\nimport type { MutableRefObject, RefObject } from 'react';\nimport { getFocusableElements, getFirstFocusableElement } from './focusableElements';\n\nexport interface UseFocusTrapOptions<T extends HTMLElement = HTMLElement> {\n /**\n * Whether the focus trap is active.\n */\n enabled: boolean;\n /**\n * Container element ref to trap focus within.\n */\n containerRef: React.RefObject<T | null>;\n /**\n * Whether to restore focus to the element that had focus before trap activated.\n * Default: true\n */\n restoreFocus?: boolean;\n /**\n * Initial focus target when trap activates.\n * - 'first': Focus first focusable element (default)\n * - 'container': Focus the container itself\n * - 'none': Skip initial focus — browser handles it (e.g. autofocus attribute)\n * - CSS selector: Focus element matching selector\n * - HTMLElement: Focus this specific element\n */\n initialFocus?: 'first' | 'container' | 'none' | string | HTMLElement;\n /**\n * Explicit element to restore focus to when the trap deactivates.\n * Overrides the automatic trigger capture (_lastInteractedElement / document.activeElement).\n * Use when the opener is known at call-site (e.g. a ref on the toggle button).\n */\n returnFocusRef?: React.RefObject<HTMLElement | null>;\n /**\n * Additional container refs that are logically part of this focus trap\n * (e.g., portal-rendered content from Popover/Dropdown). Focus moving to\n * these containers will NOT trigger the safety net redirect.\n */\n portalContainerRefs?: MutableRefObject<RefObject<HTMLElement | null>[]>;\n}\n\nexport interface UseFocusTrapReturn {\n /**\n * Ref to the element that had focus before trap activated.\n * Useful for manual focus restoration if needed.\n */\n triggerRef: React.MutableRefObject<HTMLElement | null>;\n}\n\n// Module-level trigger tracking: React's commit phase is bottom-up, so by the\n// time useFocusTrap's useLayoutEffect runs, document.activeElement may already\n// be the autoFocus element inside the modal rather than the opener button.\n// We capture the last interacted element via pointerdown/keydown listeners\n// (which fire before any React state update commits) to work around this.\nlet _lastInteractedElement: HTMLElement | null = null;\n\nfunction _onPointerDown(e: PointerEvent): void {\n // Walk composedPath to find the nearest focusable element being pressed.\n const path = e.composedPath();\n for (const node of path) {\n if (node instanceof HTMLElement && node.tabIndex >= 0) {\n _lastInteractedElement = node;\n return;\n }\n }\n}\n\nfunction _onKeyDown(e: KeyboardEvent): void {\n // Enter/Space on a focused button will synthesise a click — capture before that.\n if (e.key === 'Enter' || e.key === ' ') {\n _lastInteractedElement = document.activeElement as HTMLElement;\n }\n}\n\nif (typeof document !== 'undefined') {\n document.addEventListener('pointerdown', _onPointerDown, true);\n document.addEventListener('keydown', _onKeyDown, true);\n}\n\n/**\n * Returns (and clears) the last element interacted with before a React commit.\n * Used by SidebarOverlay complementary mode to seed its trigger ref without\n * relying on document.activeElement timing.\n */\nexport function consumeLastInteractedElement(): HTMLElement | null {\n const el = _lastInteractedElement;\n _lastInteractedElement = null;\n return el;\n}\n\n// Focus anchor — explicit stable return-focus target, higher priority than\n// _lastInteractedElement. Auto-clears via setTimeout(0) to prevent a stale\n// anchor leaking to an unrelated open.\nlet _focusAnchor: HTMLElement | null = null;\nlet _focusAnchorClearFrame: ReturnType<typeof requestAnimationFrame> | null = null;\n\n/**\n * Sets an explicit focus-return anchor element.\n * Call this before dispatching an action that will open a modal or sidebar,\n * when the natural last-interacted element is not the right return target\n * (e.g. a popover menu item that will be unmounted when the popover closes).\n */\nexport function setFocusAnchor(el: HTMLElement | null): void {\n if (_focusAnchorClearFrame !== null) cancelAnimationFrame(_focusAnchorClearFrame);\n _focusAnchor = el;\n // Auto-clear if not consumed — prevents stale anchor leaking to unrelated opens.\n // rAF fires after React has committed and painted, giving useFocusTrap time to\n // consume the anchor before it is discarded.\n _focusAnchorClearFrame = requestAnimationFrame(() => {\n _focusAnchor = null;\n _focusAnchorClearFrame = null;\n });\n}\n\n/**\n * Returns (and clears) the focus anchor if one was set, otherwise null.\n * Used internally by useFocusTrap and SidebarOverlay.\n */\nexport function consumeFocusAnchor(): HTMLElement | null {\n if (_focusAnchorClearFrame !== null) {\n cancelAnimationFrame(_focusAnchorClearFrame);\n _focusAnchorClearFrame = null;\n }\n const el = _focusAnchor;\n _focusAnchor = null;\n return el;\n}\n\n/**\n * Resolve the initial focus target based on the initialFocus option.\n */\nfunction resolveInitialFocusTarget(\n container: HTMLElement,\n initialFocus: 'first' | 'container' | 'none' | string | HTMLElement\n): HTMLElement | null {\n if (initialFocus === 'none') return null;\n if (initialFocus === 'first') {\n return getFirstFocusableElement({ container }) || container;\n }\n if (initialFocus === 'container') {\n return container;\n }\n if (typeof initialFocus === 'string') {\n return container.querySelector<HTMLElement>(initialFocus);\n }\n if (initialFocus instanceof HTMLElement) {\n return initialFocus;\n }\n return null;\n}\n\n/**\n * Hook to trap focus within a container (for modals, dialogs, drawers).\n *\n * Implements WCAG 2.1 focus trap pattern:\n * - Moves focus into container on activation\n * - Wraps Tab/Shift+Tab navigation within container\n * - Restores focus to trigger element on deactivation\n * - Safety net: catches focus escaping via other means\n * - Handles autoFocus content: captures trigger before autoFocus fires\n * - Handles {isOpen && <Modal>} pattern: restores focus on unmount\n *\n * Note: For Escape key handling, use `useDismissOnEscape` hook separately.\n * This keeps focus trap (accessibility) separate from Escape handling (UX).\n *\n * @example\n * ```tsx\n * const MyModal = ({ isOpen, onClose }) => {\n * const containerRef = useRef<HTMLDivElement>(null);\n *\n * // Escape handling (UX)\n * useDismissOnEscape({\n * containerRef,\n * onDismiss: onClose,\n * enabled: isOpen\n * });\n *\n * // Focus trap (accessibility)\n * const { triggerRef } = useFocusTrap({\n * enabled: isOpen,\n * containerRef,\n * restoreFocus: true\n * });\n *\n * return (\n * <div ref={containerRef}>\n * <button>First</button>\n * <button>Second</button>\n * </div>\n * );\n * };\n * ```\n */\nexport function useFocusTrap<T extends HTMLElement = HTMLElement>({\n enabled,\n containerRef,\n restoreFocus = true,\n initialFocus = 'first',\n returnFocusRef,\n portalContainerRefs,\n}: UseFocusTrapOptions<T>): UseFocusTrapReturn {\n const triggerRef = useRef<HTMLElement | null>(null);\n const lastFocusedInContainer = useRef<HTMLElement | null>(null);\n\n // Focus management: save trigger, move focus into container on activate, restore on deactivate\n useLayoutEffect(() => {\n if (!enabled) {\n // Restore focus to trigger when trap deactivates\n if (restoreFocus && triggerRef.current) {\n const el = triggerRef.current;\n triggerRef.current = null;\n requestAnimationFrame(() => {\n if (el.isConnected) el.focus();\n });\n }\n return;\n }\n\n const container = containerRef.current;\n if (!container) return;\n\n // Resolve trigger: explicit returnFocusRef wins, then focusAnchor (explicitly set\n // by caller for two-step flows like popover menu → modal), then the pre-commit\n // interaction record, then document.activeElement as final fallback.\n const previousActiveElement = returnFocusRef?.current ?? consumeFocusAnchor() ?? _lastInteractedElement ?? (document.activeElement as HTMLElement);\n _lastInteractedElement = null;\n\n // iframes manage their own internal focus. document.activeElement only ever\n // resolves to the <iframe> element from the parent doc — calling .focus()\n // on any parent-doc element forcibly blurs the iframe content (kills caret\n // in textareas, cancels native <select> dropdowns). Skip capture so the\n // auto-focus on open and focus-restore on close short-circuit on null trigger.\n if (previousActiveElement?.tagName === 'IFRAME') {\n triggerRef.current = null;\n return;\n }\n\n triggerRef.current = previousActiveElement;\n\n // Only move initial focus if autoFocus hasn't already placed it inside the container.\n if (!container.contains(document.activeElement)) {\n requestAnimationFrame(() => {\n resolveInitialFocusTarget(container, initialFocus)?.focus();\n });\n }\n\n // Restore focus on unmount while enabled (covers {isOpen && <Modal>} pattern\n // where the component unmounts before enabled can transition true → false)\n return () => {\n if (restoreFocus && triggerRef.current) {\n const el = triggerRef.current;\n triggerRef.current = null;\n requestAnimationFrame(() => {\n if (el.isConnected) el.focus();\n });\n }\n };\n }, [enabled, containerRef, restoreFocus, initialFocus]);\n\n // Focus trap: Tab wrapping (only when enabled)\n useLayoutEffect(() => {\n if (!enabled) return;\n\n const container = containerRef.current;\n if (!container) return;\n\n const handleKeyDown = (e: KeyboardEvent) => {\n // Tab wrapping\n if (e.key === 'Tab') {\n const focusables = getFocusableElements({ container });\n\n if (focusables.length === 0) {\n e.preventDefault();\n container.focus();\n return;\n }\n\n const first = focusables[0];\n const last = focusables[focusables.length - 1];\n const activeElement = document.activeElement;\n\n if (e.shiftKey && activeElement === first) {\n e.preventDefault();\n last.focus();\n } else if (!e.shiftKey && activeElement === last) {\n e.preventDefault();\n first.focus();\n }\n }\n };\n\n document.addEventListener('keydown', handleKeyDown, true);\n return () => document.removeEventListener('keydown', handleKeyDown, true);\n }, [enabled, containerRef]);\n\n // Focus trap safety net: catch focus escaping\n useLayoutEffect(() => {\n if (!enabled) return;\n\n const container = containerRef.current;\n if (!container) return;\n\n const handleFocusIn = (e: FocusEvent) => {\n const target = e.target as Node;\n\n // iframe focus is opaque from the parent doc — leave it alone, otherwise\n // a click into the iframe gets yanked back into the trap.\n if ((target as Element | null)?.tagName === 'IFRAME') return;\n\n if (container.contains(target)) {\n lastFocusedInContainer.current = target as HTMLElement;\n } else if (portalContainerRefs?.current?.some(ref => ref.current?.contains(target))) {\n // Focus is in a registered portal — allow it, but don't update\n // lastFocusedInContainer so safety net restores to the last main-container\n // element (e.g., the dropdown trigger) when the portal unmounts\n } else {\n // Focus escaped — redirect back\n const fallback = lastFocusedInContainer.current\n || getFirstFocusableElement({ container })\n || container;\n fallback.focus();\n }\n };\n\n document.addEventListener('focusin', handleFocusIn, true);\n return () => document.removeEventListener('focusin', handleFocusIn, true);\n }, [enabled, containerRef]);\n\n return { triggerRef };\n}\n"],"names":["_lastInteractedElement","_onPointerDown","e","path","composedPath","node","HTMLElement","tabIndex","_onKeyDown","key","document","activeElement","addEventListener","consumeLastInteractedElement","el","_focusAnchor","_focusAnchorClearFrame","setFocusAnchor","cancelAnimationFrame","requestAnimationFrame","consumeFocusAnchor","resolveInitialFocusTarget","container","initialFocus","getFirstFocusableElement","querySelector","useFocusTrap","enabled","containerRef","restoreFocus","returnFocusRef","portalContainerRefs","triggerRef","useRef","lastFocusedInContainer","useLayoutEffect","current","isConnected","focus","previousActiveElement","tagName","contains","handleKeyDown","focusables","getFocusableElements","length","preventDefault","first","last","shiftKey","removeEventListener","handleFocusIn","target","some","ref"],"mappings":"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"}
package/dist/index76.js CHANGED
@@ -1,53 +1,56 @@
1
- import { useState as m, useEffect as w, useCallback as b } from "react";
2
- import { useScrollActiveIntoView as x } from "./index240.js";
1
+ import { useState as v, useEffect as w, useCallback as h } from "react";
2
+ import { useScrollActiveIntoView as x } from "./index80.js";
3
3
  function E({
4
4
  items: u,
5
5
  isOpen: t,
6
6
  onSelect: o,
7
- onClose: c,
8
- onOpen: l,
9
- loop: i = !0,
10
- disabled: h = !1,
7
+ onClose: i,
8
+ onOpen: n,
9
+ loop: l = !0,
10
+ disabled: b = !1,
11
11
  listboxRef: k,
12
- optionSelector: g = '[role="option"]'
12
+ optionSelector: D = '[role="option"]'
13
13
  }) {
14
- const [f, a] = m(-1);
14
+ const [e, r] = v(-1);
15
15
  w(() => {
16
- t || a(-1);
16
+ t || r(-1);
17
17
  }, [t]), x({
18
18
  containerRef: k,
19
- activeIndex: f,
20
- itemSelector: g,
19
+ activeIndex: e,
20
+ itemSelector: D,
21
21
  enabled: t
22
22
  });
23
- const D = b((r) => {
24
- if (h) {
25
- r.key === "Escape" && t && (r.preventDefault(), c());
23
+ const g = h((a) => {
24
+ if (b) {
25
+ a.key === "Escape" && t && (a.preventDefault(), i());
26
26
  return;
27
27
  }
28
- const e = u.length;
29
- switch (r.key) {
28
+ const f = u.length;
29
+ switch (a.key) {
30
30
  case "ArrowDown":
31
- r.preventDefault(), !t && e > 0 ? (l?.(), a(0)) : t && e > 0 && a((n) => i ? (n + 1) % e : Math.min(n + 1, e - 1));
31
+ a.preventDefault(), !t && f > 0 ? (n?.(), r(0)) : t && f > 0 && r((c) => l ? (c + 1) % f : Math.min(c + 1, f - 1));
32
32
  break;
33
33
  case "ArrowUp":
34
- r.preventDefault(), t && e > 0 && a((n) => n === -1 ? e - 1 : i ? (n - 1 + e) % e : Math.max(n - 1, 0));
34
+ a.preventDefault(), t && f > 0 && r((c) => c === -1 ? f - 1 : l ? (c - 1 + f) % f : Math.max(c - 1, 0));
35
35
  break;
36
36
  case "Enter":
37
- t && f >= 0 && u[f] && (r.preventDefault(), o(u[f], f), a(-1));
37
+ a.preventDefault(), t ? e >= 0 && u[e] && (o(u[e], e), r(-1)) : (n?.(), r(0));
38
+ break;
39
+ case " ":
40
+ a.preventDefault(), t ? e >= 0 && u[e] && (o(u[e], e), r(-1)) : (n?.(), r(0));
38
41
  break;
39
42
  case "Escape":
40
- t && (r.preventDefault(), c(), a(-1));
43
+ t && (a.preventDefault(), i(), r(-1));
41
44
  break;
42
45
  case "Tab":
43
- t && (c(), a(-1));
46
+ t && (i(), r(-1));
44
47
  break;
45
48
  }
46
- }, [h, u, t, f, o, c, l, i]), d = b((r, e) => `${r}-option-${e}`, []);
49
+ }, [b, u, t, e, o, i, n, l]), d = h((a, f) => `${a}-option-${f}`, []);
47
50
  return {
48
- highlightedIndex: f,
49
- setHighlightedIndex: a,
50
- handleKeyDown: D,
51
+ highlightedIndex: e,
52
+ setHighlightedIndex: r,
53
+ handleKeyDown: g,
51
54
  getOptionId: d
52
55
  };
53
56
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index76.js","sources":["../src/utils/a11y/useComboboxNavigation.ts"],"sourcesContent":["import { useCallback, useState, useEffect } from 'react';\nimport type { RefObject } from 'react';\nimport { useScrollActiveIntoView } from './useScrollActiveIntoView';\n\nexport interface UseComboboxNavigationOptions<T = any> {\n /**\n * Array of items to navigate through\n */\n items: T[];\n \n /**\n * Whether the dropdown is currently open\n */\n isOpen: boolean;\n \n /**\n * Callback when an item is selected (Enter key)\n */\n onSelect: (item: T, index: number) => void;\n \n /**\n * Callback to close the dropdown\n */\n onClose: () => void;\n \n /**\n * Optional: Callback to open the dropdown\n */\n onOpen?: () => void;\n \n /**\n * Whether to wrap around at the ends of the list.\n * Default: true\n */\n loop?: boolean;\n \n /**\n * Whether keyboard navigation is disabled\n * (e.g., for custom rendered content)\n */\n disabled?: boolean;\n \n /**\n * Ref to the listbox container for scroll management\n */\n listboxRef?: RefObject<HTMLElement | null>;\n \n /**\n * CSS selector for option elements (default: '[role=\"option\"]')\n */\n optionSelector?: string;\n}\n\nexport interface UseComboboxNavigationReturn {\n /**\n * Currently highlighted index (-1 if none)\n */\n highlightedIndex: number;\n \n /**\n * Set the highlighted index manually\n */\n setHighlightedIndex: (index: number | ((prev: number) => number)) => void;\n \n /**\n * Keyboard event handler for the combobox input\n */\n handleKeyDown: (e: React.KeyboardEvent) => void;\n \n /**\n * Generate stable ID for an option\n */\n getOptionId: (listboxId: string, index: number) => string;\n \n}\n\n/**\n * Hook for managing combobox keyboard navigation with aria-activedescendant.\n * \n * Implements WAI-ARIA 1.2 Combobox pattern:\n * - Arrow Up/Down to navigate options\n * - Enter to select highlighted option\n * - Escape to close dropdown\n * - Tab to close and move focus\n * - Auto-scrolls highlighted option into view\n * \n * @example\n * ```tsx\n * const { \n * highlightedIndex, \n * handleKeyDown, \n * getOptionId \n * } = useComboboxNavigation({\n * items: suggestions,\n * isOpen: isDropdownOpen,\n * onSelect: (item, idx) => handleSelect(item),\n * onClose: () => setIsOpen(false),\n * listboxRef\n * });\n * \n * <input\n * role=\"combobox\"\n * onKeyDown={handleKeyDown}\n * aria-activedescendant={highlightedIndex >= 0 ? getOptionId(listboxId, highlightedIndex) : undefined}\n * />\n * ```\n */\nexport function useComboboxNavigation<T = any>({\n items,\n isOpen,\n onSelect,\n onClose,\n onOpen,\n loop = true,\n disabled = false,\n listboxRef,\n optionSelector = '[role=\"option\"]'\n}: UseComboboxNavigationOptions<T>): UseComboboxNavigationReturn {\n const [highlightedIndex, setHighlightedIndex] = useState<number>(-1);\n \n // Reset highlighted index when dropdown closes\n useEffect(() => {\n if (!isOpen) {\n setHighlightedIndex(-1);\n }\n }, [isOpen]);\n \n // Auto-scroll highlighted item into view\n useScrollActiveIntoView({\n containerRef: listboxRef,\n activeIndex: highlightedIndex,\n itemSelector: optionSelector,\n enabled: isOpen\n });\n \n const handleKeyDown = useCallback(\n (e: React.KeyboardEvent) => {\n if (disabled) {\n // For disabled navigation, still handle Escape\n if (e.key === 'Escape' && isOpen) {\n e.preventDefault();\n onClose();\n }\n return;\n }\n \n const itemCount = items.length;\n \n switch (e.key) {\n case 'ArrowDown':\n e.preventDefault();\n if (!isOpen && itemCount > 0) {\n // Open dropdown and highlight first item\n onOpen?.();\n setHighlightedIndex(0);\n } else if (isOpen && itemCount > 0) {\n // Navigate down\n setHighlightedIndex((prev) => {\n if (loop) {\n return (prev + 1) % itemCount;\n }\n return Math.min(prev + 1, itemCount - 1);\n });\n }\n break;\n \n case 'ArrowUp':\n e.preventDefault();\n if (isOpen && itemCount > 0) {\n // Navigate up\n setHighlightedIndex((prev) => {\n // If nothing highlighted, go to last item\n if (prev === -1) {\n return itemCount - 1;\n }\n if (loop) {\n return (prev - 1 + itemCount) % itemCount;\n }\n return Math.max(prev - 1, 0);\n });\n }\n break;\n \n case 'Enter':\n if (isOpen && highlightedIndex >= 0 && items[highlightedIndex]) {\n e.preventDefault();\n onSelect(items[highlightedIndex], highlightedIndex);\n setHighlightedIndex(-1);\n }\n break;\n \n case 'Escape':\n if (isOpen) {\n e.preventDefault();\n onClose();\n setHighlightedIndex(-1);\n }\n break;\n \n case 'Tab':\n // Close dropdown on Tab (don't preventDefault - let focus move naturally)\n if (isOpen) {\n onClose();\n setHighlightedIndex(-1);\n }\n break;\n }\n },\n [disabled, items, isOpen, highlightedIndex, onSelect, onClose, onOpen, loop]\n );\n \n const getOptionId = useCallback(\n (listboxId: string, index: number) => `${listboxId}-option-${index}`,\n []\n );\n \n return {\n highlightedIndex,\n setHighlightedIndex,\n handleKeyDown,\n getOptionId\n };\n}\n"],"names":["useState","useEffect","useCallback","useScrollActiveIntoView","useComboboxNavigation","items","isOpen","onSelect","onClose","onOpen","loop","disabled","listboxRef","optionSelector","highlightedIndex","setHighlightedIndex","containerRef","activeIndex","itemSelector","enabled","handleKeyDown","e","key","preventDefault","itemCount","length","prev","Math","min","max","getOptionId","listboxId","index"],"mappings":"AA2GO,SAAA,YAAAA,GAAA,aAAAC,GAAA,eAAAC,SAAA;AAAA,SAAA,2BAAAC,SAAA;AAAA,SAASC,EAA+B;AAAA,EAC7CC,OAAAA;AAAAA,EACAC,QAAAA;AAAAA,EACAC,UAAAA;AAAAA,EACAC,SAAAA;AAAAA,EACAC,QAAAA;AAAAA,EACAC,MAAAA,IAAO;AAAA,EACPC,UAAAA,IAAW;AAAA,EACXC,YAAAA;AAAAA,EACAC,gBAAAA,IAAiB;AACc,GAAgC;AAC/D,QAAM,CAACC,GAAkBC,CAAmB,IAAIf,EAAiB,EAAE;AAGnEC,EAAAA,EAAU,MAAM;AACd,IAAKK,KACHS,EAAoB,EAAE;AAAA,EAE1B,GAAG,CAACT,CAAM,CAAC,GAGXH,EAAwB;AAAA,IACtBa,cAAcJ;AAAAA,IACdK,aAAaH;AAAAA,IACbI,cAAcL;AAAAA,IACdM,SAASb;AAAAA,EAAAA,CACV;AAED,QAAMc,IAAgBlB,EACpB,CAACmB,MAA2B;AAC1B,QAAIV,GAAU;AAEZ,MAAIU,EAAEC,QAAQ,YAAYhB,MACxBe,EAAEE,eAAAA,GACFf,EAAAA;AAEF;AAAA,IACF;AAEA,UAAMgB,IAAYnB,EAAMoB;AAExB,YAAQJ,EAAEC,KAAAA;AAAAA,MACR,KAAK;AACHD,QAAAA,EAAEE,eAAAA,GACE,CAACjB,KAAUkB,IAAY,KAEzBf,IAAAA,GACAM,EAAoB,CAAC,KACZT,KAAUkB,IAAY,KAE/BT,EAAqBW,CAAAA,MACfhB,KACMgB,IAAO,KAAKF,IAEfG,KAAKC,IAAIF,IAAO,GAAGF,IAAY,CAAC,CACxC;AAEH;AAAA,MAEF,KAAK;AACHH,QAAAA,EAAEE,eAAAA,GACEjB,KAAUkB,IAAY,KAExBT,EAAqBW,CAAAA,MAEfA,MAAS,KACJF,IAAY,IAEjBd,KACMgB,IAAO,IAAIF,KAAaA,IAE3BG,KAAKE,IAAIH,IAAO,GAAG,CAAC,CAC5B;AAEH;AAAA,MAEF,KAAK;AACH,QAAIpB,KAAUQ,KAAoB,KAAKT,EAAMS,CAAgB,MAC3DO,EAAEE,eAAAA,GACFhB,EAASF,EAAMS,CAAgB,GAAGA,CAAgB,GAClDC,EAAoB,EAAE;AAExB;AAAA,MAEF,KAAK;AACH,QAAIT,MACFe,EAAEE,eAAAA,GACFf,EAAAA,GACAO,EAAoB,EAAE;AAExB;AAAA,MAEF,KAAK;AAEH,QAAIT,MACFE,EAAAA,GACAO,EAAoB,EAAE;AAExB;AAAA,IAAA;AAAA,EAEN,GACA,CAACJ,GAAUN,GAAOC,GAAQQ,GAAkBP,GAAUC,GAASC,GAAQC,CAAI,CAC7E,GAEMoB,IAAc5B,EAClB,CAAC6B,GAAmBC,MAAkB,GAAGD,CAAS,WAAWC,CAAK,IAClE,CAAA,CACF;AAEA,SAAO;AAAA,IACLlB,kBAAAA;AAAAA,IACAC,qBAAAA;AAAAA,IACAK,eAAAA;AAAAA,IACAU,aAAAA;AAAAA,EAAAA;AAEJ;"}
1
+ {"version":3,"file":"index76.js","sources":["../src/utils/a11y/useComboboxNavigation.ts"],"sourcesContent":["import { useCallback, useState, useEffect } from 'react';\nimport type { RefObject } from 'react';\nimport { useScrollActiveIntoView } from './useScrollActiveIntoView';\n\nexport interface UseComboboxNavigationOptions<T = any> {\n /**\n * Array of items to navigate through\n */\n items: T[];\n \n /**\n * Whether the dropdown is currently open\n */\n isOpen: boolean;\n \n /**\n * Callback when an item is selected (Enter key)\n */\n onSelect: (item: T, index: number) => void;\n \n /**\n * Callback to close the dropdown\n */\n onClose: () => void;\n \n /**\n * Optional: Callback to open the dropdown\n */\n onOpen?: () => void;\n \n /**\n * Whether to wrap around at the ends of the list.\n * Default: true\n */\n loop?: boolean;\n \n /**\n * Whether keyboard navigation is disabled\n * (e.g., for custom rendered content)\n */\n disabled?: boolean;\n \n /**\n * Ref to the listbox container for scroll management\n */\n listboxRef?: RefObject<HTMLElement | null>;\n \n /**\n * CSS selector for option elements (default: '[role=\"option\"]')\n */\n optionSelector?: string;\n}\n\nexport interface UseComboboxNavigationReturn {\n /**\n * Currently highlighted index (-1 if none)\n */\n highlightedIndex: number;\n \n /**\n * Set the highlighted index manually\n */\n setHighlightedIndex: (index: number | ((prev: number) => number)) => void;\n \n /**\n * Keyboard event handler for the combobox input\n */\n handleKeyDown: (e: React.KeyboardEvent) => void;\n \n /**\n * Generate stable ID for an option\n */\n getOptionId: (listboxId: string, index: number) => string;\n \n}\n\n/**\n * Hook for managing combobox keyboard navigation with aria-activedescendant.\n * \n * Implements WAI-ARIA 1.2 Combobox pattern:\n * - Arrow Up/Down to navigate options\n * - Enter to select highlighted option\n * - Escape to close dropdown\n * - Tab to close and move focus\n * - Auto-scrolls highlighted option into view\n * \n * @example\n * ```tsx\n * const { \n * highlightedIndex, \n * handleKeyDown, \n * getOptionId \n * } = useComboboxNavigation({\n * items: suggestions,\n * isOpen: isDropdownOpen,\n * onSelect: (item, idx) => handleSelect(item),\n * onClose: () => setIsOpen(false),\n * listboxRef\n * });\n * \n * <input\n * role=\"combobox\"\n * onKeyDown={handleKeyDown}\n * aria-activedescendant={highlightedIndex >= 0 ? getOptionId(listboxId, highlightedIndex) : undefined}\n * />\n * ```\n */\nexport function useComboboxNavigation<T = any>({\n items,\n isOpen,\n onSelect,\n onClose,\n onOpen,\n loop = true,\n disabled = false,\n listboxRef,\n optionSelector = '[role=\"option\"]'\n}: UseComboboxNavigationOptions<T>): UseComboboxNavigationReturn {\n const [highlightedIndex, setHighlightedIndex] = useState<number>(-1);\n \n // Reset highlighted index when dropdown closes\n useEffect(() => {\n if (!isOpen) {\n setHighlightedIndex(-1);\n }\n }, [isOpen]);\n \n // Auto-scroll highlighted item into view\n useScrollActiveIntoView({\n containerRef: listboxRef,\n activeIndex: highlightedIndex,\n itemSelector: optionSelector,\n enabled: isOpen\n });\n \n const handleKeyDown = useCallback(\n (e: React.KeyboardEvent) => {\n if (disabled) {\n // For disabled navigation, still handle Escape\n if (e.key === 'Escape' && isOpen) {\n e.preventDefault();\n onClose();\n }\n return;\n }\n \n const itemCount = items.length;\n \n switch (e.key) {\n case 'ArrowDown':\n e.preventDefault();\n if (!isOpen && itemCount > 0) {\n // Open dropdown and highlight first item\n onOpen?.();\n setHighlightedIndex(0);\n } else if (isOpen && itemCount > 0) {\n // Navigate down\n setHighlightedIndex((prev) => {\n if (loop) {\n return (prev + 1) % itemCount;\n }\n return Math.min(prev + 1, itemCount - 1);\n });\n }\n break;\n \n case 'ArrowUp':\n e.preventDefault();\n if (isOpen && itemCount > 0) {\n // Navigate up\n setHighlightedIndex((prev) => {\n // If nothing highlighted, go to last item\n if (prev === -1) {\n return itemCount - 1;\n }\n if (loop) {\n return (prev - 1 + itemCount) % itemCount;\n }\n return Math.max(prev - 1, 0);\n });\n }\n break;\n \n case 'Enter':\n e.preventDefault();\n if (!isOpen) {\n onOpen?.();\n setHighlightedIndex(0);\n } else if (highlightedIndex >= 0 && items[highlightedIndex]) {\n onSelect(items[highlightedIndex], highlightedIndex);\n setHighlightedIndex(-1);\n }\n break;\n\n case ' ':\n e.preventDefault();\n if (!isOpen) {\n onOpen?.();\n setHighlightedIndex(0);\n } else if (highlightedIndex >= 0 && items[highlightedIndex]) {\n onSelect(items[highlightedIndex], highlightedIndex);\n setHighlightedIndex(-1);\n }\n break;\n \n case 'Escape':\n if (isOpen) {\n e.preventDefault();\n onClose();\n setHighlightedIndex(-1);\n }\n break;\n \n case 'Tab':\n // Close dropdown on Tab (don't preventDefault - let focus move naturally)\n if (isOpen) {\n onClose();\n setHighlightedIndex(-1);\n }\n break;\n }\n },\n [disabled, items, isOpen, highlightedIndex, onSelect, onClose, onOpen, loop]\n );\n \n const getOptionId = useCallback(\n (listboxId: string, index: number) => `${listboxId}-option-${index}`,\n []\n );\n \n return {\n highlightedIndex,\n setHighlightedIndex,\n handleKeyDown,\n getOptionId\n };\n}\n"],"names":["useState","useEffect","useCallback","useScrollActiveIntoView","useComboboxNavigation","items","isOpen","onSelect","onClose","onOpen","loop","disabled","listboxRef","optionSelector","highlightedIndex","setHighlightedIndex","containerRef","activeIndex","itemSelector","enabled","handleKeyDown","e","key","preventDefault","itemCount","length","prev","Math","min","max","getOptionId","listboxId","index"],"mappings":"AA2GO,SAAA,YAAAA,GAAA,aAAAC,GAAA,eAAAC,SAAA;AAAA,SAAA,2BAAAC,SAAA;AAAA,SAASC,EAA+B;AAAA,EAC7CC,OAAAA;AAAAA,EACAC,QAAAA;AAAAA,EACAC,UAAAA;AAAAA,EACAC,SAAAA;AAAAA,EACAC,QAAAA;AAAAA,EACAC,MAAAA,IAAO;AAAA,EACPC,UAAAA,IAAW;AAAA,EACXC,YAAAA;AAAAA,EACAC,gBAAAA,IAAiB;AACc,GAAgC;AAC/D,QAAM,CAACC,GAAkBC,CAAmB,IAAIf,EAAiB,EAAE;AAGnEC,EAAAA,EAAU,MAAM;AACd,IAAKK,KACHS,EAAoB,EAAE;AAAA,EAE1B,GAAG,CAACT,CAAM,CAAC,GAGXH,EAAwB;AAAA,IACtBa,cAAcJ;AAAAA,IACdK,aAAaH;AAAAA,IACbI,cAAcL;AAAAA,IACdM,SAASb;AAAAA,EAAAA,CACV;AAED,QAAMc,IAAgBlB,EACpB,CAACmB,MAA2B;AAC1B,QAAIV,GAAU;AAEZ,MAAIU,EAAEC,QAAQ,YAAYhB,MACxBe,EAAEE,eAAAA,GACFf,EAAAA;AAEF;AAAA,IACF;AAEA,UAAMgB,IAAYnB,EAAMoB;AAExB,YAAQJ,EAAEC,KAAAA;AAAAA,MACR,KAAK;AACHD,QAAAA,EAAEE,eAAAA,GACE,CAACjB,KAAUkB,IAAY,KAEzBf,IAAAA,GACAM,EAAoB,CAAC,KACZT,KAAUkB,IAAY,KAE/BT,EAAqBW,CAAAA,MACfhB,KACMgB,IAAO,KAAKF,IAEfG,KAAKC,IAAIF,IAAO,GAAGF,IAAY,CAAC,CACxC;AAEH;AAAA,MAEF,KAAK;AACHH,QAAAA,EAAEE,eAAAA,GACEjB,KAAUkB,IAAY,KAExBT,EAAqBW,CAAAA,MAEfA,MAAS,KACJF,IAAY,IAEjBd,KACMgB,IAAO,IAAIF,KAAaA,IAE3BG,KAAKE,IAAIH,IAAO,GAAG,CAAC,CAC5B;AAEH;AAAA,MAEF,KAAK;AACHL,QAAAA,EAAEE,eAAAA,GACGjB,IAGMQ,KAAoB,KAAKT,EAAMS,CAAgB,MACxDP,EAASF,EAAMS,CAAgB,GAAGA,CAAgB,GAClDC,EAAoB,EAAE,MAJtBN,IAAAA,GACAM,EAAoB,CAAC;AAKvB;AAAA,MAEF,KAAK;AACHM,QAAAA,EAAEE,eAAAA,GACGjB,IAGMQ,KAAoB,KAAKT,EAAMS,CAAgB,MACxDP,EAASF,EAAMS,CAAgB,GAAGA,CAAgB,GAClDC,EAAoB,EAAE,MAJtBN,IAAAA,GACAM,EAAoB,CAAC;AAKvB;AAAA,MAEF,KAAK;AACH,QAAIT,MACFe,EAAEE,eAAAA,GACFf,EAAAA,GACAO,EAAoB,EAAE;AAExB;AAAA,MAEF,KAAK;AAEH,QAAIT,MACFE,EAAAA,GACAO,EAAoB,EAAE;AAExB;AAAA,IAAA;AAAA,EAEN,GACA,CAACJ,GAAUN,GAAOC,GAAQQ,GAAkBP,GAAUC,GAASC,GAAQC,CAAI,CAC7E,GAEMoB,IAAc5B,EAClB,CAAC6B,GAAmBC,MAAkB,GAAGD,CAAS,WAAWC,CAAK,IAClE,CAAA,CACF;AAEA,SAAO;AAAA,IACLlB,kBAAAA;AAAAA,IACAC,qBAAAA;AAAAA,IACAK,eAAAA;AAAAA,IACAU,aAAAA;AAAAA,EAAAA;AAEJ;"}
@@ -23,4 +23,4 @@ function p({
23
23
  export {
24
24
  p as useDismissOnEscape
25
25
  };
26
- //# sourceMappingURL=index208.js.map
26
+ //# sourceMappingURL=index79.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index79.js","sources":["../src/utils/a11y/useDismissOnEscape.ts"],"sourcesContent":["import { useEffect } from 'react';\nimport type { RefObject } from 'react';\n\nexport interface UseDismissOnEscapeOptions<T extends HTMLElement = HTMLElement> {\n /**\n * Container element ref to check if focus is within.\n * Escape will only trigger if focus is within this container.\n */\n containerRef: RefObject<T | null>;\n /**\n * Callback when Escape key is pressed and focus is within container.\n */\n onDismiss?: () => void;\n /**\n * Whether the Escape handler is active.\n * Default: true\n */\n enabled?: boolean;\n /**\n * Whether to call preventDefault() when handling Escape.\n * Default: true\n */\n preventDefault?: boolean;\n /**\n * Whether to call stopPropagation() when handling Escape.\n * Default: true\n */\n stopPropagation?: boolean;\n}\n\n/**\n * Hook to handle Escape key dismissal when focus is within a container.\n *\n * This is a UX pattern: if user is interacting with an overlay/sidebar\n * (indicated by focus being within it), Escape should close it.\n *\n * @example\n * ```tsx\n * const MySidebar = ({ isOpen, onClose }) => {\n * const containerRef = useRef<HTMLDivElement>(null);\n *\n * useDismissOnEscape({\n * containerRef,\n * onDismiss: onClose,\n * enabled: isOpen\n * });\n *\n * return <div ref={containerRef}>...</div>;\n * };\n * ```\n */\nexport function useDismissOnEscape<T extends HTMLElement = HTMLElement>({\n containerRef,\n onDismiss,\n enabled = true,\n preventDefault = true,\n stopPropagation = true\n}: UseDismissOnEscapeOptions<T>): void {\n useEffect(() => {\n if (!enabled || !onDismiss) return;\n\n const container = containerRef.current;\n if (!container) return;\n\n const handleEscape = (e: KeyboardEvent) => {\n if (e.key === 'Escape' && container.contains(document.activeElement)) {\n preventDefault && e.preventDefault();\n stopPropagation && e.stopPropagation();\n onDismiss();\n }\n };\n\n document.addEventListener('keydown', handleEscape, { capture: true });\n return () => document.removeEventListener('keydown', handleEscape, { capture: true });\n }, [enabled, onDismiss, containerRef, preventDefault, stopPropagation]);\n}\n"],"names":["useEffect","useDismissOnEscape","containerRef","onDismiss","enabled","preventDefault","stopPropagation","container","current","handleEscape","e","key","contains","document","activeElement","addEventListener","capture","removeEventListener"],"mappings":"AAmDO,SAAA,aAAAA,SAAA;AAAA,SAASC,EAAwD;AAAA,EACtEC,cAAAA;AAAAA,EACAC,WAAAA;AAAAA,EACAC,SAAAA,IAAU;AAAA,EACVC,gBAAAA,IAAiB;AAAA,EACjBC,iBAAAA,IAAkB;AACU,GAAS;AACrCN,EAAAA,EAAU,MAAM;AACd,QAAI,CAACI,KAAW,CAACD,EAAW;AAE5B,UAAMI,IAAYL,EAAaM;AAC/B,QAAI,CAACD,EAAW;AAEhB,UAAME,IAAeA,CAACC,MAAqB;AACzC,MAAIA,EAAEC,QAAQ,YAAYJ,EAAUK,SAASC,SAASC,aAAa,MACjET,KAAkBK,EAAEL,eAAAA,GACpBC,KAAmBI,EAAEJ,gBAAAA,GACrBH,EAAAA;AAAAA,IAEJ;AAEAU,oBAASE,iBAAiB,WAAWN,GAAc;AAAA,MAAEO,SAAS;AAAA,IAAA,CAAM,GAC7D,MAAMH,SAASI,oBAAoB,WAAWR,GAAc;AAAA,MAAEO,SAAS;AAAA,IAAA,CAAM;AAAA,EACtF,GAAG,CAACZ,GAASD,GAAWD,GAAcG,GAAgBC,CAAe,CAAC;AACxE;"}
package/dist/index80.js CHANGED
@@ -1,5 +1,22 @@
1
- const L = "data:image/svg+xml,%3csvg%20width='32'%20height='32'%20viewBox='0%200%2032%2032'%20fill='none'%20xmlns='http://www.w3.org/2000/svg'%3e%3crect%20width='32'%20height='32'%20rx='16'%20fill='white'/%3e%3cpath%20d='M11.0179%2013.3597L12.27%2010.855L13.5222%2013.3597C13.9204%2014.1563%2014.5662%2014.8021%2015.3627%2015.2004L17.8682%2016.4531L15.3627%2017.7059C14.5662%2018.1041%2013.9204%2018.75%2013.5222%2019.5465L12.27%2022.0513L11.0179%2019.5465C10.6197%2018.75%209.97387%2018.1041%209.17738%2017.7059L6.67188%2016.4531L9.17738%2015.2004C9.97387%2014.8021%2010.6197%2014.1563%2011.0179%2013.3597Z'%20fill='%23415575'/%3e%3cpath%20d='M19.0159%207.18859L19.4685%206.2832L19.9211%207.18859C20.3193%207.98511%2020.9651%208.63098%2021.7616%209.02923L22.6674%209.48215L21.7616%209.93506C20.9651%2010.3333%2020.3193%2010.9792%2019.9211%2011.7757L19.4685%2012.6811L19.0159%2011.7757C18.6177%2010.9792%2017.9719%2010.3333%2017.1754%209.93506L16.2695%209.48215L17.1754%209.02923C17.9719%208.63098%2018.6177%207.98511%2019.0159%207.18859Z'%20fill='%23415575'/%3e%3cpath%20d='M19.0159%2021.3561L19.4685%2020.4507L19.9211%2021.3561C20.3193%2022.1526%2020.9651%2022.7985%2021.7616%2023.1967L22.6674%2023.6496L21.7616%2024.1025C20.9651%2024.5008%2020.3193%2025.1467%2019.9211%2025.9432L19.4685%2026.8486L19.0159%2025.9432C18.6177%2025.1467%2017.9719%2024.5008%2017.1754%2024.1025L16.2695%2023.6496L17.1754%2023.1967C17.9719%2022.7985%2018.6177%2022.1526%2019.0159%2021.3561Z'%20fill='%23415575'/%3e%3c/svg%3e";
1
+ import { useEffect as s } from "react";
2
+ const u = {
3
+ block: "nearest"
4
+ };
5
+ function m({
6
+ containerRef: t,
7
+ activeIndex: o,
8
+ itemSelector: r = '[role="option"]',
9
+ enabled: c = !0,
10
+ scrollOptions: e = u
11
+ }) {
12
+ s(() => {
13
+ if (!c || o < 0 || !t?.current)
14
+ return;
15
+ const n = t.current.querySelectorAll(r)[o];
16
+ n && n.scrollIntoView(e);
17
+ }, [o, t, r, c, e]);
18
+ }
2
19
  export {
3
- L as default
20
+ m as useScrollActiveIntoView
4
21
  };
5
22
  //# sourceMappingURL=index80.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index80.js","sources":["../src/assets/icons/ai-off.svg?url"],"sourcesContent":["export default \"data:image/svg+xml,%3csvg%20width='32'%20height='32'%20viewBox='0%200%2032%2032'%20fill='none'%20xmlns='http://www.w3.org/2000/svg'%3e%3crect%20width='32'%20height='32'%20rx='16'%20fill='white'/%3e%3cpath%20d='M11.0179%2013.3597L12.27%2010.855L13.5222%2013.3597C13.9204%2014.1563%2014.5662%2014.8021%2015.3627%2015.2004L17.8682%2016.4531L15.3627%2017.7059C14.5662%2018.1041%2013.9204%2018.75%2013.5222%2019.5465L12.27%2022.0513L11.0179%2019.5465C10.6197%2018.75%209.97387%2018.1041%209.17738%2017.7059L6.67188%2016.4531L9.17738%2015.2004C9.97387%2014.8021%2010.6197%2014.1563%2011.0179%2013.3597Z'%20fill='%23415575'/%3e%3cpath%20d='M19.0159%207.18859L19.4685%206.2832L19.9211%207.18859C20.3193%207.98511%2020.9651%208.63098%2021.7616%209.02923L22.6674%209.48215L21.7616%209.93506C20.9651%2010.3333%2020.3193%2010.9792%2019.9211%2011.7757L19.4685%2012.6811L19.0159%2011.7757C18.6177%2010.9792%2017.9719%2010.3333%2017.1754%209.93506L16.2695%209.48215L17.1754%209.02923C17.9719%208.63098%2018.6177%207.98511%2019.0159%207.18859Z'%20fill='%23415575'/%3e%3cpath%20d='M19.0159%2021.3561L19.4685%2020.4507L19.9211%2021.3561C20.3193%2022.1526%2020.9651%2022.7985%2021.7616%2023.1967L22.6674%2023.6496L21.7616%2024.1025C20.9651%2024.5008%2020.3193%2025.1467%2019.9211%2025.9432L19.4685%2026.8486L19.0159%2025.9432C18.6177%2025.1467%2017.9719%2024.5008%2017.1754%2024.1025L16.2695%2023.6496L17.1754%2023.1967C17.9719%2022.7985%2018.6177%2022.1526%2019.0159%2021.3561Z'%20fill='%23415575'/%3e%3c/svg%3e\""],"names":["__vite_glob_0_0"],"mappings":"AAAA,MAAAA,IAAe;"}
1
+ {"version":3,"file":"index80.js","sources":["../src/utils/a11y/useScrollActiveIntoView.ts"],"sourcesContent":["import { useEffect } from 'react';\nimport type { RefObject } from 'react';\n\nconst DEFAULT_SCROLL_OPTIONS: ScrollIntoViewOptions = { block: 'nearest' };\n\nexport interface UseScrollActiveIntoViewOptions {\n /**\n * Ref to the container element\n */\n containerRef?: RefObject<HTMLElement | null>;\n \n /**\n * Index of the currently active/highlighted item (-1 if none)\n */\n activeIndex: number;\n \n /**\n * CSS selector for item elements\n * Default: '[role=\"option\"]'\n */\n itemSelector?: string;\n \n /**\n * Whether scrolling is enabled\n * Default: true\n */\n enabled?: boolean;\n \n /**\n * ScrollIntoView options\n * Default: { block: 'nearest' }\n */\n scrollOptions?: ScrollIntoViewOptions;\n}\n\n/**\n * Hook to automatically scroll the active item into view.\n * \n * Useful for aria-activedescendant patterns where DOM focus stays\n * on the container (e.g., input field) but we need to visually show\n * which descendant option is logically active.\n * \n * Common use cases:\n * - Combobox dropdown options\n * - Menu items with virtual focus\n * - Grid cells with keyboard navigation\n * - Tree view items\n * - Listbox options\n * \n * @example\n * ```tsx\n * const [highlightedIndex, setHighlightedIndex] = useState(-1);\n * const listboxRef = useRef<HTMLDivElement>(null);\n * \n * useScrollActiveIntoView({\n * containerRef: listboxRef,\n * activeIndex: highlightedIndex,\n * itemSelector: '[role=\"option\"]'\n * });\n * \n * // Now when highlightedIndex changes, the item scrolls into view\n * ```\n * \n * @example Custom scroll behavior\n * ```tsx\n * useScrollActiveIntoView({\n * containerRef: menuRef,\n * activeIndex: activeMenuIndex,\n * itemSelector: '[role=\"menuitem\"]',\n * scrollOptions: { block: 'center', behavior: 'smooth' }\n * });\n * ```\n */\nexport function useScrollActiveIntoView({\n containerRef,\n activeIndex,\n itemSelector = '[role=\"option\"]',\n enabled = true,\n scrollOptions = DEFAULT_SCROLL_OPTIONS\n}: UseScrollActiveIntoViewOptions): void {\n useEffect(() => {\n // Early returns for disabled states\n if (!enabled || activeIndex < 0 || !containerRef?.current) {\n return;\n }\n \n const container = containerRef.current;\n const items = container.querySelectorAll(itemSelector);\n const activeItem = items[activeIndex] as HTMLElement;\n \n if (activeItem) {\n activeItem.scrollIntoView(scrollOptions);\n }\n }, [activeIndex, containerRef, itemSelector, enabled, scrollOptions]);\n}\n"],"names":["useEffect","DEFAULT_SCROLL_OPTIONS","block","useScrollActiveIntoView","containerRef","activeIndex","itemSelector","enabled","scrollOptions","current","activeItem","querySelectorAll","scrollIntoView"],"mappings":"AAGA,SAAA,aAAAA,SAAA;AAAA,MAAMC,IAAgD;AAAA,EAAEC,OAAO;AAAU;AAsElE,SAASC,EAAwB;AAAA,EACtCC,cAAAA;AAAAA,EACAC,aAAAA;AAAAA,EACAC,cAAAA,IAAe;AAAA,EACfC,SAAAA,IAAU;AAAA,EACVC,eAAAA,IAAgBP;AACc,GAAS;AACvCD,EAAAA,EAAU,MAAM;AAEd,QAAI,CAACO,KAAWF,IAAc,KAAK,CAACD,GAAcK;AAChD;AAKF,UAAMC,IAFYN,EAAaK,QACPE,iBAAiBL,CAAY,EAC5BD,CAAW;AAEpC,IAAIK,KACFA,EAAWE,eAAeJ,CAAa;AAAA,EAE3C,GAAG,CAACH,GAAaD,GAAcE,GAAcC,GAASC,CAAa,CAAC;AACtE;"}
package/dist/index81.js CHANGED
@@ -1,5 +1,12 @@
1
- const C = "data:image/svg+xml,%3csvg%20width='67'%20height='67'%20viewBox='0%200%2067%2067'%20fill='none'%20xmlns='http://www.w3.org/2000/svg'%3e%3cpath%20d='M19.166%204.53418C25.8215%201.28372%2033.4025%200.455651%2040.6025%202.19336C45.6308%203.40697%2050.254%205.81881%2054.0977%209.18262L56.2627%2011.0771V5.22852C56.2628%204.50782%2056.8467%203.92384%2057.5674%203.92383C58.288%203.92383%2058.872%204.50784%2058.8721%205.22852V14.8369C58.872%2015.5575%2058.288%2016.1416%2057.5674%2016.1416H47.874C47.1533%2016.1416%2046.5684%2015.5576%2046.5684%2014.8369C46.5684%2014.1161%2047.1533%2013.5322%2047.874%2013.5322H55.0752L52.4951%2011.249C48.9439%208.10762%2044.6571%205.85686%2039.9902%204.73047C33.3806%203.13527%2026.4212%203.89496%2020.3115%206.87891C14.2018%209.86288%209.32423%2014.8845%206.51855%2021.0781C3.71296%2027.2719%203.15512%2034.2508%204.94141%2040.8115C5.1304%2041.5068%204.72038%2042.2236%204.02539%2042.4131C3.32995%2042.6024%202.6123%2042.1923%202.42285%2041.4971C0.47701%2034.3503%201.08442%2026.748%204.14062%2020.001C7.19678%2013.2541%2012.5107%207.78477%2019.166%204.53418Z'%20stroke='black'%20stroke-width='2.61'/%3e%3cpath%20d='M62.2422%2023.8568C62.9375%2023.6675%2063.6544%2024.0777%2063.8438%2024.7728C65.7896%2031.9196%2065.1823%2039.522%2062.126%2046.2689C59.0697%2053.0158%2053.756%2058.4853%2047.1006%2061.7357C40.445%2064.9863%2032.8642%2065.8144%2025.6641%2064.0765C20.6357%2062.8629%2016.0126%2060.4512%2012.1689%2057.0873L10.0049%2055.1927V60.892C10.0048%2061.6124%209.42064%2062.1965%208.7002%2062.1967C7.97953%2062.1967%207.39465%2061.6126%207.39453%2060.892V51.433C7.39459%2050.7123%207.97949%2050.1283%208.7002%2050.1283H18.2441C18.9647%2050.1284%2019.5488%2050.7124%2019.5488%2051.433C19.5488%2052.1537%2018.9648%2052.7376%2018.2441%2052.7377H11.1914L13.7715%2055.0209C17.3228%2058.1623%2021.6095%2060.413%2026.2764%2061.5394C32.886%2063.1347%2039.8453%2062.3748%2045.9551%2059.391C52.0648%2056.407%2056.9434%2051.3855%2059.749%2045.1918C62.5546%2038.998%2063.1125%2032.0191%2061.3262%2025.4584C61.1488%2024.8064%2061.4978%2024.1351%2062.1152%2023.8978L62.2422%2023.8568Z'%20stroke='black'%20stroke-width='2.61'/%3e%3cpath%20d='M32.5%2020.4045C32.6936%2019.8812%2033.4332%2019.881%2033.627%2020.4045C35.7001%2026.0073%2040.1179%2030.425%2045.7207%2032.4983C46.2441%2032.6919%2046.2441%2033.4316%2045.7207%2033.6252C40.1179%2035.6985%2035.7001%2040.1162%2033.627%2045.719C33.4332%2046.2424%2032.6937%2046.2424%2032.5%2045.719C30.4267%2040.1162%2026.0091%2035.6985%2020.4062%2033.6252C19.8829%2033.4316%2019.8829%2032.6919%2020.4062%2032.4983C26.0091%2030.425%2030.4267%2026.0073%2032.5%2020.4045Z'%20stroke='black'%20stroke-width='3.48'/%3e%3c/svg%3e";
1
+ function n(i) {
2
+ if (!i) return !1;
3
+ const t = window.getComputedStyle(i);
4
+ if (t.display === "none" || t.visibility === "hidden")
5
+ return !1;
6
+ const e = i.getBoundingClientRect();
7
+ return e.width > 0 && e.height > 0;
8
+ }
2
9
  export {
3
- C as default
10
+ n as isElementVisible
4
11
  };
5
12
  //# sourceMappingURL=index81.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index81.js","sources":["../src/assets/icons/ai-re-run.svg?url"],"sourcesContent":["export default \"data:image/svg+xml,%3csvg%20width='67'%20height='67'%20viewBox='0%200%2067%2067'%20fill='none'%20xmlns='http://www.w3.org/2000/svg'%3e%3cpath%20d='M19.166%204.53418C25.8215%201.28372%2033.4025%200.455651%2040.6025%202.19336C45.6308%203.40697%2050.254%205.81881%2054.0977%209.18262L56.2627%2011.0771V5.22852C56.2628%204.50782%2056.8467%203.92384%2057.5674%203.92383C58.288%203.92383%2058.872%204.50784%2058.8721%205.22852V14.8369C58.872%2015.5575%2058.288%2016.1416%2057.5674%2016.1416H47.874C47.1533%2016.1416%2046.5684%2015.5576%2046.5684%2014.8369C46.5684%2014.1161%2047.1533%2013.5322%2047.874%2013.5322H55.0752L52.4951%2011.249C48.9439%208.10762%2044.6571%205.85686%2039.9902%204.73047C33.3806%203.13527%2026.4212%203.89496%2020.3115%206.87891C14.2018%209.86288%209.32423%2014.8845%206.51855%2021.0781C3.71296%2027.2719%203.15512%2034.2508%204.94141%2040.8115C5.1304%2041.5068%204.72038%2042.2236%204.02539%2042.4131C3.32995%2042.6024%202.6123%2042.1923%202.42285%2041.4971C0.47701%2034.3503%201.08442%2026.748%204.14062%2020.001C7.19678%2013.2541%2012.5107%207.78477%2019.166%204.53418Z'%20stroke='black'%20stroke-width='2.61'/%3e%3cpath%20d='M62.2422%2023.8568C62.9375%2023.6675%2063.6544%2024.0777%2063.8438%2024.7728C65.7896%2031.9196%2065.1823%2039.522%2062.126%2046.2689C59.0697%2053.0158%2053.756%2058.4853%2047.1006%2061.7357C40.445%2064.9863%2032.8642%2065.8144%2025.6641%2064.0765C20.6357%2062.8629%2016.0126%2060.4512%2012.1689%2057.0873L10.0049%2055.1927V60.892C10.0048%2061.6124%209.42064%2062.1965%208.7002%2062.1967C7.97953%2062.1967%207.39465%2061.6126%207.39453%2060.892V51.433C7.39459%2050.7123%207.97949%2050.1283%208.7002%2050.1283H18.2441C18.9647%2050.1284%2019.5488%2050.7124%2019.5488%2051.433C19.5488%2052.1537%2018.9648%2052.7376%2018.2441%2052.7377H11.1914L13.7715%2055.0209C17.3228%2058.1623%2021.6095%2060.413%2026.2764%2061.5394C32.886%2063.1347%2039.8453%2062.3748%2045.9551%2059.391C52.0648%2056.407%2056.9434%2051.3855%2059.749%2045.1918C62.5546%2038.998%2063.1125%2032.0191%2061.3262%2025.4584C61.1488%2024.8064%2061.4978%2024.1351%2062.1152%2023.8978L62.2422%2023.8568Z'%20stroke='black'%20stroke-width='2.61'/%3e%3cpath%20d='M32.5%2020.4045C32.6936%2019.8812%2033.4332%2019.881%2033.627%2020.4045C35.7001%2026.0073%2040.1179%2030.425%2045.7207%2032.4983C46.2441%2032.6919%2046.2441%2033.4316%2045.7207%2033.6252C40.1179%2035.6985%2035.7001%2040.1162%2033.627%2045.719C33.4332%2046.2424%2032.6937%2046.2424%2032.5%2045.719C30.4267%2040.1162%2026.0091%2035.6985%2020.4062%2033.6252C19.8829%2033.4316%2019.8829%2032.6919%2020.4062%2032.4983C26.0091%2030.425%2030.4267%2026.0073%2032.5%2020.4045Z'%20stroke='black'%20stroke-width='3.48'/%3e%3c/svg%3e\""],"names":["__vite_glob_0_1"],"mappings":"AAAA,MAAAA,IAAe;"}
1
+ {"version":3,"file":"index81.js","sources":["../src/utils/a11y/elementVisibility.ts"],"sourcesContent":["/**\n * Checks if an element is visible in the DOM.\n * \n * An element is considered visible if:\n * - It exists in the DOM\n * - It's not hidden via CSS (display: none, visibility: hidden)\n * - It has actual dimensions (width > 0 and height > 0)\n * \n * @param element - The element to check, or null\n * @returns true if the element is visible, false otherwise\n * \n * @example\n * const element = document.getElementById('my-element');\n * if (isElementVisible(element)) {\n * // Element is visible\n * }\n */\nexport function isElementVisible(element: HTMLElement | null): boolean {\n if (!element) return false;\n\n // Check computed style for display/visibility\n const style = window.getComputedStyle(element);\n if (style.display === 'none' || style.visibility === 'hidden') {\n return false;\n }\n\n // Check if element has dimensions\n const rect = element.getBoundingClientRect();\n return rect.width > 0 && rect.height > 0;\n}\n"],"names":["isElementVisible","element","style","window","getComputedStyle","display","visibility","rect","getBoundingClientRect","width","height"],"mappings":"AAiBO,SAASA,EAAiBC,GAAsC;AACrE,MAAI,CAACA,EAAS,QAAO;AAGrB,QAAMC,IAAQC,OAAOC,iBAAiBH,CAAO;AAC7C,MAAIC,EAAMG,YAAY,UAAUH,EAAMI,eAAe;AACnD,WAAO;AAIT,QAAMC,IAAON,EAAQO,sBAAAA;AACrB,SAAOD,EAAKE,QAAQ,KAAKF,EAAKG,SAAS;AACzC;"}
package/dist/index82.js CHANGED
@@ -1,5 +1,45 @@
1
- const e = "data:image/svg+xml,%3csvg%20width='21'%20height='20'%20viewBox='0%200%2021%2020'%20fill='none'%20xmlns='http://www.w3.org/2000/svg'%3e%3cg%20opacity='0.8'%3e%3cg%20clip-path='url(%23clip0_11623_94780)'%3e%3cpath%20d='M8.93929%2014.7575C12.1504%2014.7575%2014.7536%2012.1543%2014.7536%208.94319C14.7536%205.73205%2012.1504%203.12891%208.93929%203.12891C5.72814%203.12891%203.125%205.73205%203.125%208.94319C3.125%2012.1543%205.72814%2014.7575%208.93929%2014.7575Z'%20stroke='%23D8E8F6'%20stroke-width='1.2'%20stroke-linecap='round'%20stroke-linejoin='round'/%3e%3cpath%20d='M16.8642%2016.872L13.0469%2013.0547'%20stroke='%23D8E8F6'%20stroke-width='1.2'%20stroke-linecap='round'%20stroke-linejoin='round'/%3e%3cpath%20d='M12.4688%201.47559C13.0214%202.58108%2013.918%203.47752%2015.0234%204.03027L15.9619%204.5L15.0234%204.96973C13.918%205.52248%2013.0214%206.41892%2012.4688%207.52441L12%208.46191L11.5313%207.52441C10.9786%206.41892%2010.082%205.52248%208.97656%204.96973L8.03711%204.5L8.97656%204.03027C10.082%203.47752%2010.9786%202.58108%2011.5313%201.47559L12%200.538086L12.4688%201.47559Z'%20fill='white'%20stroke='%233E8BD1'%20stroke-width='1.375'/%3e%3c/g%3e%3c/g%3e%3cdefs%3e%3cclipPath%20id='clip0_11623_94780'%3e%3crect%20width='16'%20height='18'%20fill='white'%20transform='translate(2)'/%3e%3c/clipPath%3e%3c/defs%3e%3c/svg%3e";
1
+ import { useRef as d } from "react";
2
+ import { useFocusTrap as u } from "./index72.js";
3
+ import { useDismissOnEscape as c } from "./index79.js";
4
+ import { getA11yNameAttributes as f } from "./index78.js";
5
+ import { useStableId as p } from "./index83.js";
6
+ function x({
7
+ isOpen: e,
8
+ onDismiss: s,
9
+ ariaLabel: o,
10
+ ariaLabelledBy: a,
11
+ titleIdPrefix: i = "modal-title",
12
+ initialFocus: m = "first",
13
+ portalContainerRefs: n
14
+ }) {
15
+ const t = d(null), r = p(void 0, i);
16
+ u({
17
+ enabled: e,
18
+ containerRef: t,
19
+ restoreFocus: !0,
20
+ initialFocus: m,
21
+ portalContainerRefs: n
22
+ }), c({
23
+ containerRef: t,
24
+ onDismiss: s,
25
+ enabled: e
26
+ });
27
+ const l = {
28
+ role: "dialog",
29
+ "aria-modal": !0,
30
+ tabIndex: -1,
31
+ ...f({
32
+ ariaLabelledBy: a ?? (o ? void 0 : r),
33
+ ariaLabel: o
34
+ })
35
+ };
36
+ return {
37
+ containerRef: t,
38
+ titleId: r,
39
+ dialogProps: l
40
+ };
41
+ }
2
42
  export {
3
- e as default
43
+ x as useModalA11y
4
44
  };
5
45
  //# sourceMappingURL=index82.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index82.js","sources":["../src/assets/icons/ai-search.svg?url"],"sourcesContent":["export default \"data:image/svg+xml,%3csvg%20width='21'%20height='20'%20viewBox='0%200%2021%2020'%20fill='none'%20xmlns='http://www.w3.org/2000/svg'%3e%3cg%20opacity='0.8'%3e%3cg%20clip-path='url(%23clip0_11623_94780)'%3e%3cpath%20d='M8.93929%2014.7575C12.1504%2014.7575%2014.7536%2012.1543%2014.7536%208.94319C14.7536%205.73205%2012.1504%203.12891%208.93929%203.12891C5.72814%203.12891%203.125%205.73205%203.125%208.94319C3.125%2012.1543%205.72814%2014.7575%208.93929%2014.7575Z'%20stroke='%23D8E8F6'%20stroke-width='1.2'%20stroke-linecap='round'%20stroke-linejoin='round'/%3e%3cpath%20d='M16.8642%2016.872L13.0469%2013.0547'%20stroke='%23D8E8F6'%20stroke-width='1.2'%20stroke-linecap='round'%20stroke-linejoin='round'/%3e%3cpath%20d='M12.4688%201.47559C13.0214%202.58108%2013.918%203.47752%2015.0234%204.03027L15.9619%204.5L15.0234%204.96973C13.918%205.52248%2013.0214%206.41892%2012.4688%207.52441L12%208.46191L11.5313%207.52441C10.9786%206.41892%2010.082%205.52248%208.97656%204.96973L8.03711%204.5L8.97656%204.03027C10.082%203.47752%2010.9786%202.58108%2011.5313%201.47559L12%200.538086L12.4688%201.47559Z'%20fill='white'%20stroke='%233E8BD1'%20stroke-width='1.375'/%3e%3c/g%3e%3c/g%3e%3cdefs%3e%3cclipPath%20id='clip0_11623_94780'%3e%3crect%20width='16'%20height='18'%20fill='white'%20transform='translate(2)'/%3e%3c/clipPath%3e%3c/defs%3e%3c/svg%3e\""],"names":["__vite_glob_0_2"],"mappings":"AAAA,MAAAA,IAAe;"}
1
+ {"version":3,"file":"index82.js","sources":["../src/utils/a11y/useModalA11y.ts"],"sourcesContent":["import { useRef } from 'react';\nimport type { MutableRefObject, RefObject } from 'react';\nimport { useFocusTrap } from './useFocusTrap';\nimport { useDismissOnEscape } from './useDismissOnEscape';\nimport { getA11yNameAttributes } from './accessibleName';\nimport { useStableId } from 'src/utils/useStableId';\n\nexport interface UseModalA11yOptions {\n /**\n * Whether the modal is open. Controls focus trap and Escape handler activation.\n */\n isOpen: boolean;\n /**\n * Called when Escape is pressed while focus is within the modal.\n * If undefined, Escape dismissal is disabled.\n */\n onDismiss?: () => void;\n /**\n * aria-label for modals without a visible title heading.\n * Only used when `ariaLabelledBy` is not provided.\n */\n ariaLabel?: string;\n /**\n * ID of an existing visible element (e.g. an h2 inside the modal content) that labels\n * the dialog. Preferred over ariaLabel when a visible heading already exists in the content.\n * Only used when `title` is not provided.\n */\n ariaLabelledBy?: string;\n /**\n * Prefix for the auto-generated title element id. Default: 'modal-title'.\n */\n titleIdPrefix?: string;\n /**\n * Initial focus target when the modal opens. Forwarded to useFocusTrap.\n * - 'first': Focus first focusable element (default)\n * - 'container': Focus the dialog container itself\n * - 'none': Skip — browser handles it (e.g. autofocus attribute on inner element)\n * - CSS selector string: Focus matching element\n * - HTMLElement: Focus specific element\n */\n initialFocus?: 'first' | 'container' | 'none' | string | HTMLElement;\n /**\n * Additional container refs for portal content that is logically part of this modal.\n * Passed through to useFocusTrap and useDismissOnEscape so their safety nets\n * allow focus to move into portal-rendered content (e.g., Dropdown with isWithPortal).\n */\n portalContainerRefs?: MutableRefObject<RefObject<HTMLElement | null>[]>;\n}\n\nexport interface UseModalA11yReturn {\n /**\n * Ref to attach to the dialog container element.\n */\n containerRef: React.RefObject<HTMLDivElement | null>;\n /**\n * Stable ID to set on the visible title element: `<h2 id={titleId}>`.\n * Only relevant when `title` is provided.\n */\n titleId: string;\n /**\n * Spread onto the dialog container element.\n * Includes: role=\"dialog\", aria-modal, tabIndex, aria-labelledby or aria-label.\n */\n dialogProps: {\n role: 'dialog';\n 'aria-modal': true;\n tabIndex: number;\n [key: string]: unknown;\n };\n}\n\n/**\n * Bundles all WCAG dialog semantics into a single hook.\n *\n * Handles:\n * - Stable ID for title element (aria-labelledby association)\n * - Focus trap: moves focus into modal on open, wraps Tab, restores focus on close\n * - Escape dismissal: calls onDismiss when Escape is pressed within the modal\n * - dialogProps: role=\"dialog\", aria-modal, tabIndex, aria-labelledby / aria-label\n *\n * @example Modal with a visible title (most common)\n * ```tsx\n * const MyModal = ({ isOpen, onClose }) => {\n * const { containerRef, titleId, dialogProps } = useModalA11y({\n * isOpen,\n * onDismiss: onClose,\n * });\n *\n * return (\n * <div ref={containerRef} {...dialogProps} className=\"modal-content\">\n * <h2 id={titleId}>My Title</h2>\n * ...\n * </div>\n * );\n * };\n * ```\n *\n * @example Modal without a visible title\n * ```tsx\n * const { containerRef, dialogProps } = useModalA11y({\n * isOpen,\n * onDismiss: onClose,\n * ariaLabel: 'Upload document',\n * });\n * ```\n *\n * @example Custom initial focus (specific button) or skip (autofocus)\n * ```tsx\n * useModalA11y({ isOpen, onDismiss, initialFocus: '.my-cta-btn' });\n * useModalA11y({ isOpen, onDismiss, initialFocus: 'none' }); // autofocus on inner element\n * ```\n */\nexport function useModalA11y({\n isOpen,\n onDismiss,\n ariaLabel,\n ariaLabelledBy,\n titleIdPrefix = 'modal-title',\n initialFocus = 'first',\n portalContainerRefs,\n}: UseModalA11yOptions): UseModalA11yReturn {\n const containerRef = useRef<HTMLDivElement>(null);\n const titleId = useStableId(undefined, titleIdPrefix);\n\n useFocusTrap({\n enabled: isOpen,\n containerRef,\n restoreFocus: true,\n initialFocus,\n portalContainerRefs,\n });\n\n useDismissOnEscape({\n containerRef,\n onDismiss,\n enabled: isOpen,\n });\n\n const nameAttrs = getA11yNameAttributes({\n ariaLabelledBy: ariaLabelledBy ?? (ariaLabel ? undefined : titleId),\n ariaLabel: ariaLabel,\n });\n\n const dialogProps = {\n role: 'dialog' as const,\n 'aria-modal': true as const,\n tabIndex: -1,\n ...nameAttrs,\n };\n\n return { containerRef, titleId, dialogProps };\n}\n"],"names":["useRef","useFocusTrap","useDismissOnEscape","getA11yNameAttributes","useStableId","useModalA11y","isOpen","onDismiss","ariaLabel","ariaLabelledBy","titleIdPrefix","initialFocus","portalContainerRefs","containerRef","titleId","undefined","enabled","restoreFocus","dialogProps","role","tabIndex","nameAttrs"],"mappings":"AAgHO,SAAA,UAAAA,SAAA;AAAA,SAAA,gBAAAC,SAAA;AAAA,SAAA,sBAAAC,SAAA;AAAA,SAAA,yBAAAC,SAAA;AAAA,SAAA,eAAAC,SAAA;AAAA,SAASC,EAAa;AAAA,EAC3BC,QAAAA;AAAAA,EACAC,WAAAA;AAAAA,EACAC,WAAAA;AAAAA,EACAC,gBAAAA;AAAAA,EACAC,eAAAA,IAAgB;AAAA,EAChBC,cAAAA,IAAe;AAAA,EACfC,qBAAAA;AACmB,GAAuB;AAC1C,QAAMC,IAAeb,EAAuB,IAAI,GAC1Cc,IAAUV,EAAYW,QAAWL,CAAa;AAEpDT,EAAAA,EAAa;AAAA,IACXe,SAASV;AAAAA,IACTO,cAAAA;AAAAA,IACAI,cAAc;AAAA,IACdN,cAAAA;AAAAA,IACAC,qBAAAA;AAAAA,EAAAA,CACD,GAEDV,EAAmB;AAAA,IACjBW,cAAAA;AAAAA,IACAN,WAAAA;AAAAA,IACAS,SAASV;AAAAA,EAAAA,CACV;AAOD,QAAMY,IAAc;AAAA,IAClBC,MAAM;AAAA,IACN,cAAc;AAAA,IACdC,UAAU;AAAA,IACV,GATgBjB,EAAsB;AAAA,MACtCM,gBAAgBA,MAAmBD,IAAYO,SAAYD;AAAAA,MAC3DN,WAAAA;AAAAA,IAAAA,CACD;AAAA,EAMIa;AAGL,SAAO;AAAA,IAAER,cAAAA;AAAAA,IAAcC,SAAAA;AAAAA,IAASI,aAAAA;AAAAA,EAAAA;AAClC;"}
package/dist/index83.js CHANGED
@@ -1,5 +1,9 @@
1
- const L = "data:image/svg+xml,%3csvg%20width='16'%20height='17'%20viewBox='0%200%2016%2017'%20fill='none'%20xmlns='http://www.w3.org/2000/svg'%3e%3cpath%20d='M10.4958%207.65801L9.58298%205.83203L8.67016%207.65801C8.37987%208.23869%207.90907%208.70953%207.32841%208.99985L5.50189%209.91312L7.32841%2010.8264C7.90907%2011.1167%208.37987%2011.5876%208.67016%2012.1682L9.58298%2013.9942L10.4958%2012.1682C10.7861%2011.5876%2011.2569%2011.1167%2011.8375%2010.8264L13.6641%209.91312L11.8375%208.99986C11.2569%208.70953%2010.7861%208.23869%2010.4958%207.65801Z'%20fill='%23415575'%20stroke='%23415575'/%3e%3cpath%20d='M4.66587%203.16003L4.33592%202.5L4.00597%203.16003C3.71568%203.7407%203.24488%204.21155%202.66423%204.50187L2.00387%204.83205L2.66422%205.16223C3.24487%205.45255%203.71568%205.9234%204.00597%206.50407L4.33592%207.1641L4.66587%206.50407C4.95615%205.9234%205.42696%205.45255%206.00761%205.16223L6.66797%204.83205L6.00761%204.50187C5.42696%204.21155%204.95615%203.7407%204.66587%203.16003Z'%20fill='%23415575'%20stroke='%23415575'/%3e%3c/svg%3e";
1
+ import { useRef as n } from "react";
2
+ function u(e, t = "se-id") {
3
+ const r = n("");
4
+ return r.current || (r.current = `${t}-${crypto.randomUUID()}`), e || r.current;
5
+ }
2
6
  export {
3
- L as default
7
+ u as useStableId
4
8
  };
5
9
  //# sourceMappingURL=index83.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index83.js","sources":["../src/assets/icons/ai-stars.svg?url"],"sourcesContent":["export default \"data:image/svg+xml,%3csvg%20width='16'%20height='17'%20viewBox='0%200%2016%2017'%20fill='none'%20xmlns='http://www.w3.org/2000/svg'%3e%3cpath%20d='M10.4958%207.65801L9.58298%205.83203L8.67016%207.65801C8.37987%208.23869%207.90907%208.70953%207.32841%208.99985L5.50189%209.91312L7.32841%2010.8264C7.90907%2011.1167%208.37987%2011.5876%208.67016%2012.1682L9.58298%2013.9942L10.4958%2012.1682C10.7861%2011.5876%2011.2569%2011.1167%2011.8375%2010.8264L13.6641%209.91312L11.8375%208.99986C11.2569%208.70953%2010.7861%208.23869%2010.4958%207.65801Z'%20fill='%23415575'%20stroke='%23415575'/%3e%3cpath%20d='M4.66587%203.16003L4.33592%202.5L4.00597%203.16003C3.71568%203.7407%203.24488%204.21155%202.66423%204.50187L2.00387%204.83205L2.66422%205.16223C3.24487%205.45255%203.71568%205.9234%204.00597%206.50407L4.33592%207.1641L4.66587%206.50407C4.95615%205.9234%205.42696%205.45255%206.00761%205.16223L6.66797%204.83205L6.00761%204.50187C5.42696%204.21155%204.95615%203.7407%204.66587%203.16003Z'%20fill='%23415575'%20stroke='%23415575'/%3e%3c/svg%3e\""],"names":["__vite_glob_0_3"],"mappings":"AAAA,MAAAA,IAAe;"}
1
+ {"version":3,"file":"index83.js","sources":["../src/utils/useStableId.ts"],"sourcesContent":["import { useRef } from 'react';\n\n/**\n * Generates a stable unique ID for component instances (React 16 compatible).\n * Returns the provided id if given, otherwise generates a stable per-mount id.\n * \n * @param id - Optional explicit id\n * @param prefix - Prefix for auto-generated ids (default: 'se-id')\n * @returns Stable id string\n */\nexport function useStableId(id?: string, prefix: string = 'se-id'): string {\n const autoIdRef = useRef<string>('');\n \n if (!autoIdRef.current) {\n autoIdRef.current = `${prefix}-${crypto.randomUUID()}`;\n }\n \n return id || autoIdRef.current;\n}\n\n\n\n\n\n\n\n"],"names":["useRef","useStableId","id","prefix","autoIdRef","current","crypto","randomUUID"],"mappings":"AAUO,SAAA,UAAAA,SAAA;AAAA,SAASC,EAAYC,GAAaC,IAAiB,SAAiB;AACzE,QAAMC,IAAYJ,EAAe,EAAE;AAEnC,SAAKI,EAAUC,YACbD,EAAUC,UAAU,GAAGF,CAAM,IAAIG,OAAOC,YAAY,KAG/CL,KAAME,EAAUC;AACzB;"}