se-design 1.0.90-dev.0 → 1.0.90
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/style.css +1 -1
- package/dist/components/AnchoredOverlay/index.d.ts +41 -0
- package/dist/components/index.d.ts +2 -0
- package/dist/index.js +132 -130
- package/dist/index.js.map +1 -1
- package/dist/index100.js +1 -1
- package/dist/index100.js.map +1 -1
- package/dist/index101.js +1 -1
- package/dist/index101.js.map +1 -1
- package/dist/index102.js +1 -1
- package/dist/index102.js.map +1 -1
- package/dist/index103.js +1 -1
- package/dist/index103.js.map +1 -1
- package/dist/index104.js +1 -1
- package/dist/index104.js.map +1 -1
- package/dist/index105.js +1 -1
- package/dist/index105.js.map +1 -1
- package/dist/index106.js +1 -1
- package/dist/index106.js.map +1 -1
- package/dist/index107.js +1 -1
- package/dist/index107.js.map +1 -1
- package/dist/index108.js +1 -1
- package/dist/index108.js.map +1 -1
- package/dist/index109.js +1 -1
- package/dist/index109.js.map +1 -1
- package/dist/index11.js +1 -1
- package/dist/index110.js +1 -1
- package/dist/index110.js.map +1 -1
- package/dist/index111.js +1 -1
- package/dist/index111.js.map +1 -1
- package/dist/index112.js +1 -1
- package/dist/index112.js.map +1 -1
- package/dist/index113.js +1 -1
- package/dist/index113.js.map +1 -1
- package/dist/index114.js +2 -2
- package/dist/index114.js.map +1 -1
- package/dist/index115.js +1 -1
- package/dist/index115.js.map +1 -1
- package/dist/index116.js +2 -2
- package/dist/index116.js.map +1 -1
- package/dist/index117.js +1 -1
- package/dist/index117.js.map +1 -1
- package/dist/index118.js +1 -1
- package/dist/index118.js.map +1 -1
- package/dist/index119.js +2 -2
- package/dist/index119.js.map +1 -1
- package/dist/index12.js +3 -3
- package/dist/index120.js +1 -1
- package/dist/index120.js.map +1 -1
- package/dist/index121.js +2 -2
- package/dist/index121.js.map +1 -1
- package/dist/index122.js +1 -1
- package/dist/index122.js.map +1 -1
- package/dist/index123.js +1 -1
- package/dist/index123.js.map +1 -1
- package/dist/index124.js +1 -1
- package/dist/index124.js.map +1 -1
- package/dist/index125.js +1 -1
- package/dist/index125.js.map +1 -1
- package/dist/index126.js +2 -2
- package/dist/index126.js.map +1 -1
- package/dist/index127.js +1 -1
- package/dist/index127.js.map +1 -1
- package/dist/index128.js +2 -2
- package/dist/index128.js.map +1 -1
- package/dist/index129.js +2 -2
- package/dist/index129.js.map +1 -1
- package/dist/index13.js +3 -3
- package/dist/index130.js +1 -1
- package/dist/index130.js.map +1 -1
- package/dist/index131.js +2 -2
- package/dist/index131.js.map +1 -1
- package/dist/index132.js +2 -2
- package/dist/index132.js.map +1 -1
- package/dist/index133.js +1 -1
- package/dist/index133.js.map +1 -1
- package/dist/index134.js +1 -1
- package/dist/index134.js.map +1 -1
- package/dist/index135.js +1 -1
- package/dist/index135.js.map +1 -1
- package/dist/index136.js +2 -2
- package/dist/index136.js.map +1 -1
- package/dist/index137.js +2 -2
- package/dist/index137.js.map +1 -1
- package/dist/index138.js +2 -2
- package/dist/index138.js.map +1 -1
- package/dist/index139.js +1 -1
- package/dist/index139.js.map +1 -1
- package/dist/index140.js +1 -1
- package/dist/index140.js.map +1 -1
- package/dist/index141.js +1 -1
- package/dist/index141.js.map +1 -1
- package/dist/index142.js +1 -1
- package/dist/index142.js.map +1 -1
- package/dist/index143.js +1 -1
- package/dist/index143.js.map +1 -1
- package/dist/index144.js +1 -1
- package/dist/index144.js.map +1 -1
- package/dist/index145.js +1 -1
- package/dist/index145.js.map +1 -1
- package/dist/index146.js +1 -1
- package/dist/index146.js.map +1 -1
- package/dist/index147.js +2 -2
- package/dist/index147.js.map +1 -1
- package/dist/index148.js +2 -2
- package/dist/index148.js.map +1 -1
- package/dist/index149.js +1 -1
- package/dist/index149.js.map +1 -1
- package/dist/index150.js +1 -1
- package/dist/index150.js.map +1 -1
- package/dist/index151.js +1 -1
- package/dist/index151.js.map +1 -1
- package/dist/index152.js +1 -1
- package/dist/index152.js.map +1 -1
- package/dist/index153.js +1 -1
- package/dist/index153.js.map +1 -1
- package/dist/index154.js +1 -1
- package/dist/index154.js.map +1 -1
- package/dist/index155.js +1 -1
- package/dist/index155.js.map +1 -1
- package/dist/index156.js +2 -2
- package/dist/index156.js.map +1 -1
- package/dist/index157.js +1 -1
- package/dist/index157.js.map +1 -1
- package/dist/index158.js +2 -2
- package/dist/index158.js.map +1 -1
- package/dist/index159.js +2 -2
- package/dist/index159.js.map +1 -1
- package/dist/index16.js +3 -3
- package/dist/index160.js +2 -2
- package/dist/index160.js.map +1 -1
- package/dist/index161.js +2 -2
- package/dist/index161.js.map +1 -1
- package/dist/index162.js +1 -1
- package/dist/index162.js.map +1 -1
- package/dist/index163.js +1 -1
- package/dist/index163.js.map +1 -1
- package/dist/index164.js +1 -1
- package/dist/index164.js.map +1 -1
- package/dist/index165.js +1 -1
- package/dist/index165.js.map +1 -1
- package/dist/index166.js +1 -1
- package/dist/index166.js.map +1 -1
- package/dist/index167.js +1 -1
- package/dist/index167.js.map +1 -1
- package/dist/index168.js +1 -1
- package/dist/index168.js.map +1 -1
- package/dist/index169.js +1 -1
- package/dist/index169.js.map +1 -1
- package/dist/index170.js +1 -1
- package/dist/index170.js.map +1 -1
- package/dist/index171.js +1 -1
- package/dist/index171.js.map +1 -1
- package/dist/index172.js +1 -1
- package/dist/index172.js.map +1 -1
- package/dist/index173.js +1 -1
- package/dist/index173.js.map +1 -1
- package/dist/index174.js +1 -1
- package/dist/index174.js.map +1 -1
- package/dist/index175.js +1 -1
- package/dist/index175.js.map +1 -1
- package/dist/index176.js +1 -1
- package/dist/index176.js.map +1 -1
- package/dist/index177.js +1 -1
- package/dist/index177.js.map +1 -1
- package/dist/index178.js +1 -1
- package/dist/index178.js.map +1 -1
- package/dist/index179.js +1 -1
- package/dist/index179.js.map +1 -1
- package/dist/index18.js +3 -3
- package/dist/index180.js +1 -1
- package/dist/index180.js.map +1 -1
- package/dist/index181.js +1 -1
- package/dist/index181.js.map +1 -1
- package/dist/index182.js +1 -1
- package/dist/index182.js.map +1 -1
- package/dist/index183.js +1 -1
- package/dist/index183.js.map +1 -1
- package/dist/index184.js +1 -1
- package/dist/index184.js.map +1 -1
- package/dist/index185.js +1 -1
- package/dist/index185.js.map +1 -1
- package/dist/index186.js +2 -2
- package/dist/index186.js.map +1 -1
- package/dist/index187.js +2 -2
- package/dist/index187.js.map +1 -1
- package/dist/index188.js +1 -1
- package/dist/index188.js.map +1 -1
- package/dist/index189.js +1 -1
- package/dist/index189.js.map +1 -1
- package/dist/index19.js +5 -5
- package/dist/index190.js +2 -2
- package/dist/index190.js.map +1 -1
- package/dist/index191.js +2 -2
- package/dist/index191.js.map +1 -1
- package/dist/index192.js +1 -1
- package/dist/index192.js.map +1 -1
- package/dist/index193.js +1 -1
- package/dist/index193.js.map +1 -1
- package/dist/index194.js +1 -1
- package/dist/index194.js.map +1 -1
- package/dist/index195.js +1 -1
- package/dist/index195.js.map +1 -1
- package/dist/index196.js +1 -1
- package/dist/index196.js.map +1 -1
- package/dist/index197.js +1 -1
- package/dist/index197.js.map +1 -1
- package/dist/index198.js +1 -1
- package/dist/index198.js.map +1 -1
- package/dist/index199.js +1 -1
- package/dist/index199.js.map +1 -1
- package/dist/index20.js +96 -18
- package/dist/index20.js.map +1 -1
- package/dist/index200.js +1 -1
- package/dist/index200.js.map +1 -1
- package/dist/index201.js +2 -2
- package/dist/index201.js.map +1 -1
- package/dist/index202.js +2 -2
- package/dist/index202.js.map +1 -1
- package/dist/index203.js +2 -2
- package/dist/index203.js.map +1 -1
- package/dist/index204.js +2 -149
- package/dist/index204.js.map +1 -1
- package/dist/index205.js +149 -9
- package/dist/index205.js.map +1 -1
- package/dist/index206.js +8 -5
- package/dist/index206.js.map +1 -1
- package/dist/index207.js +5 -42
- package/dist/index207.js.map +1 -1
- package/dist/index208.js +40 -18
- package/dist/index208.js.map +1 -1
- package/dist/index209.js +24 -0
- package/dist/index209.js.map +1 -0
- package/dist/index21.js +17 -32
- package/dist/index21.js.map +1 -1
- package/dist/index216.js +24 -68
- package/dist/index216.js.map +1 -1
- package/dist/index217.js +75 -0
- package/dist/index217.js.map +1 -0
- package/dist/index22.js +33 -66
- package/dist/index22.js.map +1 -1
- package/dist/{index223.js → index224.js} +1 -1
- package/dist/{index223.js.map → index224.js.map} +1 -1
- package/dist/{index225.js → index226.js} +1 -1
- package/dist/{index225.js.map → index226.js.map} +1 -1
- package/dist/index23.js +62 -83
- package/dist/index23.js.map +1 -1
- package/dist/{index233.js → index234.js} +1 -1
- package/dist/{index233.js.map → index234.js.map} +1 -1
- package/dist/{index236.js → index237.js} +1 -1
- package/dist/{index236.js.map → index237.js.map} +1 -1
- package/dist/index24.js +85 -21
- package/dist/index24.js.map +1 -1
- package/dist/index246.js +169 -3
- package/dist/index246.js.map +1 -1
- package/dist/index247.js +7 -0
- package/dist/index247.js.map +1 -0
- package/dist/index249.js +18 -9
- package/dist/index249.js.map +1 -1
- package/dist/index25.js +19 -401
- package/dist/index25.js.map +1 -1
- package/dist/index250.js +9 -9
- package/dist/index250.js.map +1 -1
- package/dist/index251.js +9 -4
- package/dist/index251.js.map +1 -1
- package/dist/index252.js +5 -170
- package/dist/index252.js.map +1 -1
- package/dist/index253.js +170 -11
- package/dist/index253.js.map +1 -1
- package/dist/index254.js +11 -6
- package/dist/index254.js.map +1 -1
- package/dist/index255.js +5 -5
- package/dist/index255.js.map +1 -1
- package/dist/index256.js +5 -37
- package/dist/index256.js.map +1 -1
- package/dist/index257.js +38 -2
- package/dist/index257.js.map +1 -1
- package/dist/index258.js +2 -8
- package/dist/index258.js.map +1 -1
- package/dist/index259.js +7 -326
- package/dist/index259.js.map +1 -1
- package/dist/index26.js +400 -44
- package/dist/index26.js.map +1 -1
- package/dist/index260.js +324 -47
- package/dist/index260.js.map +1 -1
- package/dist/index261.js +50 -2
- package/dist/index261.js.map +1 -1
- package/dist/index262.js +2 -76
- package/dist/index262.js.map +1 -1
- package/dist/index263.js +65 -82
- package/dist/index263.js.map +1 -1
- package/dist/index264.js +89 -48
- package/dist/index264.js.map +1 -1
- package/dist/index265.js +51 -7
- package/dist/index265.js.map +1 -1
- package/dist/index266.js +7 -4
- package/dist/index266.js.map +1 -1
- package/dist/index267.js +4 -51
- package/dist/index267.js.map +1 -1
- package/dist/index268.js +52 -2
- package/dist/index268.js.map +1 -1
- package/dist/index269.js +2 -2
- package/dist/index27.js +48 -23
- package/dist/index27.js.map +1 -1
- package/dist/index270.js +5 -0
- package/dist/index270.js.map +1 -0
- package/dist/index28.js +21 -108
- package/dist/index28.js.map +1 -1
- package/dist/index29.js +107 -147
- package/dist/index29.js.map +1 -1
- package/dist/index3.js +3 -3
- package/dist/index30.js +146 -132
- package/dist/index30.js.map +1 -1
- package/dist/index31.js +136 -76
- package/dist/index31.js.map +1 -1
- package/dist/index32.js +73 -94
- package/dist/index32.js.map +1 -1
- package/dist/index33.js +95 -73
- package/dist/index33.js.map +1 -1
- package/dist/index34.js +72 -38
- package/dist/index34.js.map +1 -1
- package/dist/index35.js +40 -72
- package/dist/index35.js.map +1 -1
- package/dist/index36.js +68 -94
- package/dist/index36.js.map +1 -1
- package/dist/index37.js +98 -77
- package/dist/index37.js.map +1 -1
- package/dist/index38.js +75 -311
- package/dist/index38.js.map +1 -1
- package/dist/index39.js +313 -75
- package/dist/index39.js.map +1 -1
- package/dist/index4.js +4 -4
- package/dist/index40.js +72 -79
- package/dist/index40.js.map +1 -1
- package/dist/index41.js +82 -32
- package/dist/index41.js.map +1 -1
- package/dist/index42.js +26 -43
- package/dist/index42.js.map +1 -1
- package/dist/index43.js +48 -109
- package/dist/index43.js.map +1 -1
- package/dist/index44.js +104 -50
- package/dist/index44.js.map +1 -1
- package/dist/index45.js +53 -142
- package/dist/index45.js.map +1 -1
- package/dist/index46.js +137 -188
- package/dist/index46.js.map +1 -1
- package/dist/index47.js +195 -35
- package/dist/index47.js.map +1 -1
- package/dist/index48.js +34 -32
- package/dist/index48.js.map +1 -1
- package/dist/index49.js +34 -147
- package/dist/index49.js.map +1 -1
- package/dist/index50.js +130 -67
- package/dist/index50.js.map +1 -1
- package/dist/index51.js +78 -453
- package/dist/index51.js.map +1 -1
- package/dist/index52.js +459 -96
- package/dist/index52.js.map +1 -1
- package/dist/index53.js +98 -43
- package/dist/index53.js.map +1 -1
- package/dist/index54.js +40 -35
- package/dist/index54.js.map +1 -1
- package/dist/index55.js +33 -87
- package/dist/index55.js.map +1 -1
- package/dist/index56.js +88 -159
- package/dist/index56.js.map +1 -1
- package/dist/index57.js +157 -143
- package/dist/index57.js.map +1 -1
- package/dist/index58.js +149 -33
- package/dist/index58.js.map +1 -1
- package/dist/index59.js +33 -86
- package/dist/index59.js.map +1 -1
- package/dist/index6.js +125 -125
- package/dist/index60.js +80 -113
- package/dist/index60.js.map +1 -1
- package/dist/index61.js +114 -73
- package/dist/index61.js.map +1 -1
- package/dist/index62.js +73 -147
- package/dist/index62.js.map +1 -1
- package/dist/index63.js +146 -312
- package/dist/index63.js.map +1 -1
- package/dist/index64.js +317 -46
- package/dist/index64.js.map +1 -1
- package/dist/index65.js +45 -142
- package/dist/index65.js.map +1 -1
- package/dist/index66.js +144 -12
- package/dist/index66.js.map +1 -1
- package/dist/index67.js +10 -53
- package/dist/index67.js.map +1 -1
- package/dist/index68.js +52 -110
- package/dist/index68.js.map +1 -1
- package/dist/index69.js +111 -17
- package/dist/index69.js.map +1 -1
- package/dist/index7.js +2 -2
- package/dist/index70.js +17 -64
- package/dist/index70.js.map +1 -1
- package/dist/index71.js +64 -25
- package/dist/index71.js.map +1 -1
- package/dist/index72.js +24 -105
- package/dist/index72.js.map +1 -1
- package/dist/index73.js +104 -58
- package/dist/index73.js.map +1 -1
- package/dist/index74.js +60 -19
- package/dist/index74.js.map +1 -1
- package/dist/index75.js +18 -168
- package/dist/index75.js.map +1 -1
- package/dist/index76.js +171 -18
- package/dist/index76.js.map +1 -1
- package/dist/index77.js +17 -10
- package/dist/index77.js.map +1 -1
- package/dist/index78.js +11 -5
- package/dist/index78.js.map +1 -1
- package/dist/index79.js +5 -62
- package/dist/index79.js.map +1 -1
- package/dist/index80.js +58 -23
- package/dist/index80.js.map +1 -1
- package/dist/index81.js +25 -9
- package/dist/index81.js.map +1 -1
- package/dist/index82.js +14 -0
- package/dist/index82.js.map +1 -0
- package/dist/index84.js +2 -2
- package/dist/index84.js.map +1 -1
- package/dist/index85.js +2 -2
- package/dist/index85.js.map +1 -1
- package/dist/index86.js +2 -2
- package/dist/index86.js.map +1 -1
- package/dist/index87.js +2 -2
- package/dist/index87.js.map +1 -1
- package/dist/index88.js +1 -1
- package/dist/index88.js.map +1 -1
- package/dist/index89.js +1 -1
- package/dist/index89.js.map +1 -1
- package/dist/index9.js +4 -4
- package/dist/index90.js +1 -1
- package/dist/index90.js.map +1 -1
- package/dist/index91.js +1 -1
- package/dist/index91.js.map +1 -1
- package/dist/index92.js +1 -1
- package/dist/index92.js.map +1 -1
- package/dist/index93.js +1 -1
- package/dist/index93.js.map +1 -1
- package/dist/index94.js +1 -1
- package/dist/index94.js.map +1 -1
- package/dist/index95.js +1 -1
- package/dist/index95.js.map +1 -1
- package/dist/index96.js +1 -1
- package/dist/index96.js.map +1 -1
- package/dist/index97.js +1 -1
- package/dist/index97.js.map +1 -1
- package/dist/index98.js +1 -1
- package/dist/index98.js.map +1 -1
- package/dist/index99.js +1 -1
- package/dist/index99.js.map +1 -1
- package/package.json +1 -1
- package/dist/index215.js +0 -31
- package/dist/index215.js.map +0 -1
- package/dist/index245.js +0 -173
- package/dist/index245.js.map +0 -1
- package/dist/index248.js +0 -22
- package/dist/index248.js.map +0 -1
- package/dist/index83.js +0 -5
- package/dist/index83.js.map +0 -1
package/dist/index68.js
CHANGED
|
@@ -1,116 +1,58 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}) {
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
}, [
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
onOpen: () => c(!0),
|
|
30
|
-
loop: C,
|
|
31
|
-
disabled: D,
|
|
32
|
-
listboxRef: h,
|
|
33
|
-
optionSelector: v,
|
|
34
|
-
keepHighlightOnSelect: P,
|
|
35
|
-
closeOnTab: k,
|
|
36
|
-
isItemDisabled: f
|
|
37
|
-
}), i = H({
|
|
38
|
-
onFocusOut: p,
|
|
39
|
-
onEscape: p,
|
|
40
|
-
disabled: !r
|
|
41
|
-
}), K = {
|
|
42
|
-
...i,
|
|
43
|
-
onPointerMove: () => {
|
|
44
|
-
w && t(!1);
|
|
45
|
-
},
|
|
46
|
-
onPointerDown: () => {
|
|
47
|
-
u.current = !0, t(!1);
|
|
48
|
-
},
|
|
49
|
-
onPointerUp: () => {
|
|
50
|
-
},
|
|
51
|
-
onFocusCapture: (e) => {
|
|
52
|
-
i.onFocusCapture(e), u.current ? t(!1) : t(!0);
|
|
53
|
-
},
|
|
54
|
-
onKeyDownCapture: (e) => {
|
|
55
|
-
i.onKeyDownCapture(e), (e.key === "Tab" || e.key === "ArrowDown" || e.key === "ArrowUp") && (u.current = !1), (e.key === "ArrowDown" || e.key === "ArrowUp") && t(!0);
|
|
56
|
-
},
|
|
57
|
-
onBlurCapture: (e) => {
|
|
58
|
-
if (t(!1), !s.current) {
|
|
59
|
-
if (d.current) {
|
|
60
|
-
d.current = !1;
|
|
61
|
-
return;
|
|
62
|
-
}
|
|
63
|
-
i.onBlurCapture(e);
|
|
64
|
-
}
|
|
1
|
+
import * as s from "react";
|
|
2
|
+
import { isVirtualClick as x } from "./index79.js";
|
|
3
|
+
function I({
|
|
4
|
+
disabled: v = !1,
|
|
5
|
+
loading: l = !1,
|
|
6
|
+
onClick: u,
|
|
7
|
+
onKeyboardActivate: n,
|
|
8
|
+
isNative: o = !0,
|
|
9
|
+
role: y = "button",
|
|
10
|
+
tabIndex: C = 0,
|
|
11
|
+
stopPropagation: c = !1,
|
|
12
|
+
preventDefault: f = !1,
|
|
13
|
+
pressed: P,
|
|
14
|
+
onPointerDown: k,
|
|
15
|
+
onMouseDown: b,
|
|
16
|
+
onTouchStart: p
|
|
17
|
+
} = {}) {
|
|
18
|
+
const e = v || l, a = s.useRef(!1), t = s.useCallback(() => {
|
|
19
|
+
a.current = !0;
|
|
20
|
+
}, []), D = s.useCallback((r) => {
|
|
21
|
+
if (e) return;
|
|
22
|
+
c && r.stopPropagation(), f && r.preventDefault();
|
|
23
|
+
const h = x(r.nativeEvent), w = a.current;
|
|
24
|
+
a.current = !1;
|
|
25
|
+
const m = h ? "virtual" : w ? "pointer" : "keyboard";
|
|
26
|
+
if ((m === "keyboard" || m === "virtual") && n) {
|
|
27
|
+
n(r);
|
|
28
|
+
return;
|
|
65
29
|
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
"
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
}
|
|
89
|
-
}, R = y((e, A = !1) => {
|
|
90
|
-
const b = f?.(a[e], e);
|
|
91
|
-
return {
|
|
92
|
-
id: o.getOptionId(n, e),
|
|
93
|
-
role: "option",
|
|
94
|
-
...b ? {} : {
|
|
95
|
-
"aria-selected": A
|
|
96
|
-
},
|
|
97
|
-
...b ? {
|
|
98
|
-
"aria-disabled": !0
|
|
99
|
-
} : {}
|
|
100
|
-
};
|
|
101
|
-
}, [o.getOptionId, n, f, a]);
|
|
102
|
-
return {
|
|
103
|
-
containerProps: K,
|
|
104
|
-
inputProps: m,
|
|
105
|
-
listboxProps: I,
|
|
106
|
-
getOptionProps: R,
|
|
107
|
-
highlightedIndex: o.highlightedIndex,
|
|
108
|
-
setHighlightedIndex: o.setHighlightedIndex,
|
|
109
|
-
getOptionId: o.getOptionId,
|
|
110
|
-
isKeyboardFocused: w
|
|
30
|
+
u?.(r);
|
|
31
|
+
}, [e, u, n, c, f]), R = s.useCallback((r) => {
|
|
32
|
+
e || (r.key === "Enter" || r.key === " ") && (r.preventDefault(), r.currentTarget.click());
|
|
33
|
+
}, [e]), d = {
|
|
34
|
+
onPointerDown: k ? (r) => {
|
|
35
|
+
t(), k(r);
|
|
36
|
+
} : t,
|
|
37
|
+
onMouseDown: b ? (r) => {
|
|
38
|
+
t(), b(r);
|
|
39
|
+
} : t,
|
|
40
|
+
onTouchStart: p ? (r) => {
|
|
41
|
+
t(), p(r);
|
|
42
|
+
} : t,
|
|
43
|
+
onClick: D,
|
|
44
|
+
"aria-disabled": e ? "true" : void 0,
|
|
45
|
+
"aria-busy": l ? "true" : void 0,
|
|
46
|
+
"aria-pressed": P
|
|
47
|
+
};
|
|
48
|
+
o || (d.onKeyDown = R);
|
|
49
|
+
const i = {
|
|
50
|
+
pressProps: d,
|
|
51
|
+
isDisabled: e
|
|
111
52
|
};
|
|
53
|
+
return o || (i.role = y, i.tabIndex = e ? -1 : C), i;
|
|
112
54
|
}
|
|
113
55
|
export {
|
|
114
|
-
|
|
56
|
+
I as useAccessiblePress
|
|
115
57
|
};
|
|
116
58
|
//# sourceMappingURL=index68.js.map
|
package/dist/index68.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index68.js","sources":["../src/utils/a11y/useCombobox.ts"],"sourcesContent":["import { useRef, useCallback, useEffect, useState } from 'react';\nimport type { RefObject } from 'react';\nimport { useComboboxNavigation } from './useComboboxNavigation';\nimport { useDismissOnFocusOut } from './useDismissOnFocusOut';\nimport type { UseDismissOnFocusOutReturn } from './useDismissOnFocusOut';\n\nexport interface UseComboboxOptions<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 to change the open state\n */\n onOpenChange: (open: boolean) => void;\n \n /**\n * Callback when an item is selected (Enter key)\n */\n onSelect: (item: T, index: number) => void;\n \n /**\n * Stable ID for the listbox element\n */\n listboxId: string;\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 * CSS selector for option elements (default: '[role=\"option\"]')\n */\n optionSelector?: string;\n \n /**\n * Whether the listbox has any items to show\n * Used for aria-expanded logic\n * Default: items.length > 0\n */\n hasItems?: boolean;\n\n /**\n * Whether to keep the highlighted index after selecting an item.\n * Useful for multi-select where the dropdown stays open after selection.\n * Default: false\n */\n keepHighlightOnSelect?: boolean;\n\n /**\n * Whether Tab should close the dropdown.\n * Set to false when Tab should move focus to elements within the popup (e.g. CTAs).\n * Default: true\n */\n closeOnTab?: boolean;\n\n /**\n * Predicate to mark items as disabled. Disabled items are reachable via arrow keys\n * (so screen readers can announce them) but Enter/Space selection is blocked.\n */\n isItemDisabled?: (item: T, index: number) => boolean;\n}\n\nexport interface UseComboboxReturn {\n /**\n * Props to spread on the container element (handles dismiss on focus out + keyboard focus tracking)\n */\n containerProps: UseDismissOnFocusOutReturn<HTMLElement> & {\n onPointerMove: () => void;\n onPointerDown: () => void;\n onPointerUp: () => void;\n };\n \n /**\n * Props to spread on the combobox input element\n */\n inputProps: {\n role: 'combobox';\n 'aria-expanded': boolean;\n 'aria-haspopup': 'listbox';\n 'aria-controls': string | undefined;\n 'aria-autocomplete': 'list';\n 'aria-activedescendant': string | undefined;\n onKeyDown: (e: React.KeyboardEvent) => void;\n };\n \n /**\n * Props to spread on the listbox element\n */\n listboxProps: {\n id: string;\n role: 'listbox';\n ref: RefObject<HTMLDivElement | null>;\n onMouseDownCapture: (e: React.MouseEvent) => void;\n onMouseUpCapture: (e: React.MouseEvent) => void;\n onMouseLeave: (e: React.MouseEvent) => void;\n };\n \n /**\n * Generate props for an option element at the given index\n * @param selected - Whether this option is the currently selected/chosen value (not keyboard highlight)\n */\n getOptionProps: (index: number, selected?: boolean) => {\n id: string;\n role: 'option';\n 'aria-selected'?: boolean;\n 'aria-disabled'?: true;\n };\n \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 * Generate stable ID for an option\n */\n getOptionId: (listboxId: string, index: number) => string;\n\n /**\n * Whether the combobox input was focused via keyboard (Tab) rather than pointer.\n * Use to conditionally show focus ring only on keyboard interaction.\n */\n isKeyboardFocused: boolean;\n}\n\n/**\n * Comprehensive hook for implementing WAI-ARIA combobox pattern.\n * \n * Combines:\n * - Keyboard navigation (Arrow Up/Down, Enter, Escape, Tab)\n * - Focus management and dismissal\n * - ARIA attributes for accessibility\n * - Auto-scroll highlighted item into view\n * \n * This hook provides a complete, batteries-included solution for building\n * accessible combobox components (autocomplete, select, search with suggestions, etc.)\n * \n * @example Basic usage\n * ```tsx\n * const MyCombobox = () => {\n * const [isOpen, setIsOpen] = useState(false);\n * const [items, setItems] = useState(['Apple', 'Banana', 'Cherry']);\n * \n * const {\n * containerProps,\n * inputProps,\n * listboxProps,\n * getOptionProps,\n * highlightedIndex\n * } = useCombobox({\n * items,\n * isOpen,\n * onOpenChange: setIsOpen,\n * onSelect: (item) => console.log('Selected:', item),\n * listboxId: 'my-listbox'\n * });\n * \n * return (\n * <div {...containerProps}>\n * <input {...inputProps} />\n * {isOpen && (\n * <div {...listboxProps}>\n * {items.map((item, i) => (\n * <div key={i} {...getOptionProps(i)}>\n * {item}\n * </div>\n * ))}\n * </div>\n * )}\n * </div>\n * );\n * };\n * ```\n * \n * @example With custom ARIA labels and handlers\n * ```tsx\n * const MySearchBox = () => {\n * const [query, setQuery] = useState('');\n * const [suggestions, setSuggestions] = useState([]);\n * const [isOpen, setIsOpen] = useState(false);\n * \n * const { containerProps, inputProps, listboxProps, getOptionProps } = useCombobox({\n * items: suggestions,\n * isOpen,\n * onOpenChange: setIsOpen,\n * onSelect: (suggestion) => {\n * setQuery(suggestion);\n * setIsOpen(false);\n * },\n * listboxId: 'search-suggestions'\n * });\n * \n * return (\n * <div {...containerProps}>\n * <input\n * {...inputProps}\n * value={query}\n * onChange={(e) => setQuery(e.target.value)}\n * aria-label=\"Search\"\n * />\n * {isOpen && suggestions.length > 0 && (\n * <div {...listboxProps} aria-label=\"Search suggestions\">\n * {suggestions.map((suggestion, i) => (\n * <div\n * key={i}\n * {...getOptionProps(i)}\n * onClick={() => {\n * setQuery(suggestion);\n * setIsOpen(false);\n * }}\n * >\n * {suggestion}\n * </div>\n * ))}\n * </div>\n * )}\n * </div>\n * );\n * };\n * ```\n */\nexport function useCombobox<T = any>({\n items,\n isOpen,\n onOpenChange,\n onSelect,\n listboxId,\n loop = true,\n disabled = false,\n optionSelector = '[role=\"option\"]',\n hasItems,\n keepHighlightOnSelect = false,\n closeOnTab = true,\n isItemDisabled\n}: UseComboboxOptions<T>): UseComboboxReturn {\n const listboxRef = useRef<HTMLDivElement | null>(null);\n const pointerDownInListboxRef = useRef(false);\n const tabKeyPressedRef = useRef(false);\n const pointerFocusRef = useRef(false);\n const [isKeyboardFocused, setIsKeyboardFocused] = useState(false);\n \n // Determine if we should show as expanded\n const shouldShowExpanded = hasItems !== undefined ? hasItems : items.length > 0;\n \n // Close dropdown callback\n const closeDropdown = useCallback(() => {\n onOpenChange(false);\n }, [onOpenChange]);\n\n // Ensure pointer state doesn't get stuck when listbox unmounts\n useEffect(() => {\n if (!isOpen) {\n pointerDownInListboxRef.current = false;\n pointerFocusRef.current = false;\n }\n }, [isOpen]);\n \n // Keyboard navigation with aria-activedescendant\n const navigation = useComboboxNavigation<T>({\n items,\n isOpen,\n onSelect,\n onClose: closeDropdown,\n onOpen: () => onOpenChange(true),\n loop,\n disabled,\n listboxRef,\n optionSelector,\n keepHighlightOnSelect,\n closeOnTab,\n isItemDisabled\n });\n \n // Focus out / Escape dismissal\n const dismissHandlers = useDismissOnFocusOut({\n onFocusOut: closeDropdown,\n onEscape: closeDropdown,\n disabled: !isOpen\n });\n\n const containerProps = {\n ...dismissHandlers,\n onPointerMove: () => {\n if (isKeyboardFocused) {\n setIsKeyboardFocused(false);\n }\n },\n onPointerDown: () => {\n pointerFocusRef.current = true;\n setIsKeyboardFocused(false);\n },\n onPointerUp: () => {\n // Don't reset pointerFocusRef here — timing races with programmatic focus\n // (e.g. focus-on-open via double rAF) cause it to clear before onFocusCapture\n // fires, incorrectly setting isKeyboardFocused=true.\n // Instead, pointerFocusRef is reset only when keyboard navigation starts\n // (Tab/Arrow in onKeyDownCapture), ensuring any programmatic focus after a\n // click is always treated as pointer context.\n },\n onFocusCapture: (e: React.FocusEvent<HTMLElement>) => {\n dismissHandlers.onFocusCapture(e);\n\n if (pointerFocusRef.current) {\n setIsKeyboardFocused(false);\n } else {\n setIsKeyboardFocused(true);\n }\n },\n onKeyDownCapture: (e: React.KeyboardEvent<HTMLElement>) => {\n dismissHandlers.onKeyDownCapture(e);\n\n // Keyboard interaction starts — clear pointer context so subsequent\n // focus events are correctly identified as keyboard-initiated.\n if (e.key === 'Tab' || e.key === 'ArrowDown' || e.key === 'ArrowUp') {\n pointerFocusRef.current = false;\n }\n\n // Arrow keys mean keyboard navigation — show focus outline even if\n // the combobox was opened with mouse (activedescendant doesn't move\n // DOM focus, so onFocusCapture alone can't detect the switch).\n if (e.key === 'ArrowDown' || e.key === 'ArrowUp') {\n setIsKeyboardFocused(true);\n }\n },\n onBlurCapture: (e: React.FocusEvent<HTMLElement>) => {\n setIsKeyboardFocused(false);\n\n // Clicking inside a listbox option can blur the input (relatedTarget is null),\n // which would dismiss before the click handler runs. Prevent that.\n if (pointerDownInListboxRef.current) return;\n\n // Tab key pressed - let Tab handler close dropdown, skip blur detection\n if (tabKeyPressedRef.current) {\n tabKeyPressedRef.current = false;\n return;\n }\n\n dismissHandlers.onBlurCapture(e);\n }\n };\n \n // Build input props\n const inputProps = {\n role: 'combobox' as const,\n 'aria-expanded': isOpen && shouldShowExpanded,\n 'aria-haspopup': 'listbox' as const,\n 'aria-controls': isOpen ? listboxId : undefined,\n 'aria-autocomplete': 'list' as const,\n 'aria-activedescendant': \n navigation.highlightedIndex >= 0 \n ? navigation.getOptionId(listboxId, navigation.highlightedIndex) \n : undefined,\n onKeyDown: (e: React.KeyboardEvent) => {\n // Set flag when Tab is pressed (before blur fires)\n if (e.key === 'Tab') {\n tabKeyPressedRef.current = true;\n }\n navigation.handleKeyDown(e);\n }\n };\n \n // Build listbox props\n const listboxProps = {\n id: listboxId,\n role: 'listbox' as const,\n ref: listboxRef,\n onMouseDownCapture: (_e: React.MouseEvent) => {\n pointerDownInListboxRef.current = true;\n },\n onMouseUpCapture: (_e: React.MouseEvent) => {\n pointerDownInListboxRef.current = false;\n },\n onMouseLeave: (_e: React.MouseEvent) => {\n pointerDownInListboxRef.current = false;\n }\n };\n \n // Option props generator\n const getOptionProps = useCallback(\n (index: number, selected: boolean = false) => {\n const disabled = isItemDisabled?.(items[index], index);\n return {\n id: navigation.getOptionId(listboxId, index),\n role: 'option' as const,\n ...(!disabled ? { 'aria-selected': selected } : {}),\n ...(disabled ? { 'aria-disabled': true as const } : {})\n };\n },\n [navigation.getOptionId, listboxId, isItemDisabled, items]\n );\n \n return {\n containerProps,\n inputProps,\n listboxProps,\n getOptionProps,\n highlightedIndex: navigation.highlightedIndex,\n setHighlightedIndex: navigation.setHighlightedIndex,\n getOptionId: navigation.getOptionId,\n isKeyboardFocused\n };\n}\n"],"names":["useRef","useState","useCallback","useEffect","useComboboxNavigation","useDismissOnFocusOut","useCombobox","items","isOpen","onOpenChange","onSelect","listboxId","loop","disabled","optionSelector","hasItems","keepHighlightOnSelect","closeOnTab","isItemDisabled","listboxRef","pointerDownInListboxRef","tabKeyPressedRef","pointerFocusRef","isKeyboardFocused","setIsKeyboardFocused","shouldShowExpanded","undefined","length","closeDropdown","current","navigation","onClose","onOpen","dismissHandlers","onFocusOut","onEscape","containerProps","onPointerMove","onPointerDown","onPointerUp","onFocusCapture","e","onKeyDownCapture","key","onBlurCapture","inputProps","role","highlightedIndex","getOptionId","onKeyDown","handleKeyDown","listboxProps","id","ref","onMouseDownCapture","_e","onMouseUpCapture","onMouseLeave","getOptionProps","index","selected","setHighlightedIndex"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index68.js","sources":["../src/utils/a11y/useAccessiblePress.ts"],"sourcesContent":["import * as React from 'react';\nimport { isVirtualClick } from '../virtualClick';\n\n/**\n * Hook for accessible press interactions (pointer vs keyboard vs virtual click).\n *\n * Handles:\n * - Pointer intent tracking (mouse/touch)\n * - Virtual click detection (NVDA browse mode, etc.)\n * - Routing to appropriate handler (onClick vs onKeyboardActivate)\n * - For non-native elements: Enter/Space → activation\n * - Optional stopPropagation and preventDefault\n *\n * @example\n * // Native button (isNative=true, the default)\n * const { pressProps } = useAccessiblePress({ onClick, disabled });\n * <button {...pressProps}>Click me</button>\n *\n * @example\n * // Non-native element (div acting as button)\n * const { pressProps, role, tabIndex } = useAccessiblePress({ onClick, isNative: false });\n * <div role={role} tabIndex={tabIndex} {...pressProps}>Click me</div>\n *\n * @example\n * // Element nested inside clickable parent (prevent event bubbling)\n * const { pressProps, tabIndex } = useAccessiblePress({ \n * onClick, \n * isNative: false, \n * stopPropagation: true \n * });\n * <div role=\"button\" tabIndex={tabIndex} {...pressProps}>Click me</div>\n */\n\ntype InputKind = 'pointer' | 'keyboard' | 'virtual';\n\nexport type UseAccessiblePressOptions = {\n /**\n * Whether the element is disabled\n */\n disabled?: boolean;\n\n /**\n * Whether the element is in a loading state (will also disable)\n */\n loading?: boolean;\n\n /**\n * Handler for pointer/touch activations (or all activations if onKeyboardActivate is not provided)\n */\n onClick?: (e: React.MouseEvent<HTMLElement>) => void;\n\n /**\n * Handler for keyboard + assistive tech virtual activation.\n * If omitted, onClick is used for all activations.\n */\n onKeyboardActivate?: (e: React.MouseEvent<HTMLElement>) => void;\n\n /**\n * If true, this is a native <button> (or other native pressable) and we MUST NOT add Enter/Space handling.\n * Default: true\n */\n isNative?: boolean;\n\n /**\n * Only for non-native elements (div/span). Defaults to 'button'.\n */\n role?: string;\n\n /**\n * Only for non-native elements. Defaults to 0.\n */\n tabIndex?: number;\n\n /**\n * If true, calls e.stopPropagation() before invoking onClick handler.\n * Useful when element is nested inside another clickable element.\n * Default: false\n */\n stopPropagation?: boolean;\n\n /**\n * If true, calls e.preventDefault() before invoking onClick handler.\n * Note: For non-native elements, preventDefault is already called on Space/Enter keys.\n * Default: false\n */\n preventDefault?: boolean;\n\n /**\n * Toggle/pressed state. When true or false, sets aria-pressed on the element (e.g. selected color swatch).\n * Omit for non-toggle buttons.\n */\n pressed?: boolean;\n\n /**\n * User-provided pointer/mouse/touch handlers. When provided, they are chained\n * after the internal pointer-intent tracking handler (markPointer), so both run.\n */\n onPointerDown?: (e: React.PointerEvent<HTMLElement>) => void;\n onMouseDown?: (e: React.MouseEvent<HTMLElement>) => void;\n onTouchStart?: (e: React.TouchEvent<HTMLElement>) => void;\n};\n\nexport type UseAccessiblePressReturn = {\n /**\n * Props to spread onto the element. Includes event handlers and ARIA attributes.\n * Does NOT include role/tabIndex — apply those separately.\n */\n pressProps: React.HTMLAttributes<HTMLElement> & {\n 'aria-disabled'?: 'true';\n 'aria-busy'?: 'true';\n 'aria-pressed'?: boolean;\n };\n\n /**\n * Combined disabled state (disabled || loading)\n */\n isDisabled: boolean;\n\n /**\n * Role for non-native elements (e.g., 'button', 'menuitem').\n * Only returned when isNative=false.\n */\n role?: string;\n\n /**\n * TabIndex for non-native elements.\n * Returns -1 when disabled, otherwise the provided tabIndex (default 0).\n * Only returned when isNative=false.\n */\n tabIndex?: number;\n};\n\nexport function useAccessiblePress({\n disabled = false,\n loading = false,\n onClick,\n onKeyboardActivate,\n isNative = true,\n role = 'button',\n tabIndex = 0,\n stopPropagation = false,\n preventDefault = false,\n pressed,\n onPointerDown,\n onMouseDown,\n onTouchStart\n}: UseAccessiblePressOptions = {}): UseAccessiblePressReturn {\n const isDisabled = disabled || loading;\n const lastWasPointerRef = React.useRef(false);\n\n const markPointer = React.useCallback(() => {\n lastWasPointerRef.current = true;\n }, []);\n\n const handleClick = React.useCallback(\n (e: React.MouseEvent<HTMLElement>) => {\n if (isDisabled) return;\n\n // Handle event control flags\n if (stopPropagation) e.stopPropagation();\n if (preventDefault) e.preventDefault();\n\n const virtual = isVirtualClick(e.nativeEvent as any);\n const isPointer = lastWasPointerRef.current;\n lastWasPointerRef.current = false;\n\n const input: InputKind = virtual ? 'virtual' : isPointer ? 'pointer' : 'keyboard';\n\n // If we have a keyboard handler, route keyboard + virtual clicks there.\n if ((input === 'keyboard' || input === 'virtual') && onKeyboardActivate) {\n onKeyboardActivate(e);\n return;\n }\n\n onClick?.(e);\n },\n [isDisabled, onClick, onKeyboardActivate, stopPropagation, preventDefault]\n );\n\n // Only used for non-native elements: Enter/Space should trigger click(), reusing the same click routing.\n const handleKeyDown = React.useCallback(\n (e: React.KeyboardEvent<HTMLElement>) => {\n if (isDisabled) return;\n\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n // Trigger native click event so all routing goes through handleClick\n (e.currentTarget as HTMLElement).click();\n }\n },\n [isDisabled]\n );\n\n const pressProps: UseAccessiblePressReturn['pressProps'] = {\n onPointerDown: onPointerDown\n ? (e: React.PointerEvent<HTMLElement>) => { markPointer(); onPointerDown(e); }\n : markPointer,\n onMouseDown: onMouseDown\n ? (e: React.MouseEvent<HTMLElement>) => { markPointer(); onMouseDown(e); }\n : markPointer,\n onTouchStart: onTouchStart\n ? (e: React.TouchEvent<HTMLElement>) => { markPointer(); onTouchStart(e); }\n : markPointer,\n onClick: handleClick,\n 'aria-disabled': isDisabled ? 'true' : undefined,\n 'aria-busy': loading ? 'true' : undefined,\n 'aria-pressed': pressed\n };\n\n // For non-native elements, add Enter/Space handling\n if (!isNative) {\n pressProps.onKeyDown = handleKeyDown;\n }\n\n // Return role/tabIndex separately (only for non-native elements)\n const result: UseAccessiblePressReturn = { pressProps, isDisabled };\n\n if (!isNative) {\n result.role = role;\n result.tabIndex = isDisabled ? -1 : tabIndex;\n }\n\n return result;\n}\n\n"],"names":["React","isVirtualClick","useAccessiblePress","disabled","loading","onClick","onKeyboardActivate","isNative","role","tabIndex","stopPropagation","preventDefault","pressed","onPointerDown","onMouseDown","onTouchStart","isDisabled","lastWasPointerRef","useRef","markPointer","useCallback","current","handleClick","e","virtual","nativeEvent","isPointer","input","handleKeyDown","key","currentTarget","click","pressProps","undefined","onKeyDown","result"],"mappings":"AAoIO,YAAAA,OAAA;AAAA,SAAA,kBAAAC,SAAA;AAAA,SAASC,EAAmB;AAAA,EACjCC,UAAAA,IAAW;AAAA,EACXC,SAAAA,IAAU;AAAA,EACVC,SAAAA;AAAAA,EACAC,oBAAAA;AAAAA,EACAC,UAAAA,IAAW;AAAA,EACXC,MAAAA,IAAO;AAAA,EACPC,UAAAA,IAAW;AAAA,EACXC,iBAAAA,IAAkB;AAAA,EAClBC,gBAAAA,IAAiB;AAAA,EACjBC,SAAAA;AAAAA,EACAC,eAAAA;AAAAA,EACAC,aAAAA;AAAAA,EACAC,cAAAA;AACyB,IAAI,IAA8B;AAC3D,QAAMC,IAAab,KAAYC,GACzBa,IAAoBjB,EAAMkB,OAAO,EAAK,GAEtCC,IAAcnB,EAAMoB,YAAY,MAAM;AAC1CH,IAAAA,EAAkBI,UAAU;AAAA,EAC9B,GAAG,CAAA,CAAE,GAECC,IAActB,EAAMoB,YACxB,CAACG,MAAqC;AACpC,QAAIP,EAAY;AAGhB,IAAIN,OAAmBA,gBAAAA,GACnBC,OAAkBA,eAAAA;AAEtB,UAAMa,IAAUvB,EAAesB,EAAEE,WAAkB,GAC7CC,IAAYT,EAAkBI;AACpCJ,IAAAA,EAAkBI,UAAU;AAE5B,UAAMM,IAAmBH,IAAU,YAAYE,IAAY,YAAY;AAGvE,SAAKC,MAAU,cAAcA,MAAU,cAAcrB,GAAoB;AACvEA,MAAAA,EAAmBiB,CAAC;AACpB;AAAA,IACF;AAEAlB,IAAAA,IAAUkB,CAAC;AAAA,EACb,GACA,CAACP,GAAYX,GAASC,GAAoBI,GAAiBC,CAAc,CAC3E,GAGMiB,IAAgB5B,EAAMoB,YAC1B,CAACG,MAAwC;AACvC,IAAIP,MAEAO,EAAEM,QAAQ,WAAWN,EAAEM,QAAQ,SACjCN,EAAEZ,eAAAA,GAEDY,EAAEO,cAA8BC,MAAAA;AAAAA,EAErC,GACA,CAACf,CAAU,CACb,GAEMgB,IAAqD;AAAA,IACzDnB,eAAeA,IACX,CAACU,MAAuC;AAAEJ,MAAAA,EAAAA,GAAeN,EAAcU,CAAC;AAAA,IAAG,IAC3EJ;AAAAA,IACJL,aAAaA,IACT,CAACS,MAAqC;AAAEJ,MAAAA,EAAAA,GAAeL,EAAYS,CAAC;AAAA,IAAG,IACvEJ;AAAAA,IACJJ,cAAcA,IACV,CAACQ,MAAqC;AAAEJ,MAAAA,EAAAA,GAAeJ,EAAaQ,CAAC;AAAA,IAAG,IACxEJ;AAAAA,IACJd,SAASiB;AAAAA,IACT,iBAAiBN,IAAa,SAASiB;AAAAA,IACvC,aAAa7B,IAAU,SAAS6B;AAAAA,IAChC,gBAAgBrB;AAAAA,EAAAA;AAIlB,EAAKL,MACHyB,EAAWE,YAAYN;AAIzB,QAAMO,IAAmC;AAAA,IAAEH,YAAAA;AAAAA,IAAYhB,YAAAA;AAAAA,EAAAA;AAEvD,SAAKT,MACH4B,EAAO3B,OAAOA,GACd2B,EAAO1B,WAAWO,IAAa,KAAKP,IAG/B0B;AACT;"}
|
package/dist/index69.js
CHANGED
|
@@ -1,22 +1,116 @@
|
|
|
1
|
-
import { useRef as
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
1
|
+
import { useRef as l, useState as M, useCallback as y, useEffect as U } from "react";
|
|
2
|
+
import { useComboboxNavigation as E } from "./index80.js";
|
|
3
|
+
import { useDismissOnFocusOut as H } from "./index81.js";
|
|
4
|
+
function L({
|
|
5
|
+
items: a,
|
|
6
|
+
isOpen: r,
|
|
7
|
+
onOpenChange: c,
|
|
8
|
+
onSelect: x,
|
|
9
|
+
listboxId: n,
|
|
10
|
+
loop: C = !0,
|
|
11
|
+
disabled: D = !1,
|
|
12
|
+
optionSelector: v = '[role="option"]',
|
|
13
|
+
hasItems: g,
|
|
14
|
+
keepHighlightOnSelect: P = !1,
|
|
15
|
+
closeOnTab: k = !0,
|
|
16
|
+
isItemDisabled: f
|
|
17
|
+
}) {
|
|
18
|
+
const h = l(null), s = l(!1), d = l(!1), u = l(!1), [w, t] = M(!1), F = g !== void 0 ? g : a.length > 0, p = y(() => {
|
|
19
|
+
c(!1);
|
|
20
|
+
}, [c]);
|
|
21
|
+
U(() => {
|
|
22
|
+
r || (s.current = !1, u.current = !1);
|
|
23
|
+
}, [r]);
|
|
24
|
+
const o = E({
|
|
25
|
+
items: a,
|
|
26
|
+
isOpen: r,
|
|
27
|
+
onSelect: x,
|
|
28
|
+
onClose: p,
|
|
29
|
+
onOpen: () => c(!0),
|
|
30
|
+
loop: C,
|
|
31
|
+
disabled: D,
|
|
32
|
+
listboxRef: h,
|
|
33
|
+
optionSelector: v,
|
|
34
|
+
keepHighlightOnSelect: P,
|
|
35
|
+
closeOnTab: k,
|
|
36
|
+
isItemDisabled: f
|
|
37
|
+
}), i = H({
|
|
38
|
+
onFocusOut: p,
|
|
39
|
+
onEscape: p,
|
|
40
|
+
disabled: !r
|
|
41
|
+
}), K = {
|
|
42
|
+
...i,
|
|
43
|
+
onPointerMove: () => {
|
|
44
|
+
w && t(!1);
|
|
45
|
+
},
|
|
46
|
+
onPointerDown: () => {
|
|
47
|
+
u.current = !0, t(!1);
|
|
48
|
+
},
|
|
49
|
+
onPointerUp: () => {
|
|
50
|
+
},
|
|
51
|
+
onFocusCapture: (e) => {
|
|
52
|
+
i.onFocusCapture(e), u.current ? t(!1) : t(!0);
|
|
53
|
+
},
|
|
54
|
+
onKeyDownCapture: (e) => {
|
|
55
|
+
i.onKeyDownCapture(e), (e.key === "Tab" || e.key === "ArrowDown" || e.key === "ArrowUp") && (u.current = !1), (e.key === "ArrowDown" || e.key === "ArrowUp") && t(!0);
|
|
56
|
+
},
|
|
57
|
+
onBlurCapture: (e) => {
|
|
58
|
+
if (t(!1), !s.current) {
|
|
59
|
+
if (d.current) {
|
|
60
|
+
d.current = !1;
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
i.onBlurCapture(e);
|
|
64
|
+
}
|
|
11
65
|
}
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
66
|
+
}, m = {
|
|
67
|
+
role: "combobox",
|
|
68
|
+
"aria-expanded": r && F,
|
|
69
|
+
"aria-haspopup": "listbox",
|
|
70
|
+
"aria-controls": r ? n : void 0,
|
|
71
|
+
"aria-autocomplete": "list",
|
|
72
|
+
"aria-activedescendant": o.highlightedIndex >= 0 ? o.getOptionId(n, o.highlightedIndex) : void 0,
|
|
73
|
+
onKeyDown: (e) => {
|
|
74
|
+
e.key === "Tab" && (d.current = !0), o.handleKeyDown(e);
|
|
75
|
+
}
|
|
76
|
+
}, I = {
|
|
77
|
+
id: n,
|
|
78
|
+
role: "listbox",
|
|
79
|
+
ref: h,
|
|
80
|
+
onMouseDownCapture: (e) => {
|
|
81
|
+
s.current = !0;
|
|
82
|
+
},
|
|
83
|
+
onMouseUpCapture: (e) => {
|
|
84
|
+
s.current = !1;
|
|
85
|
+
},
|
|
86
|
+
onMouseLeave: (e) => {
|
|
87
|
+
s.current = !1;
|
|
88
|
+
}
|
|
89
|
+
}, R = y((e, A = !1) => {
|
|
90
|
+
const b = f?.(a[e], e);
|
|
91
|
+
return {
|
|
92
|
+
id: o.getOptionId(n, e),
|
|
93
|
+
role: "option",
|
|
94
|
+
...b ? {} : {
|
|
95
|
+
"aria-selected": A
|
|
96
|
+
},
|
|
97
|
+
...b ? {
|
|
98
|
+
"aria-disabled": !0
|
|
99
|
+
} : {}
|
|
100
|
+
};
|
|
101
|
+
}, [o.getOptionId, n, f, a]);
|
|
102
|
+
return {
|
|
103
|
+
containerProps: K,
|
|
104
|
+
inputProps: m,
|
|
105
|
+
listboxProps: I,
|
|
106
|
+
getOptionProps: R,
|
|
107
|
+
highlightedIndex: o.highlightedIndex,
|
|
108
|
+
setHighlightedIndex: o.setHighlightedIndex,
|
|
109
|
+
getOptionId: o.getOptionId,
|
|
110
|
+
isKeyboardFocused: w
|
|
111
|
+
};
|
|
18
112
|
}
|
|
19
113
|
export {
|
|
20
|
-
|
|
114
|
+
L as useCombobox
|
|
21
115
|
};
|
|
22
116
|
//# sourceMappingURL=index69.js.map
|
package/dist/index69.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index69.js","sources":["../src/utils/a11y/useFocusManagement.ts"],"sourcesContent":["import { useEffect, useRef } from 'react';\nimport type { DependencyList } from 'react';\n\nexport interface UseFocusManagementOptions {\n /**\n * CSS selector to query the primary focus target.\n * Default: 'h1'\n */\n targetSelector?: string;\n /**\n * Fallback element id if selector target is not found.\n * Default: 'main-content'\n */\n fallbackId?: string;\n}\n\n/**\n * Generic focus management hook for route/state driven UI transitions.\n * Useful for both route changes and in-page multi-step wizards.\n * \n * Always skips first render and uses animation frame for safe DOM timing.\n */\nexport function useFocusManagement(\n dependencies: DependencyList,\n {\n targetSelector = '#main-content h1',\n fallbackId = 'main-content'\n }: UseFocusManagementOptions = {}\n): void {\n const isFirstRender = useRef(true);\n\n useEffect(() => {\n // Always skip first render\n if (isFirstRender.current) {\n isFirstRender.current = false;\n return;\n }\n\n const focusTarget = () => {\n const el = (document.querySelector(targetSelector) || document.getElementById(fallbackId)) as HTMLElement;\n if (el) {\n if (!el.hasAttribute('tabindex')) el.setAttribute('tabindex', '-1');\n el.focus();\n }\n };\n\n // Always use animation frame for safe DOM timing\n const rafId = requestAnimationFrame(focusTarget);\n return () => cancelAnimationFrame(rafId);\n }, dependencies);\n}\n"],"names":["useFocusManagement","dependencies","targetSelector","fallbackId","isFirstRender","useRef","useEffect","current","rafId","requestAnimationFrame","focusTarget","el","document","querySelector","getElementById","hasAttribute","setAttribute","focus","cancelAnimationFrame"],"mappings":";AAsBO,SAASA,EACdC,GACA;AAAA,EACEC,gBAAAA,IAAiB;AAAA,EACjBC,YAAAA,IAAa;AACY,IAAI,IACzB;AACN,QAAMC,IAAgBC,EAAO,EAAI;AAEjCC,EAAAA,EAAU,MAAM;AAEd,QAAIF,EAAcG,SAAS;AACzBH,MAAAA,EAAcG,UAAU;AACxB;AAAA,IACF;AAWA,UAAMC,IAAQC,sBATMC,MAAM;AACxB,YAAMC,IAAMC,SAASC,cAAcX,CAAc,KAAKU,SAASE,eAAeX,CAAU;AACxF,MAAIQ,MACGA,EAAGI,aAAa,UAAU,KAAGJ,EAAGK,aAAa,YAAY,IAAI,GAClEL,EAAGM,MAAAA;AAAAA,IAEP,CAG+C;AAC/C,WAAO,MAAMC,qBAAqBV,CAAK;AAAA,EACzC,GAAGP,CAAY;AACjB;"}
|
|
1
|
+
{"version":3,"file":"index69.js","sources":["../src/utils/a11y/useCombobox.ts"],"sourcesContent":["import { useRef, useCallback, useEffect, useState } from 'react';\nimport type { RefObject } from 'react';\nimport { useComboboxNavigation } from './useComboboxNavigation';\nimport { useDismissOnFocusOut } from './useDismissOnFocusOut';\nimport type { UseDismissOnFocusOutReturn } from './useDismissOnFocusOut';\n\nexport interface UseComboboxOptions<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 to change the open state\n */\n onOpenChange: (open: boolean) => void;\n \n /**\n * Callback when an item is selected (Enter key)\n */\n onSelect: (item: T, index: number) => void;\n \n /**\n * Stable ID for the listbox element\n */\n listboxId: string;\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 * CSS selector for option elements (default: '[role=\"option\"]')\n */\n optionSelector?: string;\n \n /**\n * Whether the listbox has any items to show\n * Used for aria-expanded logic\n * Default: items.length > 0\n */\n hasItems?: boolean;\n\n /**\n * Whether to keep the highlighted index after selecting an item.\n * Useful for multi-select where the dropdown stays open after selection.\n * Default: false\n */\n keepHighlightOnSelect?: boolean;\n\n /**\n * Whether Tab should close the dropdown.\n * Set to false when Tab should move focus to elements within the popup (e.g. CTAs).\n * Default: true\n */\n closeOnTab?: boolean;\n\n /**\n * Predicate to mark items as disabled. Disabled items are reachable via arrow keys\n * (so screen readers can announce them) but Enter/Space selection is blocked.\n */\n isItemDisabled?: (item: T, index: number) => boolean;\n}\n\nexport interface UseComboboxReturn {\n /**\n * Props to spread on the container element (handles dismiss on focus out + keyboard focus tracking)\n */\n containerProps: UseDismissOnFocusOutReturn<HTMLElement> & {\n onPointerMove: () => void;\n onPointerDown: () => void;\n onPointerUp: () => void;\n };\n \n /**\n * Props to spread on the combobox input element\n */\n inputProps: {\n role: 'combobox';\n 'aria-expanded': boolean;\n 'aria-haspopup': 'listbox';\n 'aria-controls': string | undefined;\n 'aria-autocomplete': 'list';\n 'aria-activedescendant': string | undefined;\n onKeyDown: (e: React.KeyboardEvent) => void;\n };\n \n /**\n * Props to spread on the listbox element\n */\n listboxProps: {\n id: string;\n role: 'listbox';\n ref: RefObject<HTMLDivElement | null>;\n onMouseDownCapture: (e: React.MouseEvent) => void;\n onMouseUpCapture: (e: React.MouseEvent) => void;\n onMouseLeave: (e: React.MouseEvent) => void;\n };\n \n /**\n * Generate props for an option element at the given index\n * @param selected - Whether this option is the currently selected/chosen value (not keyboard highlight)\n */\n getOptionProps: (index: number, selected?: boolean) => {\n id: string;\n role: 'option';\n 'aria-selected'?: boolean;\n 'aria-disabled'?: true;\n };\n \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 * Generate stable ID for an option\n */\n getOptionId: (listboxId: string, index: number) => string;\n\n /**\n * Whether the combobox input was focused via keyboard (Tab) rather than pointer.\n * Use to conditionally show focus ring only on keyboard interaction.\n */\n isKeyboardFocused: boolean;\n}\n\n/**\n * Comprehensive hook for implementing WAI-ARIA combobox pattern.\n * \n * Combines:\n * - Keyboard navigation (Arrow Up/Down, Enter, Escape, Tab)\n * - Focus management and dismissal\n * - ARIA attributes for accessibility\n * - Auto-scroll highlighted item into view\n * \n * This hook provides a complete, batteries-included solution for building\n * accessible combobox components (autocomplete, select, search with suggestions, etc.)\n * \n * @example Basic usage\n * ```tsx\n * const MyCombobox = () => {\n * const [isOpen, setIsOpen] = useState(false);\n * const [items, setItems] = useState(['Apple', 'Banana', 'Cherry']);\n * \n * const {\n * containerProps,\n * inputProps,\n * listboxProps,\n * getOptionProps,\n * highlightedIndex\n * } = useCombobox({\n * items,\n * isOpen,\n * onOpenChange: setIsOpen,\n * onSelect: (item) => console.log('Selected:', item),\n * listboxId: 'my-listbox'\n * });\n * \n * return (\n * <div {...containerProps}>\n * <input {...inputProps} />\n * {isOpen && (\n * <div {...listboxProps}>\n * {items.map((item, i) => (\n * <div key={i} {...getOptionProps(i)}>\n * {item}\n * </div>\n * ))}\n * </div>\n * )}\n * </div>\n * );\n * };\n * ```\n * \n * @example With custom ARIA labels and handlers\n * ```tsx\n * const MySearchBox = () => {\n * const [query, setQuery] = useState('');\n * const [suggestions, setSuggestions] = useState([]);\n * const [isOpen, setIsOpen] = useState(false);\n * \n * const { containerProps, inputProps, listboxProps, getOptionProps } = useCombobox({\n * items: suggestions,\n * isOpen,\n * onOpenChange: setIsOpen,\n * onSelect: (suggestion) => {\n * setQuery(suggestion);\n * setIsOpen(false);\n * },\n * listboxId: 'search-suggestions'\n * });\n * \n * return (\n * <div {...containerProps}>\n * <input\n * {...inputProps}\n * value={query}\n * onChange={(e) => setQuery(e.target.value)}\n * aria-label=\"Search\"\n * />\n * {isOpen && suggestions.length > 0 && (\n * <div {...listboxProps} aria-label=\"Search suggestions\">\n * {suggestions.map((suggestion, i) => (\n * <div\n * key={i}\n * {...getOptionProps(i)}\n * onClick={() => {\n * setQuery(suggestion);\n * setIsOpen(false);\n * }}\n * >\n * {suggestion}\n * </div>\n * ))}\n * </div>\n * )}\n * </div>\n * );\n * };\n * ```\n */\nexport function useCombobox<T = any>({\n items,\n isOpen,\n onOpenChange,\n onSelect,\n listboxId,\n loop = true,\n disabled = false,\n optionSelector = '[role=\"option\"]',\n hasItems,\n keepHighlightOnSelect = false,\n closeOnTab = true,\n isItemDisabled\n}: UseComboboxOptions<T>): UseComboboxReturn {\n const listboxRef = useRef<HTMLDivElement | null>(null);\n const pointerDownInListboxRef = useRef(false);\n const tabKeyPressedRef = useRef(false);\n const pointerFocusRef = useRef(false);\n const [isKeyboardFocused, setIsKeyboardFocused] = useState(false);\n \n // Determine if we should show as expanded\n const shouldShowExpanded = hasItems !== undefined ? hasItems : items.length > 0;\n \n // Close dropdown callback\n const closeDropdown = useCallback(() => {\n onOpenChange(false);\n }, [onOpenChange]);\n\n // Ensure pointer state doesn't get stuck when listbox unmounts\n useEffect(() => {\n if (!isOpen) {\n pointerDownInListboxRef.current = false;\n pointerFocusRef.current = false;\n }\n }, [isOpen]);\n \n // Keyboard navigation with aria-activedescendant\n const navigation = useComboboxNavigation<T>({\n items,\n isOpen,\n onSelect,\n onClose: closeDropdown,\n onOpen: () => onOpenChange(true),\n loop,\n disabled,\n listboxRef,\n optionSelector,\n keepHighlightOnSelect,\n closeOnTab,\n isItemDisabled\n });\n \n // Focus out / Escape dismissal\n const dismissHandlers = useDismissOnFocusOut({\n onFocusOut: closeDropdown,\n onEscape: closeDropdown,\n disabled: !isOpen\n });\n\n const containerProps = {\n ...dismissHandlers,\n onPointerMove: () => {\n if (isKeyboardFocused) {\n setIsKeyboardFocused(false);\n }\n },\n onPointerDown: () => {\n pointerFocusRef.current = true;\n setIsKeyboardFocused(false);\n },\n onPointerUp: () => {\n // Don't reset pointerFocusRef here — timing races with programmatic focus\n // (e.g. focus-on-open via double rAF) cause it to clear before onFocusCapture\n // fires, incorrectly setting isKeyboardFocused=true.\n // Instead, pointerFocusRef is reset only when keyboard navigation starts\n // (Tab/Arrow in onKeyDownCapture), ensuring any programmatic focus after a\n // click is always treated as pointer context.\n },\n onFocusCapture: (e: React.FocusEvent<HTMLElement>) => {\n dismissHandlers.onFocusCapture(e);\n\n if (pointerFocusRef.current) {\n setIsKeyboardFocused(false);\n } else {\n setIsKeyboardFocused(true);\n }\n },\n onKeyDownCapture: (e: React.KeyboardEvent<HTMLElement>) => {\n dismissHandlers.onKeyDownCapture(e);\n\n // Keyboard interaction starts — clear pointer context so subsequent\n // focus events are correctly identified as keyboard-initiated.\n if (e.key === 'Tab' || e.key === 'ArrowDown' || e.key === 'ArrowUp') {\n pointerFocusRef.current = false;\n }\n\n // Arrow keys mean keyboard navigation — show focus outline even if\n // the combobox was opened with mouse (activedescendant doesn't move\n // DOM focus, so onFocusCapture alone can't detect the switch).\n if (e.key === 'ArrowDown' || e.key === 'ArrowUp') {\n setIsKeyboardFocused(true);\n }\n },\n onBlurCapture: (e: React.FocusEvent<HTMLElement>) => {\n setIsKeyboardFocused(false);\n\n // Clicking inside a listbox option can blur the input (relatedTarget is null),\n // which would dismiss before the click handler runs. Prevent that.\n if (pointerDownInListboxRef.current) return;\n\n // Tab key pressed - let Tab handler close dropdown, skip blur detection\n if (tabKeyPressedRef.current) {\n tabKeyPressedRef.current = false;\n return;\n }\n\n dismissHandlers.onBlurCapture(e);\n }\n };\n \n // Build input props\n const inputProps = {\n role: 'combobox' as const,\n 'aria-expanded': isOpen && shouldShowExpanded,\n 'aria-haspopup': 'listbox' as const,\n 'aria-controls': isOpen ? listboxId : undefined,\n 'aria-autocomplete': 'list' as const,\n 'aria-activedescendant': \n navigation.highlightedIndex >= 0 \n ? navigation.getOptionId(listboxId, navigation.highlightedIndex) \n : undefined,\n onKeyDown: (e: React.KeyboardEvent) => {\n // Set flag when Tab is pressed (before blur fires)\n if (e.key === 'Tab') {\n tabKeyPressedRef.current = true;\n }\n navigation.handleKeyDown(e);\n }\n };\n \n // Build listbox props\n const listboxProps = {\n id: listboxId,\n role: 'listbox' as const,\n ref: listboxRef,\n onMouseDownCapture: (_e: React.MouseEvent) => {\n pointerDownInListboxRef.current = true;\n },\n onMouseUpCapture: (_e: React.MouseEvent) => {\n pointerDownInListboxRef.current = false;\n },\n onMouseLeave: (_e: React.MouseEvent) => {\n pointerDownInListboxRef.current = false;\n }\n };\n \n // Option props generator\n const getOptionProps = useCallback(\n (index: number, selected: boolean = false) => {\n const disabled = isItemDisabled?.(items[index], index);\n return {\n id: navigation.getOptionId(listboxId, index),\n role: 'option' as const,\n ...(!disabled ? { 'aria-selected': selected } : {}),\n ...(disabled ? { 'aria-disabled': true as const } : {})\n };\n },\n [navigation.getOptionId, listboxId, isItemDisabled, items]\n );\n \n return {\n containerProps,\n inputProps,\n listboxProps,\n getOptionProps,\n highlightedIndex: navigation.highlightedIndex,\n setHighlightedIndex: navigation.setHighlightedIndex,\n getOptionId: navigation.getOptionId,\n isKeyboardFocused\n };\n}\n"],"names":["useRef","useState","useCallback","useEffect","useComboboxNavigation","useDismissOnFocusOut","useCombobox","items","isOpen","onOpenChange","onSelect","listboxId","loop","disabled","optionSelector","hasItems","keepHighlightOnSelect","closeOnTab","isItemDisabled","listboxRef","pointerDownInListboxRef","tabKeyPressedRef","pointerFocusRef","isKeyboardFocused","setIsKeyboardFocused","shouldShowExpanded","undefined","length","closeDropdown","current","navigation","onClose","onOpen","dismissHandlers","onFocusOut","onEscape","containerProps","onPointerMove","onPointerDown","onPointerUp","onFocusCapture","e","onKeyDownCapture","key","onBlurCapture","inputProps","role","highlightedIndex","getOptionId","onKeyDown","handleKeyDown","listboxProps","id","ref","onMouseDownCapture","_e","onMouseUpCapture","onMouseLeave","getOptionProps","index","selected","setHighlightedIndex"],"mappings":"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"}
|
package/dist/index7.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import c, { useState as h, useCallback as i } from "react";
|
|
2
|
-
import "./
|
|
3
|
-
import { isElementVisible as p } from "./
|
|
2
|
+
import "./index73.js";
|
|
3
|
+
import { isElementVisible as p } from "./index206.js";
|
|
4
4
|
const x = ({
|
|
5
5
|
skipLinks: n,
|
|
6
6
|
className: r = ""
|
package/dist/index70.js
CHANGED
|
@@ -1,69 +1,22 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
role: h
|
|
12
|
-
}) {
|
|
13
|
-
const [c, b] = n.useState(u || r[0] || ""), g = n.useRef({});
|
|
14
|
-
n.useEffect(() => {
|
|
15
|
-
if (r.length > 0 && !r.includes(c)) {
|
|
16
|
-
const t = u || r[0] || "";
|
|
17
|
-
b(t);
|
|
1
|
+
import { useRef as u, useEffect as i } from "react";
|
|
2
|
+
function f(n, {
|
|
3
|
+
targetSelector: r = "#main-content h1",
|
|
4
|
+
fallbackId: c = "main-content"
|
|
5
|
+
} = {}) {
|
|
6
|
+
const t = u(!0);
|
|
7
|
+
i(() => {
|
|
8
|
+
if (t.current) {
|
|
9
|
+
t.current = !1;
|
|
10
|
+
return;
|
|
18
11
|
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
}, [f]), p = n.useCallback((t, e = 1) => {
|
|
26
|
-
if (r.length === 0) return;
|
|
27
|
-
const o = r.indexOf(c), l = Math.max(0, o);
|
|
28
|
-
let s = l;
|
|
29
|
-
switch (t) {
|
|
30
|
-
case "first":
|
|
31
|
-
s = 0;
|
|
32
|
-
break;
|
|
33
|
-
case "last":
|
|
34
|
-
s = r.length - 1;
|
|
35
|
-
break;
|
|
36
|
-
case "prev":
|
|
37
|
-
k ? s = (l - e + r.length) % r.length : s = Math.max(0, l - e);
|
|
38
|
-
break;
|
|
39
|
-
case "next":
|
|
40
|
-
k ? s = (l + e) % r.length : s = Math.min(r.length - 1, l + e);
|
|
41
|
-
break;
|
|
42
|
-
}
|
|
43
|
-
const w = r[s];
|
|
44
|
-
w && g.current[w]?.focus();
|
|
45
|
-
}, [r, c, k]), A = n.useCallback((t) => ({
|
|
46
|
-
ref: (e) => {
|
|
47
|
-
g.current[t] = e;
|
|
48
|
-
},
|
|
49
|
-
tabIndex: c === t ? v : -1,
|
|
50
|
-
onFocus: () => x(t)
|
|
51
|
-
}), [c, v, x]), R = n.useCallback((t) => {
|
|
52
|
-
let e = null, o = 1;
|
|
53
|
-
t.key === "Home" ? e = "first" : t.key === "End" ? e = "last" : (a !== "vertical" && (t.key === "ArrowLeft" ? e = "prev" : t.key === "ArrowRight" && (e = "next")), !e && a !== "horizontal" && (t.key === "ArrowUp" ? e = "prev" : t.key === "ArrowDown" && (e = "next"), e && i && (o = i))), e && (t.preventDefault(), t.stopPropagation(), p(e, o));
|
|
54
|
-
}, [a, i, p]), z = n.useCallback((t) => {
|
|
55
|
-
const e = {};
|
|
56
|
-
return h && (e.role = h), a === "horizontal" ? e["aria-orientation"] = "horizontal" : a === "vertical" && (e["aria-orientation"] = "vertical"), t && Object.assign(e, C(t)), e;
|
|
57
|
-
}, [h, a]);
|
|
58
|
-
return {
|
|
59
|
-
setFocusedId: x,
|
|
60
|
-
focusItem: y,
|
|
61
|
-
handleKeyDown: R,
|
|
62
|
-
getRovingItemProps: A,
|
|
63
|
-
getContainerProps: z
|
|
64
|
-
};
|
|
12
|
+
const o = requestAnimationFrame(() => {
|
|
13
|
+
const e = document.querySelector(r) || document.getElementById(c);
|
|
14
|
+
e && (e.hasAttribute("tabindex") || e.setAttribute("tabindex", "-1"), e.focus());
|
|
15
|
+
});
|
|
16
|
+
return () => cancelAnimationFrame(o);
|
|
17
|
+
}, n);
|
|
65
18
|
}
|
|
66
19
|
export {
|
|
67
|
-
|
|
20
|
+
f as useFocusManagement
|
|
68
21
|
};
|
|
69
22
|
//# sourceMappingURL=index70.js.map
|
package/dist/index70.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index70.js","sources":["../src/utils/a11y/useRovingFocus.ts"],"sourcesContent":["import * as React from 'react';\n\nimport { getA11yNameAttributes, AccessibleNameInput } from './accessibleName';\nexport type { AccessibleNameInput };\n\nexport type RovingDirection = 'prev' | 'next' | 'first' | 'last';\n\nexport interface UseRovingFocusOptions {\n /**\n * Array of item IDs in order\n */\n itemIds: string[];\n\n /**\n * The tabIndex to apply to the currently focused item in the roving group.\n * Defaults to 0 \n */\n tabIndex?: number;\n\n /**\n * Initial focused item ID. Defaults to first item.\n */\n defaultFocusedId?: string;\n\n /**\n * Orientation for arrow key mapping.\n * - horizontal: ArrowLeft/ArrowRight\n * - vertical: ArrowUp/ArrowDown\n * - grid: all four arrow keys (Left/Right move by 1, Up/Down move by `cols`)\n */\n orientation?: 'horizontal' | 'vertical' | 'grid';\n\n /**\n * Number of columns in the grid. Required when orientation is 'grid'.\n * ArrowUp/ArrowDown navigate by this many items in the flat itemIds array.\n */\n cols?: number;\n\n /**\n * Whether navigation wraps around at ends. Defaults to true.\n */\n loop?: boolean;\n\n /**\n * Callback when focus changes\n */\n onFocusChange?: (id: string) => void;\n\n /**\n * ARIA role for the container element (e.g. 'grid', 'menu', 'tablist', 'toolbar').\n * Returned via getContainerProps().\n */\n role?: React.AriaRole;\n}\n\nexport interface RovingItemProps {\n ref: (el: HTMLElement | null) => void;\n tabIndex: number;\n onFocus: () => void;\n}\n\nexport interface RovingContainerProps {\n role?: React.AriaRole;\n 'aria-orientation'?: 'horizontal' | 'vertical';\n 'aria-label'?: string;\n 'aria-labelledby'?: string;\n 'aria-describedby'?: string;\n}\n\nexport interface UseRovingFocusReturn {\n /**\n * Set focused item ID manually\n */\n setFocusedId: (id: string) => void;\n\n /**\n * Imperatively focus a DOM element by id.\n * If the element exists in refs, focus it immediately.\n * If not yet in DOM, update state so it gets focus once rendered.\n */\n focusItem: (id: string) => void;\n\n /**\n * Keyboard handler for arrow/Home/End navigation.\n * Attach to each item's onKeyDown.\n */\n handleKeyDown: (e: React.KeyboardEvent) => void;\n\n /**\n * Get props for an item in the roving focus group (ref + tabIndex)\n */\n getRovingItemProps: (id: string) => RovingItemProps;\n\n /**\n * Props to spread on the container element.\n * Returns role (if provided), aria-orientation (derived from orientation; omitted for grid),\n * and any accessible name/description attributes passed in.\n */\n getContainerProps: (nameInput?: AccessibleNameInput) => RovingContainerProps;\n}\n\n/**\n * Hook for managing roving focus pattern (roving tabindex).\n * Reusable for composite widgets: tabs, toolbars, menus, listboxes, radio groups, grids.\n *\n * @example\n * // 1D (toolbar/tabs):\n * const { getRovingItemProps, handleKeyDown } = useRovingFocus({\n * itemIds: ['tab1', 'tab2', 'tab3'],\n * orientation: 'horizontal'\n * });\n *\n * // 2D (grid — flat itemIds, cols for row-jump math):\n * const { getRovingItemProps, handleKeyDown } = useRovingFocus({\n * itemIds: ['r0c0', 'r0c1', 'r0c2', 'r1c0', 'r1c1', 'r1c2'],\n * orientation: 'grid',\n * cols: 3\n * });\n *\n * // In render:\n * <button {...getRovingItemProps('tab1')} onKeyDown={handleKeyDown}>Tab 1</button>\n */\nexport function useRovingFocus({\n itemIds,\n tabIndex = 0,\n defaultFocusedId,\n orientation = 'horizontal',\n cols,\n loop = true,\n onFocusChange,\n role\n}: UseRovingFocusOptions): UseRovingFocusReturn {\n const [focusedId, setFocusedIdState] = React.useState<string>(\n defaultFocusedId || itemIds[0] || ''\n );\n\n const itemRefs = React.useRef<Record<string, HTMLElement | null>>({});\n\n // Sync focusedId if itemIds change and current focusedId is no longer valid\n React.useEffect(() => {\n if (itemIds.length > 0 && !itemIds.includes(focusedId)) {\n const newFocusedId = defaultFocusedId || itemIds[0] || '';\n setFocusedIdState(newFocusedId);\n }\n }, [itemIds, focusedId, defaultFocusedId]);\n\n const setFocusedId = React.useCallback(\n (id: string) => {\n setFocusedIdState((prev) => {\n if (prev === id) return prev;\n onFocusChange?.(id);\n return id;\n });\n },\n [onFocusChange]\n );\n\n const focusItem = React.useCallback(\n (id: string) => {\n const el = itemRefs.current[id];\n if (el) {\n el.focus();\n } else {\n // element not yet in DOM (e.g. month just changed) — update state so it gets focus once rendered\n setFocusedIdState(id);\n onFocusChange?.(id);\n }\n },\n [onFocusChange]\n );\n\n const moveFocus = React.useCallback(\n (direction: RovingDirection, step: number = 1) => {\n if (itemIds.length === 0) return;\n\n const currentIdx = itemIds.indexOf(focusedId);\n const safeIdx = Math.max(0, currentIdx);\n let nextIdx = safeIdx;\n\n switch (direction) {\n case 'first':\n nextIdx = 0;\n break;\n case 'last':\n nextIdx = itemIds.length - 1;\n break;\n case 'prev':\n if (loop) {\n nextIdx = (safeIdx - step + itemIds.length) % itemIds.length;\n } else {\n nextIdx = Math.max(0, safeIdx - step);\n }\n break;\n case 'next':\n if (loop) {\n nextIdx = (safeIdx + step) % itemIds.length;\n } else {\n nextIdx = Math.min(itemIds.length - 1, safeIdx + step);\n }\n break;\n }\n\n const nextId = itemIds[nextIdx];\n if (!nextId) return;\n\n itemRefs.current[nextId]?.focus();\n },\n [itemIds, focusedId, loop]\n );\n\n const getRovingItemProps = React.useCallback(\n (id: string): RovingItemProps => ({\n ref: (el: HTMLElement | null) => {\n itemRefs.current[id] = el;\n },\n tabIndex: focusedId === id ? tabIndex : -1,\n onFocus: () => setFocusedId(id)\n }),\n [focusedId, tabIndex, setFocusedId]\n );\n\n // Keyboard handler for arrow/Home/End navigation\n const handleKeyDown = React.useCallback(\n (e: React.KeyboardEvent) => {\n let direction: RovingDirection | null = null;\n let step = 1;\n\n if (e.key === 'Home') {\n direction = 'first';\n } else if (e.key === 'End') {\n direction = 'last';\n } else {\n // Horizontal axis (Left/Right) — active for 'horizontal' and 'grid'\n if (orientation !== 'vertical') {\n if (e.key === 'ArrowLeft') direction = 'prev';\n else if (e.key === 'ArrowRight') direction = 'next';\n }\n // Vertical axis (Up/Down) — active for 'vertical' and 'grid'\n if (!direction && orientation !== 'horizontal') {\n if (e.key === 'ArrowUp') direction = 'prev';\n else if (e.key === 'ArrowDown') direction = 'next';\n if (direction && cols) step = cols;\n }\n }\n\n if (direction) {\n e.preventDefault();\n e.stopPropagation();\n moveFocus(direction, step);\n }\n },\n [orientation, cols, moveFocus]\n );\n\n const getContainerProps = React.useCallback((nameInput?: AccessibleNameInput): RovingContainerProps => {\n const props: RovingContainerProps = {};\n if (role) props.role = role;\n if (orientation === 'horizontal') props['aria-orientation'] = 'horizontal';\n else if (orientation === 'vertical') props['aria-orientation'] = 'vertical';\n // grid: aria-orientation omitted — not applicable for role=\"grid\"\n if (nameInput) Object.assign(props, getA11yNameAttributes(nameInput));\n return props;\n }, [role, orientation]);\n\n return {\n setFocusedId,\n focusItem,\n handleKeyDown,\n getRovingItemProps,\n getContainerProps\n };\n}\n"],"names":["React","getA11yNameAttributes","useRovingFocus","itemIds","tabIndex","defaultFocusedId","orientation","cols","loop","onFocusChange","role","focusedId","setFocusedIdState","useState","itemRefs","useRef","useEffect","length","includes","newFocusedId","setFocusedId","useCallback","id","prev","focusItem","el","current","focus","moveFocus","direction","step","currentIdx","indexOf","safeIdx","Math","max","nextIdx","min","nextId","getRovingItemProps","ref","onFocus","handleKeyDown","e","key","preventDefault","stopPropagation","getContainerProps","nameInput","props","Object","assign"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index70.js","sources":["../src/utils/a11y/useFocusManagement.ts"],"sourcesContent":["import { useEffect, useRef } from 'react';\nimport type { DependencyList } from 'react';\n\nexport interface UseFocusManagementOptions {\n /**\n * CSS selector to query the primary focus target.\n * Default: 'h1'\n */\n targetSelector?: string;\n /**\n * Fallback element id if selector target is not found.\n * Default: 'main-content'\n */\n fallbackId?: string;\n}\n\n/**\n * Generic focus management hook for route/state driven UI transitions.\n * Useful for both route changes and in-page multi-step wizards.\n * \n * Always skips first render and uses animation frame for safe DOM timing.\n */\nexport function useFocusManagement(\n dependencies: DependencyList,\n {\n targetSelector = '#main-content h1',\n fallbackId = 'main-content'\n }: UseFocusManagementOptions = {}\n): void {\n const isFirstRender = useRef(true);\n\n useEffect(() => {\n // Always skip first render\n if (isFirstRender.current) {\n isFirstRender.current = false;\n return;\n }\n\n const focusTarget = () => {\n const el = (document.querySelector(targetSelector) || document.getElementById(fallbackId)) as HTMLElement;\n if (el) {\n if (!el.hasAttribute('tabindex')) el.setAttribute('tabindex', '-1');\n el.focus();\n }\n };\n\n // Always use animation frame for safe DOM timing\n const rafId = requestAnimationFrame(focusTarget);\n return () => cancelAnimationFrame(rafId);\n }, dependencies);\n}\n"],"names":["useFocusManagement","dependencies","targetSelector","fallbackId","isFirstRender","useRef","useEffect","current","rafId","requestAnimationFrame","focusTarget","el","document","querySelector","getElementById","hasAttribute","setAttribute","focus","cancelAnimationFrame"],"mappings":";AAsBO,SAASA,EACdC,GACA;AAAA,EACEC,gBAAAA,IAAiB;AAAA,EACjBC,YAAAA,IAAa;AACY,IAAI,IACzB;AACN,QAAMC,IAAgBC,EAAO,EAAI;AAEjCC,EAAAA,EAAU,MAAM;AAEd,QAAIF,EAAcG,SAAS;AACzBH,MAAAA,EAAcG,UAAU;AACxB;AAAA,IACF;AAWA,UAAMC,IAAQC,sBATMC,MAAM;AACxB,YAAMC,IAAMC,SAASC,cAAcX,CAAc,KAAKU,SAASE,eAAeX,CAAU;AACxF,MAAIQ,MACGA,EAAGI,aAAa,UAAU,KAAGJ,EAAGK,aAAa,YAAY,IAAI,GAClEL,EAAGM,MAAAA;AAAAA,IAEP,CAG+C;AAC/C,WAAO,MAAMC,qBAAqBV,CAAK;AAAA,EACzC,GAAGP,CAAY;AACjB;"}
|