@dxos/react-ui-tabs 0.8.4-main.c85a9c8dae → 0.8.4-main.cb12b3f963
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 +27 -34
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +27 -34
- 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 +5 -6
- package/dist/types/src/Tabs.d.ts.map +1 -1
- package/dist/types/src/Tabs.stories.d.ts +8 -5
- package/dist/types/src/Tabs.stories.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +10 -13
- package/src/Tabs.stories.tsx +48 -41
- package/src/Tabs.tsx +29 -52
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/react-ui-tabs",
|
|
3
|
-
"version": "0.8.4-main.
|
|
3
|
+
"version": "0.8.4-main.cb12b3f963",
|
|
4
4
|
"description": "Components for facilitating a Tabs pattern.",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
@@ -21,9 +21,6 @@
|
|
|
21
21
|
}
|
|
22
22
|
},
|
|
23
23
|
"types": "dist/types/src/index.d.ts",
|
|
24
|
-
"typesVersions": {
|
|
25
|
-
"*": {}
|
|
26
|
-
},
|
|
27
24
|
"files": [
|
|
28
25
|
"dist",
|
|
29
26
|
"src"
|
|
@@ -36,25 +33,25 @@
|
|
|
36
33
|
"@radix-ui/react-slot": "1.1.2",
|
|
37
34
|
"@radix-ui/react-tabs": "1.1.3",
|
|
38
35
|
"@radix-ui/react-use-controllable-state": "1.1.0",
|
|
39
|
-
"@dxos/react-ui-attention": "0.8.4-main.
|
|
40
|
-
"@dxos/util": "0.8.4-main.
|
|
36
|
+
"@dxos/react-ui-attention": "0.8.4-main.cb12b3f963",
|
|
37
|
+
"@dxos/util": "0.8.4-main.cb12b3f963"
|
|
41
38
|
},
|
|
42
39
|
"devDependencies": {
|
|
43
40
|
"@types/react": "~19.2.7",
|
|
44
41
|
"@types/react-dom": "~19.2.3",
|
|
45
42
|
"react": "~19.2.3",
|
|
46
43
|
"react-dom": "~19.2.3",
|
|
47
|
-
"vite": "^
|
|
48
|
-
"@dxos/react-ui": "0.8.4-main.
|
|
49
|
-
"@dxos/
|
|
50
|
-
"@dxos/
|
|
51
|
-
"@dxos/
|
|
44
|
+
"vite": "^8.0.10",
|
|
45
|
+
"@dxos/react-ui": "0.8.4-main.cb12b3f963",
|
|
46
|
+
"@dxos/random": "0.8.4-main.cb12b3f963",
|
|
47
|
+
"@dxos/storybook-utils": "0.8.4-main.cb12b3f963",
|
|
48
|
+
"@dxos/ui-theme": "0.8.4-main.cb12b3f963"
|
|
52
49
|
},
|
|
53
50
|
"peerDependencies": {
|
|
54
51
|
"react": "~19.2.3",
|
|
55
52
|
"react-dom": "~19.2.3",
|
|
56
|
-
"@dxos/
|
|
57
|
-
"@dxos/ui
|
|
53
|
+
"@dxos/ui-theme": "0.8.4-main.cb12b3f963",
|
|
54
|
+
"@dxos/react-ui": "0.8.4-main.cb12b3f963"
|
|
58
55
|
},
|
|
59
56
|
"publishConfig": {
|
|
60
57
|
"access": "public"
|
package/src/Tabs.stories.tsx
CHANGED
|
@@ -5,66 +5,73 @@
|
|
|
5
5
|
import { type Meta, type StoryObj } from '@storybook/react-vite';
|
|
6
6
|
import React from 'react';
|
|
7
7
|
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
8
|
+
import { random } from '@dxos/random';
|
|
9
|
+
import { withLayout, withTheme } from '@dxos/react-ui/testing';
|
|
10
|
+
import { mx } from '@dxos/ui-theme';
|
|
11
11
|
|
|
12
|
-
import { Tabs
|
|
12
|
+
import { Tabs, TabsRootProps } from './Tabs';
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
random.seed(1234);
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
const DefaultStory = ({ orientation }: TabsRootProps) => {
|
|
17
17
|
return (
|
|
18
|
-
<
|
|
19
|
-
<
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
);
|
|
42
|
-
})}
|
|
43
|
-
</NaturalTabs.Viewport>
|
|
44
|
-
</NaturalTabs.Root>
|
|
45
|
-
</Dialog.Content>
|
|
46
|
-
</Dialog.Overlay>
|
|
47
|
-
</Dialog.Root>
|
|
18
|
+
<Tabs.Root orientation={orientation} defaultValue={Object.keys(content)[3]} defaultActivePart='list'>
|
|
19
|
+
<Tabs.Viewport
|
|
20
|
+
classNames={mx(
|
|
21
|
+
'w-full overflow-hidden grid',
|
|
22
|
+
orientation === 'vertical' && 'grid-cols-[minmax(min-content,1fr)_3fr]',
|
|
23
|
+
)}
|
|
24
|
+
>
|
|
25
|
+
<Tabs.Tablist>
|
|
26
|
+
{Object.entries(content).map(([id, { title }]) => (
|
|
27
|
+
<Tabs.Tab key={id} value={id}>
|
|
28
|
+
{title}
|
|
29
|
+
</Tabs.Tab>
|
|
30
|
+
))}
|
|
31
|
+
</Tabs.Tablist>
|
|
32
|
+
<div className='dx-container'>
|
|
33
|
+
{Object.entries(content).map(([id, { panel }]) => (
|
|
34
|
+
<Tabs.Panel key={id} value={id}>
|
|
35
|
+
<p className='px-1'>{panel}</p>
|
|
36
|
+
</Tabs.Panel>
|
|
37
|
+
))}
|
|
38
|
+
</div>
|
|
39
|
+
</Tabs.Viewport>
|
|
40
|
+
</Tabs.Root>
|
|
48
41
|
);
|
|
49
42
|
};
|
|
50
43
|
|
|
51
44
|
const content = [...Array(24)].reduce((acc: { [key: string]: { title: string; panel: string } }, _, index) => {
|
|
52
45
|
acc[`t${index}`] = {
|
|
53
|
-
title:
|
|
54
|
-
panel:
|
|
46
|
+
title: random.commerce.productName(),
|
|
47
|
+
panel: random.lorem.paragraphs(5),
|
|
55
48
|
};
|
|
56
49
|
return acc;
|
|
57
50
|
}, {});
|
|
58
51
|
|
|
59
52
|
const meta = {
|
|
60
53
|
title: 'ui/react-ui-tabs/Tabs',
|
|
61
|
-
component:
|
|
54
|
+
component: Tabs.Root,
|
|
62
55
|
render: DefaultStory,
|
|
63
|
-
decorators: [withTheme()],
|
|
56
|
+
decorators: [withTheme(), withLayout({ layout: 'column' })],
|
|
57
|
+
parameters: {
|
|
58
|
+
layout: 'fullscreen',
|
|
59
|
+
},
|
|
64
60
|
} satisfies Meta<typeof DefaultStory>;
|
|
65
61
|
|
|
66
62
|
export default meta;
|
|
67
63
|
|
|
68
64
|
type Story = StoryObj<typeof meta>;
|
|
69
65
|
|
|
70
|
-
|
|
66
|
+
// TODO(burdon): Scrolling.
|
|
67
|
+
export const Horizontal: Story = {
|
|
68
|
+
args: {
|
|
69
|
+
orientation: 'horizontal',
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
export const Vertical: Story = {
|
|
74
|
+
args: {
|
|
75
|
+
orientation: 'vertical',
|
|
76
|
+
},
|
|
77
|
+
};
|
package/src/Tabs.tsx
CHANGED
|
@@ -24,7 +24,7 @@ import {
|
|
|
24
24
|
useForwardedRef,
|
|
25
25
|
} from '@dxos/react-ui';
|
|
26
26
|
import { useAttention } from '@dxos/react-ui-attention';
|
|
27
|
-
import {
|
|
27
|
+
import { mx } from '@dxos/ui-theme';
|
|
28
28
|
|
|
29
29
|
type TabsActivePart = 'list' | 'panel';
|
|
30
30
|
|
|
@@ -34,21 +34,21 @@ type TabsContextValue = {
|
|
|
34
34
|
activePart: TabsActivePart;
|
|
35
35
|
setActivePart: (nextActivePart: TabsActivePart) => void;
|
|
36
36
|
attendableId?: string;
|
|
37
|
-
verticalVariant?: 'stateful' | 'stateless';
|
|
38
37
|
} & Pick<TabsPrimitive.TabsProps, 'orientation' | 'value'>;
|
|
39
38
|
|
|
40
39
|
const [TabsContextProvider, useTabsContext] = createContext<TabsContextValue>(TABS_NAME, {
|
|
40
|
+
orientation: 'vertical',
|
|
41
41
|
activePart: 'list',
|
|
42
42
|
setActivePart: () => {},
|
|
43
|
-
orientation: 'vertical',
|
|
44
43
|
});
|
|
45
44
|
|
|
46
45
|
type TabsRootProps = ThemedClassName<TabsPrimitive.TabsProps> &
|
|
47
|
-
Partial<
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
46
|
+
Partial<
|
|
47
|
+
Pick<TabsContextValue, 'activePart' | 'attendableId'> & {
|
|
48
|
+
onActivePartChange: (nextActivePart: TabsActivePart) => void;
|
|
49
|
+
defaultActivePart: TabsActivePart;
|
|
50
|
+
}
|
|
51
|
+
>;
|
|
52
52
|
|
|
53
53
|
const TabsRoot = forwardRef<HTMLDivElement, TabsRootProps>(
|
|
54
54
|
(
|
|
@@ -63,7 +63,6 @@ const TabsRoot = forwardRef<HTMLDivElement, TabsRootProps>(
|
|
|
63
63
|
defaultValue,
|
|
64
64
|
orientation = 'vertical',
|
|
65
65
|
activationMode = 'manual',
|
|
66
|
-
verticalVariant = 'stateful',
|
|
67
66
|
attendableId,
|
|
68
67
|
...props
|
|
69
68
|
},
|
|
@@ -110,22 +109,15 @@ const TabsRoot = forwardRef<HTMLDivElement, TabsRootProps>(
|
|
|
110
109
|
setActivePart={setActivePart}
|
|
111
110
|
value={value}
|
|
112
111
|
attendableId={attendableId}
|
|
113
|
-
verticalVariant={verticalVariant}
|
|
114
112
|
>
|
|
115
113
|
<TabsPrimitive.Root
|
|
114
|
+
{...props}
|
|
115
|
+
className={mx('overflow-hidden', classNames)}
|
|
116
|
+
orientation={orientation}
|
|
116
117
|
activationMode={activationMode}
|
|
117
118
|
data-active={activePart}
|
|
118
|
-
orientation={orientation}
|
|
119
|
-
{...props}
|
|
120
119
|
value={value}
|
|
121
120
|
onValueChange={handleValueChange}
|
|
122
|
-
className={mx(
|
|
123
|
-
'overflow-hidden',
|
|
124
|
-
orientation === 'vertical' &&
|
|
125
|
-
verticalVariant === 'stateful' &&
|
|
126
|
-
'[&[data-active=list]_[role=tabpanel]]:invisible @md:[&[data-active=list]_[role=tabpanel]]:visible',
|
|
127
|
-
classNames,
|
|
128
|
-
)}
|
|
129
121
|
ref={tabsRoot}
|
|
130
122
|
>
|
|
131
123
|
{children}
|
|
@@ -138,21 +130,9 @@ const TabsRoot = forwardRef<HTMLDivElement, TabsRootProps>(
|
|
|
138
130
|
type TabsViewportProps = ThemedClassName<ComponentPropsWithoutRef<'div'>>;
|
|
139
131
|
|
|
140
132
|
const TabsViewport = ({ classNames, children, ...props }: TabsViewportProps) => {
|
|
141
|
-
const {
|
|
133
|
+
const { activePart } = useTabsContext('TabsViewport');
|
|
142
134
|
return (
|
|
143
|
-
<div
|
|
144
|
-
role='none'
|
|
145
|
-
{...props}
|
|
146
|
-
data-active={activePart}
|
|
147
|
-
className={mx(
|
|
148
|
-
orientation === 'vertical' &&
|
|
149
|
-
verticalVariant === 'stateful' && [
|
|
150
|
-
'grid w-[200%] grid-cols-2 data-[active=panel]:ms-[-100%]',
|
|
151
|
-
'@md:w-auto @md:data-[active=panel]:ms-0 @md:grid-cols-[minmax(min-content,1fr)_3fr] @md:gap-1',
|
|
152
|
-
],
|
|
153
|
-
classNames,
|
|
154
|
-
)}
|
|
155
|
-
>
|
|
135
|
+
<div role='none' {...props} data-active={activePart} className={mx(classNames)}>
|
|
156
136
|
{children}
|
|
157
137
|
</div>
|
|
158
138
|
);
|
|
@@ -161,16 +141,15 @@ const TabsViewport = ({ classNames, children, ...props }: TabsViewportProps) =>
|
|
|
161
141
|
type TabsTablistProps = ThemedClassName<TabsPrimitive.TabsListProps>;
|
|
162
142
|
|
|
163
143
|
const TabsTablist = ({ children, classNames, ...props }: TabsTablistProps) => {
|
|
164
|
-
const { orientation
|
|
144
|
+
const { orientation } = useTabsContext('TabsTablist');
|
|
165
145
|
return (
|
|
166
146
|
<TabsPrimitive.List
|
|
167
147
|
{...props}
|
|
168
148
|
data-arrow-keys={orientation === 'vertical' ? 'up down' : 'left right'}
|
|
169
149
|
className={mx(
|
|
170
150
|
'max-h-full w-full',
|
|
171
|
-
//
|
|
172
|
-
orientation === 'vertical' ? 'overflow-y-auto' : 'flex items-stretch justify-start overflow-x-auto
|
|
173
|
-
orientation === 'vertical' && verticalVariant === 'stateful' && 'place-self-start p-1',
|
|
151
|
+
// TODO(burdon): Should be embeddable inside Toolbar (if horizontal).
|
|
152
|
+
orientation === 'vertical' ? 'overflow-y-auto' : 'flex p-1 gap-1 items-stretch justify-start overflow-x-auto',
|
|
174
153
|
classNames,
|
|
175
154
|
)}
|
|
176
155
|
>
|
|
@@ -186,10 +165,10 @@ const TabsBackButton = ({ onClick, classNames, ...props }: ButtonProps) => {
|
|
|
186
165
|
setActivePart('list');
|
|
187
166
|
return onClick?.(event);
|
|
188
167
|
},
|
|
189
|
-
[
|
|
168
|
+
[setActivePart, onClick],
|
|
190
169
|
);
|
|
191
170
|
|
|
192
|
-
return <Button {...props} classNames={['
|
|
171
|
+
return <Button {...props} classNames={['@md:hidden text-start', classNames]} onClick={handleClick} />;
|
|
193
172
|
};
|
|
194
173
|
|
|
195
174
|
type TabsTabGroupHeadingProps = ThemedClassName<ComponentPropsWithoutRef<'h2'>>;
|
|
@@ -220,17 +199,16 @@ const TabsTab = ({ value, classNames, children, onClick, ...props }: TabsTabProp
|
|
|
220
199
|
return (
|
|
221
200
|
<TabsPrimitive.Trigger value={value} asChild>
|
|
222
201
|
<Button
|
|
223
|
-
|
|
202
|
+
{...props}
|
|
224
203
|
variant={
|
|
225
204
|
orientation === 'horizontal' && contextValue === value ? (hasAttention ? 'primary' : 'default') : 'ghost'
|
|
226
205
|
}
|
|
227
|
-
{...props}
|
|
228
|
-
onClick={handleClick}
|
|
229
206
|
classNames={[
|
|
230
207
|
orientation === 'vertical' && 'block justify-start text-start w-full',
|
|
231
|
-
orientation === 'vertical' &&
|
|
208
|
+
orientation === 'vertical' && 'dx-selected',
|
|
232
209
|
classNames,
|
|
233
210
|
]}
|
|
211
|
+
onClick={handleClick}
|
|
234
212
|
>
|
|
235
213
|
{children}
|
|
236
214
|
</Button>
|
|
@@ -256,29 +234,28 @@ const TabsIconTab = ({ value, classNames, onClick, ...props }: TabsIconTabProps)
|
|
|
256
234
|
return (
|
|
257
235
|
<TabsPrimitive.Trigger value={value} asChild>
|
|
258
236
|
<IconButton
|
|
259
|
-
|
|
237
|
+
{...props}
|
|
260
238
|
variant={
|
|
261
239
|
orientation === 'horizontal' && contextValue === value ? (hasAttention ? 'primary' : 'default') : 'ghost'
|
|
262
240
|
}
|
|
263
|
-
{...props}
|
|
264
|
-
onClick={handleClick}
|
|
265
241
|
classNames={[
|
|
266
242
|
orientation === 'vertical' && 'justify-start text-start w-full',
|
|
267
|
-
orientation === 'vertical' &&
|
|
243
|
+
orientation === 'vertical' && 'dx-selected',
|
|
268
244
|
classNames,
|
|
269
245
|
]}
|
|
246
|
+
onClick={handleClick}
|
|
270
247
|
/>
|
|
271
248
|
</TabsPrimitive.Trigger>
|
|
272
249
|
);
|
|
273
250
|
};
|
|
274
251
|
|
|
275
|
-
type
|
|
252
|
+
type TabsPanelProps = ThemedClassName<TabsPrimitive.TabsContentProps>;
|
|
276
253
|
|
|
277
|
-
const
|
|
254
|
+
const TabsPanel = ({ classNames, children, ...props }: TabsPanelProps) => {
|
|
278
255
|
const { value: contextValue } = useTabsContext('TabsTab');
|
|
279
256
|
return (
|
|
280
257
|
<Activity mode={contextValue === props.value ? 'visible' : 'hidden'}>
|
|
281
|
-
<TabsPrimitive.Content {...props} className={mx('dx-focus-ring-inset-over-all', classNames)}>
|
|
258
|
+
<TabsPrimitive.Content {...props} className={mx('p-0! dx-focus-ring-inset-over-all', classNames)}>
|
|
282
259
|
{children}
|
|
283
260
|
</TabsPrimitive.Content>
|
|
284
261
|
</Activity>
|
|
@@ -294,7 +271,7 @@ export const Tabs = {
|
|
|
294
271
|
IconTab: TabsIconTab,
|
|
295
272
|
TabPrimitive: TabsPrimitive.Trigger,
|
|
296
273
|
TabGroupHeading: TabsTabGroupHeading,
|
|
297
|
-
|
|
274
|
+
Panel: TabsPanel,
|
|
298
275
|
BackButton: TabsBackButton,
|
|
299
276
|
Viewport: TabsViewport,
|
|
300
277
|
};
|
|
@@ -306,6 +283,6 @@ export type {
|
|
|
306
283
|
TabsTabProps,
|
|
307
284
|
TabsTabPrimitiveProps,
|
|
308
285
|
TabsTabGroupHeadingProps,
|
|
309
|
-
|
|
286
|
+
TabsPanelProps,
|
|
310
287
|
TabsViewportProps,
|
|
311
288
|
};
|