se-design 1.0.83-dev.2 → 1.0.83-dev.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index29.js +32 -28
- package/dist/index29.js.map +1 -1
- package/dist/index70.js +22 -22
- package/dist/index70.js.map +1 -1
- package/dist/index80.js +21 -18
- package/dist/index80.js.map +1 -1
- package/package.json +1 -1
package/dist/index29.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import r, { useState as $, useMemo as j, useRef as
|
|
2
|
-
import { Icon as
|
|
1
|
+
import r, { useState as $, useMemo as j, useRef as L, useEffect as B } from "react";
|
|
2
|
+
import { Icon as O } from "./index6.js";
|
|
3
3
|
import { Popover as z } from "./index19.js";
|
|
4
4
|
import { MenuList as H } from "./index18.js";
|
|
5
5
|
import { useStableId as U } from "./index205.js";
|
|
@@ -21,19 +21,19 @@ const re = ({
|
|
|
21
21
|
onTabChange: m,
|
|
22
22
|
primaryTabCount: u,
|
|
23
23
|
headingLevel: g,
|
|
24
|
-
id:
|
|
25
|
-
ariaLabel:
|
|
24
|
+
id: A,
|
|
25
|
+
ariaLabel: F = "Tabs",
|
|
26
26
|
ariaLabelledBy: M,
|
|
27
27
|
panelId: p
|
|
28
28
|
}) => {
|
|
29
|
-
const K = i || (o[0] ? o[0].id : ""), [b, h] = $(K), [w, y] = $(!1), T = u ?? o?.length, f = o.slice(0, T), c = o.slice(T),
|
|
30
|
-
const e = f.filter((
|
|
29
|
+
const K = i || (o[0] ? o[0].id : ""), [b, h] = $(K), [w, y] = $(!1), T = u ?? o?.length, f = o.slice(0, T), c = o.slice(T), l = c.find((e) => e.id === b), E = o.some((e) => e.renderTabContent), k = U(A, "tabs"), R = j(() => {
|
|
30
|
+
const e = f.filter((s) => !s.disabled), t = c.filter((s) => !s.disabled), n = e.map((s) => s.id);
|
|
31
31
|
return t.length > 0 ? [...n, "overflow"] : n;
|
|
32
32
|
}, [f, c]), {
|
|
33
|
-
getTabProps:
|
|
33
|
+
getTabProps: x,
|
|
34
34
|
getPanelProps: S,
|
|
35
35
|
getTabListProps: _,
|
|
36
|
-
handleKeyDown:
|
|
36
|
+
handleKeyDown: I,
|
|
37
37
|
setFocusedTabId: C
|
|
38
38
|
} = V({
|
|
39
39
|
itemIds: R,
|
|
@@ -42,11 +42,11 @@ const re = ({
|
|
|
42
42
|
idBase: k,
|
|
43
43
|
includePanelLinks: E || !!p,
|
|
44
44
|
externalPanelId: p
|
|
45
|
-
}),
|
|
45
|
+
}), N = L(null), v = L(!1);
|
|
46
46
|
B(() => {
|
|
47
47
|
h(i || "");
|
|
48
48
|
}, [i]);
|
|
49
|
-
const
|
|
49
|
+
const P = (e) => {
|
|
50
50
|
h(e?.id), m?.(e?.id);
|
|
51
51
|
}, D = (e, t) => e.id === t;
|
|
52
52
|
if (g && o.length === 1) {
|
|
@@ -63,19 +63,19 @@ const re = ({
|
|
|
63
63
|
className: "se-design-tabs flex items-stretch relative border rounded-md border-[var(--color-gray-400)] w-fit",
|
|
64
64
|
"data-automation-id": "tabs-container"
|
|
65
65
|
}, _({
|
|
66
|
-
ariaLabel:
|
|
66
|
+
ariaLabel: F,
|
|
67
67
|
ariaLabelledBy: M
|
|
68
68
|
})), f.map((e) => {
|
|
69
|
-
const t = b === e.id, n = !!e.disabled,
|
|
69
|
+
const t = b === e.id, n = !!e.disabled, s = x(e.id);
|
|
70
70
|
return /* @__PURE__ */ r.createElement("button", d({
|
|
71
71
|
type: "button",
|
|
72
72
|
key: e.id
|
|
73
|
-
},
|
|
73
|
+
}, s, {
|
|
74
74
|
disabled: n,
|
|
75
75
|
"aria-label": e.ariaLabel,
|
|
76
76
|
onFocus: () => !n && C(e.id),
|
|
77
|
-
onKeyDown:
|
|
78
|
-
onClick: () =>
|
|
77
|
+
onKeyDown: I,
|
|
78
|
+
onClick: () => P(e),
|
|
79
79
|
className: `se-design-tab-item flex items-center text-base px-3 py-0.5 min-w-0 border-l first:border-l-0 first:rounded-l-[0.3rem] last:rounded-r-[0.3rem] border-[var(--color-gray-400)] ${n ? "" : "focus-outline"} ${n ? "text-[var(--color-gray-400)] cursor-not-allowed" : t ? "se-design-tab-item-active text-[var(--color-white)] bg-[var(--color-blue-500)] font-medium hover:cursor-pointer" : "text-[var(--color-gray-700)] font-normal hover:bg-[var(--color-gray-50)] hover:text-[var(--color-gray-900)] cursor-pointer transition-all duration-200 ease-in-out"}`,
|
|
80
80
|
"data-automation-id": `tab-item-${e.automationId || e.id || ""}`
|
|
81
81
|
}), e.label);
|
|
@@ -85,20 +85,20 @@ const re = ({
|
|
|
85
85
|
noBorder: !0,
|
|
86
86
|
disableClickToggle: !0,
|
|
87
87
|
onPopoverToggle: (e) => {
|
|
88
|
-
e || (v.current &&
|
|
88
|
+
e || (v.current && N.current?.focus(), v.current = !1);
|
|
89
89
|
},
|
|
90
90
|
renderPopoverSrcElement: ({
|
|
91
91
|
displayPopover: e,
|
|
92
92
|
togglePopover: t
|
|
93
93
|
}) => {
|
|
94
|
-
const n =
|
|
94
|
+
const n = x("overflow"), s = l ? q(l.id, k) : void 0;
|
|
95
95
|
return /* @__PURE__ */ r.createElement("div", d({}, n, {
|
|
96
96
|
ref: (a) => {
|
|
97
|
-
|
|
97
|
+
N.current = a, n.ref(a);
|
|
98
98
|
},
|
|
99
|
-
"aria-selected": !!
|
|
100
|
-
"aria-label":
|
|
101
|
-
"aria-controls":
|
|
99
|
+
"aria-selected": !!l,
|
|
100
|
+
"aria-label": l?.label ? void 0 : `More tabs (${c.length})`,
|
|
101
|
+
"aria-controls": s,
|
|
102
102
|
"aria-haspopup": "true",
|
|
103
103
|
"aria-expanded": e,
|
|
104
104
|
onClick: () => {
|
|
@@ -107,21 +107,25 @@ const re = ({
|
|
|
107
107
|
onFocus: () => C("overflow"),
|
|
108
108
|
"data-automation-id": "tabs-kebab-menu",
|
|
109
109
|
onKeyDown: (a) => {
|
|
110
|
-
a.key === "Enter" || a.key === " " || a.key === "ArrowDown" ? (a.preventDefault(), v.current = !0, t(!0)) : a.key === "ArrowUp" ? (a.preventDefault(), v.current = !0, t("last")) :
|
|
110
|
+
a.key === "Enter" || a.key === " " || a.key === "ArrowDown" ? (a.preventDefault(), v.current = !0, t(!0)) : a.key === "ArrowUp" ? (a.preventDefault(), v.current = !0, t("last")) : I(a);
|
|
111
111
|
},
|
|
112
|
-
className: `overflow-tabs-src-element focus-outline border-l px-3 py-0.5 rounded-r-md font-medium hover:cursor-pointer transition-all duration-200 ease-in-out ${e ? "bg-[var(--color-blue-100)]" : ""} ${
|
|
112
|
+
className: `overflow-tabs-src-element focus-outline border-l px-3 py-0.5 rounded-r-md font-medium hover:cursor-pointer transition-all duration-200 ease-in-out ${e ? "bg-[var(--color-blue-100)]" : ""} ${l?.label ? "bg-[var(--color-blue-500)]" : "hover:bg-[var(--color-gray-50)]"}`,
|
|
113
113
|
onMouseEnter: () => y(!0),
|
|
114
114
|
onMouseLeave: () => y(!1)
|
|
115
|
-
}),
|
|
115
|
+
}), l?.label ? /* @__PURE__ */ r.createElement("span", {
|
|
116
|
+
className: "pointer-events-none flex items-center gap-1"
|
|
117
|
+
}, /* @__PURE__ */ r.createElement("span", {
|
|
116
118
|
className: "text-[var(--color-white)]"
|
|
117
|
-
},
|
|
119
|
+
}, l?.label), /* @__PURE__ */ r.createElement(O, {
|
|
118
120
|
name: "chevron",
|
|
119
121
|
rotation: e ? "180" : "0",
|
|
120
122
|
stroke: w ? "var(--color-gray-100)" : "var(--color-white)"
|
|
121
|
-
})) : /* @__PURE__ */ r.createElement(
|
|
123
|
+
})) : /* @__PURE__ */ r.createElement("span", {
|
|
124
|
+
className: "pointer-events-none"
|
|
125
|
+
}, /* @__PURE__ */ r.createElement(O, {
|
|
122
126
|
name: "kebab-menu",
|
|
123
127
|
fill: w ? "var(--color-gray-900)" : "var(--color-gray-700)"
|
|
124
|
-
}));
|
|
128
|
+
})));
|
|
125
129
|
},
|
|
126
130
|
renderPopoverContents: ({
|
|
127
131
|
closePopoverCb: e
|
|
@@ -131,7 +135,7 @@ const re = ({
|
|
|
131
135
|
label: t?.label,
|
|
132
136
|
automationId: t?.automationId || t?.id,
|
|
133
137
|
onClick: () => {
|
|
134
|
-
|
|
138
|
+
P(t), e();
|
|
135
139
|
}
|
|
136
140
|
}))
|
|
137
141
|
})
|
package/dist/index29.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index29.js","sources":["../src/components/Tabs/index.tsx"],"sourcesContent":["import React, { FC, ReactNode, useState, useEffect, useMemo, useRef } from 'react';\nimport { Icon } from '../Icon';\nimport { Popover } from '../Popover';\nimport { MenuList } from '../MenuList';\nimport { useStableId } from '../../utils/useStableId';\nimport { useTabsA11y, getPanelId } from '../../utils/a11y';\n\nimport './style.scss';\n\ninterface TabProps {\n label: string;\n id: string;\n disabled?: boolean;\n renderTabContent?: (tab: TabProps) => ReactNode;\n automationId?: string;\n ariaLabel?: string;\n}\ninterface TabsProps {\n defaultActiveTab?: string;\n tabs: TabProps[];\n onTabChange?: (tabId: string) => void;\n primaryTabCount?: number; // prop for controlling primary tabs\n headingLevel?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'span'; // heading tag to render single tab as a heading element when only one tab is present\n automationId?: string;\n id?: string; // custom ID for baseId (passed to useStableId)\n ariaLabel?: string; // Accessible name when no visible label exists\n ariaLabelledBy?: string; // ID of element that labels this tablist (preferred over ariaLabel)\n panelId?: string; // When consumer manages a single external panel, pass its id here\n}\n\nexport const Tabs: FC<TabsProps> = ({\n defaultActiveTab,\n tabs,\n onTabChange,\n primaryTabCount,\n headingLevel: HeadingTag,\n id,\n ariaLabel = 'Tabs',\n ariaLabelledBy,\n panelId\n}) => {\n const defaultTabId = defaultActiveTab || (tabs[0] ? tabs[0].id : '');\n const [activeTab, setActiveTab] = useState(defaultTabId);\n const [isIconTabHover, setIsIconTabHover] = useState(false);\n\n const visibleTabCount = primaryTabCount ?? tabs?.length;\n const visibleTabs = tabs.slice(0, visibleTabCount);\n const overflowTabs = tabs.slice(visibleTabCount);\n const activeOverflowTab = overflowTabs.find((tab) => tab.id === activeTab);\n\n // Only render internal panels if at least one tab provides content via renderTabContent\n const hasPanelContent = tabs.some(t => t.renderTabContent);\n\n // A11y setup\n const baseId = useStableId(id, 'tabs');\n const itemIds = useMemo(() => {\n const enabledVisibleTabs = visibleTabs.filter(t => !t.disabled);\n const enabledOverflowTabs = overflowTabs.filter(t => !t.disabled);\n const visibleIds = enabledVisibleTabs.map(t => t.id);\n return enabledOverflowTabs.length > 0 ? [...visibleIds, 'overflow'] : visibleIds;\n }, [visibleTabs, overflowTabs]);\n\n const { getTabProps, getPanelProps, getTabListProps, handleKeyDown, setFocusedTabId } = useTabsA11y({\n itemIds,\n activeItem: activeTab,\n orientation: 'horizontal',\n idBase: baseId,\n includePanelLinks: hasPanelContent || !!panelId,\n externalPanelId: panelId\n });\n\n // Ref for the overflow button div — needed to return focus after menu closes\n const overflowDivRef = useRef<HTMLDivElement>(null);\n // Track whether the overflow popover was opened via keyboard — only return focus\n // programmatically in that case (mouse-opened popovers should not trigger :focus-visible on close)\n const wasKeyboardOpenedRef = useRef(false);\n\n useEffect(() => {\n setActiveTab(defaultActiveTab || '');\n }, [defaultActiveTab]);\n\n const handleTabClick = (tab: TabProps) => {\n setActiveTab(tab?.id);\n onTabChange?.(tab?.id);\n };\n\n const isTabActive = (tab: TabProps, activeTab: string) => {\n return tab.id === activeTab;\n };\n\n if (HeadingTag && tabs.length === 1) {\n const singleTab = tabs[0];\n return (\n <>\n <HeadingTag className=\"se-design-tabs se-design-tabs-heading\">\n {singleTab.label}\n </HeadingTag>\n <div className=\"se-design-tabs-content\">\n <div className=\"tab-content block\">\n {singleTab?.renderTabContent && singleTab?.renderTabContent(singleTab)}\n </div>\n </div>\n </>\n );\n }\n\n return (\n <>\n <div\n className=\"se-design-tabs flex items-stretch relative border rounded-md border-[var(--color-gray-400)] w-fit\"\n data-automation-id=\"tabs-container\"\n {...getTabListProps({ ariaLabel, ariaLabelledBy })}\n >\n {visibleTabs.map((tab) => {\n const isActive = activeTab === tab.id;\n const isDisabled = !!tab.disabled;\n const tabProps = getTabProps(tab.id);\n return (\n <button\n type=\"button\"\n key={tab.id}\n {...tabProps}\n disabled={isDisabled}\n aria-label={tab.ariaLabel}\n onFocus={() => !isDisabled && setFocusedTabId(tab.id)}\n onKeyDown={handleKeyDown}\n onClick={() => handleTabClick(tab)}\n className={`se-design-tab-item flex items-center text-base px-3 py-0.5 min-w-0 border-l first:border-l-0 first:rounded-l-[0.3rem] last:rounded-r-[0.3rem] border-[var(--color-gray-400)] ${!isDisabled ? 'focus-outline' : ''} ${\n isDisabled\n ? 'text-[var(--color-gray-400)] cursor-not-allowed'\n : isActive\n ? 'se-design-tab-item-active text-[var(--color-white)] bg-[var(--color-blue-500)] font-medium hover:cursor-pointer'\n : 'text-[var(--color-gray-700)] font-normal hover:bg-[var(--color-gray-50)] hover:text-[var(--color-gray-900)] cursor-pointer transition-all duration-200 ease-in-out'\n }`}\n data-automation-id={`tab-item-${tab.automationId || tab.id || ''}`}\n >\n {tab.label}\n </button>\n );\n })}\n\n {overflowTabs.length > 0 && (\n <Popover\n className=\"se-design-overflow-tabs\"\n position=\"bottom-left\"\n noBorder\n disableClickToggle={true}\n onPopoverToggle={(isOpen) => {\n if (!isOpen) {\n // Only return focus programmatically when the popover was opened via keyboard.\n // Mouse-opened popovers must not call .focus() — programmatic focus after a\n // pointer interaction triggers :focus-visible intermittently across browsers.\n if (wasKeyboardOpenedRef.current) overflowDivRef.current?.focus();\n wasKeyboardOpenedRef.current = false;\n }\n }}\n renderPopoverSrcElement={({ displayPopover, togglePopover }) => {\n const overflowTabProps = getTabProps('overflow');\n const overflowAriaControls = activeOverflowTab\n ? getPanelId(activeOverflowTab.id, baseId)\n : undefined;\n\n return (\n <div\n {...overflowTabProps}\n ref={(el) => { overflowDivRef.current = el; overflowTabProps.ref(el); }}\n aria-selected={!!activeOverflowTab}\n aria-label={activeOverflowTab?.label ? undefined : `More tabs (${overflowTabs.length})`}\n aria-controls={overflowAriaControls}\n aria-haspopup=\"true\"\n aria-expanded={displayPopover}\n onClick={() => { wasKeyboardOpenedRef.current = false; togglePopover(true); }}\n onFocus={() => setFocusedTabId('overflow')}\n data-automation-id=\"tabs-kebab-menu\"\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ' || e.key === 'ArrowDown') {\n e.preventDefault();\n wasKeyboardOpenedRef.current = true;\n togglePopover(true);\n } else if (e.key === 'ArrowUp') {\n e.preventDefault();\n wasKeyboardOpenedRef.current = true;\n togglePopover('last');\n } else {\n handleKeyDown(e);\n }\n }}\n className={`overflow-tabs-src-element focus-outline border-l px-3 py-0.5 rounded-r-md font-medium hover:cursor-pointer transition-all duration-200 ease-in-out ${\n displayPopover ? 'bg-[var(--color-blue-100)]' : ''\n } ${activeOverflowTab?.label ? 'bg-[var(--color-blue-500)]' : 'hover:bg-[var(--color-gray-50)]'}`}\n onMouseEnter={() => setIsIconTabHover(true)}\n onMouseLeave={() => setIsIconTabHover(false)}\n >\n {activeOverflowTab?.label ? (\n <>\n <span className=\"text-[var(--color-white)]\">{activeOverflowTab?.label}</span>\n <Icon\n name=\"chevron\"\n rotation={displayPopover ? '180' : '0'}\n stroke={isIconTabHover ? 'var(--color-gray-100)' : 'var(--color-white)'}\n />\n </>\n ) : (\n <Icon name=\"kebab-menu\" fill={isIconTabHover ? 'var(--color-gray-900)' : 'var(--color-gray-700)'} />\n )}\n </div>\n );\n }}\n renderPopoverContents={({ closePopoverCb }) => (\n <MenuList\n items={overflowTabs.map((tab) => ({\n id: tab?.id,\n label: tab?.label,\n automationId: tab?.automationId || tab?.id,\n onClick: () => {\n handleTabClick(tab);\n closePopoverCb();\n }\n }))}\n />\n )}\n />\n )}\n </div>\n\n {hasPanelContent && (\n <div className=\"se-design-tabs-content\">\n {tabs.map((tab) => (\n <div\n key={tab.id}\n {...getPanelProps(tab.id)}\n className={`tab-content ${isTabActive(tab, activeTab) ? 'block' : 'hidden'}`}\n >\n {isTabActive(tab, activeTab) && tab.renderTabContent?.(tab)}\n </div>\n ))}\n </div>\n )}\n </>\n );\n};\n"],"names":["Tabs","defaultActiveTab","tabs","onTabChange","primaryTabCount","headingLevel","HeadingTag","id","ariaLabel","ariaLabelledBy","panelId","defaultTabId","activeTab","setActiveTab","useState","isIconTabHover","setIsIconTabHover","visibleTabCount","length","visibleTabs","slice","overflowTabs","activeOverflowTab","find","tab","hasPanelContent","some","t","renderTabContent","baseId","useStableId","itemIds","useMemo","enabledVisibleTabs","filter","disabled","enabledOverflowTabs","visibleIds","map","getTabProps","getPanelProps","getTabListProps","handleKeyDown","setFocusedTabId","useTabsA11y","activeItem","orientation","idBase","includePanelLinks","externalPanelId","overflowDivRef","useRef","wasKeyboardOpenedRef","useEffect","handleTabClick","isTabActive","singleTab","createElement","React","Fragment","className","label","_extends","isActive","isDisabled","tabProps","type","key","onFocus","onKeyDown","onClick","automationId","Popover","position","noBorder","disableClickToggle","onPopoverToggle","isOpen","current","focus","renderPopoverSrcElement","displayPopover","togglePopover","overflowTabProps","overflowAriaControls","getPanelId","undefined","ref","el","e","preventDefault","onMouseEnter","onMouseLeave","Icon","name","rotation","stroke","fill","renderPopoverContents","closePopoverCb","MenuList","items"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index29.js","sources":["../src/components/Tabs/index.tsx"],"sourcesContent":["import React, { FC, ReactNode, useState, useEffect, useMemo, useRef } from 'react';\nimport { Icon } from '../Icon';\nimport { Popover } from '../Popover';\nimport { MenuList } from '../MenuList';\nimport { useStableId } from '../../utils/useStableId';\nimport { useTabsA11y, getPanelId } from '../../utils/a11y';\n\nimport './style.scss';\n\ninterface TabProps {\n label: string;\n id: string;\n disabled?: boolean;\n renderTabContent?: (tab: TabProps) => ReactNode;\n automationId?: string;\n ariaLabel?: string;\n}\ninterface TabsProps {\n defaultActiveTab?: string;\n tabs: TabProps[];\n onTabChange?: (tabId: string) => void;\n primaryTabCount?: number; // prop for controlling primary tabs\n headingLevel?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'span'; // heading tag to render single tab as a heading element when only one tab is present\n automationId?: string;\n id?: string; // custom ID for baseId (passed to useStableId)\n ariaLabel?: string; // Accessible name when no visible label exists\n ariaLabelledBy?: string; // ID of element that labels this tablist (preferred over ariaLabel)\n panelId?: string; // When consumer manages a single external panel, pass its id here\n}\n\nexport const Tabs: FC<TabsProps> = ({\n defaultActiveTab,\n tabs,\n onTabChange,\n primaryTabCount,\n headingLevel: HeadingTag,\n id,\n ariaLabel = 'Tabs',\n ariaLabelledBy,\n panelId\n}) => {\n const defaultTabId = defaultActiveTab || (tabs[0] ? tabs[0].id : '');\n const [activeTab, setActiveTab] = useState(defaultTabId);\n const [isIconTabHover, setIsIconTabHover] = useState(false);\n\n const visibleTabCount = primaryTabCount ?? tabs?.length;\n const visibleTabs = tabs.slice(0, visibleTabCount);\n const overflowTabs = tabs.slice(visibleTabCount);\n const activeOverflowTab = overflowTabs.find((tab) => tab.id === activeTab);\n\n // Only render internal panels if at least one tab provides content via renderTabContent\n const hasPanelContent = tabs.some(t => t.renderTabContent);\n\n // A11y setup\n const baseId = useStableId(id, 'tabs');\n const itemIds = useMemo(() => {\n const enabledVisibleTabs = visibleTabs.filter(t => !t.disabled);\n const enabledOverflowTabs = overflowTabs.filter(t => !t.disabled);\n const visibleIds = enabledVisibleTabs.map(t => t.id);\n return enabledOverflowTabs.length > 0 ? [...visibleIds, 'overflow'] : visibleIds;\n }, [visibleTabs, overflowTabs]);\n\n const { getTabProps, getPanelProps, getTabListProps, handleKeyDown, setFocusedTabId } = useTabsA11y({\n itemIds,\n activeItem: activeTab,\n orientation: 'horizontal',\n idBase: baseId,\n includePanelLinks: hasPanelContent || !!panelId,\n externalPanelId: panelId\n });\n\n // Ref for the overflow button div — needed to return focus after menu closes\n const overflowDivRef = useRef<HTMLDivElement>(null);\n // Track whether the overflow popover was opened via keyboard — only return focus\n // programmatically in that case (mouse-opened popovers should not trigger :focus-visible on close)\n const wasKeyboardOpenedRef = useRef(false);\n\n useEffect(() => {\n setActiveTab(defaultActiveTab || '');\n }, [defaultActiveTab]);\n\n const handleTabClick = (tab: TabProps) => {\n setActiveTab(tab?.id);\n onTabChange?.(tab?.id);\n };\n\n const isTabActive = (tab: TabProps, activeTab: string) => {\n return tab.id === activeTab;\n };\n\n if (HeadingTag && tabs.length === 1) {\n const singleTab = tabs[0];\n return (\n <>\n <HeadingTag className=\"se-design-tabs se-design-tabs-heading\">\n {singleTab.label}\n </HeadingTag>\n <div className=\"se-design-tabs-content\">\n <div className=\"tab-content block\">\n {singleTab?.renderTabContent && singleTab?.renderTabContent(singleTab)}\n </div>\n </div>\n </>\n );\n }\n\n return (\n <>\n <div\n className=\"se-design-tabs flex items-stretch relative border rounded-md border-[var(--color-gray-400)] w-fit\"\n data-automation-id=\"tabs-container\"\n {...getTabListProps({ ariaLabel, ariaLabelledBy })}\n >\n {visibleTabs.map((tab) => {\n const isActive = activeTab === tab.id;\n const isDisabled = !!tab.disabled;\n const tabProps = getTabProps(tab.id);\n return (\n <button\n type=\"button\"\n key={tab.id}\n {...tabProps}\n disabled={isDisabled}\n aria-label={tab.ariaLabel}\n onFocus={() => !isDisabled && setFocusedTabId(tab.id)}\n onKeyDown={handleKeyDown}\n onClick={() => handleTabClick(tab)}\n className={`se-design-tab-item flex items-center text-base px-3 py-0.5 min-w-0 border-l first:border-l-0 first:rounded-l-[0.3rem] last:rounded-r-[0.3rem] border-[var(--color-gray-400)] ${!isDisabled ? 'focus-outline' : ''} ${\n isDisabled\n ? 'text-[var(--color-gray-400)] cursor-not-allowed'\n : isActive\n ? 'se-design-tab-item-active text-[var(--color-white)] bg-[var(--color-blue-500)] font-medium hover:cursor-pointer'\n : 'text-[var(--color-gray-700)] font-normal hover:bg-[var(--color-gray-50)] hover:text-[var(--color-gray-900)] cursor-pointer transition-all duration-200 ease-in-out'\n }`}\n data-automation-id={`tab-item-${tab.automationId || tab.id || ''}`}\n >\n {tab.label}\n </button>\n );\n })}\n\n {overflowTabs.length > 0 && (\n <Popover\n className=\"se-design-overflow-tabs\"\n position=\"bottom-left\"\n noBorder\n disableClickToggle={true}\n onPopoverToggle={(isOpen) => {\n if (!isOpen) {\n if (wasKeyboardOpenedRef.current) overflowDivRef.current?.focus();\n wasKeyboardOpenedRef.current = false;\n }\n }}\n renderPopoverSrcElement={({ displayPopover, togglePopover }) => {\n const overflowTabProps = getTabProps('overflow');\n const overflowAriaControls = activeOverflowTab\n ? getPanelId(activeOverflowTab.id, baseId)\n : undefined;\n\n return (\n <div\n {...overflowTabProps}\n ref={(el) => { overflowDivRef.current = el; overflowTabProps.ref(el); }}\n aria-selected={!!activeOverflowTab}\n aria-label={activeOverflowTab?.label ? undefined : `More tabs (${overflowTabs.length})`}\n aria-controls={overflowAriaControls}\n aria-haspopup=\"true\"\n aria-expanded={displayPopover}\n onClick={() => { wasKeyboardOpenedRef.current = false; togglePopover(true); }}\n onFocus={() => setFocusedTabId('overflow')}\n data-automation-id=\"tabs-kebab-menu\"\n onKeyDown={(e) => {\n if (e.key === 'Enter' || e.key === ' ' || e.key === 'ArrowDown') {\n e.preventDefault();\n wasKeyboardOpenedRef.current = true;\n togglePopover(true);\n } else if (e.key === 'ArrowUp') {\n e.preventDefault();\n wasKeyboardOpenedRef.current = true;\n togglePopover('last');\n } else {\n handleKeyDown(e);\n }\n }}\n className={`overflow-tabs-src-element focus-outline border-l px-3 py-0.5 rounded-r-md font-medium hover:cursor-pointer transition-all duration-200 ease-in-out ${\n displayPopover ? 'bg-[var(--color-blue-100)]' : ''\n } ${activeOverflowTab?.label ? 'bg-[var(--color-blue-500)]' : 'hover:bg-[var(--color-gray-50)]'}`}\n onMouseEnter={() => setIsIconTabHover(true)}\n onMouseLeave={() => setIsIconTabHover(false)}\n >\n {activeOverflowTab?.label ? (\n <span className=\"pointer-events-none flex items-center gap-1\">\n <span className=\"text-[var(--color-white)]\">{activeOverflowTab?.label}</span>\n <Icon\n name=\"chevron\"\n rotation={displayPopover ? '180' : '0'}\n stroke={isIconTabHover ? 'var(--color-gray-100)' : 'var(--color-white)'}\n />\n </span>\n ) : (\n <span className=\"pointer-events-none\">\n <Icon name=\"kebab-menu\" fill={isIconTabHover ? 'var(--color-gray-900)' : 'var(--color-gray-700)'} />\n </span>\n )}\n </div>\n );\n }}\n renderPopoverContents={({ closePopoverCb }) => (\n <MenuList\n items={overflowTabs.map((tab) => ({\n id: tab?.id,\n label: tab?.label,\n automationId: tab?.automationId || tab?.id,\n onClick: () => {\n handleTabClick(tab);\n closePopoverCb();\n }\n }))}\n />\n )}\n />\n )}\n </div>\n\n {hasPanelContent && (\n <div className=\"se-design-tabs-content\">\n {tabs.map((tab) => (\n <div\n key={tab.id}\n {...getPanelProps(tab.id)}\n className={`tab-content ${isTabActive(tab, activeTab) ? 'block' : 'hidden'}`}\n >\n {isTabActive(tab, activeTab) && tab.renderTabContent?.(tab)}\n </div>\n ))}\n </div>\n )}\n </>\n );\n};\n"],"names":["Tabs","defaultActiveTab","tabs","onTabChange","primaryTabCount","headingLevel","HeadingTag","id","ariaLabel","ariaLabelledBy","panelId","defaultTabId","activeTab","setActiveTab","useState","isIconTabHover","setIsIconTabHover","visibleTabCount","length","visibleTabs","slice","overflowTabs","activeOverflowTab","find","tab","hasPanelContent","some","t","renderTabContent","baseId","useStableId","itemIds","useMemo","enabledVisibleTabs","filter","disabled","enabledOverflowTabs","visibleIds","map","getTabProps","getPanelProps","getTabListProps","handleKeyDown","setFocusedTabId","useTabsA11y","activeItem","orientation","idBase","includePanelLinks","externalPanelId","overflowDivRef","useRef","wasKeyboardOpenedRef","useEffect","handleTabClick","isTabActive","singleTab","createElement","React","Fragment","className","label","_extends","isActive","isDisabled","tabProps","type","key","onFocus","onKeyDown","onClick","automationId","Popover","position","noBorder","disableClickToggle","onPopoverToggle","isOpen","current","focus","renderPopoverSrcElement","displayPopover","togglePopover","overflowTabProps","overflowAriaControls","getPanelId","undefined","ref","el","e","preventDefault","onMouseEnter","onMouseLeave","Icon","name","rotation","stroke","fill","renderPopoverContents","closePopoverCb","MenuList","items"],"mappings":"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"}
|
package/dist/index70.js
CHANGED
|
@@ -13,20 +13,20 @@ function M({
|
|
|
13
13
|
const [c, b] = n.useState(u || r[0] || ""), g = n.useRef({});
|
|
14
14
|
n.useEffect(() => {
|
|
15
15
|
if (r.length > 0 && !r.includes(c)) {
|
|
16
|
-
const
|
|
17
|
-
b(
|
|
16
|
+
const t = u || r[0] || "";
|
|
17
|
+
b(t);
|
|
18
18
|
}
|
|
19
19
|
}, [r, c, u]);
|
|
20
|
-
const x = n.useCallback((
|
|
21
|
-
b(e)
|
|
22
|
-
}, [f]), y = n.useCallback((
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
}, [f]), p = n.useCallback((
|
|
20
|
+
const x = n.useCallback((t) => {
|
|
21
|
+
b((e) => e === t ? e : (f?.(t), t));
|
|
22
|
+
}, [f]), y = n.useCallback((t) => {
|
|
23
|
+
const e = g.current[t];
|
|
24
|
+
e ? e.focus() : (b(t), f?.(t));
|
|
25
|
+
}, [f]), p = n.useCallback((t, e = 1) => {
|
|
26
26
|
if (r.length === 0) return;
|
|
27
27
|
const o = r.indexOf(c), l = Math.max(0, o);
|
|
28
28
|
let s = l;
|
|
29
|
-
switch (
|
|
29
|
+
switch (t) {
|
|
30
30
|
case "first":
|
|
31
31
|
s = 0;
|
|
32
32
|
break;
|
|
@@ -34,26 +34,26 @@ function M({
|
|
|
34
34
|
s = r.length - 1;
|
|
35
35
|
break;
|
|
36
36
|
case "prev":
|
|
37
|
-
k ? s = (l -
|
|
37
|
+
k ? s = (l - e + r.length) % r.length : s = Math.max(0, l - e);
|
|
38
38
|
break;
|
|
39
39
|
case "next":
|
|
40
|
-
k ? s = (l +
|
|
40
|
+
k ? s = (l + e) % r.length : s = Math.min(r.length - 1, l + e);
|
|
41
41
|
break;
|
|
42
42
|
}
|
|
43
43
|
const w = r[s];
|
|
44
44
|
w && g.current[w]?.focus();
|
|
45
|
-
}, [r, c, k]), A = n.useCallback((
|
|
46
|
-
ref: (
|
|
47
|
-
g.current[
|
|
45
|
+
}, [r, c, k]), A = n.useCallback((t) => ({
|
|
46
|
+
ref: (e) => {
|
|
47
|
+
g.current[t] = e;
|
|
48
48
|
},
|
|
49
|
-
tabIndex: c ===
|
|
50
|
-
onFocus: () => x(
|
|
51
|
-
}), [c, v, x]), R = n.useCallback((
|
|
52
|
-
let
|
|
53
|
-
|
|
54
|
-
}, [a, i, p]), z = n.useCallback((
|
|
55
|
-
const
|
|
56
|
-
return h && (
|
|
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
57
|
}, [h, a]);
|
|
58
58
|
return {
|
|
59
59
|
setFocusedId: x,
|
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(id);\n onFocusChange?.(id);\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","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/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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"}
|
package/dist/index80.js
CHANGED
|
@@ -1,27 +1,30 @@
|
|
|
1
1
|
import * as e from "react";
|
|
2
|
-
function
|
|
3
|
-
disabled:
|
|
4
|
-
onFocusIn:
|
|
5
|
-
onFocusOut:
|
|
6
|
-
onEscape:
|
|
7
|
-
closeOnEscape:
|
|
2
|
+
function m({
|
|
3
|
+
disabled: r = !1,
|
|
4
|
+
onFocusIn: n,
|
|
5
|
+
onFocusOut: u,
|
|
6
|
+
onEscape: c,
|
|
7
|
+
closeOnEscape: a = !0
|
|
8
8
|
}) {
|
|
9
|
-
const f = e.useCallback((
|
|
10
|
-
|
|
11
|
-
}, [
|
|
12
|
-
if (
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
9
|
+
const f = e.useCallback((t) => {
|
|
10
|
+
r || n?.();
|
|
11
|
+
}, [r, n]), o = e.useRef(null), i = e.useCallback((t) => {
|
|
12
|
+
if (r) return;
|
|
13
|
+
o.current = t.currentTarget;
|
|
14
|
+
const s = t.relatedTarget;
|
|
15
|
+
s && t.currentTarget.contains(s) || requestAnimationFrame(() => {
|
|
16
|
+
o.current?.contains(document.activeElement) || u?.();
|
|
17
|
+
});
|
|
18
|
+
}, [r, u]), l = e.useCallback((t) => {
|
|
19
|
+
r || !a || t.key !== "Escape" || (t.preventDefault(), c?.());
|
|
20
|
+
}, [r, a, c]);
|
|
18
21
|
return {
|
|
19
22
|
onFocusCapture: f,
|
|
20
|
-
onBlurCapture:
|
|
21
|
-
onKeyDownCapture:
|
|
23
|
+
onBlurCapture: i,
|
|
24
|
+
onKeyDownCapture: l
|
|
22
25
|
};
|
|
23
26
|
}
|
|
24
27
|
export {
|
|
25
|
-
|
|
28
|
+
m as useDismissOnFocusOut
|
|
26
29
|
};
|
|
27
30
|
//# sourceMappingURL=index80.js.map
|
package/dist/index80.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index80.js","sources":["../src/utils/a11y/useDismissOnFocusOut.ts"],"sourcesContent":["import * as React from 'react';\n\nexport type UseDismissOnFocusOutOptions = {\n /**\n * Disable all handlers (no-ops). Useful when a component provides alternate\n * focus/keyboard behavior (e.g., disabled-trigger tooltip wrapper).\n */\n disabled?: boolean;\n /**\n * Called when focus enters anywhere within the target.\n */\n onFocusIn?: () => void;\n /**\n * Called when focus leaves the target (i.e., focus moves to an element\n * outside the currentTarget).\n */\n onFocusOut?: () => void;\n /**\n * Called when Escape is pressed while focus is within the target.\n */\n onEscape?: () => void;\n /**\n * Whether Escape should trigger dismissal. Default: true.\n */\n closeOnEscape?: boolean;\n};\n\nexport type UseDismissOnFocusOutReturn<T extends HTMLElement = HTMLElement> = {\n onFocusCapture: (e: React.FocusEvent<T>) => void;\n onBlurCapture: (e: React.FocusEvent<T>) => void;\n onKeyDownCapture: (e: React.KeyboardEvent<T>) => void;\n};\n\n/**\n * Returns capture-phase handlers to \"show on focus within\" and \"dismiss on focus out\",\n * with optional Escape-to-dismiss.\n *\n * Intended for non-interactive surfaces like tooltips where content should remain\n * visible while focus stays within the wrapper.\n */\nexport function useDismissOnFocusOut<T extends HTMLElement = HTMLElement>({\n disabled = false,\n onFocusIn,\n onFocusOut,\n onEscape,\n closeOnEscape = true\n}: UseDismissOnFocusOutOptions): UseDismissOnFocusOutReturn<T> {\n const onFocusCapture = React.useCallback(\n (_e: React.FocusEvent<T>) => {\n if (disabled) return;\n onFocusIn?.();\n },\n [disabled, onFocusIn]\n );\n\n const onBlurCapture = React.useCallback(\n (e: React.FocusEvent<T>) => {\n if (disabled) return;\n\n const nextFocused = e.relatedTarget as Node | null;\n if (nextFocused && e.currentTarget.contains(nextFocused)) return;\n\n onFocusOut?.();\n },\n [disabled, onFocusOut]\n );\n\n const onKeyDownCapture = React.useCallback(\n (e: React.KeyboardEvent<T>) => {\n if (disabled || !closeOnEscape || e.key !== 'Escape') return;\n\n e.preventDefault();\n onEscape?.();\n },\n [disabled, closeOnEscape, onEscape]\n );\n\n return { onFocusCapture, onBlurCapture, onKeyDownCapture };\n}\n\n"],"names":["React","useDismissOnFocusOut","disabled","onFocusIn","onFocusOut","onEscape","closeOnEscape","onFocusCapture","useCallback","_e","onBlurCapture","e","nextFocused","relatedTarget","
|
|
1
|
+
{"version":3,"file":"index80.js","sources":["../src/utils/a11y/useDismissOnFocusOut.ts"],"sourcesContent":["import * as React from 'react';\n\nexport type UseDismissOnFocusOutOptions = {\n /**\n * Disable all handlers (no-ops). Useful when a component provides alternate\n * focus/keyboard behavior (e.g., disabled-trigger tooltip wrapper).\n */\n disabled?: boolean;\n /**\n * Called when focus enters anywhere within the target.\n */\n onFocusIn?: () => void;\n /**\n * Called when focus leaves the target (i.e., focus moves to an element\n * outside the currentTarget).\n */\n onFocusOut?: () => void;\n /**\n * Called when Escape is pressed while focus is within the target.\n */\n onEscape?: () => void;\n /**\n * Whether Escape should trigger dismissal. Default: true.\n */\n closeOnEscape?: boolean;\n};\n\nexport type UseDismissOnFocusOutReturn<T extends HTMLElement = HTMLElement> = {\n onFocusCapture: (e: React.FocusEvent<T>) => void;\n onBlurCapture: (e: React.FocusEvent<T>) => void;\n onKeyDownCapture: (e: React.KeyboardEvent<T>) => void;\n};\n\n/**\n * Returns capture-phase handlers to \"show on focus within\" and \"dismiss on focus out\",\n * with optional Escape-to-dismiss.\n *\n * Intended for non-interactive surfaces like tooltips where content should remain\n * visible while focus stays within the wrapper.\n */\nexport function useDismissOnFocusOut<T extends HTMLElement = HTMLElement>({\n disabled = false,\n onFocusIn,\n onFocusOut,\n onEscape,\n closeOnEscape = true\n}: UseDismissOnFocusOutOptions): UseDismissOnFocusOutReturn<T> {\n const onFocusCapture = React.useCallback(\n (_e: React.FocusEvent<T>) => {\n if (disabled) return;\n onFocusIn?.();\n },\n [disabled, onFocusIn]\n );\n\n const containerRef = React.useRef<T | null>(null);\n\n const onBlurCapture = React.useCallback(\n (e: React.FocusEvent<T>) => {\n if (disabled) return;\n\n // Capture the container element for the async check — e.currentTarget\n // is only valid synchronously during this event handler.\n containerRef.current = e.currentTarget;\n\n const nextFocused = e.relatedTarget as Node | null;\n if (nextFocused && e.currentTarget.contains(nextFocused)) return;\n\n // Defer the close check: when focus transitions between elements inside\n // the container (e.g. a React re-render replaces a focused DOM node),\n // relatedTarget can be null transiently. By the next frame the browser\n // has settled activeElement, so we re-check containment before closing.\n requestAnimationFrame(() => {\n if (containerRef.current?.contains(document.activeElement)) return;\n onFocusOut?.();\n });\n },\n [disabled, onFocusOut]\n );\n\n const onKeyDownCapture = React.useCallback(\n (e: React.KeyboardEvent<T>) => {\n if (disabled || !closeOnEscape || e.key !== 'Escape') return;\n\n e.preventDefault();\n onEscape?.();\n },\n [disabled, closeOnEscape, onEscape]\n );\n\n return { onFocusCapture, onBlurCapture, onKeyDownCapture };\n}\n\n"],"names":["React","useDismissOnFocusOut","disabled","onFocusIn","onFocusOut","onEscape","closeOnEscape","onFocusCapture","useCallback","_e","containerRef","useRef","onBlurCapture","e","current","currentTarget","nextFocused","relatedTarget","contains","requestAnimationFrame","document","activeElement","onKeyDownCapture","key","preventDefault"],"mappings":"AAwCO,YAAAA,OAAA;AAAA,SAASC,EAA0D;AAAA,EACxEC,UAAAA,IAAW;AAAA,EACXC,WAAAA;AAAAA,EACAC,YAAAA;AAAAA,EACAC,UAAAA;AAAAA,EACAC,eAAAA,IAAgB;AACW,GAAkC;AAC7D,QAAMC,IAAiBP,EAAMQ,YAC3B,CAACC,MAA4B;AAC3B,IAAIP,KACJC,IAAAA;AAAAA,EACF,GACA,CAACD,GAAUC,CAAS,CACtB,GAEMO,IAAeV,EAAMW,OAAiB,IAAI,GAE1CC,IAAgBZ,EAAMQ,YAC1B,CAACK,MAA2B;AAC1B,QAAIX,EAAU;AAIdQ,IAAAA,EAAaI,UAAUD,EAAEE;AAEzB,UAAMC,IAAcH,EAAEI;AACtB,IAAID,KAAeH,EAAEE,cAAcG,SAASF,CAAW,KAMvDG,sBAAsB,MAAM;AAC1B,MAAIT,EAAaI,SAASI,SAASE,SAASC,aAAa,KACzDjB,IAAAA;AAAAA,IACF,CAAC;AAAA,EACH,GACA,CAACF,GAAUE,CAAU,CACvB,GAEMkB,IAAmBtB,EAAMQ,YAC7B,CAACK,MAA8B;AAC7B,IAAIX,KAAY,CAACI,KAAiBO,EAAEU,QAAQ,aAE5CV,EAAEW,eAAAA,GACFnB,IAAAA;AAAAA,EACF,GACA,CAACH,GAAUI,GAAeD,CAAQ,CACpC;AAEA,SAAO;AAAA,IAAEE,gBAAAA;AAAAA,IAAgBK,eAAAA;AAAAA,IAAeU,kBAAAA;AAAAA,EAAAA;AAC1C;"}
|