@dxos/react-ui-tabs 0.8.4-main.9735255 → 0.8.4-main.9be5663bfe
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 +30 -37
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +30 -37
- 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 -10
- package/src/Tabs.stories.tsx +48 -41
- package/src/Tabs.tsx +33 -55
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.9be5663bfe",
|
|
4
4
|
"description": "Components for facilitating a Tabs pattern.",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
@@ -36,25 +36,25 @@
|
|
|
36
36
|
"@radix-ui/react-slot": "1.1.2",
|
|
37
37
|
"@radix-ui/react-tabs": "1.1.3",
|
|
38
38
|
"@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.
|
|
39
|
+
"@dxos/react-ui-attention": "0.8.4-main.9be5663bfe",
|
|
40
|
+
"@dxos/util": "0.8.4-main.9be5663bfe"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"@types/react": "~19.2.7",
|
|
44
44
|
"@types/react-dom": "~19.2.3",
|
|
45
45
|
"react": "~19.2.3",
|
|
46
46
|
"react-dom": "~19.2.3",
|
|
47
|
-
"vite": "7.1.
|
|
48
|
-
"@dxos/
|
|
49
|
-
"@dxos/
|
|
50
|
-
"@dxos/
|
|
51
|
-
"@dxos/ui-theme": "0.8.4-main.
|
|
47
|
+
"vite": "^7.1.11",
|
|
48
|
+
"@dxos/react-ui": "0.8.4-main.9be5663bfe",
|
|
49
|
+
"@dxos/storybook-utils": "0.8.4-main.9be5663bfe",
|
|
50
|
+
"@dxos/random": "0.8.4-main.9be5663bfe",
|
|
51
|
+
"@dxos/ui-theme": "0.8.4-main.9be5663bfe"
|
|
52
52
|
},
|
|
53
53
|
"peerDependencies": {
|
|
54
54
|
"react": "~19.2.3",
|
|
55
55
|
"react-dom": "~19.2.3",
|
|
56
|
-
"@dxos/
|
|
57
|
-
"@dxos/ui
|
|
56
|
+
"@dxos/ui-theme": "0.8.4-main.9be5663bfe",
|
|
57
|
+
"@dxos/react-ui": "0.8.4-main.9be5663bfe"
|
|
58
58
|
},
|
|
59
59
|
"publishConfig": {
|
|
60
60
|
"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 is-[200%] grid-cols-2 data-[active=panel]:mis-[-100%]',
|
|
151
|
-
'@md:is-auto @md:data-[active=panel]:mis-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
|
-
'max-
|
|
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',
|
|
150
|
+
'max-h-full w-full',
|
|
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,17 +165,17 @@ 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'>>;
|
|
196
175
|
|
|
197
176
|
const TabsTabGroupHeading = ({ children, classNames, ...props }: ThemedClassName<TabsTabGroupHeadingProps>) => {
|
|
198
177
|
return (
|
|
199
|
-
<h2 {...props} className={mx('
|
|
178
|
+
<h2 {...props} className={mx('my-1 px-2 text-sm text-un-accent', classNames)}>
|
|
200
179
|
{children}
|
|
201
180
|
</h2>
|
|
202
181
|
);
|
|
@@ -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
|
-
orientation === 'vertical' && 'block justify-start text-start
|
|
231
|
-
orientation === 'vertical' &&
|
|
207
|
+
orientation === 'vertical' && 'block justify-start text-start w-full',
|
|
208
|
+
orientation === 'vertical' && 'dx-selected',
|
|
232
209
|
classNames,
|
|
233
210
|
]}
|
|
211
|
+
onClick={handleClick}
|
|
234
212
|
>
|
|
235
213
|
{children}
|
|
236
214
|
</Button>
|
|
@@ -256,25 +234,25 @@ 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
|
-
orientation === 'vertical' && 'justify-start text-start
|
|
267
|
-
orientation === 'vertical' &&
|
|
242
|
+
orientation === 'vertical' && 'justify-start text-start w-full',
|
|
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
|
-
|
|
254
|
+
// TODO(burdon): Make slottable.
|
|
255
|
+
const TabsPanel = ({ classNames, children, ...props }: TabsPanelProps) => {
|
|
278
256
|
const { value: contextValue } = useTabsContext('TabsTab');
|
|
279
257
|
return (
|
|
280
258
|
<Activity mode={contextValue === props.value ? 'visible' : 'hidden'}>
|
|
@@ -294,7 +272,7 @@ export const Tabs = {
|
|
|
294
272
|
IconTab: TabsIconTab,
|
|
295
273
|
TabPrimitive: TabsPrimitive.Trigger,
|
|
296
274
|
TabGroupHeading: TabsTabGroupHeading,
|
|
297
|
-
|
|
275
|
+
Panel: TabsPanel,
|
|
298
276
|
BackButton: TabsBackButton,
|
|
299
277
|
Viewport: TabsViewport,
|
|
300
278
|
};
|
|
@@ -306,6 +284,6 @@ export type {
|
|
|
306
284
|
TabsTabProps,
|
|
307
285
|
TabsTabPrimitiveProps,
|
|
308
286
|
TabsTabGroupHeadingProps,
|
|
309
|
-
|
|
287
|
+
TabsPanelProps,
|
|
310
288
|
TabsViewportProps,
|
|
311
289
|
};
|