se-design 1.0.82 → 1.0.83-dev.2
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/icons/chat.svg +4 -0
- package/dist/assets/icons/tag.svg +2 -2
- package/dist/assets/style.css +1 -1
- package/dist/components/AccessibleDiv/index.d.ts +23 -1
- package/dist/components/Dropdown/index.d.ts +2 -0
- package/dist/components/DropdownWithInputTags/index.d.ts +3 -0
- package/dist/components/Link/index.d.ts +6 -2
- package/dist/index.js +62 -54
- 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 +2 -2
- package/dist/index109.js.map +1 -1
- package/dist/index110.js +2 -2
- 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 +2 -2
- package/dist/index113.js.map +1 -1
- package/dist/index114.js +1 -1
- package/dist/index114.js.map +1 -1
- package/dist/index115.js +2 -2
- package/dist/index115.js.map +1 -1
- package/dist/index116.js +1 -1
- package/dist/index116.js.map +1 -1
- package/dist/index117.js +1 -1
- package/dist/index117.js.map +1 -1
- package/dist/index118.js +2 -2
- package/dist/index118.js.map +1 -1
- package/dist/index119.js +2 -2
- package/dist/index119.js.map +1 -1
- package/dist/index12.js +2 -2
- 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 +2 -2
- package/dist/index122.js.map +1 -1
- package/dist/index123.js +2 -2
- package/dist/index123.js.map +1 -1
- package/dist/index124.js +1 -1
- package/dist/index124.js.map +1 -1
- package/dist/index125.js +2 -2
- package/dist/index125.js.map +1 -1
- package/dist/index126.js +2 -2
- package/dist/index126.js.map +1 -1
- package/dist/index127.js +2 -2
- package/dist/index127.js.map +1 -1
- package/dist/index128.js +1 -1
- package/dist/index128.js.map +1 -1
- package/dist/index129.js +1 -1
- package/dist/index129.js.map +1 -1
- package/dist/index13.js +1 -1
- package/dist/index130.js +2 -2
- 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 +2 -2
- package/dist/index135.js.map +1 -1
- package/dist/index136.js +2 -2
- package/dist/index136.js.map +1 -1
- package/dist/index137.js +1 -1
- package/dist/index137.js.map +1 -1
- package/dist/index138.js +1 -1
- 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 +2 -2
- 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 +2 -2
- package/dist/index146.js.map +1 -1
- package/dist/index147.js +1 -1
- package/dist/index147.js.map +1 -1
- package/dist/index148.js +1 -1
- 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 +2 -2
- package/dist/index151.js.map +1 -1
- package/dist/index152.js +2 -2
- package/dist/index152.js.map +1 -1
- package/dist/index153.js +1 -1
- package/dist/index153.js.map +1 -1
- package/dist/index154.js +2 -2
- 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 +25 -23
- package/dist/index16.js.map +1 -1
- package/dist/index160.js +1 -1
- package/dist/index160.js.map +1 -1
- package/dist/index161.js +1 -1
- 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/index17.js +29 -29
- package/dist/index17.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 +85 -63
- package/dist/index18.js.map +1 -1
- package/dist/index180.js +1 -1
- package/dist/index180.js.map +1 -1
- package/dist/index181.js +2 -2
- 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 +2 -2
- package/dist/index185.js.map +1 -1
- package/dist/index186.js +1 -1
- package/dist/index186.js.map +1 -1
- package/dist/index187.js +1 -1
- package/dist/index187.js.map +1 -1
- package/dist/index188.js +1 -1
- package/dist/index188.js.map +1 -1
- package/dist/index189.js +2 -2
- package/dist/index189.js.map +1 -1
- package/dist/index19.js +181 -166
- package/dist/index19.js.map +1 -1
- package/dist/index190.js +1 -1
- package/dist/index190.js.map +1 -1
- package/dist/index191.js +1 -1
- 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 +2 -2
- package/dist/index196.js.map +1 -1
- package/dist/index197.js +1 -1
- package/dist/index197.js.map +1 -1
- package/dist/index198.js +2 -2
- package/dist/index198.js.map +1 -1
- package/dist/index199.js +2 -149
- package/dist/index199.js.map +1 -1
- package/dist/index200.js +2 -9
- package/dist/index200.js.map +1 -1
- package/dist/index201.js +2 -6
- package/dist/index201.js.map +1 -1
- package/dist/index202.js +2 -5
- package/dist/index202.js.map +1 -1
- package/dist/index203.js +149 -42
- package/dist/index203.js.map +1 -1
- package/dist/index204.js +8 -20
- package/dist/index204.js.map +1 -1
- package/dist/index205.js +9 -0
- package/dist/index205.js.map +1 -0
- package/dist/index206.js +8 -0
- package/dist/index206.js.map +1 -0
- package/dist/index207.js +45 -0
- package/dist/index207.js.map +1 -0
- package/dist/index208.js +24 -0
- package/dist/index208.js.map +1 -0
- package/dist/{index211.js → index215.js} +1 -1
- package/dist/{index211.js.map → index215.js.map} +1 -1
- package/dist/{index212.js → index216.js} +13 -9
- package/dist/index216.js.map +1 -0
- package/dist/{index220.js → index224.js} +1 -1
- package/dist/{index220.js.map → index224.js.map} +1 -1
- package/dist/index23.js +3 -3
- package/dist/{index228.js → index232.js} +1 -1
- package/dist/{index228.js.map → index232.js.map} +1 -1
- package/dist/{index231.js → index235.js} +1 -1
- package/dist/{index231.js.map → index235.js.map} +1 -1
- package/dist/index244.js +168 -8
- package/dist/index244.js.map +1 -1
- package/dist/index245.js +3 -9
- package/dist/index245.js.map +1 -1
- package/dist/index247.js +18 -169
- package/dist/index247.js.map +1 -1
- package/dist/index248.js +10 -11
- package/dist/index248.js.map +1 -1
- package/dist/index249.js +8 -4
- package/dist/index249.js.map +1 -1
- package/dist/index25.js +175 -161
- package/dist/index25.js.map +1 -1
- package/dist/index250.js +4 -5
- package/dist/index250.js.map +1 -1
- package/dist/index251.js +168 -36
- package/dist/index251.js.map +1 -1
- package/dist/index252.js +11 -2
- package/dist/index252.js.map +1 -1
- package/dist/index253.js +5 -7
- package/dist/index253.js.map +1 -1
- package/dist/index254.js +5 -326
- package/dist/index254.js.map +1 -1
- package/dist/index255.js +36 -48
- package/dist/index255.js.map +1 -1
- package/dist/index256.js +2 -2
- package/dist/index257.js +7 -75
- package/dist/index257.js.map +1 -1
- package/dist/index258.js +308 -74
- package/dist/index258.js.map +1 -1
- package/dist/index259.js +45 -47
- package/dist/index259.js.map +1 -1
- package/dist/index260.js +2 -8
- package/dist/index260.js.map +1 -1
- package/dist/index261.js +75 -4
- package/dist/index261.js.map +1 -1
- package/dist/index262.js +89 -48
- package/dist/index262.js.map +1 -1
- package/dist/index263.js +52 -2
- package/dist/index263.js.map +1 -1
- package/dist/index264.js +8 -2
- package/dist/index264.js.map +1 -1
- package/dist/index265.js +8 -0
- package/dist/index265.js.map +1 -0
- package/dist/index266.js +55 -0
- package/dist/index266.js.map +1 -0
- package/dist/index267.js +5 -0
- package/dist/index267.js.map +1 -0
- package/dist/index268.js +5 -0
- package/dist/index268.js.map +1 -0
- package/dist/index28.js +5 -5
- package/dist/index28.js.map +1 -1
- package/dist/index29.js +1 -1
- package/dist/index3.js +59 -49
- package/dist/index3.js.map +1 -1
- package/dist/index30.js +1 -1
- package/dist/index33.js +1 -1
- package/dist/index35.js +1 -1
- package/dist/index36.js +2 -2
- package/dist/index38.js +209 -194
- package/dist/index38.js.map +1 -1
- package/dist/index39.js +3 -3
- package/dist/index4.js +1 -1
- package/dist/index40.js +1 -1
- package/dist/index43.js +16 -16
- package/dist/index43.js.map +1 -1
- package/dist/index45.js +60 -59
- package/dist/index45.js.map +1 -1
- package/dist/index46.js +3 -3
- package/dist/index49.js +1 -1
- package/dist/index51.js +1 -1
- package/dist/index52.js +2 -2
- package/dist/index53.js +1 -1
- package/dist/index55.js +2 -2
- package/dist/index55.js.map +1 -1
- package/dist/index57.js +1 -1
- package/dist/index6.js +238 -236
- package/dist/index6.js.map +1 -1
- package/dist/index61.js +9 -8
- package/dist/index61.js.map +1 -1
- package/dist/index63.js +1 -1
- package/dist/index64.js +35 -34
- package/dist/index64.js.map +1 -1
- package/dist/index65.js +1 -1
- package/dist/index67.js +1 -1
- package/dist/index68.js +80 -58
- package/dist/index68.js.map +1 -1
- package/dist/index7.js +1 -1
- package/dist/index70.js +1 -1
- package/dist/index75.js +108 -5
- package/dist/index75.js.map +1 -1
- package/dist/index76.js +18 -54
- package/dist/index76.js.map +1 -1
- package/dist/index77.js +10 -23
- package/dist/index77.js.map +1 -1
- package/dist/index78.js +5 -9
- package/dist/index78.js.map +1 -1
- package/dist/index79.js +62 -0
- package/dist/index79.js.map +1 -0
- package/dist/index80.js +24 -2
- package/dist/index80.js.map +1 -1
- package/dist/index81.js +9 -2
- package/dist/index81.js.map +1 -1
- package/dist/index83.js +1 -1
- package/dist/index83.js.map +1 -1
- package/dist/index84.js +2 -2
- package/dist/index84.js.map +1 -1
- package/dist/index85.js +1 -1
- package/dist/index85.js.map +1 -1
- package/dist/index86.js +2 -2
- package/dist/index86.js.map +1 -1
- package/dist/index87.js +1 -1
- 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 +3 -3
- 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/index212.js.map +0 -1
- package/dist/index240.js +0 -173
- package/dist/index240.js.map +0 -1
- package/dist/index241.js +0 -7
- package/dist/index241.js.map +0 -1
- package/dist/index243.js +0 -22
- package/dist/index243.js.map +0 -1
- package/dist/index246.js +0 -8
- package/dist/index246.js.map +0 -1
- package/dist/index82.js +0 -5
- package/dist/index82.js.map +0 -1
package/dist/index61.js
CHANGED
|
@@ -18,28 +18,29 @@ const I = ({
|
|
|
18
18
|
isDisabled: r = !1,
|
|
19
19
|
noPadding: u = !1
|
|
20
20
|
}) => {
|
|
21
|
-
const [m,
|
|
22
|
-
o.key === "Escape" && (
|
|
21
|
+
const [m, i] = p(!1), [g, a] = p(!1), c = m || g, d = E((o) => {
|
|
22
|
+
o.key === "Escape" && (i(!1), a(!1), o.stopImmediatePropagation());
|
|
23
23
|
}, []);
|
|
24
24
|
y(() => {
|
|
25
25
|
if (c)
|
|
26
26
|
return document.addEventListener("keydown", d), () => document.removeEventListener("keydown", d);
|
|
27
27
|
}, [c, d]);
|
|
28
28
|
const v = {
|
|
29
|
-
onMouseEnter: () =>
|
|
30
|
-
onMouseLeave: () =>
|
|
29
|
+
onMouseEnter: () => i(!0),
|
|
30
|
+
onMouseLeave: () => i(!1),
|
|
31
31
|
onFocus: (o) => {
|
|
32
|
-
o.target.matches(":focus-visible") &&
|
|
32
|
+
o.target.matches(":focus-visible") && a(!0);
|
|
33
33
|
},
|
|
34
|
-
onBlur: () =>
|
|
34
|
+
onBlur: () => a(!1)
|
|
35
35
|
};
|
|
36
36
|
return /* @__PURE__ */ l.createElement("div", f({
|
|
37
|
-
className: r ? "se-design-info-tooltip-wrapper-disabled" : ""
|
|
37
|
+
className: `se-design-info-tooltip-outer ${r ? "se-design-info-tooltip-wrapper-disabled" : ""}`
|
|
38
38
|
}, r ? {} : v), /* @__PURE__ */ l.createElement(P, {
|
|
39
|
+
className: "inline-flex items-center",
|
|
39
40
|
position: "bottom-center",
|
|
40
41
|
isPopoverOpen: c,
|
|
41
42
|
onPopoverToggle: (o) => {
|
|
42
|
-
o || (
|
|
43
|
+
o || (i(!1), a(!1));
|
|
43
44
|
},
|
|
44
45
|
renderPopoverSrcElement: () => /* @__PURE__ */ l.createElement("div", {
|
|
45
46
|
className: `se-design-info-tooltip-src ${u ? "no-padding" : ""} ${r ? "se-design-info-tooltip-disabled" : ""}`,
|
package/dist/index61.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index61.js","sources":["../src/components/InfoTooltip/index.tsx"],"sourcesContent":["import React, { useState, useEffect, useCallback } from 'react';\nimport { Popover } from '../Popover';\nimport './styles.scss';\n\nexport interface InfoTooltipProps {\n label: string;\n children: React.ReactNode;\n iconColor?: string;\n /**\n * Background color shown on hover. Defaults to var(--color-blue-200).\n */\n hoverBackgroundColor?: string;\n isDisabled?: boolean;\n /**\n * Remove padding from tooltip wrapper (useful for precise alignment)\n */\n noPadding?: boolean;\n}\n\nexport const InfoTooltip = ({\n label,\n children,\n iconColor = '',\n hoverBackgroundColor,\n isDisabled = false,\n noPadding = false\n}: InfoTooltipProps) => {\n const [isHovered, setIsHovered] = useState(false);\n const [isFocused, setIsFocused] = useState(false);\n\n // Show tooltip on hover OR focus (for keyboard accessibility)\n const isOpen = isHovered || isFocused;\n\n // Global Escape key handler (W3C WAI-ARIA tooltip pattern requirement)\n const handleEscapeKey = useCallback((event: KeyboardEvent) => {\n if (event.key === 'Escape') {\n setIsHovered(false);\n setIsFocused(false);\n // Prevent other handlers (e.g., modal) from also closing - \"innermost first\" pattern\n event.stopImmediatePropagation();\n }\n }, []);\n\n useEffect(() => {\n if (isOpen) {\n document.addEventListener('keydown', handleEscapeKey);\n return () => document.removeEventListener('keydown', handleEscapeKey);\n }\n }, [isOpen, handleEscapeKey]);\n\n const interactionHandlers = {\n onMouseEnter: () => setIsHovered(true),\n onMouseLeave: () => setIsHovered(false),\n onFocus: (event: React.FocusEvent<HTMLDivElement>) => {\n const focusTarget = event.target as HTMLElement;\n if (focusTarget.matches(':focus-visible')) {\n setIsFocused(true);\n }\n },\n onBlur: () => setIsFocused(false)\n };\n\n return (\n <div\n className={isDisabled ? 'se-design-info-tooltip-wrapper-disabled' : ''}\n {...(isDisabled ? {} : interactionHandlers)}\n >\n <Popover\n position={'bottom-center'}\n isPopoverOpen={isOpen}\n onPopoverToggle={(open) => {\n // Sync popover state changes (e.g., Escape key) back to component state\n if (!open) {\n setIsHovered(false);\n setIsFocused(false);\n }\n }}\n renderPopoverSrcElement={() => (\n <div\n className={`se-design-info-tooltip-src ${noPadding ? 'no-padding' : ''} ${\n isDisabled ? 'se-design-info-tooltip-disabled' : ''\n }`}\n style={\n {\n '--info-tooltip-icon-color': iconColor,\n ...(hoverBackgroundColor ? { '--info-tooltip-hover-bg': hoverBackgroundColor } : {}),\n cursor: isDisabled ? 'not-allowed' : 'pointer'\n } as React.CSSProperties\n }\n >\n {children}\n </div>\n )}\n renderPopoverContents={() => (\n <div className=\"se-design-info-tooltip-content\" data-automation-id=\"se-design-info-tooltip-content\">\n {label}\n </div>\n )}\n isWithPortal\n noBorder\n disableClickToggle\n popoverContentStyleProperty={{\n zIndex: 2000,\n backgroundColor: ''\n }}\n />\n </div>\n );\n};\n"],"names":["InfoTooltip","label","children","iconColor","hoverBackgroundColor","isDisabled","noPadding","isHovered","setIsHovered","useState","isFocused","setIsFocused","isOpen","handleEscapeKey","useCallback","event","key","stopImmediatePropagation","useEffect","document","addEventListener","removeEventListener","interactionHandlers","onMouseEnter","onMouseLeave","onFocus","target","matches","onBlur","React","createElement","_extends","className","Popover","position","isPopoverOpen","onPopoverToggle","open","renderPopoverSrcElement","style","cursor","renderPopoverContents","isWithPortal","noBorder","disableClickToggle","popoverContentStyleProperty","zIndex","backgroundColor"],"mappings":";;;;;;;;;;;;AAmBO,MAAMA,IAAcA,CAAC;AAAA,EAC1BC,OAAAA;AAAAA,EACAC,UAAAA;AAAAA,EACAC,WAAAA,IAAY;AAAA,EACZC,sBAAAA;AAAAA,EACAC,YAAAA,IAAa;AAAA,EACbC,WAAAA,IAAY;AACI,MAAM;AACtB,QAAM,CAACC,GAAWC,CAAY,IAAIC,EAAS,EAAK,GAC1C,CAACC,GAAWC,CAAY,IAAIF,EAAS,EAAK,GAG1CG,IAASL,KAAaG,GAGtBG,IAAkBC,EAAY,CAACC,MAAyB;AAC5D,IAAIA,EAAMC,QAAQ,aAChBR,EAAa,EAAK,GAClBG,EAAa,EAAK,GAElBI,EAAME,yBAAAA;AAAAA,EAEV,GAAG,CAAA,CAAE;AAELC,EAAAA,EAAU,MAAM;AACd,QAAIN;AACFO,sBAASC,iBAAiB,WAAWP,CAAe,GAC7C,MAAMM,SAASE,oBAAoB,WAAWR,CAAe;AAAA,EAExE,GAAG,CAACD,GAAQC,CAAe,CAAC;AAE5B,QAAMS,IAAsB;AAAA,IAC1BC,cAAcA,MAAMf,EAAa,EAAI;AAAA,IACrCgB,cAAcA,MAAMhB,EAAa,EAAK;AAAA,IACtCiB,SAASA,CAACV,MAA4C;AAEpD,MADoBA,EAAMW,OACVC,QAAQ,gBAAgB,KACtChB,EAAa,EAAI;AAAA,IAErB;AAAA,IACAiB,QAAQA,MAAMjB,EAAa,EAAK;AAAA,EAAA;AAGlC,SACEkB,gBAAAA,EAAAC,cAAA,OAAAC,EAAA;AAAA,IACEC,
|
|
1
|
+
{"version":3,"file":"index61.js","sources":["../src/components/InfoTooltip/index.tsx"],"sourcesContent":["import React, { useState, useEffect, useCallback } from 'react';\nimport { Popover } from '../Popover';\nimport './styles.scss';\n\nexport interface InfoTooltipProps {\n label: string;\n children: React.ReactNode;\n iconColor?: string;\n /**\n * Background color shown on hover. Defaults to var(--color-blue-200).\n */\n hoverBackgroundColor?: string;\n isDisabled?: boolean;\n /**\n * Remove padding from tooltip wrapper (useful for precise alignment)\n */\n noPadding?: boolean;\n}\n\nexport const InfoTooltip = ({\n label,\n children,\n iconColor = '',\n hoverBackgroundColor,\n isDisabled = false,\n noPadding = false\n}: InfoTooltipProps) => {\n const [isHovered, setIsHovered] = useState(false);\n const [isFocused, setIsFocused] = useState(false);\n\n // Show tooltip on hover OR focus (for keyboard accessibility)\n const isOpen = isHovered || isFocused;\n\n // Global Escape key handler (W3C WAI-ARIA tooltip pattern requirement)\n const handleEscapeKey = useCallback((event: KeyboardEvent) => {\n if (event.key === 'Escape') {\n setIsHovered(false);\n setIsFocused(false);\n // Prevent other handlers (e.g., modal) from also closing - \"innermost first\" pattern\n event.stopImmediatePropagation();\n }\n }, []);\n\n useEffect(() => {\n if (isOpen) {\n document.addEventListener('keydown', handleEscapeKey);\n return () => document.removeEventListener('keydown', handleEscapeKey);\n }\n }, [isOpen, handleEscapeKey]);\n\n const interactionHandlers = {\n onMouseEnter: () => setIsHovered(true),\n onMouseLeave: () => setIsHovered(false),\n onFocus: (event: React.FocusEvent<HTMLDivElement>) => {\n const focusTarget = event.target as HTMLElement;\n if (focusTarget.matches(':focus-visible')) {\n setIsFocused(true);\n }\n },\n onBlur: () => setIsFocused(false)\n };\n\n return (\n <div\n className={`se-design-info-tooltip-outer ${isDisabled ? 'se-design-info-tooltip-wrapper-disabled' : ''}`}\n {...(isDisabled ? {} : interactionHandlers)}\n >\n <Popover\n className=\"inline-flex items-center\"\n position={'bottom-center'}\n isPopoverOpen={isOpen}\n onPopoverToggle={(open) => {\n // Sync popover state changes (e.g., Escape key) back to component state\n if (!open) {\n setIsHovered(false);\n setIsFocused(false);\n }\n }}\n renderPopoverSrcElement={() => (\n <div\n className={`se-design-info-tooltip-src ${noPadding ? 'no-padding' : ''} ${\n isDisabled ? 'se-design-info-tooltip-disabled' : ''\n }`}\n style={\n {\n '--info-tooltip-icon-color': iconColor,\n ...(hoverBackgroundColor ? { '--info-tooltip-hover-bg': hoverBackgroundColor } : {}),\n cursor: isDisabled ? 'not-allowed' : 'pointer'\n } as React.CSSProperties\n }\n >\n {children}\n </div>\n )}\n renderPopoverContents={() => (\n <div className=\"se-design-info-tooltip-content\" data-automation-id=\"se-design-info-tooltip-content\">\n {label}\n </div>\n )}\n isWithPortal\n noBorder\n disableClickToggle\n popoverContentStyleProperty={{\n zIndex: 2000,\n backgroundColor: ''\n }}\n />\n </div>\n );\n};\n"],"names":["InfoTooltip","label","children","iconColor","hoverBackgroundColor","isDisabled","noPadding","isHovered","setIsHovered","useState","isFocused","setIsFocused","isOpen","handleEscapeKey","useCallback","event","key","stopImmediatePropagation","useEffect","document","addEventListener","removeEventListener","interactionHandlers","onMouseEnter","onMouseLeave","onFocus","target","matches","onBlur","React","createElement","_extends","className","Popover","position","isPopoverOpen","onPopoverToggle","open","renderPopoverSrcElement","style","cursor","renderPopoverContents","isWithPortal","noBorder","disableClickToggle","popoverContentStyleProperty","zIndex","backgroundColor"],"mappings":";;;;;;;;;;;;AAmBO,MAAMA,IAAcA,CAAC;AAAA,EAC1BC,OAAAA;AAAAA,EACAC,UAAAA;AAAAA,EACAC,WAAAA,IAAY;AAAA,EACZC,sBAAAA;AAAAA,EACAC,YAAAA,IAAa;AAAA,EACbC,WAAAA,IAAY;AACI,MAAM;AACtB,QAAM,CAACC,GAAWC,CAAY,IAAIC,EAAS,EAAK,GAC1C,CAACC,GAAWC,CAAY,IAAIF,EAAS,EAAK,GAG1CG,IAASL,KAAaG,GAGtBG,IAAkBC,EAAY,CAACC,MAAyB;AAC5D,IAAIA,EAAMC,QAAQ,aAChBR,EAAa,EAAK,GAClBG,EAAa,EAAK,GAElBI,EAAME,yBAAAA;AAAAA,EAEV,GAAG,CAAA,CAAE;AAELC,EAAAA,EAAU,MAAM;AACd,QAAIN;AACFO,sBAASC,iBAAiB,WAAWP,CAAe,GAC7C,MAAMM,SAASE,oBAAoB,WAAWR,CAAe;AAAA,EAExE,GAAG,CAACD,GAAQC,CAAe,CAAC;AAE5B,QAAMS,IAAsB;AAAA,IAC1BC,cAAcA,MAAMf,EAAa,EAAI;AAAA,IACrCgB,cAAcA,MAAMhB,EAAa,EAAK;AAAA,IACtCiB,SAASA,CAACV,MAA4C;AAEpD,MADoBA,EAAMW,OACVC,QAAQ,gBAAgB,KACtChB,EAAa,EAAI;AAAA,IAErB;AAAA,IACAiB,QAAQA,MAAMjB,EAAa,EAAK;AAAA,EAAA;AAGlC,SACEkB,gBAAAA,EAAAC,cAAA,OAAAC,EAAA;AAAA,IACEC,WAAW,gCAAgC3B,IAAa,4CAA4C,EAAE;AAAA,EAAA,GACjGA,IAAa,CAAA,IAAKiB,CAAmB,GAE1CO,gBAAAA,EAAAC,cAACG,GAAO;AAAA,IACND,WAAU;AAAA,IACVE,UAAU;AAAA,IACVC,eAAevB;AAAAA,IACfwB,iBAAkBC,CAAAA,MAAS;AAEzB,MAAKA,MACH7B,EAAa,EAAK,GAClBG,EAAa,EAAK;AAAA,IAEtB;AAAA,IACA2B,yBAAyBA,MACvBT,gBAAAA,EAAAC,cAAA,OAAA;AAAA,MACEE,WAAW,8BAA8B1B,IAAY,eAAe,EAAE,IACpED,IAAa,oCAAoC,EAAE;AAAA,MAErDkC,OACE;AAAA,QACE,6BAA6BpC;AAAAA,QAC7B,GAAIC,IAAuB;AAAA,UAAE,2BAA2BA;AAAAA,QAAAA,IAAyB,CAAA;AAAA,QACjFoC,QAAQnC,IAAa,gBAAgB;AAAA,MAAA;AAAA,IACvC,GAGDH,CACE;AAAA,IAEPuC,uBAAuBA,MACrBZ,gBAAAA,EAAAC,cAAA,OAAA;AAAA,MAAKE,WAAU;AAAA,MAAiC,sBAAmB;AAAA,IAAA,GAChE/B,CACE;AAAA,IAEPyC,cAAY;AAAA,IACZC,UAAQ;AAAA,IACRC,oBAAkB;AAAA,IAClBC,6BAA6B;AAAA,MAC3BC,QAAQ;AAAA,MACRC,iBAAiB;AAAA,IAAA;AAAA,EACnB,CACD,CACE;AAET;"}
|
package/dist/index63.js
CHANGED
|
@@ -2,7 +2,7 @@ import F, { useState as ot, useRef as X, useEffect as $ } from "react";
|
|
|
2
2
|
import { createPortal as nt } from "react-dom";
|
|
3
3
|
import { Icon as it } from "./index6.js";
|
|
4
4
|
import { Button as rt } from "./index4.js";
|
|
5
|
-
import { debounce as lt } from "./
|
|
5
|
+
import { debounce as lt } from "./index224.js";
|
|
6
6
|
const q = 500, S = 50, U = 150, st = {
|
|
7
7
|
"top-left": {
|
|
8
8
|
rotate: "315",
|
package/dist/index64.js
CHANGED
|
@@ -1,49 +1,50 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { getA11yNameAttributes as
|
|
1
|
+
import v, { forwardRef as k } from "react";
|
|
2
|
+
import { getA11yNameAttributes as L } from "./index81.js";
|
|
3
3
|
import "./index72.js";
|
|
4
4
|
/* empty css */
|
|
5
|
-
function
|
|
6
|
-
return
|
|
7
|
-
for (var
|
|
8
|
-
var
|
|
9
|
-
for (var
|
|
5
|
+
function r() {
|
|
6
|
+
return r = Object.assign ? Object.assign.bind() : function(o) {
|
|
7
|
+
for (var t = 1; t < arguments.length; t++) {
|
|
8
|
+
var n = arguments[t];
|
|
9
|
+
for (var e in n) ({}).hasOwnProperty.call(n, e) && (o[e] = n[e]);
|
|
10
10
|
}
|
|
11
|
-
return
|
|
12
|
-
},
|
|
11
|
+
return o;
|
|
12
|
+
}, r.apply(null, arguments);
|
|
13
13
|
}
|
|
14
|
-
const
|
|
15
|
-
href:
|
|
16
|
-
label:
|
|
14
|
+
const y = " (opens in a new tab)", R = /* @__PURE__ */ k(({
|
|
15
|
+
href: o,
|
|
16
|
+
label: t,
|
|
17
|
+
children: n,
|
|
17
18
|
external: e = !1,
|
|
18
|
-
className:
|
|
19
|
+
className: l = "",
|
|
19
20
|
automationId: c = "",
|
|
20
|
-
ariaLabel:
|
|
21
|
-
ariaLabelledBy:
|
|
22
|
-
ariaDescribedBy:
|
|
23
|
-
onClick:
|
|
21
|
+
ariaLabel: a,
|
|
22
|
+
ariaLabelledBy: m,
|
|
23
|
+
ariaDescribedBy: u,
|
|
24
|
+
onClick: f,
|
|
24
25
|
target: s,
|
|
25
26
|
rel: i,
|
|
26
|
-
...
|
|
27
|
-
},
|
|
28
|
-
const
|
|
27
|
+
...p
|
|
28
|
+
}, d) => {
|
|
29
|
+
const g = n ? void 0 : t, b = e ? s ?? "_blank" : s, A = e ? i ?? "noopener noreferrer" : i, N = L({
|
|
29
30
|
// External link aria-label enhancement for screen readers:
|
|
30
31
|
// When external={true}, always append "(opens in a new tab)"
|
|
31
|
-
ariaLabel: e ? `${
|
|
32
|
-
ariaLabelledBy:
|
|
33
|
-
ariaDescribedBy:
|
|
34
|
-
}),
|
|
35
|
-
return /* @__PURE__ */
|
|
36
|
-
ref:
|
|
37
|
-
href:
|
|
38
|
-
target:
|
|
39
|
-
rel:
|
|
40
|
-
className:
|
|
32
|
+
ariaLabel: e ? `${a ?? g ?? ""}${y}` : a,
|
|
33
|
+
ariaLabelledBy: m,
|
|
34
|
+
ariaDescribedBy: u
|
|
35
|
+
}), _ = ["se-design-link", "focus-outline", "focus-visible:underline", l].filter(Boolean).join(" ");
|
|
36
|
+
return /* @__PURE__ */ v.createElement("a", r({
|
|
37
|
+
ref: d,
|
|
38
|
+
href: o,
|
|
39
|
+
target: b,
|
|
40
|
+
rel: A,
|
|
41
|
+
className: _,
|
|
41
42
|
"data-automation-id": c,
|
|
42
|
-
onClick:
|
|
43
|
-
},
|
|
43
|
+
onClick: f
|
|
44
|
+
}, p, N), n ?? t);
|
|
44
45
|
});
|
|
45
|
-
|
|
46
|
+
R.displayName = "Link";
|
|
46
47
|
export {
|
|
47
|
-
|
|
48
|
+
R as Link
|
|
48
49
|
};
|
|
49
50
|
//# sourceMappingURL=index64.js.map
|
package/dist/index64.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index64.js","sources":["../src/components/Link/index.tsx"],"sourcesContent":["import React, { forwardRef } from 'react';\nimport { getA11yNameAttributes } from '../../utils/a11y';\nimport './style.scss';\n\n/**\n * Allows native anchor attributes (aria-*, data-*, etc.) to be passed through,\n * but keeps our own href/onClick/aria-label/aria-labelledby/aria-describedby typing.\n */\ntype NativeAnchorProps = Omit<\n React.AnchorHTMLAttributes<HTMLAnchorElement>,\n 'href' | 'onClick' | 'target' | 'rel' | 'aria-label' | 'aria-labelledby' | 'aria-describedby'\n>;\n\nexport interface LinkProps extends NativeAnchorProps {\n /**\n * URL to navigate to (required for actual links)\n */\n href: string;\n /**\n * Link text content (string only)
|
|
1
|
+
{"version":3,"file":"index64.js","sources":["../src/components/Link/index.tsx"],"sourcesContent":["import React, { forwardRef } from 'react';\nimport { getA11yNameAttributes } from '../../utils/a11y';\nimport './style.scss';\n\n/**\n * Allows native anchor attributes (aria-*, data-*, etc.) to be passed through,\n * but keeps our own href/onClick/aria-label/aria-labelledby/aria-describedby typing.\n */\ntype NativeAnchorProps = Omit<\n React.AnchorHTMLAttributes<HTMLAnchorElement>,\n 'href' | 'onClick' | 'target' | 'rel' | 'aria-label' | 'aria-labelledby' | 'aria-describedby'\n>;\n\nexport interface LinkProps extends NativeAnchorProps {\n /**\n * URL to navigate to (required for actual links)\n */\n href: string;\n /**\n * Link text content (string only). Ignored when children are provided.\n */\n label?: string;\n /**\n * Rich content to render inside the link. Takes precedence over label.\n */\n children?: React.ReactNode;\n /**\n * If true, automatically adds target=\"_blank\" and rel=\"noopener noreferrer\"\n * Also appends \" (opens in a new tab)\" to aria-label for screen readers\n */\n external?: boolean;\n /**\n * Accessible name for the link. Use when link text is generic or unclear.\n * Prefer ariaLabelledBy when a visible label exists.\n */\n ariaLabel?: string;\n /**\n * ID(s) of element(s) that label this link.\n * Preferred over ariaLabel when a visible label exists (keeps SR and visual text in sync).\n */\n ariaLabelledBy?: string;\n /**\n * ID(s) of element(s) that describe this link.\n * Provides additional context announced after the accessible name.\n */\n ariaDescribedBy?: string;\n /**\n * Click handler (e.g., for analytics tracking)\n */\n onClick?: (e: React.MouseEvent<HTMLAnchorElement>) => void;\n /**\n * Custom class name\n */\n className?: string;\n /**\n * Automation ID for testing\n */\n automationId?: string;\n /**\n * Override target (if you need something other than \"_blank\" for external links).\n * Note: If external={true} and target is provided, the provided target will be used.\n */\n target?: string;\n /**\n * Override rel (if you need something other than \"noopener noreferrer\" for external links).\n * Note: If external={true} and rel is provided, the provided rel will be used.\n */\n rel?: string;\n}\n\nconst EXTERNAL_LINK_ARIA_SUFFIX = ' (opens in a new tab)';\n\nexport const Link = forwardRef<HTMLAnchorElement, LinkProps>(\n (\n {\n href,\n label,\n children,\n external = false,\n className = '',\n automationId = '',\n ariaLabel,\n ariaLabelledBy,\n ariaDescribedBy,\n onClick,\n target,\n rel,\n ...props\n },\n ref\n ) => {\n const resolvedLabel = children ? undefined : label;\n // Handle external link attributes\n // If external={true}, default to target=\"_blank\" and rel=\"noopener noreferrer\"\n // Explicit target/rel props can override these defaults\n const targetAttr = external ? (target ?? '_blank') : target;\n const relAttr = external ? (rel ?? 'noopener noreferrer') : rel;\n\n // Compute accessible name/description props with correct precedence\n // Precedence: ariaLabelledBy > ariaLabel > visible text content\n const accessibleNameProps = getA11yNameAttributes({\n // External link aria-label enhancement for screen readers:\n // When external={true}, always append \"(opens in a new tab)\"\n ariaLabel:\n external ? `${ariaLabel ?? resolvedLabel ?? ''}${EXTERNAL_LINK_ARIA_SUFFIX}` : ariaLabel,\n ariaLabelledBy,\n ariaDescribedBy\n });\n\n const linkClassName = ['se-design-link', 'focus-outline', 'focus-visible:underline', className]\n .filter(Boolean)\n .join(' ');\n\n return (\n <a\n ref={ref}\n href={href}\n target={targetAttr}\n rel={relAttr}\n className={linkClassName}\n data-automation-id={automationId}\n onClick={onClick}\n {...props}\n {...accessibleNameProps}\n >\n {children ?? label}\n </a>\n );\n }\n);\n\nLink.displayName = 'Link';\n"],"names":["EXTERNAL_LINK_ARIA_SUFFIX","Link","href","label","children","external","className","automationId","ariaLabel","ariaLabelledBy","ariaDescribedBy","onClick","target","rel","props","ref","resolvedLabel","undefined","targetAttr","relAttr","accessibleNameProps","getA11yNameAttributes","linkClassName","filter","Boolean","join","React","createElement","_extends","displayName"],"mappings":";;;;;;;;;;;;;AAsEA,MAAMA,IAA4B,yBAErBC,sBACX,CACE;AAAA,EACEC,MAAAA;AAAAA,EACAC,OAAAA;AAAAA,EACAC,UAAAA;AAAAA,EACAC,UAAAA,IAAW;AAAA,EACXC,WAAAA,IAAY;AAAA,EACZC,cAAAA,IAAe;AAAA,EACfC,WAAAA;AAAAA,EACAC,gBAAAA;AAAAA,EACAC,iBAAAA;AAAAA,EACAC,SAAAA;AAAAA,EACAC,QAAAA;AAAAA,EACAC,KAAAA;AAAAA,EACA,GAAGC;AACL,GACAC,MACG;AACH,QAAMC,IAAgBZ,IAAWa,SAAYd,GAIvCe,IAAab,IAAYO,KAAU,WAAYA,GAC/CO,IAAUd,IAAYQ,KAAO,wBAAyBA,GAItDO,IAAsBC,EAAsB;AAAA;AAAA;AAAA,IAGhDb,WACEH,IAAW,GAAGG,KAAaQ,KAAiB,EAAE,GAAGhB,CAAyB,KAAKQ;AAAAA,IACjFC,gBAAAA;AAAAA,IACAC,iBAAAA;AAAAA,EAAAA,CACD,GAEKY,IAAgB,CAAC,kBAAkB,iBAAiB,2BAA2BhB,CAAS,EAC3FiB,OAAOC,OAAO,EACdC,KAAK,GAAG;AAEX,SACEC,gBAAAA,EAAAC,cAAA,KAAAC,EAAA;AAAA,IACEb,KAAAA;AAAAA,IACAb,MAAAA;AAAAA,IACAU,QAAQM;AAAAA,IACRL,KAAKM;AAAAA,IACLb,WAAWgB;AAAAA,IACX,sBAAoBf;AAAAA,IACpBI,SAAAA;AAAAA,EAAAA,GACIG,GACAM,CAAmB,GAEtBhB,KAAYD,CACZ;AAEP,CACF;AAEAF,EAAK4B,cAAc;"}
|
package/dist/index65.js
CHANGED
|
@@ -4,7 +4,7 @@ import { Badge as j } from "./index10.js";
|
|
|
4
4
|
import { Icon as q } from "./index6.js";
|
|
5
5
|
import { Link as N } from "./index64.js";
|
|
6
6
|
import { CustomModal as G } from "./index13.js";
|
|
7
|
-
import { useStableId as J } from "./
|
|
7
|
+
import { useStableId as J } from "./index205.js";
|
|
8
8
|
/* empty css */
|
|
9
9
|
const K = {
|
|
10
10
|
lg: {
|
package/dist/index67.js
CHANGED
package/dist/index68.js
CHANGED
|
@@ -1,87 +1,109 @@
|
|
|
1
|
-
import { useRef as
|
|
2
|
-
import { useComboboxNavigation as
|
|
3
|
-
import { useDismissOnFocusOut as
|
|
4
|
-
function
|
|
5
|
-
items:
|
|
1
|
+
import { useRef as i, useState as k, useCallback as b, useEffect as M } from "react";
|
|
2
|
+
import { useComboboxNavigation as A } from "./index79.js";
|
|
3
|
+
import { useDismissOnFocusOut as E } from "./index80.js";
|
|
4
|
+
function _({
|
|
5
|
+
items: f,
|
|
6
6
|
isOpen: t,
|
|
7
|
-
onOpenChange:
|
|
8
|
-
onSelect:
|
|
7
|
+
onOpenChange: u,
|
|
8
|
+
onSelect: x,
|
|
9
9
|
listboxId: n,
|
|
10
|
-
loop:
|
|
11
|
-
disabled:
|
|
12
|
-
optionSelector:
|
|
13
|
-
hasItems:
|
|
10
|
+
loop: m = !0,
|
|
11
|
+
disabled: w = !1,
|
|
12
|
+
optionSelector: y = '[role="option"]',
|
|
13
|
+
hasItems: p,
|
|
14
|
+
keepHighlightOnSelect: C = !1,
|
|
15
|
+
closeOnTab: D = !0
|
|
14
16
|
}) {
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
}, [
|
|
18
|
-
|
|
19
|
-
t || (
|
|
17
|
+
const g = i(null), s = i(!1), l = i(!1), c = i(!1), [h, r] = k(!1), v = p !== void 0 ? p : f.length > 0, d = b(() => {
|
|
18
|
+
u(!1);
|
|
19
|
+
}, [u]);
|
|
20
|
+
M(() => {
|
|
21
|
+
t || (s.current = !1);
|
|
20
22
|
}, [t]);
|
|
21
|
-
const
|
|
22
|
-
items:
|
|
23
|
+
const o = A({
|
|
24
|
+
items: f,
|
|
23
25
|
isOpen: t,
|
|
24
|
-
onSelect:
|
|
25
|
-
onClose:
|
|
26
|
-
onOpen: () =>
|
|
27
|
-
loop:
|
|
28
|
-
disabled:
|
|
29
|
-
listboxRef:
|
|
30
|
-
optionSelector:
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
26
|
+
onSelect: x,
|
|
27
|
+
onClose: d,
|
|
28
|
+
onOpen: () => u(!0),
|
|
29
|
+
loop: m,
|
|
30
|
+
disabled: w,
|
|
31
|
+
listboxRef: g,
|
|
32
|
+
optionSelector: y,
|
|
33
|
+
keepHighlightOnSelect: C,
|
|
34
|
+
closeOnTab: D
|
|
35
|
+
}), a = E({
|
|
36
|
+
onFocusOut: d,
|
|
37
|
+
onEscape: d,
|
|
34
38
|
disabled: !t
|
|
35
|
-
}),
|
|
36
|
-
...
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
}), F = {
|
|
40
|
+
...a,
|
|
41
|
+
onPointerMove: () => {
|
|
42
|
+
h && r(!1);
|
|
43
|
+
},
|
|
44
|
+
onPointerDown: () => {
|
|
45
|
+
c.current = !0, r(!1);
|
|
46
|
+
},
|
|
47
|
+
onPointerUp: () => {
|
|
48
|
+
requestAnimationFrame(() => {
|
|
49
|
+
c.current = !1;
|
|
50
|
+
});
|
|
51
|
+
},
|
|
52
|
+
onFocusCapture: (e) => {
|
|
53
|
+
a.onFocusCapture(e), c.current ? r(!1) : r(!0);
|
|
54
|
+
},
|
|
55
|
+
onKeyDownCapture: (e) => {
|
|
56
|
+
a.onKeyDownCapture(e), (e.key === "ArrowDown" || e.key === "ArrowUp") && r(!0);
|
|
57
|
+
},
|
|
58
|
+
onBlurCapture: (e) => {
|
|
59
|
+
if (r(!1), !s.current) {
|
|
60
|
+
if (l.current) {
|
|
61
|
+
l.current = !1;
|
|
41
62
|
return;
|
|
42
63
|
}
|
|
43
|
-
|
|
64
|
+
a.onBlurCapture(e);
|
|
44
65
|
}
|
|
45
66
|
}
|
|
46
67
|
}, I = {
|
|
47
68
|
role: "combobox",
|
|
48
|
-
"aria-expanded": t &&
|
|
69
|
+
"aria-expanded": t && v,
|
|
49
70
|
"aria-haspopup": "listbox",
|
|
50
71
|
"aria-controls": t ? n : void 0,
|
|
51
72
|
"aria-autocomplete": "list",
|
|
52
|
-
"aria-activedescendant":
|
|
53
|
-
onKeyDown: (
|
|
54
|
-
|
|
73
|
+
"aria-activedescendant": o.highlightedIndex >= 0 ? o.getOptionId(n, o.highlightedIndex) : void 0,
|
|
74
|
+
onKeyDown: (e) => {
|
|
75
|
+
e.key === "Tab" && (l.current = !0), o.handleKeyDown(e);
|
|
55
76
|
}
|
|
56
|
-
},
|
|
77
|
+
}, P = {
|
|
57
78
|
id: n,
|
|
58
79
|
role: "listbox",
|
|
59
|
-
ref:
|
|
60
|
-
onMouseDownCapture: (
|
|
61
|
-
|
|
80
|
+
ref: g,
|
|
81
|
+
onMouseDownCapture: (e) => {
|
|
82
|
+
s.current = !0;
|
|
62
83
|
},
|
|
63
|
-
onMouseUpCapture: (
|
|
64
|
-
|
|
84
|
+
onMouseUpCapture: (e) => {
|
|
85
|
+
s.current = !1;
|
|
65
86
|
},
|
|
66
|
-
onMouseLeave: (
|
|
67
|
-
|
|
87
|
+
onMouseLeave: (e) => {
|
|
88
|
+
s.current = !1;
|
|
68
89
|
}
|
|
69
|
-
},
|
|
70
|
-
id:
|
|
90
|
+
}, K = b((e, R = !1) => ({
|
|
91
|
+
id: o.getOptionId(n, e),
|
|
71
92
|
role: "option",
|
|
72
|
-
"aria-selected":
|
|
73
|
-
}), [
|
|
93
|
+
"aria-selected": R
|
|
94
|
+
}), [o.getOptionId, n]);
|
|
74
95
|
return {
|
|
75
|
-
containerProps:
|
|
96
|
+
containerProps: F,
|
|
76
97
|
inputProps: I,
|
|
77
|
-
listboxProps:
|
|
78
|
-
getOptionProps:
|
|
79
|
-
highlightedIndex:
|
|
80
|
-
setHighlightedIndex:
|
|
81
|
-
getOptionId:
|
|
98
|
+
listboxProps: P,
|
|
99
|
+
getOptionProps: K,
|
|
100
|
+
highlightedIndex: o.highlightedIndex,
|
|
101
|
+
setHighlightedIndex: o.setHighlightedIndex,
|
|
102
|
+
getOptionId: o.getOptionId,
|
|
103
|
+
isKeyboardFocused: h
|
|
82
104
|
};
|
|
83
105
|
}
|
|
84
106
|
export {
|
|
85
|
-
|
|
107
|
+
_ as useCombobox
|
|
86
108
|
};
|
|
87
109
|
//# 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 } 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\nexport interface UseComboboxReturn {\n /**\n * Props to spread on the container element (handles dismiss on focus out)\n */\n containerProps: UseDismissOnFocusOutReturn<HTMLElement>;\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 };\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/**\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}: UseComboboxOptions<T>): UseComboboxReturn {\n const listboxRef = useRef<HTMLDivElement | null>(null);\n const pointerDownInListboxRef = useRef(false);\n const tabKeyPressedRef = useRef(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 }\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 });\n \n // Focus out / Escape dismissal\n const dismissHandlers = useDismissOnFocusOut({\n onFocusOut: closeDropdown,\n onEscape: closeDropdown,\n disabled: !isOpen\n });\n\n const containerProps: UseDismissOnFocusOutReturn<HTMLElement> = {\n ...dismissHandlers,\n onBlurCapture: (e) => {\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 id: navigation.getOptionId(listboxId, index),\n role: 'option' as const,\n 'aria-selected': selected\n }),\n [navigation.getOptionId, listboxId]\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 };\n}\n"],"names":["useRef","useCallback","useEffect","useComboboxNavigation","useDismissOnFocusOut","useCombobox","items","isOpen","onOpenChange","onSelect","listboxId","loop","disabled","optionSelector","hasItems","listboxRef","pointerDownInListboxRef","tabKeyPressedRef","shouldShowExpanded","undefined","length","closeDropdown","current","navigation","onClose","onOpen","dismissHandlers","onFocusOut","onEscape","containerProps","onBlurCapture","e","inputProps","role","highlightedIndex","getOptionId","onKeyDown","key","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/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\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 };\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}: 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 }\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 });\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 // Reset after the full pointer interaction (down → focus → up).\n // Delayed so any setTimeout-based auto-focus (e.g. Popover open)\n // still sees pointerFocusRef=true and doesn't flip to keyboard mode.\n requestAnimationFrame(() => {\n pointerFocusRef.current = false;\n });\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 // 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 id: navigation.getOptionId(listboxId, index),\n role: 'option' as const,\n 'aria-selected': selected\n }),\n [navigation.getOptionId, listboxId]\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","listboxRef","pointerDownInListboxRef","tabKeyPressedRef","pointerFocusRef","isKeyboardFocused","setIsKeyboardFocused","shouldShowExpanded","undefined","length","closeDropdown","current","navigation","onClose","onOpen","dismissHandlers","onFocusOut","onEscape","containerProps","onPointerMove","onPointerDown","onPointerUp","requestAnimationFrame","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
package/dist/index70.js
CHANGED
package/dist/index75.js
CHANGED
|
@@ -1,8 +1,111 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
var u = Object.defineProperty;
|
|
2
|
+
var l = (i, e, t) => e in i ? u(i, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : i[e] = t;
|
|
3
|
+
var r = (i, e, t) => l(i, typeof e != "symbol" ? e + "" : e, t);
|
|
4
|
+
const h = "sr-only", a = "data-batch-id";
|
|
5
|
+
let s = null;
|
|
6
|
+
function d() {
|
|
7
|
+
return s || (s = new f()), s;
|
|
8
|
+
}
|
|
9
|
+
class f {
|
|
10
|
+
constructor() {
|
|
11
|
+
r(this, "container", null);
|
|
12
|
+
r(this, "assertiveLog", null);
|
|
13
|
+
r(this, "politeLog", null);
|
|
14
|
+
r(this, "cleanupTimers", /* @__PURE__ */ new Map());
|
|
15
|
+
r(this, "ready", !1);
|
|
16
|
+
r(this, "pendingQueue", []);
|
|
17
|
+
typeof document > "u" || (this.container = document.createElement("div"), this.container.dataset.liveAnnouncer = "true", this.container.className = h, this.assertiveLog = this.createLog("assertive"), this.politeLog = this.createLog("polite"), this.container.appendChild(this.assertiveLog), this.container.appendChild(this.politeLog), document.body.prepend(this.container), this.isTestEnvironment() ? this.ready = !0 : setTimeout(() => {
|
|
18
|
+
this.ready = !0, this.flushPendingQueue();
|
|
19
|
+
}, 100));
|
|
20
|
+
}
|
|
21
|
+
// -----------------------------------------------------------------------
|
|
22
|
+
// Public
|
|
23
|
+
// -----------------------------------------------------------------------
|
|
24
|
+
announce(e, t = {}) {
|
|
25
|
+
const n = {
|
|
26
|
+
assertiveness: t.assertiveness ?? "polite",
|
|
27
|
+
timeout: t.timeout ?? 7e3,
|
|
28
|
+
batchId: t.batchId ?? ""
|
|
29
|
+
};
|
|
30
|
+
if (!this.ready) {
|
|
31
|
+
this.pendingQueue.push({
|
|
32
|
+
message: e,
|
|
33
|
+
options: n
|
|
34
|
+
});
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
this.doAnnounce(e, n);
|
|
38
|
+
}
|
|
39
|
+
clear(e) {
|
|
40
|
+
(!e || e === "assertive") && this.clearLog(this.assertiveLog), (!e || e === "polite") && this.clearLog(this.politeLog);
|
|
41
|
+
}
|
|
42
|
+
destroy() {
|
|
43
|
+
this.cleanupTimers.forEach((e) => clearTimeout(e)), this.cleanupTimers.clear(), this.container?.remove(), this.container = null, this.assertiveLog = null, this.politeLog = null, this.ready = !1, this.pendingQueue = [], s === this && (s = null);
|
|
44
|
+
}
|
|
45
|
+
isAttached() {
|
|
46
|
+
return this.container?.isConnected ?? !1;
|
|
47
|
+
}
|
|
48
|
+
// -----------------------------------------------------------------------
|
|
49
|
+
// Private
|
|
50
|
+
// -----------------------------------------------------------------------
|
|
51
|
+
createLog(e) {
|
|
52
|
+
const t = document.createElement("div");
|
|
53
|
+
return t.setAttribute("role", "log"), t.setAttribute("aria-live", e), t.setAttribute("aria-relevant", "additions"), t;
|
|
54
|
+
}
|
|
55
|
+
doAnnounce(e, t) {
|
|
56
|
+
const n = t.assertiveness === "assertive" ? this.assertiveLog : this.politeLog;
|
|
57
|
+
if (!n) return;
|
|
58
|
+
if (t.batchId) {
|
|
59
|
+
const c = n.querySelector(`[${a}="${CSS.escape(t.batchId)}"]`);
|
|
60
|
+
c && this.removeNode(c);
|
|
61
|
+
}
|
|
62
|
+
const o = document.createElement("div");
|
|
63
|
+
if (o.textContent = e, t.batchId && o.setAttribute(a, t.batchId), n.appendChild(o), e !== "") {
|
|
64
|
+
const c = setTimeout(() => {
|
|
65
|
+
this.removeNode(o);
|
|
66
|
+
}, t.timeout);
|
|
67
|
+
this.cleanupTimers.set(o, c);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
removeNode(e) {
|
|
71
|
+
const t = this.cleanupTimers.get(e);
|
|
72
|
+
t && (clearTimeout(t), this.cleanupTimers.delete(e)), e.remove();
|
|
73
|
+
}
|
|
74
|
+
clearLog(e) {
|
|
75
|
+
e && (Array.from(e.children).forEach((t) => {
|
|
76
|
+
const n = this.cleanupTimers.get(t);
|
|
77
|
+
n && (clearTimeout(n), this.cleanupTimers.delete(t));
|
|
78
|
+
}), e.innerHTML = "");
|
|
79
|
+
}
|
|
80
|
+
flushPendingQueue() {
|
|
81
|
+
this.pendingQueue.splice(0).forEach(({
|
|
82
|
+
message: t,
|
|
83
|
+
options: n
|
|
84
|
+
}) => this.doAnnounce(t, n));
|
|
85
|
+
}
|
|
86
|
+
isTestEnvironment() {
|
|
87
|
+
try {
|
|
88
|
+
if (typeof IS_REACT_ACT_ENVIRONMENT == "boolean" && IS_REACT_ACT_ENVIRONMENT || typeof jest < "u" || typeof vitest < "u") return !0;
|
|
89
|
+
} catch {
|
|
90
|
+
}
|
|
91
|
+
return !1;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
function T(i, e) {
|
|
95
|
+
const t = typeof e == "string" ? {
|
|
96
|
+
assertiveness: e
|
|
97
|
+
} : e ?? {};
|
|
98
|
+
d().announce(i, t);
|
|
99
|
+
}
|
|
100
|
+
function p(i) {
|
|
101
|
+
s?.clear(i);
|
|
102
|
+
}
|
|
103
|
+
function g() {
|
|
104
|
+
s?.destroy();
|
|
105
|
+
}
|
|
5
106
|
export {
|
|
6
|
-
|
|
107
|
+
T as announce,
|
|
108
|
+
p as clearAnnouncer,
|
|
109
|
+
g as destroyAnnouncer
|
|
7
110
|
};
|
|
8
111
|
//# sourceMappingURL=index75.js.map
|
package/dist/index75.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index75.js","sources":["../src/utils/virtualClick.ts"],"sourcesContent":["/**\n * Input/virtual click detection helpers.\n */\n\nconst isAndroid = () =>\n typeof navigator !== 'undefined' && /Android/i.test(navigator.userAgent);\n\nexport const isVirtualClick = (event: MouseEvent | PointerEvent): boolean => {\n const pointerType = 'pointerType' in event ? event.pointerType : undefined;\n\n // JAWS/NVDA with Firefox.\n if (pointerType === '' && event.isTrusted) {\n return true;\n }\n\n // Android TalkBack's detail value varies depending on listener type.\n if (isAndroid() && pointerType) {\n return event.type === 'click' && event.buttons === 1;\n }\n\n // Most browsers: virtual click has detail === 0 and no pointerType.\n return event.detail === 0 && !pointerType;\n};\n\n\n"],"names":["isAndroid","navigator","test","userAgent","isVirtualClick","event","pointerType","undefined","isTrusted","type","buttons","detail"],"mappings":"AAIA,MAAMA,IAAYA,MAChB,OAAOC,YAAc,OAAe,WAAWC,KAAKD,UAAUE,SAAS,GAE5DC,IAAiBA,CAACC,MAA8C;AAC3E,QAAMC,IAAc,iBAAiBD,IAAQA,EAAMC,cAAcC;AAGjE,SAAID,MAAgB,MAAMD,EAAMG,YACvB,KAILR,EAAAA,KAAeM,IACVD,EAAMI,SAAS,WAAWJ,EAAMK,YAAY,IAI9CL,EAAMM,WAAW,KAAK,CAACL;AAChC;"}
|
|
1
|
+
{"version":3,"file":"index75.js","sources":["../src/utils/a11y/liveAnnouncer/LiveAnnouncer.ts"],"sourcesContent":["/**\n * LiveAnnouncer — singleton vanilla-DOM announcer for screen readers.\n *\n * Architecture:\n * - Prepends a visually-hidden container to document.body on first use.\n * - Two <div role=\"log\" aria-live=\"...\"> regions: one polite, one assertive.\n * - Each announce() appends a NEW child node (aria-relevant=\"additions\" makes\n * screen readers announce only additions, never re-read existing content).\n * - Child nodes auto-remove after a timeout (default 7 s) to keep the DOM clean.\n * - batchId option: if a node with the same batchId already exists in a log,\n * it is replaced — so only the final value is announced (e.g. \"N results\").\n *\n * No React dependency. No role=\"status\" or role=\"alert\" (avoids double-announce\n * bugs on iOS VoiceOver).\n */\n\nexport type Assertiveness = 'assertive' | 'polite';\n\nexport interface AnnounceOptions {\n /** Default: 'polite' */\n assertiveness?: Assertiveness;\n /** Auto-clear timeout in ms. Default: 7000 */\n timeout?: number;\n /**\n * When provided, any pending node with the same batchId is replaced rather\n * than appending a second node. Useful for rapidly-updating counts\n * (e.g. search results, selection count).\n */\n batchId?: string;\n}\n\nconst DEFAULT_TIMEOUT = 7000;\nconst SAFARI_INIT_DELAY = 100;\n\nconst SR_ONLY_CLASS = 'sr-only';\n\n/** Attribute used to find batchId nodes for replacement. */\nconst BATCH_ATTR = 'data-batch-id';\n\n// ---------------------------------------------------------------------------\n// Singleton\n// ---------------------------------------------------------------------------\n\nlet instance: LiveAnnouncer | null = null;\n\n/**\n * Get or create the singleton LiveAnnouncer.\n * Safe to call multiple times — returns the same instance.\n */\nfunction getInstance(): LiveAnnouncer {\n if (!instance) {\n instance = new LiveAnnouncer();\n }\n return instance;\n}\n\n// ---------------------------------------------------------------------------\n// Class\n// ---------------------------------------------------------------------------\n\nclass LiveAnnouncer {\n private container: HTMLDivElement | null = null;\n private assertiveLog: HTMLDivElement | null = null;\n private politeLog: HTMLDivElement | null = null;\n private cleanupTimers: Map<HTMLElement, ReturnType<typeof setTimeout>> = new Map();\n private ready = false;\n private pendingQueue: Array<{ message: string; options: Required<AnnounceOptions> }> = [];\n\n constructor() {\n if (typeof document === 'undefined') return;\n\n this.container = document.createElement('div');\n this.container.dataset.liveAnnouncer = 'true';\n this.container.className = SR_ONLY_CLASS;\n\n this.assertiveLog = this.createLog('assertive');\n this.politeLog = this.createLog('polite');\n\n this.container.appendChild(this.assertiveLog);\n this.container.appendChild(this.politeLog);\n\n // Prepend so screen readers encounter it early in the DOM.\n document.body.prepend(this.container);\n\n // Safari/VoiceOver ignores content injected within ~100 ms of the live\n // region being added to the DOM. Delay readiness accordingly.\n // In test environments, skip the delay.\n if (this.isTestEnvironment()) {\n this.ready = true;\n } else {\n setTimeout(() => {\n this.ready = true;\n this.flushPendingQueue();\n }, SAFARI_INIT_DELAY);\n }\n }\n\n // -----------------------------------------------------------------------\n // Public\n // -----------------------------------------------------------------------\n\n announce(message: string, options: AnnounceOptions = {}): void {\n const resolved: Required<AnnounceOptions> = {\n assertiveness: options.assertiveness ?? 'polite',\n timeout: options.timeout ?? DEFAULT_TIMEOUT,\n batchId: options.batchId ?? '',\n };\n\n if (!this.ready) {\n this.pendingQueue.push({ message, options: resolved });\n return;\n }\n\n this.doAnnounce(message, resolved);\n }\n\n clear(assertiveness?: Assertiveness): void {\n if (!assertiveness || assertiveness === 'assertive') {\n this.clearLog(this.assertiveLog);\n }\n if (!assertiveness || assertiveness === 'polite') {\n this.clearLog(this.politeLog);\n }\n }\n\n destroy(): void {\n // Cancel all pending auto-clear timers.\n this.cleanupTimers.forEach((timer) => clearTimeout(timer));\n this.cleanupTimers.clear();\n\n this.container?.remove();\n this.container = null;\n this.assertiveLog = null;\n this.politeLog = null;\n this.ready = false;\n this.pendingQueue = [];\n\n if (instance === this) {\n instance = null;\n }\n }\n\n isAttached(): boolean {\n return this.container?.isConnected ?? false;\n }\n\n // -----------------------------------------------------------------------\n // Private\n // -----------------------------------------------------------------------\n\n private createLog(ariaLive: Assertiveness): HTMLDivElement {\n const log = document.createElement('div');\n log.setAttribute('role', 'log');\n log.setAttribute('aria-live', ariaLive);\n log.setAttribute('aria-relevant', 'additions');\n return log;\n }\n\n private doAnnounce(message: string, options: Required<AnnounceOptions>): void {\n const log = options.assertiveness === 'assertive' ? this.assertiveLog : this.politeLog;\n if (!log) return;\n\n // batchId dedup: remove any existing node with the same batchId.\n if (options.batchId) {\n const existing = log.querySelector(`[${BATCH_ATTR}=\"${CSS.escape(options.batchId)}\"]`) as HTMLElement | null;\n if (existing) {\n this.removeNode(existing);\n }\n }\n\n const node = document.createElement('div');\n node.textContent = message;\n\n if (options.batchId) {\n node.setAttribute(BATCH_ATTR, options.batchId);\n }\n\n log.appendChild(node);\n\n // Auto-remove after timeout to keep the DOM clean.\n if (message !== '') {\n const timer = setTimeout(() => {\n this.removeNode(node);\n }, options.timeout);\n this.cleanupTimers.set(node, timer);\n }\n }\n\n private removeNode(node: HTMLElement): void {\n const timer = this.cleanupTimers.get(node);\n if (timer) {\n clearTimeout(timer);\n this.cleanupTimers.delete(node);\n }\n node.remove();\n }\n\n private clearLog(log: HTMLDivElement | null): void {\n if (!log) return;\n // Cancel timers for all children in this log.\n Array.from(log.children).forEach((child) => {\n const timer = this.cleanupTimers.get(child as HTMLElement);\n if (timer) {\n clearTimeout(timer);\n this.cleanupTimers.delete(child as HTMLElement);\n }\n });\n log.innerHTML = '';\n }\n\n private flushPendingQueue(): void {\n const queued = this.pendingQueue.splice(0);\n queued.forEach(({ message, options }) => this.doAnnounce(message, options));\n }\n\n private isTestEnvironment(): boolean {\n try {\n // React 18+ test flag\n // @ts-expect-error – global test flag\n if (typeof IS_REACT_ACT_ENVIRONMENT === 'boolean' && IS_REACT_ACT_ENVIRONMENT) return true;\n // Jest / Vitest\n // @ts-expect-error – jest global may not be typed\n if (typeof jest !== 'undefined') return true;\n // @ts-expect-error – Vitest global\n if (typeof vitest !== 'undefined') return true;\n } catch {\n // ignore\n }\n return false;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Public imperative API (module-level)\n// ---------------------------------------------------------------------------\n\n/**\n * Announce a message to screen readers.\n *\n * Works anywhere — React components, event handlers, thunks, vanilla JS.\n * The singleton live region is lazily created on first call.\n *\n * @example\n * announce('5 results found');\n * announce('Error: upload failed', { assertiveness: 'assertive' });\n * announce('3 items selected', { batchId: 'selection-count' });\n */\nexport function announce(message: string, options?: AnnounceOptions): void;\nexport function announce(message: string, assertiveness?: Assertiveness): void;\nexport function announce(\n message: string,\n optionsOrAssertiveness?: AnnounceOptions | Assertiveness\n): void {\n const options: AnnounceOptions =\n typeof optionsOrAssertiveness === 'string'\n ? { assertiveness: optionsOrAssertiveness }\n : optionsOrAssertiveness ?? {};\n\n getInstance().announce(message, options);\n}\n\n/**\n * Clear all pending announcements.\n * @param assertiveness — if omitted, clears both polite and assertive logs.\n */\nexport function clearAnnouncer(assertiveness?: Assertiveness): void {\n instance?.clear(assertiveness);\n}\n\n/**\n * Remove the live-region container from the DOM and reset the singleton.\n * Typically called when the host app unmounts (via LiveAnnouncerProvider).\n */\nexport function destroyAnnouncer(): void {\n instance?.destroy();\n}\n\n/**\n * Check whether the live-region container is currently in the DOM.\n */\nexport function isAnnouncerAttached(): boolean {\n return instance?.isAttached() ?? false;\n}\n"],"names":["SR_ONLY_CLASS","BATCH_ATTR","instance","getInstance","LiveAnnouncer","constructor","container","assertiveLog","politeLog","cleanupTimers","Map","ready","pendingQueue","document","createElement","dataset","liveAnnouncer","className","createLog","appendChild","body","prepend","isTestEnvironment","setTimeout","flushPendingQueue","SAFARI_INIT_DELAY","announce","message","options","resolved","assertiveness","timeout","DEFAULT_TIMEOUT","batchId","push","doAnnounce","clear","clearLog","destroy","forEach","timer","clearTimeout","remove","isAttached","isConnected","ariaLive","log","setAttribute","existing","querySelector","CSS","escape","removeNode","node","textContent","set","get","delete","Array","from","children","child","innerHTML","queued","splice","IS_REACT_ACT_ENVIRONMENT","jest","vitest","optionsOrAssertiveness","clearAnnouncer","destroyAnnouncer"],"mappings":"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"}
|