@dxos/react-ui-tabs 0.8.4-staging.60fe92afc8 → 0.9.1-main.c7dcc2e112
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/lib/browser/index.mjs +42 -16
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +42 -16
- package/dist/lib/node-esm/index.mjs.map +3 -3
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/types/src/Tabs.d.ts +19 -15
- package/dist/types/src/Tabs.d.ts.map +1 -1
- package/dist/types/src/Tabs.stories.d.ts +7 -4
- package/dist/types/src/Tabs.stories.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +9 -9
- package/src/Tabs.stories.tsx +1 -1
- package/src/Tabs.tsx +56 -18
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
// src/Tabs.tsx
|
|
2
2
|
import { useArrowNavigationGroup, useFocusFinders, useFocusableGroup } from "@fluentui/react-tabster";
|
|
3
3
|
import { createContext } from "@radix-ui/react-context";
|
|
4
|
+
import { Slot } from "@radix-ui/react-slot";
|
|
4
5
|
import * as TabsPrimitive from "@radix-ui/react-tabs";
|
|
5
6
|
import { useControllableState } from "@radix-ui/react-use-controllable-state";
|
|
6
|
-
import React, {
|
|
7
|
-
import { Button, IconButton, useForwardedRef } from "@dxos/react-ui";
|
|
7
|
+
import React, { useCallback, useLayoutEffect } from "react";
|
|
8
|
+
import { Button, IconButton, composableProps, slottable, useForwardedRef } from "@dxos/react-ui";
|
|
8
9
|
import { useAttention } from "@dxos/react-ui-attention";
|
|
9
10
|
import { mx } from "@dxos/ui-theme";
|
|
10
11
|
var TABS_NAME = "Tabs";
|
|
@@ -14,10 +15,10 @@ var [TabsContextProvider, useTabsContext] = createContext(TABS_NAME, {
|
|
|
14
15
|
setActivePart: () => {
|
|
15
16
|
}
|
|
16
17
|
});
|
|
17
|
-
var TabsRoot =
|
|
18
|
+
var TabsRoot = slottable(({ children, activePart: propsActivePart, onActivePartChange, defaultActivePart, value: propsValue, onValueChange, defaultValue, orientation = "vertical", activationMode = "manual", attendableId, suppressRegionFocus = false, asChild, ...props }, forwardedRef) => {
|
|
18
19
|
const tabsRoot = useForwardedRef(forwardedRef);
|
|
19
|
-
|
|
20
|
-
|
|
20
|
+
useArrowNavigationGroup();
|
|
21
|
+
useFocusableGroup();
|
|
21
22
|
const [activePart = "list", setActivePart] = useControllableState({
|
|
22
23
|
prop: propsActivePart,
|
|
23
24
|
onChange: onActivePartChange,
|
|
@@ -34,13 +35,37 @@ var TabsRoot = /* @__PURE__ */ forwardRef(({ children, classNames, activePart: p
|
|
|
34
35
|
}, [
|
|
35
36
|
value
|
|
36
37
|
]);
|
|
37
|
-
const { findFirstFocusable } = useFocusFinders();
|
|
38
|
+
const { findFirstFocusable, findNextFocusable } = useFocusFinders();
|
|
38
39
|
useLayoutEffect(() => {
|
|
39
|
-
if (
|
|
40
|
-
|
|
40
|
+
if (suppressRegionFocus) {
|
|
41
|
+
return;
|
|
41
42
|
}
|
|
43
|
+
const root = tabsRoot.current;
|
|
44
|
+
if (!root) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
if (activePart === "list") {
|
|
48
|
+
const tablist = root.querySelector('[role="tablist"]');
|
|
49
|
+
findFirstFocusable(tablist)?.focus();
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
const panel = root.querySelector('[role="tabpanel"][data-state="active"]');
|
|
53
|
+
if (!panel) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
let target = findFirstFocusable(panel);
|
|
57
|
+
if (target === panel) {
|
|
58
|
+
target = findNextFocusable(panel, {
|
|
59
|
+
container: panel
|
|
60
|
+
}) ?? void 0;
|
|
61
|
+
}
|
|
62
|
+
target?.focus();
|
|
42
63
|
}, [
|
|
43
|
-
activePart
|
|
64
|
+
activePart,
|
|
65
|
+
value,
|
|
66
|
+
findFirstFocusable,
|
|
67
|
+
findNextFocusable,
|
|
68
|
+
suppressRegionFocus
|
|
44
69
|
]);
|
|
45
70
|
return /* @__PURE__ */ React.createElement(TabsContextProvider, {
|
|
46
71
|
orientation,
|
|
@@ -49,8 +74,8 @@ var TabsRoot = /* @__PURE__ */ forwardRef(({ children, classNames, activePart: p
|
|
|
49
74
|
value,
|
|
50
75
|
attendableId
|
|
51
76
|
}, /* @__PURE__ */ React.createElement(TabsPrimitive.Root, {
|
|
52
|
-
...props,
|
|
53
|
-
|
|
77
|
+
...composableProps(props),
|
|
78
|
+
asChild,
|
|
54
79
|
orientation,
|
|
55
80
|
activationMode,
|
|
56
81
|
"data-active": activePart,
|
|
@@ -60,14 +85,15 @@ var TabsRoot = /* @__PURE__ */ forwardRef(({ children, classNames, activePart: p
|
|
|
60
85
|
}, children));
|
|
61
86
|
});
|
|
62
87
|
TabsRoot.displayName = "Tabs.Root";
|
|
63
|
-
var TabsViewport = ({
|
|
88
|
+
var TabsViewport = slottable(({ children, asChild, ...props }, forwardedRef) => {
|
|
64
89
|
const { activePart } = useTabsContext("TabsViewport");
|
|
65
|
-
|
|
66
|
-
|
|
90
|
+
const Comp = asChild ? Slot : "div";
|
|
91
|
+
return /* @__PURE__ */ React.createElement(Comp, {
|
|
92
|
+
...composableProps(props),
|
|
67
93
|
"data-active": activePart,
|
|
68
|
-
|
|
94
|
+
ref: forwardedRef
|
|
69
95
|
}, children);
|
|
70
|
-
};
|
|
96
|
+
});
|
|
71
97
|
TabsViewport.displayName = "Tabs.Viewport";
|
|
72
98
|
var TabsTablist = ({ children, classNames, ...props }) => {
|
|
73
99
|
const { orientation } = useTabsContext("TabsTablist");
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/Tabs.tsx"],
|
|
4
|
-
"sourcesContent": ["//\n// Copyright 2024 DXOS.org\n//\n\nimport { useArrowNavigationGroup, useFocusFinders, useFocusableGroup } from '@fluentui/react-tabster';\nimport { createContext } from '@radix-ui/react-context';\nimport * as TabsPrimitive from '@radix-ui/react-tabs';\nimport { useControllableState } from '@radix-ui/react-use-controllable-state';\nimport React, { type ComponentPropsWithoutRef, type MouseEvent, forwardRef, useCallback, useLayoutEffect } from 'react';\n\nimport {\n Button,\n type ButtonProps,\n IconButton,\n type IconButtonProps,\n type ThemedClassName,\n useForwardedRef,\n} from '@dxos/react-ui';\nimport { useAttention } from '@dxos/react-ui-attention';\nimport { mx } from '@dxos/ui-theme';\n\n// TODO(burdon): Move to @dxos/react-ui.\n\ntype TabsActivePart = 'list' | 'panel';\n\nconst TABS_NAME = 'Tabs';\n\n//\n// Context\n//\n\ntype TabsContextValue = {\n activePart: TabsActivePart;\n setActivePart: (nextActivePart: TabsActivePart) => void;\n attendableId?: string;\n} & Pick<TabsPrimitive.TabsProps, 'orientation' | 'value'>;\n\nconst [TabsContextProvider, useTabsContext] = createContext<TabsContextValue>(TABS_NAME, {\n orientation: 'vertical',\n activePart: 'list',\n setActivePart: () => {},\n});\n\n//\n// Root\n//\n\ntype TabsRootProps = ThemedClassName<TabsPrimitive.TabsProps> &\n Partial<\n Pick<TabsContextValue, 'activePart' | 'attendableId'> & {\n onActivePartChange: (nextActivePart: TabsActivePart) => void;\n defaultActivePart: TabsActivePart;\n }\n >;\n\nconst TabsRoot = forwardRef<HTMLDivElement, TabsRootProps>(\n (\n {\n children,\n classNames,\n activePart: propsActivePart,\n onActivePartChange,\n defaultActivePart,\n value: propsValue,\n onValueChange,\n defaultValue,\n orientation = 'vertical',\n activationMode = 'manual',\n attendableId,\n ...props\n },\n forwardedRef,\n ) => {\n const tabsRoot = useForwardedRef(forwardedRef);\n\n // TODO(thure): Without these, we get Groupper/Mover `API used before initialization`, but why?\n const _1 = useArrowNavigationGroup();\n const _2 = useFocusableGroup();\n const [activePart = 'list', setActivePart] = useControllableState({\n prop: propsActivePart,\n onChange: onActivePartChange,\n defaultProp: defaultActivePart,\n });\n\n const [value, setValue] = useControllableState({\n prop: propsValue,\n onChange: onValueChange,\n defaultProp: defaultValue,\n });\n\n const handleValueChange = useCallback(\n (nextValue: string) => {\n setActivePart('panel');\n setValue(nextValue);\n },\n [value],\n );\n\n const { findFirstFocusable } = useFocusFinders();\n\n useLayoutEffect(() => {\n if (tabsRoot.current) {\n findFirstFocusable(tabsRoot.current)?.focus();\n }\n }, [activePart]);\n\n return (\n <TabsContextProvider\n orientation={orientation}\n activePart={activePart}\n setActivePart={setActivePart}\n value={value}\n attendableId={attendableId}\n >\n <TabsPrimitive.Root\n {...props}\n className={mx('overflow-hidden', classNames)}\n orientation={orientation}\n activationMode={activationMode}\n data-active={activePart}\n value={value}\n onValueChange={handleValueChange}\n ref={tabsRoot}\n >\n {children}\n </TabsPrimitive.Root>\n </TabsContextProvider>\n );\n },\n);\n\nTabsRoot.displayName = 'Tabs.Root';\n\n//\n// Viewport\n//\n\ntype TabsViewportProps = ThemedClassName<ComponentPropsWithoutRef<'div'>>;\n\nconst TabsViewport = ({ classNames, children, ...props }: TabsViewportProps) => {\n const { activePart } = useTabsContext('TabsViewport');\n return (\n <div {...props} data-active={activePart} className={mx(classNames)}>\n {children}\n </div>\n );\n};\n\nTabsViewport.displayName = 'Tabs.Viewport';\n\n//\n// Tablist\n//\n\ntype TabsTablistProps = ThemedClassName<TabsPrimitive.TabsListProps>;\n\nconst TabsTablist = ({ children, classNames, ...props }: TabsTablistProps) => {\n const { orientation } = useTabsContext('TabsTablist');\n return (\n <TabsPrimitive.List\n {...props}\n data-arrow-keys={orientation === 'vertical' ? 'up down' : 'left right'}\n className={mx(\n 'max-h-full w-full',\n // TODO(burdon): Should be embeddable inside Toolbar (if horizontal).\n orientation === 'vertical' ? 'overflow-y-auto' : 'flex p-1 gap-1 items-stretch justify-start overflow-x-auto',\n classNames,\n )}\n >\n {children}\n </TabsPrimitive.List>\n );\n};\n\nTabsTablist.displayName = 'Tabs.Tablist';\n\n//\n// BackButton\n//\n\nconst TabsBackButton = ({ onClick, classNames, ...props }: ButtonProps) => {\n const { setActivePart } = useTabsContext('TabsBackButton');\n const handleClick = useCallback(\n (event: MouseEvent<HTMLButtonElement>) => {\n setActivePart('list');\n return onClick?.(event);\n },\n [setActivePart, onClick],\n );\n\n return <Button {...props} classNames={['@md:hidden text-start', classNames]} onClick={handleClick} />;\n};\n\nTabsBackButton.displayName = 'Tabs.BackButton';\n\n//\n// TabGroupHeading\n//\n\ntype TabsTabGroupHeadingProps = ThemedClassName<ComponentPropsWithoutRef<'h2'>>;\n\nconst TabsTabGroupHeading = ({ children, classNames, ...props }: TabsTabGroupHeadingProps) => (\n <h2 {...props} className={mx('my-1 px-2 text-sm text-un-accent', classNames)}>\n {children}\n </h2>\n);\n\nTabsTabGroupHeading.displayName = 'Tabs.TabGroupHeading';\n\n//\n// Tab\n//\n\ntype TabsTabProps = ButtonProps & Pick<TabsPrimitive.TabsTriggerProps, 'value'>;\n\nconst TabsTab = ({ value, classNames, children, onClick, ...props }: TabsTabProps) => {\n const { setActivePart, orientation, value: contextValue, attendableId } = useTabsContext('TabsTab');\n const { hasAttention } = useAttention(attendableId);\n\n const handleClick = useCallback(\n // NOTE: This handler is only called if the tab is *already active*.\n (event: MouseEvent<HTMLButtonElement>) => {\n setActivePart('panel');\n onClick?.(event);\n },\n [setActivePart, onClick],\n );\n\n return (\n <TabsPrimitive.Trigger value={value} asChild>\n <Button\n {...props}\n variant={\n orientation === 'horizontal' && contextValue === value ? (hasAttention ? 'primary' : 'default') : 'ghost'\n }\n classNames={[\n orientation === 'vertical' && 'block justify-start text-start w-full',\n orientation === 'vertical' && 'dx-selected',\n classNames,\n ]}\n onClick={handleClick}\n >\n {children}\n </Button>\n </TabsPrimitive.Trigger>\n );\n};\n\nTabsTab.displayName = 'Tabs.Tab';\n\n//\n// IconTab\n//\n\ntype TabsIconTabProps = IconButtonProps & Pick<TabsPrimitive.TabsTriggerProps, 'value'>;\n\nconst TabsIconTab = ({ value, classNames, onClick, ...props }: TabsIconTabProps) => {\n const { setActivePart, orientation, value: contextValue, attendableId } = useTabsContext('TabsTab');\n const { hasAttention } = useAttention(attendableId);\n\n // NOTE: This handler is only called if the tab is *already active*.\n const handleClick = useCallback(\n (event: MouseEvent<HTMLButtonElement>) => {\n setActivePart('panel');\n onClick?.(event);\n },\n [setActivePart, onClick],\n );\n\n return (\n <TabsPrimitive.Trigger value={value} asChild>\n <IconButton\n {...props}\n variant={\n orientation === 'horizontal' && contextValue === value ? (hasAttention ? 'primary' : 'default') : 'ghost'\n }\n classNames={[\n orientation === 'vertical' && 'justify-start text-start w-full',\n orientation === 'vertical' && 'dx-selected',\n classNames,\n ]}\n onClick={handleClick}\n />\n </TabsPrimitive.Trigger>\n );\n};\n\nTabsIconTab.displayName = 'Tabs.IconTab';\n\n//\n// Panel\n//\n// Do NOT wrap TabsPanel children in React.Activity.\n// Radix TabsPrimitive.Content already unmounts inactive panels (no forceMount) — inactive tab\n// content is not in the DOM and effects do not run, which is the desired behaviour.\n// React.Activity (experimental in React 19) is a reconciler-level symbol that deactivates its\n// subtree when mode='hidden'. It was redundant here and prevented initial render of active panels.\n//\n\ntype TabsPanelProps = ThemedClassName<TabsPrimitive.TabsContentProps>;\n\nconst TabsPanel = ({ classNames, children, ...props }: TabsPanelProps) => (\n <TabsPrimitive.Content {...props} className={mx('p-0! dx-focus-ring-inset-over-all', classNames)}>\n {children}\n </TabsPrimitive.Content>\n);\n\nTabsPanel.displayName = 'Tabs.Panel';\n\ntype TabsTabPrimitiveProps = TabsPrimitive.TabsTriggerProps;\n\n//\n// Tabs\n//\n\nexport const Tabs = {\n Root: TabsRoot,\n Tablist: TabsTablist,\n Tab: TabsTab,\n IconTab: TabsIconTab,\n TabPrimitive: TabsPrimitive.Trigger,\n TabGroupHeading: TabsTabGroupHeading,\n Viewport: TabsViewport,\n Panel: TabsPanel,\n BackButton: TabsBackButton,\n};\n\nexport type {\n TabsActivePart,\n TabsRootProps,\n TabsTablistProps,\n TabsTabProps,\n TabsTabPrimitiveProps,\n TabsTabGroupHeadingProps,\n TabsViewportProps,\n TabsPanelProps,\n};\n"],
|
|
5
|
-
"mappings": ";AAIA,SAASA,yBAAyBC,iBAAiBC,yBAAyB;AAC5E,SAASC,qBAAqB;AAC9B,YAAYC,mBAAmB;AAC/B,SAASC,4BAA4B;AACrC,OAAOC,SAAyDC,
|
|
6
|
-
"names": ["useArrowNavigationGroup", "useFocusFinders", "useFocusableGroup", "createContext", "
|
|
4
|
+
"sourcesContent": ["//\n// Copyright 2024 DXOS.org\n//\n\nimport { useArrowNavigationGroup, useFocusFinders, useFocusableGroup } from '@fluentui/react-tabster';\nimport { createContext } from '@radix-ui/react-context';\nimport { Slot } from '@radix-ui/react-slot';\nimport * as TabsPrimitive from '@radix-ui/react-tabs';\nimport { useControllableState } from '@radix-ui/react-use-controllable-state';\nimport React, { type ComponentPropsWithoutRef, type MouseEvent, useCallback, useLayoutEffect } from 'react';\n\nimport {\n Button,\n type ButtonProps,\n IconButton,\n type IconButtonProps,\n type SlottableProps,\n type ThemedClassName,\n composableProps,\n slottable,\n useForwardedRef,\n} from '@dxos/react-ui';\nimport { useAttention } from '@dxos/react-ui-attention';\nimport { mx } from '@dxos/ui-theme';\n\n// TODO(burdon): Rewrite this; there are too many hacks/quirks.\n\ntype TabsActivePart = 'list' | 'panel';\n\nconst TABS_NAME = 'Tabs';\n\n//\n// Context\n//\n\ntype TabsContextValue = {\n activePart: TabsActivePart;\n setActivePart: (nextActivePart: TabsActivePart) => void;\n attendableId?: string;\n} & Pick<TabsPrimitive.TabsProps, 'orientation' | 'value'>;\n\nconst [TabsContextProvider, useTabsContext] = createContext<TabsContextValue>(TABS_NAME, {\n orientation: 'vertical',\n activePart: 'list',\n setActivePart: () => {},\n});\n\n//\n// Root\n//\n\ntype TabsRootCustomProps = TabsPrimitive.TabsProps &\n Partial<\n Pick<TabsContextValue, 'activePart' | 'attendableId'> & {\n onActivePartChange: (nextActivePart: TabsActivePart) => void;\n defaultActivePart: TabsActivePart;\n /** Skip master-detail focus moves (e.g. when a child form owns initial focus). */\n suppressRegionFocus?: boolean;\n }\n >;\n\ntype TabsRootProps = SlottableProps<TabsRootCustomProps>;\n\nconst TabsRoot = slottable<HTMLDivElement, TabsRootCustomProps>(\n (\n {\n children,\n activePart: propsActivePart,\n onActivePartChange,\n defaultActivePart,\n value: propsValue,\n onValueChange,\n defaultValue,\n orientation = 'vertical',\n activationMode = 'manual',\n attendableId,\n suppressRegionFocus = false,\n asChild,\n ...props\n },\n forwardedRef,\n ) => {\n const tabsRoot = useForwardedRef(forwardedRef);\n\n // TODO(thure): Without these, we get Groupper/Mover `API used before initialization`, but why?\n useArrowNavigationGroup();\n useFocusableGroup();\n const [activePart = 'list', setActivePart] = useControllableState({\n prop: propsActivePart,\n onChange: onActivePartChange,\n defaultProp: defaultActivePart,\n });\n\n const [value, setValue] = useControllableState({\n prop: propsValue,\n onChange: onValueChange,\n defaultProp: defaultValue,\n });\n\n const handleValueChange = useCallback(\n (nextValue: string) => {\n setActivePart('panel');\n setValue(nextValue);\n },\n [value],\n );\n\n const { findFirstFocusable, findNextFocusable } = useFocusFinders();\n\n useLayoutEffect(() => {\n if (suppressRegionFocus) {\n return;\n }\n\n const root = tabsRoot.current;\n if (!root) {\n return;\n }\n\n if (activePart === 'list') {\n const tablist = root.querySelector<HTMLElement>('[role=\"tablist\"]');\n findFirstFocusable(tablist)?.focus();\n return;\n }\n\n const panel = root.querySelector<HTMLElement>('[role=\"tabpanel\"][data-state=\"active\"]');\n if (!panel) {\n return;\n }\n\n // Radix marks the active panel focusable for roving tabindex; skip it so content receives focus.\n let target = findFirstFocusable(panel);\n if (target === panel) {\n target = findNextFocusable(panel, { container: panel }) ?? undefined;\n }\n target?.focus();\n }, [activePart, value, findFirstFocusable, findNextFocusable, suppressRegionFocus]);\n\n return (\n <TabsContextProvider\n orientation={orientation}\n activePart={activePart}\n setActivePart={setActivePart}\n value={value}\n attendableId={attendableId}\n >\n <TabsPrimitive.Root\n {...composableProps<HTMLDivElement>(props)}\n asChild={asChild}\n orientation={orientation}\n activationMode={activationMode}\n data-active={activePart}\n value={value}\n onValueChange={handleValueChange}\n ref={tabsRoot}\n >\n {children}\n </TabsPrimitive.Root>\n </TabsContextProvider>\n );\n },\n);\n\nTabsRoot.displayName = 'Tabs.Root';\n\n//\n// Viewport\n//\n\ntype TabsViewportProps = SlottableProps<\n Omit<ComponentPropsWithoutRef<'div'>, 'className' | 'style' | 'children' | 'role'>\n>;\n\nconst TabsViewport = slottable<\n HTMLDivElement,\n Omit<ComponentPropsWithoutRef<'div'>, 'className' | 'style' | 'children' | 'role'>\n>(({ children, asChild, ...props }, forwardedRef) => {\n const { activePart } = useTabsContext('TabsViewport');\n const Comp = asChild ? Slot : 'div';\n return (\n <Comp {...composableProps<HTMLDivElement>(props)} data-active={activePart} ref={forwardedRef}>\n {children}\n </Comp>\n );\n});\n\nTabsViewport.displayName = 'Tabs.Viewport';\n\n//\n// Tablist\n//\n\ntype TabsTablistProps = ThemedClassName<TabsPrimitive.TabsListProps>;\n\nconst TabsTablist = ({ children, classNames, ...props }: TabsTablistProps) => {\n const { orientation } = useTabsContext('TabsTablist');\n return (\n <TabsPrimitive.List\n {...props}\n data-arrow-keys={orientation === 'vertical' ? 'up down' : 'left right'}\n className={mx(\n 'max-h-full w-full',\n // TODO(burdon): Should be embeddable inside Toolbar (if horizontal).\n orientation === 'vertical' ? 'overflow-y-auto' : 'flex p-1 gap-1 items-stretch justify-start overflow-x-auto',\n classNames,\n )}\n >\n {children}\n </TabsPrimitive.List>\n );\n};\n\nTabsTablist.displayName = 'Tabs.Tablist';\n\n//\n// BackButton\n//\n\nconst TabsBackButton = ({ onClick, classNames, ...props }: ButtonProps) => {\n const { setActivePart } = useTabsContext('TabsBackButton');\n const handleClick = useCallback(\n (event: MouseEvent<HTMLButtonElement>) => {\n setActivePart('list');\n return onClick?.(event);\n },\n [setActivePart, onClick],\n );\n\n return <Button {...props} classNames={['@md:hidden text-start', classNames]} onClick={handleClick} />;\n};\n\nTabsBackButton.displayName = 'Tabs.BackButton';\n\n//\n// TabGroupHeading\n//\n\ntype TabsTabGroupHeadingProps = ThemedClassName<ComponentPropsWithoutRef<'h2'>>;\n\nconst TabsTabGroupHeading = ({ children, classNames, ...props }: TabsTabGroupHeadingProps) => (\n <h2 {...props} className={mx('my-1 px-2 text-sm text-un-accent', classNames)}>\n {children}\n </h2>\n);\n\nTabsTabGroupHeading.displayName = 'Tabs.TabGroupHeading';\n\n//\n// Tab\n//\n\ntype TabsTabProps = ButtonProps & Pick<TabsPrimitive.TabsTriggerProps, 'value'>;\n\nconst TabsTab = ({ value, classNames, children, onClick, ...props }: TabsTabProps) => {\n const { setActivePart, orientation, value: contextValue, attendableId } = useTabsContext('TabsTab');\n const { hasAttention } = useAttention(attendableId);\n\n const handleClick = useCallback(\n // NOTE: This handler is only called if the tab is *already active*.\n (event: MouseEvent<HTMLButtonElement>) => {\n setActivePart('panel');\n onClick?.(event);\n },\n [setActivePart, onClick],\n );\n\n return (\n <TabsPrimitive.Trigger value={value} asChild>\n <Button\n {...props}\n variant={\n orientation === 'horizontal' && contextValue === value ? (hasAttention ? 'primary' : 'default') : 'ghost'\n }\n classNames={[\n orientation === 'vertical' && 'block justify-start text-start w-full',\n orientation === 'vertical' && 'dx-selected',\n classNames,\n ]}\n onClick={handleClick}\n >\n {children}\n </Button>\n </TabsPrimitive.Trigger>\n );\n};\n\nTabsTab.displayName = 'Tabs.Tab';\n\n//\n// IconTab\n//\n\ntype TabsIconTabProps = IconButtonProps & Pick<TabsPrimitive.TabsTriggerProps, 'value'>;\n\nconst TabsIconTab = ({ value, classNames, onClick, ...props }: TabsIconTabProps) => {\n const { setActivePart, orientation, value: contextValue, attendableId } = useTabsContext('TabsTab');\n const { hasAttention } = useAttention(attendableId);\n\n // NOTE: This handler is only called if the tab is *already active*.\n const handleClick = useCallback(\n (event: MouseEvent<HTMLButtonElement>) => {\n setActivePart('panel');\n onClick?.(event);\n },\n [setActivePart, onClick],\n );\n\n return (\n <TabsPrimitive.Trigger value={value} asChild>\n <IconButton\n {...props}\n variant={\n orientation === 'horizontal' && contextValue === value ? (hasAttention ? 'primary' : 'default') : 'ghost'\n }\n classNames={[\n orientation === 'vertical' && 'justify-start text-start w-full',\n orientation === 'vertical' && 'dx-selected',\n classNames,\n ]}\n onClick={handleClick}\n />\n </TabsPrimitive.Trigger>\n );\n};\n\nTabsIconTab.displayName = 'Tabs.IconTab';\n\n//\n// Panel\n//\n// Do NOT wrap TabsPanel children in React.Activity.\n// Radix TabsPrimitive.Content already unmounts inactive panels (no forceMount) — inactive tab\n// content is not in the DOM and effects do not run, which is the desired behaviour.\n// React.Activity (experimental in React 19) is a reconciler-level symbol that deactivates its\n// subtree when mode='hidden'. It was redundant here and prevented initial render of active panels.\n//\n\ntype TabsPanelProps = ThemedClassName<TabsPrimitive.TabsContentProps>;\n\nconst TabsPanel = ({ classNames, children, ...props }: TabsPanelProps) => (\n <TabsPrimitive.Content {...props} className={mx('p-0! dx-focus-ring-inset-over-all', classNames)}>\n {children}\n </TabsPrimitive.Content>\n);\n\nTabsPanel.displayName = 'Tabs.Panel';\n\ntype TabsTabPrimitiveProps = TabsPrimitive.TabsTriggerProps;\n\n//\n// Tabs\n//\n\nexport const Tabs = {\n Root: TabsRoot,\n Tablist: TabsTablist,\n Tab: TabsTab,\n IconTab: TabsIconTab,\n TabPrimitive: TabsPrimitive.Trigger,\n TabGroupHeading: TabsTabGroupHeading,\n Viewport: TabsViewport,\n Panel: TabsPanel,\n BackButton: TabsBackButton,\n};\n\nexport type {\n TabsActivePart,\n TabsRootProps,\n TabsTablistProps,\n TabsTabProps,\n TabsTabPrimitiveProps,\n TabsTabGroupHeadingProps,\n TabsViewportProps,\n TabsPanelProps,\n};\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["useArrowNavigationGroup", "useFocusFinders", "useFocusableGroup", "createContext", "Slot", "TabsPrimitive", "useControllableState", "React", "useCallback", "useLayoutEffect", "Button", "IconButton", "composableProps", "slottable", "useForwardedRef", "useAttention", "mx", "TABS_NAME", "TabsContextProvider", "useTabsContext", "orientation", "activePart", "setActivePart", "TabsRoot", "children", "propsActivePart", "onActivePartChange", "defaultActivePart", "value", "propsValue", "onValueChange", "defaultValue", "activationMode", "attendableId", "suppressRegionFocus", "asChild", "props", "forwardedRef", "tabsRoot", "prop", "onChange", "defaultProp", "setValue", "handleValueChange", "nextValue", "findFirstFocusable", "findNextFocusable", "root", "current", "tablist", "querySelector", "focus", "panel", "target", "container", "undefined", "Root", "data-active", "ref", "displayName", "TabsViewport", "Comp", "TabsTablist", "classNames", "List", "data-arrow-keys", "className", "TabsBackButton", "onClick", "handleClick", "event", "TabsTabGroupHeading", "h2", "TabsTab", "contextValue", "hasAttention", "Trigger", "variant", "TabsIconTab", "TabsPanel", "Content", "Tabs", "Tablist", "Tab", "IconTab", "TabPrimitive", "TabGroupHeading", "Viewport", "Panel", "BackButton"]
|
|
7
7
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"inputs":{"src/Tabs.tsx":{"bytes":
|
|
1
|
+
{"inputs":{"src/Tabs.tsx":{"bytes":29707,"imports":[{"path":"@fluentui/react-tabster","kind":"import-statement","external":true},{"path":"@radix-ui/react-context","kind":"import-statement","external":true},{"path":"@radix-ui/react-slot","kind":"import-statement","external":true},{"path":"@radix-ui/react-tabs","kind":"import-statement","external":true},{"path":"@radix-ui/react-use-controllable-state","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"@dxos/react-ui","kind":"import-statement","external":true},{"path":"@dxos/react-ui-attention","kind":"import-statement","external":true},{"path":"@dxos/ui-theme","kind":"import-statement","external":true}],"format":"esm"},"src/index.ts":{"bytes":368,"imports":[{"path":"src/Tabs.tsx","kind":"import-statement","original":"./Tabs"}],"format":"esm"}},"outputs":{"dist/lib/browser/index.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":16099},"dist/lib/browser/index.mjs":{"imports":[{"path":"@fluentui/react-tabster","kind":"import-statement","external":true},{"path":"@radix-ui/react-context","kind":"import-statement","external":true},{"path":"@radix-ui/react-slot","kind":"import-statement","external":true},{"path":"@radix-ui/react-tabs","kind":"import-statement","external":true},{"path":"@radix-ui/react-use-controllable-state","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"@dxos/react-ui","kind":"import-statement","external":true},{"path":"@dxos/react-ui-attention","kind":"import-statement","external":true},{"path":"@dxos/ui-theme","kind":"import-statement","external":true}],"exports":["Tabs"],"entryPoint":"src/index.ts","inputs":{"src/Tabs.tsx":{"bytesInOutput":6965},"src/index.ts":{"bytesInOutput":0}},"bytes":7035}}}
|
|
@@ -3,10 +3,11 @@ import { createRequire } from 'node:module';const require = createRequire(import
|
|
|
3
3
|
// src/Tabs.tsx
|
|
4
4
|
import { useArrowNavigationGroup, useFocusFinders, useFocusableGroup } from "@fluentui/react-tabster";
|
|
5
5
|
import { createContext } from "@radix-ui/react-context";
|
|
6
|
+
import { Slot } from "@radix-ui/react-slot";
|
|
6
7
|
import * as TabsPrimitive from "@radix-ui/react-tabs";
|
|
7
8
|
import { useControllableState } from "@radix-ui/react-use-controllable-state";
|
|
8
|
-
import React, {
|
|
9
|
-
import { Button, IconButton, useForwardedRef } from "@dxos/react-ui";
|
|
9
|
+
import React, { useCallback, useLayoutEffect } from "react";
|
|
10
|
+
import { Button, IconButton, composableProps, slottable, useForwardedRef } from "@dxos/react-ui";
|
|
10
11
|
import { useAttention } from "@dxos/react-ui-attention";
|
|
11
12
|
import { mx } from "@dxos/ui-theme";
|
|
12
13
|
var TABS_NAME = "Tabs";
|
|
@@ -16,10 +17,10 @@ var [TabsContextProvider, useTabsContext] = createContext(TABS_NAME, {
|
|
|
16
17
|
setActivePart: () => {
|
|
17
18
|
}
|
|
18
19
|
});
|
|
19
|
-
var TabsRoot =
|
|
20
|
+
var TabsRoot = slottable(({ children, activePart: propsActivePart, onActivePartChange, defaultActivePart, value: propsValue, onValueChange, defaultValue, orientation = "vertical", activationMode = "manual", attendableId, suppressRegionFocus = false, asChild, ...props }, forwardedRef) => {
|
|
20
21
|
const tabsRoot = useForwardedRef(forwardedRef);
|
|
21
|
-
|
|
22
|
-
|
|
22
|
+
useArrowNavigationGroup();
|
|
23
|
+
useFocusableGroup();
|
|
23
24
|
const [activePart = "list", setActivePart] = useControllableState({
|
|
24
25
|
prop: propsActivePart,
|
|
25
26
|
onChange: onActivePartChange,
|
|
@@ -36,13 +37,37 @@ var TabsRoot = /* @__PURE__ */ forwardRef(({ children, classNames, activePart: p
|
|
|
36
37
|
}, [
|
|
37
38
|
value
|
|
38
39
|
]);
|
|
39
|
-
const { findFirstFocusable } = useFocusFinders();
|
|
40
|
+
const { findFirstFocusable, findNextFocusable } = useFocusFinders();
|
|
40
41
|
useLayoutEffect(() => {
|
|
41
|
-
if (
|
|
42
|
-
|
|
42
|
+
if (suppressRegionFocus) {
|
|
43
|
+
return;
|
|
43
44
|
}
|
|
45
|
+
const root = tabsRoot.current;
|
|
46
|
+
if (!root) {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
if (activePart === "list") {
|
|
50
|
+
const tablist = root.querySelector('[role="tablist"]');
|
|
51
|
+
findFirstFocusable(tablist)?.focus();
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
const panel = root.querySelector('[role="tabpanel"][data-state="active"]');
|
|
55
|
+
if (!panel) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
let target = findFirstFocusable(panel);
|
|
59
|
+
if (target === panel) {
|
|
60
|
+
target = findNextFocusable(panel, {
|
|
61
|
+
container: panel
|
|
62
|
+
}) ?? void 0;
|
|
63
|
+
}
|
|
64
|
+
target?.focus();
|
|
44
65
|
}, [
|
|
45
|
-
activePart
|
|
66
|
+
activePart,
|
|
67
|
+
value,
|
|
68
|
+
findFirstFocusable,
|
|
69
|
+
findNextFocusable,
|
|
70
|
+
suppressRegionFocus
|
|
46
71
|
]);
|
|
47
72
|
return /* @__PURE__ */ React.createElement(TabsContextProvider, {
|
|
48
73
|
orientation,
|
|
@@ -51,8 +76,8 @@ var TabsRoot = /* @__PURE__ */ forwardRef(({ children, classNames, activePart: p
|
|
|
51
76
|
value,
|
|
52
77
|
attendableId
|
|
53
78
|
}, /* @__PURE__ */ React.createElement(TabsPrimitive.Root, {
|
|
54
|
-
...props,
|
|
55
|
-
|
|
79
|
+
...composableProps(props),
|
|
80
|
+
asChild,
|
|
56
81
|
orientation,
|
|
57
82
|
activationMode,
|
|
58
83
|
"data-active": activePart,
|
|
@@ -62,14 +87,15 @@ var TabsRoot = /* @__PURE__ */ forwardRef(({ children, classNames, activePart: p
|
|
|
62
87
|
}, children));
|
|
63
88
|
});
|
|
64
89
|
TabsRoot.displayName = "Tabs.Root";
|
|
65
|
-
var TabsViewport = ({
|
|
90
|
+
var TabsViewport = slottable(({ children, asChild, ...props }, forwardedRef) => {
|
|
66
91
|
const { activePart } = useTabsContext("TabsViewport");
|
|
67
|
-
|
|
68
|
-
|
|
92
|
+
const Comp = asChild ? Slot : "div";
|
|
93
|
+
return /* @__PURE__ */ React.createElement(Comp, {
|
|
94
|
+
...composableProps(props),
|
|
69
95
|
"data-active": activePart,
|
|
70
|
-
|
|
96
|
+
ref: forwardedRef
|
|
71
97
|
}, children);
|
|
72
|
-
};
|
|
98
|
+
});
|
|
73
99
|
TabsViewport.displayName = "Tabs.Viewport";
|
|
74
100
|
var TabsTablist = ({ children, classNames, ...props }) => {
|
|
75
101
|
const { orientation } = useTabsContext("TabsTablist");
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/Tabs.tsx"],
|
|
4
|
-
"sourcesContent": ["//\n// Copyright 2024 DXOS.org\n//\n\nimport { useArrowNavigationGroup, useFocusFinders, useFocusableGroup } from '@fluentui/react-tabster';\nimport { createContext } from '@radix-ui/react-context';\nimport * as TabsPrimitive from '@radix-ui/react-tabs';\nimport { useControllableState } from '@radix-ui/react-use-controllable-state';\nimport React, { type ComponentPropsWithoutRef, type MouseEvent, forwardRef, useCallback, useLayoutEffect } from 'react';\n\nimport {\n Button,\n type ButtonProps,\n IconButton,\n type IconButtonProps,\n type ThemedClassName,\n useForwardedRef,\n} from '@dxos/react-ui';\nimport { useAttention } from '@dxos/react-ui-attention';\nimport { mx } from '@dxos/ui-theme';\n\n// TODO(burdon): Move to @dxos/react-ui.\n\ntype TabsActivePart = 'list' | 'panel';\n\nconst TABS_NAME = 'Tabs';\n\n//\n// Context\n//\n\ntype TabsContextValue = {\n activePart: TabsActivePart;\n setActivePart: (nextActivePart: TabsActivePart) => void;\n attendableId?: string;\n} & Pick<TabsPrimitive.TabsProps, 'orientation' | 'value'>;\n\nconst [TabsContextProvider, useTabsContext] = createContext<TabsContextValue>(TABS_NAME, {\n orientation: 'vertical',\n activePart: 'list',\n setActivePart: () => {},\n});\n\n//\n// Root\n//\n\ntype TabsRootProps = ThemedClassName<TabsPrimitive.TabsProps> &\n Partial<\n Pick<TabsContextValue, 'activePart' | 'attendableId'> & {\n onActivePartChange: (nextActivePart: TabsActivePart) => void;\n defaultActivePart: TabsActivePart;\n }\n >;\n\nconst TabsRoot = forwardRef<HTMLDivElement, TabsRootProps>(\n (\n {\n children,\n classNames,\n activePart: propsActivePart,\n onActivePartChange,\n defaultActivePart,\n value: propsValue,\n onValueChange,\n defaultValue,\n orientation = 'vertical',\n activationMode = 'manual',\n attendableId,\n ...props\n },\n forwardedRef,\n ) => {\n const tabsRoot = useForwardedRef(forwardedRef);\n\n // TODO(thure): Without these, we get Groupper/Mover `API used before initialization`, but why?\n const _1 = useArrowNavigationGroup();\n const _2 = useFocusableGroup();\n const [activePart = 'list', setActivePart] = useControllableState({\n prop: propsActivePart,\n onChange: onActivePartChange,\n defaultProp: defaultActivePart,\n });\n\n const [value, setValue] = useControllableState({\n prop: propsValue,\n onChange: onValueChange,\n defaultProp: defaultValue,\n });\n\n const handleValueChange = useCallback(\n (nextValue: string) => {\n setActivePart('panel');\n setValue(nextValue);\n },\n [value],\n );\n\n const { findFirstFocusable } = useFocusFinders();\n\n useLayoutEffect(() => {\n if (tabsRoot.current) {\n findFirstFocusable(tabsRoot.current)?.focus();\n }\n }, [activePart]);\n\n return (\n <TabsContextProvider\n orientation={orientation}\n activePart={activePart}\n setActivePart={setActivePart}\n value={value}\n attendableId={attendableId}\n >\n <TabsPrimitive.Root\n {...props}\n className={mx('overflow-hidden', classNames)}\n orientation={orientation}\n activationMode={activationMode}\n data-active={activePart}\n value={value}\n onValueChange={handleValueChange}\n ref={tabsRoot}\n >\n {children}\n </TabsPrimitive.Root>\n </TabsContextProvider>\n );\n },\n);\n\nTabsRoot.displayName = 'Tabs.Root';\n\n//\n// Viewport\n//\n\ntype TabsViewportProps = ThemedClassName<ComponentPropsWithoutRef<'div'>>;\n\nconst TabsViewport = ({ classNames, children, ...props }: TabsViewportProps) => {\n const { activePart } = useTabsContext('TabsViewport');\n return (\n <div {...props} data-active={activePart} className={mx(classNames)}>\n {children}\n </div>\n );\n};\n\nTabsViewport.displayName = 'Tabs.Viewport';\n\n//\n// Tablist\n//\n\ntype TabsTablistProps = ThemedClassName<TabsPrimitive.TabsListProps>;\n\nconst TabsTablist = ({ children, classNames, ...props }: TabsTablistProps) => {\n const { orientation } = useTabsContext('TabsTablist');\n return (\n <TabsPrimitive.List\n {...props}\n data-arrow-keys={orientation === 'vertical' ? 'up down' : 'left right'}\n className={mx(\n 'max-h-full w-full',\n // TODO(burdon): Should be embeddable inside Toolbar (if horizontal).\n orientation === 'vertical' ? 'overflow-y-auto' : 'flex p-1 gap-1 items-stretch justify-start overflow-x-auto',\n classNames,\n )}\n >\n {children}\n </TabsPrimitive.List>\n );\n};\n\nTabsTablist.displayName = 'Tabs.Tablist';\n\n//\n// BackButton\n//\n\nconst TabsBackButton = ({ onClick, classNames, ...props }: ButtonProps) => {\n const { setActivePart } = useTabsContext('TabsBackButton');\n const handleClick = useCallback(\n (event: MouseEvent<HTMLButtonElement>) => {\n setActivePart('list');\n return onClick?.(event);\n },\n [setActivePart, onClick],\n );\n\n return <Button {...props} classNames={['@md:hidden text-start', classNames]} onClick={handleClick} />;\n};\n\nTabsBackButton.displayName = 'Tabs.BackButton';\n\n//\n// TabGroupHeading\n//\n\ntype TabsTabGroupHeadingProps = ThemedClassName<ComponentPropsWithoutRef<'h2'>>;\n\nconst TabsTabGroupHeading = ({ children, classNames, ...props }: TabsTabGroupHeadingProps) => (\n <h2 {...props} className={mx('my-1 px-2 text-sm text-un-accent', classNames)}>\n {children}\n </h2>\n);\n\nTabsTabGroupHeading.displayName = 'Tabs.TabGroupHeading';\n\n//\n// Tab\n//\n\ntype TabsTabProps = ButtonProps & Pick<TabsPrimitive.TabsTriggerProps, 'value'>;\n\nconst TabsTab = ({ value, classNames, children, onClick, ...props }: TabsTabProps) => {\n const { setActivePart, orientation, value: contextValue, attendableId } = useTabsContext('TabsTab');\n const { hasAttention } = useAttention(attendableId);\n\n const handleClick = useCallback(\n // NOTE: This handler is only called if the tab is *already active*.\n (event: MouseEvent<HTMLButtonElement>) => {\n setActivePart('panel');\n onClick?.(event);\n },\n [setActivePart, onClick],\n );\n\n return (\n <TabsPrimitive.Trigger value={value} asChild>\n <Button\n {...props}\n variant={\n orientation === 'horizontal' && contextValue === value ? (hasAttention ? 'primary' : 'default') : 'ghost'\n }\n classNames={[\n orientation === 'vertical' && 'block justify-start text-start w-full',\n orientation === 'vertical' && 'dx-selected',\n classNames,\n ]}\n onClick={handleClick}\n >\n {children}\n </Button>\n </TabsPrimitive.Trigger>\n );\n};\n\nTabsTab.displayName = 'Tabs.Tab';\n\n//\n// IconTab\n//\n\ntype TabsIconTabProps = IconButtonProps & Pick<TabsPrimitive.TabsTriggerProps, 'value'>;\n\nconst TabsIconTab = ({ value, classNames, onClick, ...props }: TabsIconTabProps) => {\n const { setActivePart, orientation, value: contextValue, attendableId } = useTabsContext('TabsTab');\n const { hasAttention } = useAttention(attendableId);\n\n // NOTE: This handler is only called if the tab is *already active*.\n const handleClick = useCallback(\n (event: MouseEvent<HTMLButtonElement>) => {\n setActivePart('panel');\n onClick?.(event);\n },\n [setActivePart, onClick],\n );\n\n return (\n <TabsPrimitive.Trigger value={value} asChild>\n <IconButton\n {...props}\n variant={\n orientation === 'horizontal' && contextValue === value ? (hasAttention ? 'primary' : 'default') : 'ghost'\n }\n classNames={[\n orientation === 'vertical' && 'justify-start text-start w-full',\n orientation === 'vertical' && 'dx-selected',\n classNames,\n ]}\n onClick={handleClick}\n />\n </TabsPrimitive.Trigger>\n );\n};\n\nTabsIconTab.displayName = 'Tabs.IconTab';\n\n//\n// Panel\n//\n// Do NOT wrap TabsPanel children in React.Activity.\n// Radix TabsPrimitive.Content already unmounts inactive panels (no forceMount) — inactive tab\n// content is not in the DOM and effects do not run, which is the desired behaviour.\n// React.Activity (experimental in React 19) is a reconciler-level symbol that deactivates its\n// subtree when mode='hidden'. It was redundant here and prevented initial render of active panels.\n//\n\ntype TabsPanelProps = ThemedClassName<TabsPrimitive.TabsContentProps>;\n\nconst TabsPanel = ({ classNames, children, ...props }: TabsPanelProps) => (\n <TabsPrimitive.Content {...props} className={mx('p-0! dx-focus-ring-inset-over-all', classNames)}>\n {children}\n </TabsPrimitive.Content>\n);\n\nTabsPanel.displayName = 'Tabs.Panel';\n\ntype TabsTabPrimitiveProps = TabsPrimitive.TabsTriggerProps;\n\n//\n// Tabs\n//\n\nexport const Tabs = {\n Root: TabsRoot,\n Tablist: TabsTablist,\n Tab: TabsTab,\n IconTab: TabsIconTab,\n TabPrimitive: TabsPrimitive.Trigger,\n TabGroupHeading: TabsTabGroupHeading,\n Viewport: TabsViewport,\n Panel: TabsPanel,\n BackButton: TabsBackButton,\n};\n\nexport type {\n TabsActivePart,\n TabsRootProps,\n TabsTablistProps,\n TabsTabProps,\n TabsTabPrimitiveProps,\n TabsTabGroupHeadingProps,\n TabsViewportProps,\n TabsPanelProps,\n};\n"],
|
|
5
|
-
"mappings": ";;;AAIA,SAASA,yBAAyBC,iBAAiBC,yBAAyB;AAC5E,SAASC,qBAAqB;AAC9B,YAAYC,mBAAmB;AAC/B,SAASC,4BAA4B;AACrC,OAAOC,SAAyDC,
|
|
6
|
-
"names": ["useArrowNavigationGroup", "useFocusFinders", "useFocusableGroup", "createContext", "
|
|
4
|
+
"sourcesContent": ["//\n// Copyright 2024 DXOS.org\n//\n\nimport { useArrowNavigationGroup, useFocusFinders, useFocusableGroup } from '@fluentui/react-tabster';\nimport { createContext } from '@radix-ui/react-context';\nimport { Slot } from '@radix-ui/react-slot';\nimport * as TabsPrimitive from '@radix-ui/react-tabs';\nimport { useControllableState } from '@radix-ui/react-use-controllable-state';\nimport React, { type ComponentPropsWithoutRef, type MouseEvent, useCallback, useLayoutEffect } from 'react';\n\nimport {\n Button,\n type ButtonProps,\n IconButton,\n type IconButtonProps,\n type SlottableProps,\n type ThemedClassName,\n composableProps,\n slottable,\n useForwardedRef,\n} from '@dxos/react-ui';\nimport { useAttention } from '@dxos/react-ui-attention';\nimport { mx } from '@dxos/ui-theme';\n\n// TODO(burdon): Rewrite this; there are too many hacks/quirks.\n\ntype TabsActivePart = 'list' | 'panel';\n\nconst TABS_NAME = 'Tabs';\n\n//\n// Context\n//\n\ntype TabsContextValue = {\n activePart: TabsActivePart;\n setActivePart: (nextActivePart: TabsActivePart) => void;\n attendableId?: string;\n} & Pick<TabsPrimitive.TabsProps, 'orientation' | 'value'>;\n\nconst [TabsContextProvider, useTabsContext] = createContext<TabsContextValue>(TABS_NAME, {\n orientation: 'vertical',\n activePart: 'list',\n setActivePart: () => {},\n});\n\n//\n// Root\n//\n\ntype TabsRootCustomProps = TabsPrimitive.TabsProps &\n Partial<\n Pick<TabsContextValue, 'activePart' | 'attendableId'> & {\n onActivePartChange: (nextActivePart: TabsActivePart) => void;\n defaultActivePart: TabsActivePart;\n /** Skip master-detail focus moves (e.g. when a child form owns initial focus). */\n suppressRegionFocus?: boolean;\n }\n >;\n\ntype TabsRootProps = SlottableProps<TabsRootCustomProps>;\n\nconst TabsRoot = slottable<HTMLDivElement, TabsRootCustomProps>(\n (\n {\n children,\n activePart: propsActivePart,\n onActivePartChange,\n defaultActivePart,\n value: propsValue,\n onValueChange,\n defaultValue,\n orientation = 'vertical',\n activationMode = 'manual',\n attendableId,\n suppressRegionFocus = false,\n asChild,\n ...props\n },\n forwardedRef,\n ) => {\n const tabsRoot = useForwardedRef(forwardedRef);\n\n // TODO(thure): Without these, we get Groupper/Mover `API used before initialization`, but why?\n useArrowNavigationGroup();\n useFocusableGroup();\n const [activePart = 'list', setActivePart] = useControllableState({\n prop: propsActivePart,\n onChange: onActivePartChange,\n defaultProp: defaultActivePart,\n });\n\n const [value, setValue] = useControllableState({\n prop: propsValue,\n onChange: onValueChange,\n defaultProp: defaultValue,\n });\n\n const handleValueChange = useCallback(\n (nextValue: string) => {\n setActivePart('panel');\n setValue(nextValue);\n },\n [value],\n );\n\n const { findFirstFocusable, findNextFocusable } = useFocusFinders();\n\n useLayoutEffect(() => {\n if (suppressRegionFocus) {\n return;\n }\n\n const root = tabsRoot.current;\n if (!root) {\n return;\n }\n\n if (activePart === 'list') {\n const tablist = root.querySelector<HTMLElement>('[role=\"tablist\"]');\n findFirstFocusable(tablist)?.focus();\n return;\n }\n\n const panel = root.querySelector<HTMLElement>('[role=\"tabpanel\"][data-state=\"active\"]');\n if (!panel) {\n return;\n }\n\n // Radix marks the active panel focusable for roving tabindex; skip it so content receives focus.\n let target = findFirstFocusable(panel);\n if (target === panel) {\n target = findNextFocusable(panel, { container: panel }) ?? undefined;\n }\n target?.focus();\n }, [activePart, value, findFirstFocusable, findNextFocusable, suppressRegionFocus]);\n\n return (\n <TabsContextProvider\n orientation={orientation}\n activePart={activePart}\n setActivePart={setActivePart}\n value={value}\n attendableId={attendableId}\n >\n <TabsPrimitive.Root\n {...composableProps<HTMLDivElement>(props)}\n asChild={asChild}\n orientation={orientation}\n activationMode={activationMode}\n data-active={activePart}\n value={value}\n onValueChange={handleValueChange}\n ref={tabsRoot}\n >\n {children}\n </TabsPrimitive.Root>\n </TabsContextProvider>\n );\n },\n);\n\nTabsRoot.displayName = 'Tabs.Root';\n\n//\n// Viewport\n//\n\ntype TabsViewportProps = SlottableProps<\n Omit<ComponentPropsWithoutRef<'div'>, 'className' | 'style' | 'children' | 'role'>\n>;\n\nconst TabsViewport = slottable<\n HTMLDivElement,\n Omit<ComponentPropsWithoutRef<'div'>, 'className' | 'style' | 'children' | 'role'>\n>(({ children, asChild, ...props }, forwardedRef) => {\n const { activePart } = useTabsContext('TabsViewport');\n const Comp = asChild ? Slot : 'div';\n return (\n <Comp {...composableProps<HTMLDivElement>(props)} data-active={activePart} ref={forwardedRef}>\n {children}\n </Comp>\n );\n});\n\nTabsViewport.displayName = 'Tabs.Viewport';\n\n//\n// Tablist\n//\n\ntype TabsTablistProps = ThemedClassName<TabsPrimitive.TabsListProps>;\n\nconst TabsTablist = ({ children, classNames, ...props }: TabsTablistProps) => {\n const { orientation } = useTabsContext('TabsTablist');\n return (\n <TabsPrimitive.List\n {...props}\n data-arrow-keys={orientation === 'vertical' ? 'up down' : 'left right'}\n className={mx(\n 'max-h-full w-full',\n // TODO(burdon): Should be embeddable inside Toolbar (if horizontal).\n orientation === 'vertical' ? 'overflow-y-auto' : 'flex p-1 gap-1 items-stretch justify-start overflow-x-auto',\n classNames,\n )}\n >\n {children}\n </TabsPrimitive.List>\n );\n};\n\nTabsTablist.displayName = 'Tabs.Tablist';\n\n//\n// BackButton\n//\n\nconst TabsBackButton = ({ onClick, classNames, ...props }: ButtonProps) => {\n const { setActivePart } = useTabsContext('TabsBackButton');\n const handleClick = useCallback(\n (event: MouseEvent<HTMLButtonElement>) => {\n setActivePart('list');\n return onClick?.(event);\n },\n [setActivePart, onClick],\n );\n\n return <Button {...props} classNames={['@md:hidden text-start', classNames]} onClick={handleClick} />;\n};\n\nTabsBackButton.displayName = 'Tabs.BackButton';\n\n//\n// TabGroupHeading\n//\n\ntype TabsTabGroupHeadingProps = ThemedClassName<ComponentPropsWithoutRef<'h2'>>;\n\nconst TabsTabGroupHeading = ({ children, classNames, ...props }: TabsTabGroupHeadingProps) => (\n <h2 {...props} className={mx('my-1 px-2 text-sm text-un-accent', classNames)}>\n {children}\n </h2>\n);\n\nTabsTabGroupHeading.displayName = 'Tabs.TabGroupHeading';\n\n//\n// Tab\n//\n\ntype TabsTabProps = ButtonProps & Pick<TabsPrimitive.TabsTriggerProps, 'value'>;\n\nconst TabsTab = ({ value, classNames, children, onClick, ...props }: TabsTabProps) => {\n const { setActivePart, orientation, value: contextValue, attendableId } = useTabsContext('TabsTab');\n const { hasAttention } = useAttention(attendableId);\n\n const handleClick = useCallback(\n // NOTE: This handler is only called if the tab is *already active*.\n (event: MouseEvent<HTMLButtonElement>) => {\n setActivePart('panel');\n onClick?.(event);\n },\n [setActivePart, onClick],\n );\n\n return (\n <TabsPrimitive.Trigger value={value} asChild>\n <Button\n {...props}\n variant={\n orientation === 'horizontal' && contextValue === value ? (hasAttention ? 'primary' : 'default') : 'ghost'\n }\n classNames={[\n orientation === 'vertical' && 'block justify-start text-start w-full',\n orientation === 'vertical' && 'dx-selected',\n classNames,\n ]}\n onClick={handleClick}\n >\n {children}\n </Button>\n </TabsPrimitive.Trigger>\n );\n};\n\nTabsTab.displayName = 'Tabs.Tab';\n\n//\n// IconTab\n//\n\ntype TabsIconTabProps = IconButtonProps & Pick<TabsPrimitive.TabsTriggerProps, 'value'>;\n\nconst TabsIconTab = ({ value, classNames, onClick, ...props }: TabsIconTabProps) => {\n const { setActivePart, orientation, value: contextValue, attendableId } = useTabsContext('TabsTab');\n const { hasAttention } = useAttention(attendableId);\n\n // NOTE: This handler is only called if the tab is *already active*.\n const handleClick = useCallback(\n (event: MouseEvent<HTMLButtonElement>) => {\n setActivePart('panel');\n onClick?.(event);\n },\n [setActivePart, onClick],\n );\n\n return (\n <TabsPrimitive.Trigger value={value} asChild>\n <IconButton\n {...props}\n variant={\n orientation === 'horizontal' && contextValue === value ? (hasAttention ? 'primary' : 'default') : 'ghost'\n }\n classNames={[\n orientation === 'vertical' && 'justify-start text-start w-full',\n orientation === 'vertical' && 'dx-selected',\n classNames,\n ]}\n onClick={handleClick}\n />\n </TabsPrimitive.Trigger>\n );\n};\n\nTabsIconTab.displayName = 'Tabs.IconTab';\n\n//\n// Panel\n//\n// Do NOT wrap TabsPanel children in React.Activity.\n// Radix TabsPrimitive.Content already unmounts inactive panels (no forceMount) — inactive tab\n// content is not in the DOM and effects do not run, which is the desired behaviour.\n// React.Activity (experimental in React 19) is a reconciler-level symbol that deactivates its\n// subtree when mode='hidden'. It was redundant here and prevented initial render of active panels.\n//\n\ntype TabsPanelProps = ThemedClassName<TabsPrimitive.TabsContentProps>;\n\nconst TabsPanel = ({ classNames, children, ...props }: TabsPanelProps) => (\n <TabsPrimitive.Content {...props} className={mx('p-0! dx-focus-ring-inset-over-all', classNames)}>\n {children}\n </TabsPrimitive.Content>\n);\n\nTabsPanel.displayName = 'Tabs.Panel';\n\ntype TabsTabPrimitiveProps = TabsPrimitive.TabsTriggerProps;\n\n//\n// Tabs\n//\n\nexport const Tabs = {\n Root: TabsRoot,\n Tablist: TabsTablist,\n Tab: TabsTab,\n IconTab: TabsIconTab,\n TabPrimitive: TabsPrimitive.Trigger,\n TabGroupHeading: TabsTabGroupHeading,\n Viewport: TabsViewport,\n Panel: TabsPanel,\n BackButton: TabsBackButton,\n};\n\nexport type {\n TabsActivePart,\n TabsRootProps,\n TabsTablistProps,\n TabsTabProps,\n TabsTabPrimitiveProps,\n TabsTabGroupHeadingProps,\n TabsViewportProps,\n TabsPanelProps,\n};\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["useArrowNavigationGroup", "useFocusFinders", "useFocusableGroup", "createContext", "Slot", "TabsPrimitive", "useControllableState", "React", "useCallback", "useLayoutEffect", "Button", "IconButton", "composableProps", "slottable", "useForwardedRef", "useAttention", "mx", "TABS_NAME", "TabsContextProvider", "useTabsContext", "orientation", "activePart", "setActivePart", "TabsRoot", "children", "propsActivePart", "onActivePartChange", "defaultActivePart", "value", "propsValue", "onValueChange", "defaultValue", "activationMode", "attendableId", "suppressRegionFocus", "asChild", "props", "forwardedRef", "tabsRoot", "prop", "onChange", "defaultProp", "setValue", "handleValueChange", "nextValue", "findFirstFocusable", "findNextFocusable", "root", "current", "tablist", "querySelector", "focus", "panel", "target", "container", "undefined", "Root", "data-active", "ref", "displayName", "TabsViewport", "Comp", "TabsTablist", "classNames", "List", "data-arrow-keys", "className", "TabsBackButton", "onClick", "handleClick", "event", "TabsTabGroupHeading", "h2", "TabsTab", "contextValue", "hasAttention", "Trigger", "variant", "TabsIconTab", "TabsPanel", "Content", "Tabs", "Tablist", "Tab", "IconTab", "TabPrimitive", "TabGroupHeading", "Viewport", "Panel", "BackButton"]
|
|
7
7
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"inputs":{"src/Tabs.tsx":{"bytes":
|
|
1
|
+
{"inputs":{"src/Tabs.tsx":{"bytes":29707,"imports":[{"path":"@fluentui/react-tabster","kind":"import-statement","external":true},{"path":"@radix-ui/react-context","kind":"import-statement","external":true},{"path":"@radix-ui/react-slot","kind":"import-statement","external":true},{"path":"@radix-ui/react-tabs","kind":"import-statement","external":true},{"path":"@radix-ui/react-use-controllable-state","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"@dxos/react-ui","kind":"import-statement","external":true},{"path":"@dxos/react-ui-attention","kind":"import-statement","external":true},{"path":"@dxos/ui-theme","kind":"import-statement","external":true}],"format":"esm"},"src/index.ts":{"bytes":368,"imports":[{"path":"src/Tabs.tsx","kind":"import-statement","original":"./Tabs"}],"format":"esm"}},"outputs":{"dist/lib/node-esm/index.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":16101},"dist/lib/node-esm/index.mjs":{"imports":[{"path":"@fluentui/react-tabster","kind":"import-statement","external":true},{"path":"@radix-ui/react-context","kind":"import-statement","external":true},{"path":"@radix-ui/react-slot","kind":"import-statement","external":true},{"path":"@radix-ui/react-tabs","kind":"import-statement","external":true},{"path":"@radix-ui/react-use-controllable-state","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"@dxos/react-ui","kind":"import-statement","external":true},{"path":"@dxos/react-ui-attention","kind":"import-statement","external":true},{"path":"@dxos/ui-theme","kind":"import-statement","external":true}],"exports":["Tabs"],"entryPoint":"src/index.ts","inputs":{"src/Tabs.tsx":{"bytesInOutput":6965},"src/index.ts":{"bytesInOutput":0}},"bytes":7128}}}
|
package/dist/types/src/Tabs.d.ts
CHANGED
|
@@ -1,21 +1,20 @@
|
|
|
1
1
|
import * as TabsPrimitive from '@radix-ui/react-tabs';
|
|
2
2
|
import React, { type ComponentPropsWithoutRef } from 'react';
|
|
3
|
-
import { type ButtonProps, type IconButtonProps, type ThemedClassName } from '@dxos/react-ui';
|
|
3
|
+
import { type ButtonProps, type IconButtonProps, type SlottableProps, type ThemedClassName } from '@dxos/react-ui';
|
|
4
4
|
type TabsActivePart = 'list' | 'panel';
|
|
5
5
|
type TabsContextValue = {
|
|
6
6
|
activePart: TabsActivePart;
|
|
7
7
|
setActivePart: (nextActivePart: TabsActivePart) => void;
|
|
8
8
|
attendableId?: string;
|
|
9
9
|
} & Pick<TabsPrimitive.TabsProps, 'orientation' | 'value'>;
|
|
10
|
-
type
|
|
10
|
+
type TabsRootCustomProps = TabsPrimitive.TabsProps & Partial<Pick<TabsContextValue, 'activePart' | 'attendableId'> & {
|
|
11
11
|
onActivePartChange: (nextActivePart: TabsActivePart) => void;
|
|
12
12
|
defaultActivePart: TabsActivePart;
|
|
13
|
+
/** Skip master-detail focus moves (e.g. when a child form owns initial focus). */
|
|
14
|
+
suppressRegionFocus?: boolean;
|
|
13
15
|
}>;
|
|
14
|
-
type
|
|
15
|
-
|
|
16
|
-
declare namespace TabsViewport {
|
|
17
|
-
var displayName: string;
|
|
18
|
-
}
|
|
16
|
+
type TabsRootProps = SlottableProps<TabsRootCustomProps>;
|
|
17
|
+
type TabsViewportProps = SlottableProps<Omit<ComponentPropsWithoutRef<'div'>, 'className' | 'style' | 'children' | 'role'>>;
|
|
19
18
|
type TabsTablistProps = ThemedClassName<TabsPrimitive.TabsListProps>;
|
|
20
19
|
declare function TabsTablist({ children, classNames, ...props }: TabsTablistProps): React.JSX.Element;
|
|
21
20
|
declare namespace TabsTablist {
|
|
@@ -47,12 +46,16 @@ declare namespace TabsPanel {
|
|
|
47
46
|
}
|
|
48
47
|
type TabsTabPrimitiveProps = TabsPrimitive.TabsTriggerProps;
|
|
49
48
|
export declare const Tabs: {
|
|
50
|
-
Root: React.ForwardRefExoticComponent<Omit<TabsPrimitive.TabsProps, "
|
|
51
|
-
classNames?: import("@dxos/ui-types").ClassNameValue;
|
|
52
|
-
} & Partial<Pick<TabsContextValue, "activePart" | "attendableId"> & {
|
|
49
|
+
Root: React.ForwardRefExoticComponent<Omit<TabsPrimitive.TabsProps & Partial<Pick<TabsContextValue, "activePart" | "attendableId"> & {
|
|
53
50
|
onActivePartChange: (nextActivePart: TabsActivePart) => void;
|
|
54
51
|
defaultActivePart: TabsActivePart;
|
|
55
|
-
|
|
52
|
+
/** Skip master-detail focus moves (e.g. when a child form owns initial focus). */
|
|
53
|
+
suppressRegionFocus?: boolean;
|
|
54
|
+
}> & {
|
|
55
|
+
asChild?: boolean;
|
|
56
|
+
}, "className"> & {
|
|
57
|
+
classNames?: import("@dxos/ui-types").ClassNameValue;
|
|
58
|
+
} & Pick<React.HTMLAttributes<Element>, "children" | "className" | "role" | "style"> & React.RefAttributes<HTMLDivElement>>;
|
|
56
59
|
Tablist: {
|
|
57
60
|
({ children, classNames, ...props }: TabsTablistProps): React.JSX.Element;
|
|
58
61
|
displayName: string;
|
|
@@ -70,10 +73,11 @@ export declare const Tabs: {
|
|
|
70
73
|
({ children, classNames, ...props }: TabsTabGroupHeadingProps): React.JSX.Element;
|
|
71
74
|
displayName: string;
|
|
72
75
|
};
|
|
73
|
-
Viewport: {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
76
|
+
Viewport: React.ForwardRefExoticComponent<Omit<Omit<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref">, "children" | "className" | "role" | "style"> & {
|
|
77
|
+
asChild?: boolean;
|
|
78
|
+
}, "className"> & {
|
|
79
|
+
classNames?: import("@dxos/ui-types").ClassNameValue;
|
|
80
|
+
} & Pick<React.HTMLAttributes<Element>, "children" | "className" | "role" | "style"> & React.RefAttributes<HTMLDivElement>>;
|
|
77
81
|
Panel: {
|
|
78
82
|
({ classNames, children, ...props }: TabsPanelProps): React.JSX.Element;
|
|
79
83
|
displayName: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Tabs.d.ts","sourceRoot":"","sources":["../../../src/Tabs.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Tabs.d.ts","sourceRoot":"","sources":["../../../src/Tabs.tsx"],"names":[],"mappings":"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"}
|
|
@@ -3,16 +3,19 @@ import React from 'react';
|
|
|
3
3
|
import { TabsRootProps } from './Tabs';
|
|
4
4
|
declare const meta: {
|
|
5
5
|
title: string;
|
|
6
|
-
component: React.ForwardRefExoticComponent<Omit<import("@radix-ui/react-tabs").TabsProps
|
|
7
|
-
classNames?: import("@dxos/ui-types").ClassNameValue;
|
|
8
|
-
} & Partial<Pick<{
|
|
6
|
+
component: React.ForwardRefExoticComponent<Omit<import("@radix-ui/react-tabs").TabsProps & Partial<Pick<{
|
|
9
7
|
activePart: import("./Tabs").TabsActivePart;
|
|
10
8
|
setActivePart: (nextActivePart: import("./Tabs").TabsActivePart) => void;
|
|
11
9
|
attendableId?: string;
|
|
12
10
|
} & Pick<import("@radix-ui/react-tabs").TabsProps, "orientation" | "value">, "activePart" | "attendableId"> & {
|
|
13
11
|
onActivePartChange: (nextActivePart: import("./Tabs").TabsActivePart) => void;
|
|
14
12
|
defaultActivePart: import("./Tabs").TabsActivePart;
|
|
15
|
-
|
|
13
|
+
suppressRegionFocus?: boolean;
|
|
14
|
+
}> & {
|
|
15
|
+
asChild?: boolean;
|
|
16
|
+
}, "className"> & {
|
|
17
|
+
classNames?: import("@dxos/ui-types").ClassNameValue;
|
|
18
|
+
} & Pick<React.HTMLAttributes<Element>, "children" | "className" | "role" | "style"> & React.RefAttributes<HTMLDivElement>>;
|
|
16
19
|
render: ({ orientation }: TabsRootProps) => React.JSX.Element;
|
|
17
20
|
decorators: import("@storybook/react").Decorator[];
|
|
18
21
|
parameters: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Tabs.stories.d.ts","sourceRoot":"","sources":["../../../src/Tabs.stories.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAa,KAAK,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACjE,OAAO,KAAK,MAAM,OAAO,CAAC;AAM1B,OAAO,EAAQ,aAAa,EAAE,MAAM,QAAQ,CAAC;AAwC7C,QAAA,MAAM,IAAI
|
|
1
|
+
{"version":3,"file":"Tabs.stories.d.ts","sourceRoot":"","sources":["../../../src/Tabs.stories.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAa,KAAK,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACjE,OAAO,KAAK,MAAM,OAAO,CAAC;AAM1B,OAAO,EAAQ,aAAa,EAAE,MAAM,QAAQ,CAAC;AAwC7C,QAAA,MAAM,IAAI;;;;;;;;;;;;;;;8BApC6B,aAAa;;;QA0ChD,MAAM;;CAE2B,CAAC;eAEvB,IAAI;AAEnB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,IAAI,CAAC,CAAC;AAGnC,eAAO,MAAM,UAAU,EAAE,KAIxB,CAAC;AAEF,eAAO,MAAM,QAAQ,EAAE,KAItB,CAAC"}
|