@refraction-ui/react 0.23.2 → 0.23.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/index.cjs +82 -223
- package/dist/index.cjs.map +1 -1
- package/dist/internal/page-header/index.d.ts +2 -2
- package/dist/react-avatar.js +17 -3
- package/dist/react-avatar.js.map +2 -2
- package/dist/react-dialog.js +53 -31
- package/dist/react-dialog.js.map +2 -2
- package/dist/react-dropdown-menu.js +4 -93
- package/dist/react-dropdown-menu.js.map +2 -2
- package/dist/react-page-header.js +1 -1
- package/dist/react-page-header.js.map +1 -1
- package/dist/react-tabs.js +4 -96
- package/dist/react-tabs.js.map +2 -2
- package/package.json +1 -1
package/dist/react-tabs.js
CHANGED
|
@@ -1,101 +1,13 @@
|
|
|
1
1
|
import {
|
|
2
|
-
Keys,
|
|
3
2
|
cn,
|
|
4
3
|
cva,
|
|
5
|
-
devWarn
|
|
6
|
-
generateId
|
|
4
|
+
devWarn
|
|
7
5
|
} from "./chunk-75BKRTPO.js";
|
|
8
6
|
|
|
9
7
|
// ../react-tabs/dist/index.js
|
|
10
8
|
import * as React from "react";
|
|
11
9
|
|
|
12
10
|
// ../tabs/dist/index.js
|
|
13
|
-
function createTabs(props = {}) {
|
|
14
|
-
const {
|
|
15
|
-
value: controlledValue,
|
|
16
|
-
defaultValue = "",
|
|
17
|
-
onValueChange,
|
|
18
|
-
orientation = "horizontal"
|
|
19
|
-
} = props;
|
|
20
|
-
let uncontrolledValue = controlledValue ?? defaultValue;
|
|
21
|
-
const idPrefix = generateId("rfr-tabs");
|
|
22
|
-
function getActiveValue() {
|
|
23
|
-
if (controlledValue !== void 0) return controlledValue;
|
|
24
|
-
return uncontrolledValue;
|
|
25
|
-
}
|
|
26
|
-
function select(value) {
|
|
27
|
-
uncontrolledValue = value;
|
|
28
|
-
onValueChange?.(value);
|
|
29
|
-
}
|
|
30
|
-
function getTabId(value) {
|
|
31
|
-
return `${idPrefix}-tab-${value}`;
|
|
32
|
-
}
|
|
33
|
-
function getPanelId(value) {
|
|
34
|
-
return `${idPrefix}-panel-${value}`;
|
|
35
|
-
}
|
|
36
|
-
function getTabProps(value) {
|
|
37
|
-
const isSelected = getActiveValue() === value;
|
|
38
|
-
return {
|
|
39
|
-
role: "tab",
|
|
40
|
-
"aria-selected": isSelected,
|
|
41
|
-
"aria-controls": getPanelId(value),
|
|
42
|
-
tabIndex: isSelected ? 0 : -1,
|
|
43
|
-
id: getTabId(value),
|
|
44
|
-
"data-state": isSelected ? "active" : "inactive"
|
|
45
|
-
};
|
|
46
|
-
}
|
|
47
|
-
function getPanelProps(value) {
|
|
48
|
-
const isSelected = getActiveValue() === value;
|
|
49
|
-
return {
|
|
50
|
-
role: "tabpanel",
|
|
51
|
-
"aria-labelledby": getTabId(value),
|
|
52
|
-
id: getPanelId(value),
|
|
53
|
-
hidden: !isSelected || void 0,
|
|
54
|
-
tabIndex: 0,
|
|
55
|
-
"data-state": isSelected ? "active" : "inactive"
|
|
56
|
-
};
|
|
57
|
-
}
|
|
58
|
-
const listProps = {
|
|
59
|
-
role: "tablist",
|
|
60
|
-
"aria-orientation": orientation
|
|
61
|
-
};
|
|
62
|
-
const keyboardHandlers = orientation === "horizontal" ? {
|
|
63
|
-
[Keys.ArrowLeft]: (e) => {
|
|
64
|
-
e.preventDefault();
|
|
65
|
-
},
|
|
66
|
-
[Keys.ArrowRight]: (e) => {
|
|
67
|
-
e.preventDefault();
|
|
68
|
-
},
|
|
69
|
-
[Keys.Home]: (e) => {
|
|
70
|
-
e.preventDefault();
|
|
71
|
-
},
|
|
72
|
-
[Keys.End]: (e) => {
|
|
73
|
-
e.preventDefault();
|
|
74
|
-
}
|
|
75
|
-
} : {
|
|
76
|
-
[Keys.ArrowUp]: (e) => {
|
|
77
|
-
e.preventDefault();
|
|
78
|
-
},
|
|
79
|
-
[Keys.ArrowDown]: (e) => {
|
|
80
|
-
e.preventDefault();
|
|
81
|
-
},
|
|
82
|
-
[Keys.Home]: (e) => {
|
|
83
|
-
e.preventDefault();
|
|
84
|
-
},
|
|
85
|
-
[Keys.End]: (e) => {
|
|
86
|
-
e.preventDefault();
|
|
87
|
-
}
|
|
88
|
-
};
|
|
89
|
-
return {
|
|
90
|
-
state: { activeValue: getActiveValue() },
|
|
91
|
-
listProps,
|
|
92
|
-
getTabProps,
|
|
93
|
-
getPanelProps,
|
|
94
|
-
select,
|
|
95
|
-
keyboardHandlers,
|
|
96
|
-
idPrefix
|
|
97
|
-
};
|
|
98
|
-
}
|
|
99
11
|
function getNextTabIndex(current, key, count, orientation = "horizontal") {
|
|
100
12
|
if (count === 0) return null;
|
|
101
13
|
const prev = orientation === "horizontal" ? "ArrowLeft" : "ArrowUp";
|
|
@@ -147,11 +59,7 @@ var Tabs = React.forwardRef(
|
|
|
147
59
|
},
|
|
148
60
|
[isControlled, onValueChange]
|
|
149
61
|
);
|
|
150
|
-
const
|
|
151
|
-
if (apiRef.current === null) {
|
|
152
|
-
apiRef.current = createTabs({ value, orientation });
|
|
153
|
-
}
|
|
154
|
-
const api = apiRef.current;
|
|
62
|
+
const idPrefix = `rfr-tabs-${React.useId()}`;
|
|
155
63
|
const [panels, setPanels] = React.useState(() => /* @__PURE__ */ new Set());
|
|
156
64
|
const registerPanel = React.useCallback((panelValue) => {
|
|
157
65
|
setPanels((prev) => prev.has(panelValue) ? prev : new Set(prev).add(panelValue));
|
|
@@ -172,11 +80,11 @@ var Tabs = React.forwardRef(
|
|
|
172
80
|
value,
|
|
173
81
|
onValueChange: handleValueChange,
|
|
174
82
|
orientation,
|
|
175
|
-
idPrefix
|
|
83
|
+
idPrefix,
|
|
176
84
|
panels: allPanels,
|
|
177
85
|
registerPanel
|
|
178
86
|
}),
|
|
179
|
-
[value, handleValueChange, orientation,
|
|
87
|
+
[value, handleValueChange, orientation, idPrefix, allPanels, registerPanel]
|
|
180
88
|
);
|
|
181
89
|
return React.createElement(
|
|
182
90
|
"div",
|
package/dist/react-tabs.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../tabs/src/tabs.ts", "../../tabs/src/tabs.styles.ts", "../../react-tabs/src/tabs.tsx"],
|
|
4
|
-
"sourcesContent": ["import type { AccessibilityProps, KeyboardHandlerMap } from '@refraction-ui/shared'\nimport { Keys, generateId } from '@refraction-ui/shared'\n\nexport interface TabsProps {\n /** The active tab value (controlled) */\n value?: string\n /** The default active tab value (uncontrolled) */\n defaultValue?: string\n /** Callback when active tab changes */\n onValueChange?: (value: string) => void\n /** Orientation of the tab list */\n orientation?: 'horizontal' | 'vertical'\n}\n\nexport interface TabsState {\n activeValue: string\n}\n\nexport interface TabsAPI {\n /** Current tabs state */\n state: TabsState\n /** ARIA attributes for the tab list */\n listProps: Partial<AccessibilityProps> & Record<string, unknown>\n /** Factory for individual tab trigger props */\n getTabProps(value: string): Partial<AccessibilityProps> & Record<string, unknown>\n /** Factory for individual tab panel props */\n getPanelProps(value: string): Partial<AccessibilityProps> & Record<string, unknown>\n /** Select a tab by value */\n select(value: string): void\n /** Keyboard handlers for the tab list */\n keyboardHandlers: KeyboardHandlerMap\n /** Generated ID prefix for aria linking */\n idPrefix: string\n}\n\nexport function createTabs(props: TabsProps = {}): TabsAPI {\n const {\n value: controlledValue,\n defaultValue = '',\n onValueChange,\n orientation = 'horizontal',\n } = props\n\n let uncontrolledValue = controlledValue ?? defaultValue\n const idPrefix = generateId('rfr-tabs')\n\n function getActiveValue(): string {\n if (controlledValue !== undefined) return controlledValue\n return uncontrolledValue\n }\n\n function select(value: string): void {\n uncontrolledValue = value\n onValueChange?.(value)\n }\n\n function getTabId(value: string): string {\n return `${idPrefix}-tab-${value}`\n }\n\n function getPanelId(value: string): string {\n return `${idPrefix}-panel-${value}`\n }\n\n function getTabProps(value: string): Partial<AccessibilityProps> & Record<string, unknown> {\n const isSelected = getActiveValue() === value\n return {\n role: 'tab',\n 'aria-selected': isSelected,\n 'aria-controls': getPanelId(value),\n tabIndex: isSelected ? 0 : -1,\n id: getTabId(value),\n 'data-state': isSelected ? 'active' : 'inactive',\n }\n }\n\n function getPanelProps(value: string): Partial<AccessibilityProps> & Record<string, unknown> {\n const isSelected = getActiveValue() === value\n return {\n role: 'tabpanel',\n 'aria-labelledby': getTabId(value),\n id: getPanelId(value),\n hidden: !isSelected || undefined,\n tabIndex: 0,\n 'data-state': isSelected ? 'active' : 'inactive',\n }\n }\n\n const listProps: Partial<AccessibilityProps> & Record<string, unknown> = {\n role: 'tablist',\n 'aria-orientation': orientation,\n }\n\n const keyboardHandlers: KeyboardHandlerMap = orientation === 'horizontal'\n ? {\n [Keys.ArrowLeft]: (e) => {\n e.preventDefault()\n },\n [Keys.ArrowRight]: (e) => {\n e.preventDefault()\n },\n [Keys.Home]: (e) => {\n e.preventDefault()\n },\n [Keys.End]: (e) => {\n e.preventDefault()\n },\n }\n : {\n [Keys.ArrowUp]: (e) => {\n e.preventDefault()\n },\n [Keys.ArrowDown]: (e) => {\n e.preventDefault()\n },\n [Keys.Home]: (e) => {\n e.preventDefault()\n },\n [Keys.End]: (e) => {\n e.preventDefault()\n },\n }\n\n return {\n state: { activeValue: getActiveValue() },\n listProps,\n getTabProps,\n getPanelProps,\n select,\n keyboardHandlers,\n idPrefix,\n }\n}\n\n/**\n * Roving-focus target for a key press inside a tab list (WAI-ARIA Tabs\n * pattern). Given the index of the focused tab among the ENABLED tabs, returns\n * the index to move to, or `null` when the key is not a navigation key for this\n * orientation. Arrow keys wrap; Home/End jump to the ends.\n */\nexport function getNextTabIndex(\n current: number,\n key: string,\n count: number,\n orientation: 'horizontal' | 'vertical' = 'horizontal',\n): number | null {\n if (count === 0) return null\n const prev = orientation === 'horizontal' ? 'ArrowLeft' : 'ArrowUp'\n const next = orientation === 'horizontal' ? 'ArrowRight' : 'ArrowDown'\n switch (key) {\n case next:\n return current < 0 ? 0 : (current + 1) % count\n case prev:\n return current < 0 ? count - 1 : (current - 1 + count) % count\n case 'Home':\n return 0\n case 'End':\n return count - 1\n default:\n return null\n }\n}\n", "import { cva } from '@refraction-ui/shared'\n\nexport const tabsListVariants = cva({\n base: 'inline-flex max-w-full overflow-x-auto items-center justify-center rounded-lg bg-muted p-1 text-muted-foreground',\n})\n\nexport const tabsTriggerVariants = cva({\n base: 'inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow',\n})\n", "import * as React from 'react'\nimport {\n createTabs,\n getNextTabIndex,\n tabsListVariants,\n tabsTriggerVariants,\n type TabsProps as CoreTabsProps,\n} from '@refraction-ui/tabs'\nimport { cn, createKeyboardHandler, Keys, devWarn } from '@refraction-ui/shared'\n\n// ---------------------------------------------------------------------------\n// Context\n// ---------------------------------------------------------------------------\n\ninterface TabsContextValue {\n value: string\n onValueChange: (value: string) => void\n orientation: 'horizontal' | 'vertical'\n idPrefix: string\n /** Values that have a TabsContent, so triggers only reference real panels. */\n panels: ReadonlySet<string>\n registerPanel: (value: string) => () => void\n}\n\nconst TabsContext = React.createContext<TabsContextValue | null>(null)\n\nfunction useTabsContext(): TabsContextValue {\n const ctx = React.useContext(TabsContext)\n if (!ctx) {\n devWarn(\n 'react-tabs/context-outside-provider',\n 'Tabs compound components (TabsList/TabsTrigger/TabsContent) must be rendered inside a <Tabs>. The missing TabsContext makes this throw.',\n )\n throw new Error('Tabs compound components must be used within <Tabs>')\n }\n return ctx\n}\n\n// ---------------------------------------------------------------------------\n// Tabs (root provider)\n// ---------------------------------------------------------------------------\n\nexport interface TabsProps extends React.HTMLAttributes<HTMLDivElement> {\n value?: string\n defaultValue?: string\n onValueChange?: (value: string) => void\n orientation?: 'horizontal' | 'vertical'\n className?: string\n children?: React.ReactNode\n}\n\nexport const Tabs = React.forwardRef<HTMLDivElement, TabsProps>(\n function Tabs({ value: controlledValue, defaultValue = '', onValueChange, orientation = 'horizontal', className, children, ...props }: TabsProps, ref) {\n const [uncontrolledValue, setUncontrolledValue] = React.useState(defaultValue)\n const isControlled = controlledValue !== undefined\n const value = isControlled ? controlledValue : uncontrolledValue\n\n const handleValueChange = React.useCallback(\n (next: string) => {\n if (!isControlled) {\n setUncontrolledValue(next)\n }\n onValueChange?.(next)\n },\n [isControlled, onValueChange],\n )\n\n // Use the headless core to get stable IDs\n const apiRef = React.useRef<ReturnType<typeof createTabs> | null>(null)\n if (apiRef.current === null) {\n apiRef.current = createTabs({ value, orientation })\n }\n const api = apiRef.current\n\n const [panels, setPanels] = React.useState<ReadonlySet<string>>(() => new Set())\n const registerPanel = React.useCallback((panelValue: string) => {\n setPanels((prev) => (prev.has(panelValue) ? prev : new Set(prev).add(panelValue)))\n return () =>\n setPanels((prev) => {\n if (!prev.has(panelValue)) return prev\n const next = new Set(prev)\n next.delete(panelValue)\n return next\n })\n }, [])\n\n // Panels found in the element tree cover the first/server render; mounted\n // panels (possibly nested in custom components) register themselves.\n const allPanels = React.useMemo(() => {\n const found = new Set(panels)\n collectPanelValues(children, found)\n return found\n }, [children, panels])\n\n const ctx = React.useMemo<TabsContextValue>(\n () => ({\n value,\n onValueChange: handleValueChange,\n orientation,\n idPrefix: api.idPrefix,\n panels: allPanels,\n registerPanel,\n }),\n [value, handleValueChange, orientation, api.idPrefix, allPanels, registerPanel],\n )\n\n return React.createElement(\n 'div',\n { ref, className, 'data-orientation': orientation, ...props },\n React.createElement(TabsContext.Provider, { value: ctx }, children),\n )\n },\n)\n\nfunction collectPanelValues(node: React.ReactNode, into: Set<string>): void {\n React.Children.forEach(node, (child) => {\n if (!React.isValidElement<{ value?: unknown; children?: React.ReactNode }>(child)) return\n if (child.type === TabsContent && typeof child.props.value === 'string') {\n into.add(child.props.value)\n return\n }\n collectPanelValues(child.props.children, into)\n })\n}\n\n// ---------------------------------------------------------------------------\n// TabsList\n// ---------------------------------------------------------------------------\n\nexport interface TabsListProps extends React.HTMLAttributes<HTMLDivElement> {}\n\nexport const TabsList = React.forwardRef<HTMLDivElement, TabsListProps>(\n function TabsList({ className, onKeyDown, ...props }, forwardedRef) {\n const { orientation } = useTabsContext()\n const listRef = React.useRef<HTMLDivElement | null>(null)\n const ref = React.useCallback(\n (node: HTMLDivElement | null) => {\n listRef.current = node\n if (typeof forwardedRef === 'function') forwardedRef(node)\n else if (forwardedRef) forwardedRef.current = node\n },\n [forwardedRef],\n )\n\n // Roving tabindex needs exactly one tab stop. A trigger only knows whether\n // IT is selected, so when no enabled trigger matches the value (no\n // defaultValue, or the selected tab is disabled) nothing would be\n // tabbable; make the first enabled tab the stop in that case.\n // This effect owns the final tabindex of every trigger (React leaves a\n // DOM value alone while its prop is unchanged, so patching only the\n // fallback would leave two tab stops after the next selection).\n React.useEffect(() => {\n const tabs = enabledTabs(listRef.current)\n const stop = tabs.find((tab) => tab.getAttribute('aria-selected') === 'true') ?? tabs[0]\n for (const tab of tabs) tab.tabIndex = tab === stop ? 0 : -1\n })\n\n const handleKeyDown = (e: React.KeyboardEvent<HTMLDivElement>) => {\n onKeyDown?.(e)\n if (e.defaultPrevented) return\n const tabs = enabledTabs(listRef.current)\n const current = tabs.indexOf(e.target as HTMLButtonElement)\n if (current === -1) return\n const next = getNextTabIndex(current, e.key, tabs.length, orientation)\n if (next === null) return\n e.preventDefault()\n tabs[next].focus()\n // Automatic activation: moving focus selects the tab.\n tabs[next].click()\n }\n\n return React.createElement('div', {\n ref,\n role: 'tablist',\n 'aria-orientation': orientation,\n className: cn(tabsListVariants(), className),\n onKeyDown: handleKeyDown,\n ...props,\n })\n },\n)\n\nfunction enabledTabs(list: HTMLElement | null): HTMLButtonElement[] {\n if (!list) return []\n return Array.from(list.querySelectorAll<HTMLButtonElement>('[role=\"tab\"]:not([disabled])'))\n}\n\n// ---------------------------------------------------------------------------\n// TabsTrigger\n// ---------------------------------------------------------------------------\n\nexport interface TabsTriggerProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n value: string\n}\n\nexport const TabsTrigger = React.forwardRef<HTMLButtonElement, TabsTriggerProps>(\n function TabsTrigger({ value, className, onClick, onKeyDown, children, ...props }, ref) {\n const { value: activeValue, onValueChange, idPrefix, panels } = useTabsContext()\n\n const isSelected = activeValue === value\n const tabId = `${idPrefix}-tab-${value}`\n const panelId = `${idPrefix}-panel-${value}`\n\n const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => {\n onValueChange(value)\n onClick?.(e)\n }\n\n // Arrow / Home / End navigation is handled by TabsList (roving focus);\n // a consumer onKeyDown runs first and can preventDefault to opt out.\n const handleKeyDown = (e: React.KeyboardEvent<HTMLButtonElement>) => {\n onKeyDown?.(e)\n }\n\n return React.createElement(\n 'button',\n {\n ref,\n type: 'button',\n role: 'tab',\n 'aria-selected': isSelected,\n // Only the selected panel is rendered; never reference a missing element.\n 'aria-controls': isSelected && panels.has(value) ? panelId : undefined,\n tabIndex: isSelected ? 0 : -1,\n id: tabId,\n 'data-state': isSelected ? 'active' : 'inactive',\n className: cn(tabsTriggerVariants(), className),\n onClick: handleClick,\n onKeyDown: handleKeyDown,\n ...props,\n },\n children,\n )\n },\n)\n\n// ---------------------------------------------------------------------------\n// TabsContent\n// ---------------------------------------------------------------------------\n\nexport interface TabsContentProps extends React.HTMLAttributes<HTMLDivElement> {\n value: string\n}\n\nexport const TabsContent = React.forwardRef<HTMLDivElement, TabsContentProps>(\n function TabsContent({ value, className, children, ...props }, ref) {\n const { value: activeValue, idPrefix, registerPanel } = useTabsContext()\n React.useEffect(() => registerPanel(value), [registerPanel, value])\n\n const isSelected = activeValue === value\n const tabId = `${idPrefix}-tab-${value}`\n const panelId = `${idPrefix}-panel-${value}`\n\n if (!isSelected) return null\n\n return React.createElement(\n 'div',\n {\n ref,\n role: 'tabpanel',\n 'aria-labelledby': tabId,\n id: panelId,\n tabIndex: 0,\n 'data-state': 'active',\n className,\n ...props,\n },\n children,\n )\n },\n)\n"],
|
|
5
|
-
"mappings": "
|
|
4
|
+
"sourcesContent": ["import type { AccessibilityProps, KeyboardHandlerMap } from '@refraction-ui/shared'\nimport { Keys, generateId } from '@refraction-ui/shared'\n\nexport interface TabsProps {\n /** The active tab value (controlled) */\n value?: string\n /** The default active tab value (uncontrolled) */\n defaultValue?: string\n /** Callback when active tab changes */\n onValueChange?: (value: string) => void\n /** Orientation of the tab list */\n orientation?: 'horizontal' | 'vertical'\n}\n\nexport interface TabsState {\n activeValue: string\n}\n\nexport interface TabsAPI {\n /** Current tabs state */\n state: TabsState\n /** ARIA attributes for the tab list */\n listProps: Partial<AccessibilityProps> & Record<string, unknown>\n /** Factory for individual tab trigger props */\n getTabProps(value: string): Partial<AccessibilityProps> & Record<string, unknown>\n /** Factory for individual tab panel props */\n getPanelProps(value: string): Partial<AccessibilityProps> & Record<string, unknown>\n /** Select a tab by value */\n select(value: string): void\n /** Keyboard handlers for the tab list */\n keyboardHandlers: KeyboardHandlerMap\n /** Generated ID prefix for aria linking */\n idPrefix: string\n}\n\nexport function createTabs(props: TabsProps = {}): TabsAPI {\n const {\n value: controlledValue,\n defaultValue = '',\n onValueChange,\n orientation = 'horizontal',\n } = props\n\n let uncontrolledValue = controlledValue ?? defaultValue\n const idPrefix = generateId('rfr-tabs')\n\n function getActiveValue(): string {\n if (controlledValue !== undefined) return controlledValue\n return uncontrolledValue\n }\n\n function select(value: string): void {\n uncontrolledValue = value\n onValueChange?.(value)\n }\n\n function getTabId(value: string): string {\n return `${idPrefix}-tab-${value}`\n }\n\n function getPanelId(value: string): string {\n return `${idPrefix}-panel-${value}`\n }\n\n function getTabProps(value: string): Partial<AccessibilityProps> & Record<string, unknown> {\n const isSelected = getActiveValue() === value\n return {\n role: 'tab',\n 'aria-selected': isSelected,\n 'aria-controls': getPanelId(value),\n tabIndex: isSelected ? 0 : -1,\n id: getTabId(value),\n 'data-state': isSelected ? 'active' : 'inactive',\n }\n }\n\n function getPanelProps(value: string): Partial<AccessibilityProps> & Record<string, unknown> {\n const isSelected = getActiveValue() === value\n return {\n role: 'tabpanel',\n 'aria-labelledby': getTabId(value),\n id: getPanelId(value),\n hidden: !isSelected || undefined,\n tabIndex: 0,\n 'data-state': isSelected ? 'active' : 'inactive',\n }\n }\n\n const listProps: Partial<AccessibilityProps> & Record<string, unknown> = {\n role: 'tablist',\n 'aria-orientation': orientation,\n }\n\n const keyboardHandlers: KeyboardHandlerMap = orientation === 'horizontal'\n ? {\n [Keys.ArrowLeft]: (e) => {\n e.preventDefault()\n },\n [Keys.ArrowRight]: (e) => {\n e.preventDefault()\n },\n [Keys.Home]: (e) => {\n e.preventDefault()\n },\n [Keys.End]: (e) => {\n e.preventDefault()\n },\n }\n : {\n [Keys.ArrowUp]: (e) => {\n e.preventDefault()\n },\n [Keys.ArrowDown]: (e) => {\n e.preventDefault()\n },\n [Keys.Home]: (e) => {\n e.preventDefault()\n },\n [Keys.End]: (e) => {\n e.preventDefault()\n },\n }\n\n return {\n state: { activeValue: getActiveValue() },\n listProps,\n getTabProps,\n getPanelProps,\n select,\n keyboardHandlers,\n idPrefix,\n }\n}\n\n/**\n * Roving-focus target for a key press inside a tab list (WAI-ARIA Tabs\n * pattern). Given the index of the focused tab among the ENABLED tabs, returns\n * the index to move to, or `null` when the key is not a navigation key for this\n * orientation. Arrow keys wrap; Home/End jump to the ends.\n */\nexport function getNextTabIndex(\n current: number,\n key: string,\n count: number,\n orientation: 'horizontal' | 'vertical' = 'horizontal',\n): number | null {\n if (count === 0) return null\n const prev = orientation === 'horizontal' ? 'ArrowLeft' : 'ArrowUp'\n const next = orientation === 'horizontal' ? 'ArrowRight' : 'ArrowDown'\n switch (key) {\n case next:\n return current < 0 ? 0 : (current + 1) % count\n case prev:\n return current < 0 ? count - 1 : (current - 1 + count) % count\n case 'Home':\n return 0\n case 'End':\n return count - 1\n default:\n return null\n }\n}\n", "import { cva } from '@refraction-ui/shared'\n\nexport const tabsListVariants = cva({\n base: 'inline-flex max-w-full overflow-x-auto items-center justify-center rounded-lg bg-muted p-1 text-muted-foreground',\n})\n\nexport const tabsTriggerVariants = cva({\n base: 'inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow',\n})\n", "import * as React from 'react'\nimport {\n getNextTabIndex,\n tabsListVariants,\n tabsTriggerVariants,\n type TabsProps as CoreTabsProps,\n} from '@refraction-ui/tabs'\nimport { cn, createKeyboardHandler, Keys, devWarn } from '@refraction-ui/shared'\n\n// ---------------------------------------------------------------------------\n// Context\n// ---------------------------------------------------------------------------\n\ninterface TabsContextValue {\n value: string\n onValueChange: (value: string) => void\n orientation: 'horizontal' | 'vertical'\n idPrefix: string\n /** Values that have a TabsContent, so triggers only reference real panels. */\n panels: ReadonlySet<string>\n registerPanel: (value: string) => () => void\n}\n\nconst TabsContext = React.createContext<TabsContextValue | null>(null)\n\nfunction useTabsContext(): TabsContextValue {\n const ctx = React.useContext(TabsContext)\n if (!ctx) {\n devWarn(\n 'react-tabs/context-outside-provider',\n 'Tabs compound components (TabsList/TabsTrigger/TabsContent) must be rendered inside a <Tabs>. The missing TabsContext makes this throw.',\n )\n throw new Error('Tabs compound components must be used within <Tabs>')\n }\n return ctx\n}\n\n// ---------------------------------------------------------------------------\n// Tabs (root provider)\n// ---------------------------------------------------------------------------\n\nexport interface TabsProps extends React.HTMLAttributes<HTMLDivElement> {\n value?: string\n defaultValue?: string\n onValueChange?: (value: string) => void\n orientation?: 'horizontal' | 'vertical'\n className?: string\n children?: React.ReactNode\n}\n\nexport const Tabs = React.forwardRef<HTMLDivElement, TabsProps>(\n function Tabs({ value: controlledValue, defaultValue = '', onValueChange, orientation = 'horizontal', className, children, ...props }: TabsProps, ref) {\n const [uncontrolledValue, setUncontrolledValue] = React.useState(defaultValue)\n const isControlled = controlledValue !== undefined\n const value = isControlled ? controlledValue : uncontrolledValue\n\n const handleValueChange = React.useCallback(\n (next: string) => {\n if (!isControlled) {\n setUncontrolledValue(next)\n }\n onValueChange?.(next)\n },\n [isControlled, onValueChange],\n )\n\n // React IDs agree across SSR and hydration, unlike the core's process counter.\n const idPrefix = `rfr-tabs-${React.useId()}`\n\n const [panels, setPanels] = React.useState<ReadonlySet<string>>(() => new Set())\n const registerPanel = React.useCallback((panelValue: string) => {\n setPanels((prev) => (prev.has(panelValue) ? prev : new Set(prev).add(panelValue)))\n return () =>\n setPanels((prev) => {\n if (!prev.has(panelValue)) return prev\n const next = new Set(prev)\n next.delete(panelValue)\n return next\n })\n }, [])\n\n // Panels found in the element tree cover the first/server render; mounted\n // panels (possibly nested in custom components) register themselves.\n const allPanels = React.useMemo(() => {\n const found = new Set(panels)\n collectPanelValues(children, found)\n return found\n }, [children, panels])\n\n const ctx = React.useMemo<TabsContextValue>(\n () => ({\n value,\n onValueChange: handleValueChange,\n orientation,\n idPrefix,\n panels: allPanels,\n registerPanel,\n }),\n [value, handleValueChange, orientation, idPrefix, allPanels, registerPanel],\n )\n\n return React.createElement(\n 'div',\n { ref, className, 'data-orientation': orientation, ...props },\n React.createElement(TabsContext.Provider, { value: ctx }, children),\n )\n },\n)\n\nfunction collectPanelValues(node: React.ReactNode, into: Set<string>): void {\n React.Children.forEach(node, (child) => {\n if (!React.isValidElement<{ value?: unknown; children?: React.ReactNode }>(child)) return\n if (child.type === TabsContent && typeof child.props.value === 'string') {\n into.add(child.props.value)\n return\n }\n collectPanelValues(child.props.children, into)\n })\n}\n\n// ---------------------------------------------------------------------------\n// TabsList\n// ---------------------------------------------------------------------------\n\nexport interface TabsListProps extends React.HTMLAttributes<HTMLDivElement> {}\n\nexport const TabsList = React.forwardRef<HTMLDivElement, TabsListProps>(\n function TabsList({ className, onKeyDown, ...props }, forwardedRef) {\n const { orientation } = useTabsContext()\n const listRef = React.useRef<HTMLDivElement | null>(null)\n const ref = React.useCallback(\n (node: HTMLDivElement | null) => {\n listRef.current = node\n if (typeof forwardedRef === 'function') forwardedRef(node)\n else if (forwardedRef) forwardedRef.current = node\n },\n [forwardedRef],\n )\n\n // Roving tabindex needs exactly one tab stop. A trigger only knows whether\n // IT is selected, so when no enabled trigger matches the value (no\n // defaultValue, or the selected tab is disabled) nothing would be\n // tabbable; make the first enabled tab the stop in that case.\n // This effect owns the final tabindex of every trigger (React leaves a\n // DOM value alone while its prop is unchanged, so patching only the\n // fallback would leave two tab stops after the next selection).\n React.useEffect(() => {\n const tabs = enabledTabs(listRef.current)\n const stop = tabs.find((tab) => tab.getAttribute('aria-selected') === 'true') ?? tabs[0]\n for (const tab of tabs) tab.tabIndex = tab === stop ? 0 : -1\n })\n\n const handleKeyDown = (e: React.KeyboardEvent<HTMLDivElement>) => {\n onKeyDown?.(e)\n if (e.defaultPrevented) return\n const tabs = enabledTabs(listRef.current)\n const current = tabs.indexOf(e.target as HTMLButtonElement)\n if (current === -1) return\n const next = getNextTabIndex(current, e.key, tabs.length, orientation)\n if (next === null) return\n e.preventDefault()\n tabs[next].focus()\n // Automatic activation: moving focus selects the tab.\n tabs[next].click()\n }\n\n return React.createElement('div', {\n ref,\n role: 'tablist',\n 'aria-orientation': orientation,\n className: cn(tabsListVariants(), className),\n onKeyDown: handleKeyDown,\n ...props,\n })\n },\n)\n\nfunction enabledTabs(list: HTMLElement | null): HTMLButtonElement[] {\n if (!list) return []\n return Array.from(list.querySelectorAll<HTMLButtonElement>('[role=\"tab\"]:not([disabled])'))\n}\n\n// ---------------------------------------------------------------------------\n// TabsTrigger\n// ---------------------------------------------------------------------------\n\nexport interface TabsTriggerProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n value: string\n}\n\nexport const TabsTrigger = React.forwardRef<HTMLButtonElement, TabsTriggerProps>(\n function TabsTrigger({ value, className, onClick, onKeyDown, children, ...props }, ref) {\n const { value: activeValue, onValueChange, idPrefix, panels } = useTabsContext()\n\n const isSelected = activeValue === value\n const tabId = `${idPrefix}-tab-${value}`\n const panelId = `${idPrefix}-panel-${value}`\n\n const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => {\n onValueChange(value)\n onClick?.(e)\n }\n\n // Arrow / Home / End navigation is handled by TabsList (roving focus);\n // a consumer onKeyDown runs first and can preventDefault to opt out.\n const handleKeyDown = (e: React.KeyboardEvent<HTMLButtonElement>) => {\n onKeyDown?.(e)\n }\n\n return React.createElement(\n 'button',\n {\n ref,\n type: 'button',\n role: 'tab',\n 'aria-selected': isSelected,\n // Only the selected panel is rendered; never reference a missing element.\n 'aria-controls': isSelected && panels.has(value) ? panelId : undefined,\n tabIndex: isSelected ? 0 : -1,\n id: tabId,\n 'data-state': isSelected ? 'active' : 'inactive',\n className: cn(tabsTriggerVariants(), className),\n onClick: handleClick,\n onKeyDown: handleKeyDown,\n ...props,\n },\n children,\n )\n },\n)\n\n// ---------------------------------------------------------------------------\n// TabsContent\n// ---------------------------------------------------------------------------\n\nexport interface TabsContentProps extends React.HTMLAttributes<HTMLDivElement> {\n value: string\n}\n\nexport const TabsContent = React.forwardRef<HTMLDivElement, TabsContentProps>(\n function TabsContent({ value, className, children, ...props }, ref) {\n const { value: activeValue, idPrefix, registerPanel } = useTabsContext()\n React.useEffect(() => registerPanel(value), [registerPanel, value])\n\n const isSelected = activeValue === value\n const tabId = `${idPrefix}-tab-${value}`\n const panelId = `${idPrefix}-panel-${value}`\n\n if (!isSelected) return null\n\n return React.createElement(\n 'div',\n {\n ref,\n role: 'tabpanel',\n 'aria-labelledby': tabId,\n id: panelId,\n tabIndex: 0,\n 'data-state': 'active',\n className,\n ...props,\n },\n children,\n )\n },\n)\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["Tabs", "TabsList", "TabsTrigger", "TabsContent"]
|
|
7
7
|
}
|
package/package.json
CHANGED