Skip to content

Commit 49cca08

Browse files
authored
fix: testing session bugs treeview and tabs (#7713)
* fix: testing session bugs * more testing session fixes * fix row heights and tap highlight * fix lint * fix more iOS heights and expand button * fix mobile height * fix missing variable * Add chromatic for s2 tree
1 parent 735b275 commit 49cca08

File tree

6 files changed

+336
-62
lines changed

6 files changed

+336
-62
lines changed

packages/@react-spectrum/s2/chromatic/Tabs.stories.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,18 +37,18 @@ export const Example = {
3737
<Tab id="Emp">Empire</Tab>
3838
</TabList>
3939
<TabPanel id="FoR">
40-
<div>
40+
<div className={style({overflow: 'auto', height: 'full'})}>
4141
<div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum non rutrum augue, a dictum est. Sed ultricies vel orci in blandit. Morbi sed tempor leo. Phasellus et sollicitudin nunc, a volutpat est. In volutpat molestie velit, nec rhoncus felis vulputate porttitor. In efficitur nibh tortor, maximus imperdiet libero sollicitudin sed. Pellentesque dictum, quam id scelerisque rutrum, lorem augue suscipit est, nec ultricies ligula lorem id dui. Cras lacus tortor, fringilla nec ligula quis, semper imperdiet ex.</div>
4242
</div>
4343
</TabPanel>
4444
<TabPanel id="MaR">
45-
<div>
45+
<div className={style({overflow: 'auto', height: 'full'})}>
4646
<div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed ut vulputate justo. Suspendisse potenti. Nunc id fringilla leo, at luctus quam. Maecenas et ipsum nisi. Curabitur in porta purus, a pretium est. Fusce eu urna diam. Sed nunc neque, consectetur ut purus nec, consequat elementum libero. Sed ut diam in quam maximus condimentum at non erat. Vestibulum sagittis rutrum velit, vitae suscipit arcu. Nulla ac feugiat ante, vitae laoreet ligula. Maecenas sed molestie ligula. Nulla sed fringilla ex. Nulla viverra tortor at enim condimentum egestas. Nulla sed tristique sapien. Integer ligula quam, vulputate eget mollis eu, interdum sit amet justo.</div>
4747
<div>Vivamus dignissim tortor ut sapien congue tristique. Sed ac aliquet mauris. Nulla metus dui, elementum sit amet luctus eu, condimentum id elit. Praesent id nibh sed ligula congue venenatis. Pellentesque urna turpis, eleifend id pellentesque a, auctor nec neque. Vestibulum ipsum mauris, rutrum sit amet magna et, aliquet mollis tellus. Pellentesque nec ultricies nibh, at tempus massa. Phasellus dictum turpis et interdum scelerisque. Aliquam fermentum tincidunt ipsum sit amet suscipit. Fusce non dui sed diam lacinia mattis fermentum eu urna. Cras pretium id nunc in elementum. Mauris laoreet odio vitae laoreet dictum. In non justo nec nunc vehicula posuere non non ligula. Nullam eleifend scelerisque nibh, in sollicitudin tortor ullamcorper vel. Praesent sagittis risus in erat dignissim, non lacinia elit efficitur. Quisque maximus nulla vel luctus pharetra.</div>
4848
</div>
4949
</TabPanel>
5050
<TabPanel id="Emp">
51-
<div>
51+
<div className={style({overflow: 'auto', height: 'full'})}>
5252
<div>Alea jacta est.</div>
5353
</div>
5454
</TabPanel>
Lines changed: 252 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,252 @@
1+
/*
2+
* Copyright 2024 Adobe. All rights reserved.
3+
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License. You may obtain a copy
5+
* of the License at http://www.apache.org/licenses/LICENSE-2.0
6+
*
7+
* Unless required by applicable law or agreed to in writing, software distributed under
8+
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9+
* OF ANY KIND, either express or implied. See the License for the specific language
10+
* governing permissions and limitations under the License.
11+
*/
12+
13+
import {ActionMenu, Content, Heading, IllustratedMessage, Link, MenuItem, Text, TreeView, TreeViewItem} from '../src';
14+
import Delete from '../s2wf-icons/S2_Icon_Delete_20_N.svg';
15+
import Edit from '../s2wf-icons/S2_Icon_Edit_20_N.svg';
16+
import FileTxt from '../s2wf-icons/S2_Icon_FileText_20_N.svg';
17+
import Folder from '../s2wf-icons/S2_Icon_Folder_20_N.svg';
18+
import FolderOpen from '../spectrum-illustrations/linear/FolderOpen';
19+
import type {Meta} from '@storybook/react';
20+
21+
const meta: Meta<typeof TreeView> = {
22+
component: TreeView,
23+
parameters: {
24+
chromaticProvider: {disableAnimations: true}
25+
},
26+
title: 'S2 Chromatic/TreeView'
27+
};
28+
29+
export default meta;
30+
31+
function TreeExample(props) {
32+
return (
33+
<div style={{width: '300px', height: '320px'}}>
34+
<TreeView
35+
{...props}
36+
disabledKeys={['projects-1']}
37+
aria-label="test static tree"
38+
expandedKeys={['projects']}>
39+
<TreeViewItem id="Photos" textValue="Photos">
40+
<Text>Photos</Text>
41+
<Folder />
42+
<ActionMenu>
43+
<MenuItem id="edit">
44+
<Edit />
45+
<Text>Edit</Text>
46+
</MenuItem>
47+
<MenuItem id="delete">
48+
<Delete />
49+
<Text>Delete</Text>
50+
</MenuItem>
51+
</ActionMenu>
52+
</TreeViewItem>
53+
<TreeViewItem id="projects" textValue="Projects">
54+
<Text>Projects</Text>
55+
<Folder />
56+
<ActionMenu>
57+
<MenuItem id="edit">
58+
<Edit />
59+
<Text>Edit</Text>
60+
</MenuItem>
61+
<MenuItem id="delete">
62+
<Delete />
63+
<Text>Delete</Text>
64+
</MenuItem>
65+
</ActionMenu>
66+
<TreeViewItem id="projects-1" textValue="Projects-1">
67+
<Text>Projects-1</Text>
68+
<Folder />
69+
<ActionMenu>
70+
<MenuItem id="edit">
71+
<Edit />
72+
<Text>Edit</Text>
73+
</MenuItem>
74+
<MenuItem id="delete">
75+
<Delete />
76+
<Text>Delete</Text>
77+
</MenuItem>
78+
</ActionMenu>
79+
<TreeViewItem id="projects-1A" textValue="Projects-1A">
80+
<Text>Projects-1A</Text>
81+
<FileTxt />
82+
<ActionMenu>
83+
<MenuItem id="edit">
84+
<Edit />
85+
<Text>Edit</Text>
86+
</MenuItem>
87+
<MenuItem id="delete">
88+
<Delete />
89+
<Text>Delete</Text>
90+
</MenuItem>
91+
</ActionMenu>
92+
</TreeViewItem>
93+
</TreeViewItem>
94+
<TreeViewItem id="projects-2" textValue="Projects-2">
95+
<Text>Projects-2</Text>
96+
<FileTxt />
97+
<ActionMenu>
98+
<MenuItem id="edit">
99+
<Edit />
100+
<Text>Edit</Text>
101+
</MenuItem>
102+
<MenuItem id="delete">
103+
<Delete />
104+
<Text>Delete</Text>
105+
</MenuItem>
106+
</ActionMenu>
107+
</TreeViewItem>
108+
<TreeViewItem id="projects-3" textValue="Projects-3">
109+
<Text>Projects-3</Text>
110+
<FileTxt />
111+
<ActionMenu>
112+
<MenuItem id="edit">
113+
<Edit />
114+
<Text>Edit</Text>
115+
</MenuItem>
116+
<MenuItem id="delete">
117+
<Delete />
118+
<Text>Delete</Text>
119+
</MenuItem>
120+
</ActionMenu>
121+
</TreeViewItem>
122+
</TreeViewItem>
123+
</TreeView>
124+
</div>
125+
);
126+
}
127+
128+
129+
export const TreeStatic = {
130+
render: (args) => <TreeExample {...args} />
131+
};
132+
133+
export const TreeSelection = {
134+
...TreeStatic,
135+
args: {
136+
selectionMode: 'multiple',
137+
defaultSelectedKeys: ['projects-2', 'projects-3']
138+
}
139+
};
140+
141+
export const TreeIsDetached = {
142+
...TreeStatic,
143+
args: {
144+
isDetached: true,
145+
selectionMode: 'multiple',
146+
defaultSelectedKeys: ['projects-2', 'projects-3']
147+
}
148+
};
149+
150+
export const TreeIsEmphasized = {
151+
...TreeStatic,
152+
args: {
153+
isEmphasized: true,
154+
selectionMode: 'multiple',
155+
defaultSelectedKeys: ['projects-2', 'projects-3']
156+
}
157+
};
158+
159+
export const TreeIsDetachedIsEmphasized = {
160+
...TreeStatic,
161+
args: {
162+
isDetached: true,
163+
isEmphasized: true,
164+
selectionMode: 'multiple',
165+
defaultSelectedKeys: ['projects-2', 'projects-3']
166+
}
167+
};
168+
169+
export const TreeIsDetachedMobile = {
170+
...TreeStatic,
171+
args: {
172+
isDetached: true,
173+
selectionMode: 'multiple',
174+
defaultSelectedKeys: ['projects-2', 'projects-3']
175+
}
176+
};
177+
178+
179+
let rows = [
180+
{id: 'projects', name: 'Projects', icon: <Folder />, childItems: [
181+
{id: 'project-1', name: 'Project 1 Level 1', icon: <FileTxt />},
182+
{id: 'project-2', name: 'Project 2 Level 1', icon: <Folder />, childItems: [
183+
{id: 'project-2A', name: 'Project 2A Level 2', icon: <FileTxt />},
184+
{id: 'project-2B', name: 'Project 2B Level 2', icon: <FileTxt />},
185+
{id: 'project-2C', name: 'Project 2C Level 3', icon: <FileTxt />}
186+
]},
187+
{id: 'project-3', name: 'Project 3', icon: <FileTxt />},
188+
{id: 'project-4', name: 'Project 4', icon: <FileTxt />},
189+
{id: 'project-5', name: 'Project 5', icon: <Folder />, childItems: [
190+
{id: 'project-5A', name: 'Project 5A', icon: <FileTxt />},
191+
{id: 'project-5B', name: 'Project 5B', icon: <FileTxt />},
192+
{id: 'project-5C', name: 'Project 5C', icon: <FileTxt />}
193+
]}
194+
]},
195+
{id: 'reports', name: 'Reports', icon: <Folder />, childItems: [
196+
{id: 'reports-1', name: 'Reports 1', icon: <Folder />, childItems: [
197+
{id: 'reports-1A', name: 'Reports 1A', icon: <Folder />, childItems: [
198+
{id: 'reports-1AB', name: 'Reports 1AB', icon: <Folder />, childItems: [
199+
{id: 'reports-1ABC', name: 'Reports 1ABC', icon: <FileTxt />}
200+
]}
201+
]},
202+
{id: 'reports-1B', name: 'Reports 1B', icon: <FileTxt />},
203+
{id: 'reports-1C', name: 'Reports 1C', icon: <FileTxt />}
204+
]},
205+
{id: 'reports-2', name: 'Reports 2', icon: <FileTxt />},
206+
...Array.from({length: 100}, (_, i) => ({id: `reports-repeat-${i}`, name: `Reports ${i}`, icon: <FileTxt />}))
207+
]}
208+
];
209+
210+
const TreeExampleDynamic = (args) => (
211+
<div style={{width: '300px', height: '320px', display: 'flex', flexDirection: 'column'}}>
212+
<TreeView aria-label="test dynamic tree" items={rows} {...args}>
213+
{(item: any) => (
214+
<TreeViewItem childItems={item.childItems} textValue={item.name}>
215+
<Text>{item.name}</Text>
216+
{item.icon}
217+
</TreeViewItem>
218+
)}
219+
</TreeView>
220+
</div>
221+
);
222+
223+
export const Dynamic = {
224+
render: (args) => <TreeExampleDynamic {...args} />,
225+
args: {
226+
disabledKeys: ['project-2C', 'project-5'],
227+
defaultExpandedKeys: ['projects', 'projects-2', 'projects-5']
228+
}
229+
};
230+
231+
232+
function renderEmptyState() {
233+
return (
234+
<IllustratedMessage>
235+
<FolderOpen />
236+
<Heading>
237+
No results
238+
</Heading>
239+
<Content>
240+
<Content>No results found, press <Link href="https://adobe.com">here</Link> for more info.</Content>
241+
</Content>
242+
</IllustratedMessage>
243+
);
244+
}
245+
246+
export const Empty = {
247+
render: TreeExampleDynamic,
248+
args: {
249+
renderEmptyState,
250+
items: []
251+
}
252+
};

packages/@react-spectrum/s2/src/Tabs.tsx

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,11 @@ import {createContext, forwardRef, ReactNode, useCallback, useContext, useEffect
3131
import {focusRing, size, style} from '../style' with {type: 'macro'};
3232
import {getAllowedOverrides, StyleProps, StylesPropWithHeight, UnsafeStyles} from './style-utils' with {type: 'macro'};
3333
import {IconContext} from './Icon';
34+
import {inertValue, useEffectEvent, useId, useLabels, useLayoutEffect, useResizeObserver} from '@react-aria/utils';
3435
import {Picker, PickerItem} from './TabsPicker';
3536
import {Text, TextContext} from './Content';
3637
import {useControlledState} from '@react-stately/utils';
3738
import {useDOMRef} from '@react-spectrum/utils';
38-
import {useEffectEvent, useId, useLabels, useLayoutEffect, useResizeObserver} from '@react-aria/utils';
3939
import {useHasTabbableChild} from '@react-aria/focus';
4040
import {useLocale} from '@react-aria/i18n';
4141
import {useSpectrumContextProps} from './useSpectrumContextProps';
@@ -349,7 +349,8 @@ const tab = style({
349349
labelBehavior: {
350350
hide: size(6)
351351
}
352-
}
352+
},
353+
disableTapHighlight: true
353354
}, getAllowedOverrides());
354355

355356
const icon = style({
@@ -412,17 +413,12 @@ export function Tab(props: TabProps) {
412413

413414
const tabPanel = style({
414415
...focusRing(),
415-
display: 'flex',
416416
marginTop: 4,
417-
marginX: -4,
418-
paddingX: 4,
419417
color: 'gray-800',
420418
flexGrow: 1,
421-
flexShrink: 1,
422419
flexBasis: '[0%]',
423420
minHeight: 0,
424-
minWidth: 0,
425-
overflow: 'auto'
421+
minWidth: 0
426422
}, getAllowedOverrides({height: true}));
427423

428424
export function TabPanel(props: TabPanelProps) {
@@ -492,7 +488,7 @@ let HiddenTabs = function (props: {
492488
return (
493489
<div
494490
// @ts-ignore
495-
inert="true"
491+
inert={inertValue(true)}
496492
ref={listRef}
497493
className={style({
498494
display: '[inherit]',
@@ -616,7 +612,8 @@ let CollapsingTabs = ({collection, containerRef, ...props}: {collection: Collect
616612
}
617613
}, [collection.size, updateOverflow]);
618614

619-
let prevOrientation = useRef(orientation);
615+
// start with null so that the first render won't have a flicker
616+
let prevOrientation = useRef<Orientation | null>(null);
620617
useLayoutEffect(() => {
621618
if (collection.size > 0 && prevOrientation.current !== orientation) {
622619
updateOverflow();

0 commit comments

Comments
 (0)