@dxos/react-ui-tabs 0.8.4-main.8360d9e660 → 0.8.4-main.8baae0fced
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/LICENSE +102 -5
- package/dist/lib/browser/index.mjs +24 -32
- package/dist/lib/browser/index.mjs.map +3 -3
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +24 -32
- 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 +11 -14
- package/src/Tabs.stories.tsx +48 -41
- package/src/Tabs.tsx +26 -51
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.8baae0fced",
|
|
4
4
|
"description": "Components for facilitating a Tabs pattern.",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"type": "git",
|
|
9
9
|
"url": "https://github.com/dxos/dxos"
|
|
10
10
|
},
|
|
11
|
-
"license": "
|
|
11
|
+
"license": "FSL-1.1-Apache-2.0",
|
|
12
12
|
"author": "DXOS.org",
|
|
13
13
|
"sideEffects": false,
|
|
14
14
|
"type": "module",
|
|
@@ -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.8baae0fced",
|
|
37
|
+
"@dxos/util": "0.8.4-main.8baae0fced"
|
|
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/random": "0.8.4-main.
|
|
49
|
-
"@dxos/
|
|
50
|
-
"@dxos/
|
|
51
|
-
"@dxos/
|
|
44
|
+
"vite": "^8.0.13",
|
|
45
|
+
"@dxos/random": "0.8.4-main.8baae0fced",
|
|
46
|
+
"@dxos/storybook-utils": "0.8.4-main.8baae0fced",
|
|
47
|
+
"@dxos/react-ui": "0.8.4-main.8baae0fced",
|
|
48
|
+
"@dxos/ui-theme": "0.8.4-main.8baae0fced"
|
|
52
49
|
},
|
|
53
50
|
"peerDependencies": {
|
|
54
51
|
"react": "~19.2.3",
|
|
55
52
|
"react-dom": "~19.2.3",
|
|
56
|
-
"@dxos/react-ui": "0.8.4-main.
|
|
57
|
-
"@dxos/ui-theme": "0.8.4-main.
|
|
53
|
+
"@dxos/react-ui": "0.8.4-main.8baae0fced",
|
|
54
|
+
"@dxos/ui-theme": "0.8.4-main.8baae0fced"
|
|
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
|
@@ -34,23 +34,22 @@ 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
|
-
// TODO(burdon): Reconcile padding with Toolbar.
|
|
54
53
|
const TabsRoot = forwardRef<HTMLDivElement, TabsRootProps>(
|
|
55
54
|
(
|
|
56
55
|
{
|
|
@@ -64,7 +63,6 @@ const TabsRoot = forwardRef<HTMLDivElement, TabsRootProps>(
|
|
|
64
63
|
defaultValue,
|
|
65
64
|
orientation = 'vertical',
|
|
66
65
|
activationMode = 'manual',
|
|
67
|
-
verticalVariant = 'stateful',
|
|
68
66
|
attendableId,
|
|
69
67
|
...props
|
|
70
68
|
},
|
|
@@ -111,22 +109,15 @@ const TabsRoot = forwardRef<HTMLDivElement, TabsRootProps>(
|
|
|
111
109
|
setActivePart={setActivePart}
|
|
112
110
|
value={value}
|
|
113
111
|
attendableId={attendableId}
|
|
114
|
-
verticalVariant={verticalVariant}
|
|
115
112
|
>
|
|
116
113
|
<TabsPrimitive.Root
|
|
114
|
+
{...props}
|
|
115
|
+
className={mx('overflow-hidden', classNames)}
|
|
116
|
+
orientation={orientation}
|
|
117
117
|
activationMode={activationMode}
|
|
118
118
|
data-active={activePart}
|
|
119
|
-
orientation={orientation}
|
|
120
|
-
{...props}
|
|
121
119
|
value={value}
|
|
122
120
|
onValueChange={handleValueChange}
|
|
123
|
-
className={mx(
|
|
124
|
-
'overflow-hidden',
|
|
125
|
-
orientation === 'vertical' &&
|
|
126
|
-
verticalVariant === 'stateful' &&
|
|
127
|
-
'[&[data-active=list]_[role=tabpanel]]:invisible @md:[&[data-active=list]_[role=tabpanel]]:visible',
|
|
128
|
-
classNames,
|
|
129
|
-
)}
|
|
130
121
|
ref={tabsRoot}
|
|
131
122
|
>
|
|
132
123
|
{children}
|
|
@@ -139,21 +130,9 @@ const TabsRoot = forwardRef<HTMLDivElement, TabsRootProps>(
|
|
|
139
130
|
type TabsViewportProps = ThemedClassName<ComponentPropsWithoutRef<'div'>>;
|
|
140
131
|
|
|
141
132
|
const TabsViewport = ({ classNames, children, ...props }: TabsViewportProps) => {
|
|
142
|
-
const {
|
|
133
|
+
const { activePart } = useTabsContext('TabsViewport');
|
|
143
134
|
return (
|
|
144
|
-
<div
|
|
145
|
-
role='none'
|
|
146
|
-
{...props}
|
|
147
|
-
data-active={activePart}
|
|
148
|
-
className={mx(
|
|
149
|
-
orientation === 'vertical' &&
|
|
150
|
-
verticalVariant === 'stateful' && [
|
|
151
|
-
'grid w-[200%] grid-cols-2 data-[active=panel]:ms-[-100%]',
|
|
152
|
-
'@md:w-auto @md:data-[active=panel]:ms-0 @md:grid-cols-[minmax(min-content,1fr)_3fr] @md:gap-1',
|
|
153
|
-
],
|
|
154
|
-
classNames,
|
|
155
|
-
)}
|
|
156
|
-
>
|
|
135
|
+
<div {...props} data-active={activePart} className={mx(classNames)}>
|
|
157
136
|
{children}
|
|
158
137
|
</div>
|
|
159
138
|
);
|
|
@@ -161,18 +140,16 @@ const TabsViewport = ({ classNames, children, ...props }: TabsViewportProps) =>
|
|
|
161
140
|
|
|
162
141
|
type TabsTablistProps = ThemedClassName<TabsPrimitive.TabsListProps>;
|
|
163
142
|
|
|
164
|
-
// TODO(burdon): Should have same geometry as Toolbar.
|
|
165
143
|
const TabsTablist = ({ children, classNames, ...props }: TabsTablistProps) => {
|
|
166
|
-
const { orientation
|
|
144
|
+
const { orientation } = useTabsContext('TabsTablist');
|
|
167
145
|
return (
|
|
168
146
|
<TabsPrimitive.List
|
|
169
147
|
{...props}
|
|
170
148
|
data-arrow-keys={orientation === 'vertical' ? 'up down' : 'left right'}
|
|
171
149
|
className={mx(
|
|
172
150
|
'max-h-full w-full',
|
|
173
|
-
//
|
|
174
|
-
orientation === 'vertical' ? 'overflow-y-auto' : 'flex items-stretch justify-start overflow-x-auto
|
|
175
|
-
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',
|
|
176
153
|
classNames,
|
|
177
154
|
)}
|
|
178
155
|
>
|
|
@@ -188,10 +165,10 @@ const TabsBackButton = ({ onClick, classNames, ...props }: ButtonProps) => {
|
|
|
188
165
|
setActivePart('list');
|
|
189
166
|
return onClick?.(event);
|
|
190
167
|
},
|
|
191
|
-
[
|
|
168
|
+
[setActivePart, onClick],
|
|
192
169
|
);
|
|
193
170
|
|
|
194
|
-
return <Button {...props} classNames={['
|
|
171
|
+
return <Button {...props} classNames={['@md:hidden text-start', classNames]} onClick={handleClick} />;
|
|
195
172
|
};
|
|
196
173
|
|
|
197
174
|
type TabsTabGroupHeadingProps = ThemedClassName<ComponentPropsWithoutRef<'h2'>>;
|
|
@@ -222,17 +199,16 @@ const TabsTab = ({ value, classNames, children, onClick, ...props }: TabsTabProp
|
|
|
222
199
|
return (
|
|
223
200
|
<TabsPrimitive.Trigger value={value} asChild>
|
|
224
201
|
<Button
|
|
225
|
-
|
|
202
|
+
{...props}
|
|
226
203
|
variant={
|
|
227
204
|
orientation === 'horizontal' && contextValue === value ? (hasAttention ? 'primary' : 'default') : 'ghost'
|
|
228
205
|
}
|
|
229
|
-
{...props}
|
|
230
|
-
onClick={handleClick}
|
|
231
206
|
classNames={[
|
|
232
207
|
orientation === 'vertical' && 'block justify-start text-start w-full',
|
|
233
208
|
orientation === 'vertical' && 'dx-selected',
|
|
234
209
|
classNames,
|
|
235
210
|
]}
|
|
211
|
+
onClick={handleClick}
|
|
236
212
|
>
|
|
237
213
|
{children}
|
|
238
214
|
</Button>
|
|
@@ -258,29 +234,28 @@ const TabsIconTab = ({ value, classNames, onClick, ...props }: TabsIconTabProps)
|
|
|
258
234
|
return (
|
|
259
235
|
<TabsPrimitive.Trigger value={value} asChild>
|
|
260
236
|
<IconButton
|
|
261
|
-
|
|
237
|
+
{...props}
|
|
262
238
|
variant={
|
|
263
239
|
orientation === 'horizontal' && contextValue === value ? (hasAttention ? 'primary' : 'default') : 'ghost'
|
|
264
240
|
}
|
|
265
|
-
{...props}
|
|
266
|
-
onClick={handleClick}
|
|
267
241
|
classNames={[
|
|
268
242
|
orientation === 'vertical' && 'justify-start text-start w-full',
|
|
269
243
|
orientation === 'vertical' && 'dx-selected',
|
|
270
244
|
classNames,
|
|
271
245
|
]}
|
|
246
|
+
onClick={handleClick}
|
|
272
247
|
/>
|
|
273
248
|
</TabsPrimitive.Trigger>
|
|
274
249
|
);
|
|
275
250
|
};
|
|
276
251
|
|
|
277
|
-
type
|
|
252
|
+
type TabsPanelProps = ThemedClassName<TabsPrimitive.TabsContentProps>;
|
|
278
253
|
|
|
279
|
-
const
|
|
254
|
+
const TabsPanel = ({ classNames, children, ...props }: TabsPanelProps) => {
|
|
280
255
|
const { value: contextValue } = useTabsContext('TabsTab');
|
|
281
256
|
return (
|
|
282
257
|
<Activity mode={contextValue === props.value ? 'visible' : 'hidden'}>
|
|
283
|
-
<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)}>
|
|
284
259
|
{children}
|
|
285
260
|
</TabsPrimitive.Content>
|
|
286
261
|
</Activity>
|
|
@@ -296,7 +271,7 @@ export const Tabs = {
|
|
|
296
271
|
IconTab: TabsIconTab,
|
|
297
272
|
TabPrimitive: TabsPrimitive.Trigger,
|
|
298
273
|
TabGroupHeading: TabsTabGroupHeading,
|
|
299
|
-
|
|
274
|
+
Panel: TabsPanel,
|
|
300
275
|
BackButton: TabsBackButton,
|
|
301
276
|
Viewport: TabsViewport,
|
|
302
277
|
};
|
|
@@ -308,6 +283,6 @@ export type {
|
|
|
308
283
|
TabsTabProps,
|
|
309
284
|
TabsTabPrimitiveProps,
|
|
310
285
|
TabsTabGroupHeadingProps,
|
|
311
|
-
|
|
286
|
+
TabsPanelProps,
|
|
312
287
|
TabsViewportProps,
|
|
313
288
|
};
|