Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 22 additions & 4 deletions packages/@adobe/spectrum-css-temp/components/tabs/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -91,12 +91,11 @@ governing permissions and limitations under the License.
&::before {
content: '';
position: absolute;
top: 50%;
top: 0;
bottom: 0;

box-sizing: border-box;

block-size: var(--spectrum-tabs-focus-ring-height);
margin-block-start: calc(calc(var(--spectrum-tabs-focus-ring-height) / -2) + calc(var(--spectrum-tabs-rule-height) / 2));
inset-inline-start: calc(var(--spectrum-tabs-focus-ring-padding-x) * -1);
inset-inline-end: calc(var(--spectrum-tabs-focus-ring-padding-x) * -1);
border: var(--spectrum-tabs-focus-ring-size) solid transparent;
Expand Down Expand Up @@ -163,6 +162,13 @@ governing permissions and limitations under the License.
& + *:not(.spectrum-Tabs-selectionIndicator) {
margin-inline-start: var(--spectrum-tabs-item-gap);
}

&::before {
top: 50%;
bottom: unset;
block-size: var(--spectrum-tabs-focus-ring-height);
margin-block-start: calc(calc(var(--spectrum-tabs-focus-ring-height) / -2) + calc(var(--spectrum-tabs-rule-height) / 2));
}
}

.spectrum-Tabs-selectionIndicator {
Expand Down Expand Up @@ -234,10 +240,22 @@ governing permissions and limitations under the License.
/* padding is included in click area of tab items, so only need to offset by the size of the focus ring's border */
inset-inline-start: calc(var(--spectrum-tabs-focus-ring-size) * -1);
inset-inline-end: calc(var(--spectrum-tabs-focus-ring-size) * -1);
margin-block-start: calc(calc(var(--spectrum-tabs-focus-ring-height) / -2));
}
}

/*
Allow tab labels to wrap when TabList component has minWidth set.
*/
&.spectrum-Tabs--verticalWrap:not(.spectrum-Tabs--compact) .spectrum-Tabs-item {
display: flex;
align-items: center;
white-space: normal;
line-height: normal;
word-break: break-word;
block-size: auto;
min-height: var(--spectrum-tabs-vertical-item-height);
}

&.spectrum-Tabs--compact {
.spectrum-Tabs-item {
block-size: var(--spectrum-tabs-compact-vertical-item-height);
Expand Down
24 changes: 19 additions & 5 deletions packages/@react-spectrum/s2/src/Tabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@ const selectedIndicator = style<{isDisabled: boolean, orientation?: Orientation}
borderRadius: 'full'
});

const tab = style<TabRenderProps & {density?: 'compact' | 'regular', labelBehavior?: 'show' | 'hide'}>({
const tab = style<TabRenderProps & {density?: 'compact' | 'regular', labelBehavior?: 'show' | 'hide', orientation?: Orientation}>({
...focusRing(),
display: 'flex',
color: {
Expand All @@ -290,9 +290,23 @@ const tab = style<TabRenderProps & {density?: 'compact' | 'regular', labelBehavi
borderRadius: 'sm',
gap: 'text-to-visual',
height: {
density: {
compact: 32,
regular: 48
orientation: {
horizontal: {
density: {
compact: 32,
regular: 48
}
}
}
},
minHeight: {
orientation: {
vertical: {
density: {
compact: 32,
regular: 48
}
}
}
},
alignItems: 'center',
Expand Down Expand Up @@ -330,7 +344,7 @@ export function Tab(props: TabProps): ReactNode {
originalProps={props}
aria-labelledby={`${labelBehavior === 'hide' ? contentId : ''} ${ariaLabelledBy}`}
style={props.UNSAFE_style}
className={renderProps => (props.UNSAFE_className || '') + tab({...renderProps, density, labelBehavior}, props.styles)}>
className={renderProps => (props.UNSAFE_className || '') + tab({...renderProps, density, labelBehavior, orientation}, props.styles)}>
{({
// @ts-ignore
isMenu,
Expand Down
3 changes: 2 additions & 1 deletion packages/@react-spectrum/s2/stories/Tabs.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,13 @@ export default meta;
type Story = StoryObj<typeof Tabs>;

const tabs = style({width: 'full', height: 'full'});
const tabList = style({maxWidth: {orientation: {vertical: 150}}});

export const Example: Story = {
render: (args) => (
<div className={style({width: 700, maxWidth: 'calc(100vw - 60px)', height: 256, resize: 'horizontal', overflow: 'hidden', padding: 8})}>
<Tabs {...args} styles={tabs} aria-label="History of Ancient Rome">
<TabList>
<TabList styles={tabList({orientation: args.orientation})}>
<Tab id="FoR">Founding of Rome</Tab>
<Tab id="MaR">Monarchy and Republic</Tab>
<Tab id="Emp">Empire</Tab>
Expand Down
7 changes: 5 additions & 2 deletions packages/@react-spectrum/tabs/src/Tabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ function TabLine(props: TabLineProps) {
* A TabList is used within Tabs to group tabs that a user can switch between.
* The keys of the items within the <TabList> must match up with a corresponding item inside the <TabPanels>.
*/
export function TabList<T>(props: SpectrumTabListProps<T>): ReactNode {
export function TabList<T>(props: SpectrumTabListProps<T> & {wrap?: boolean}): ReactNode {
const tabContext = useContext(TabContext)!;
const {refs, tabState, tabProps, tabPanelProps} = tabContext;
const {isQuiet, density, isEmphasized, orientation} = tabProps;
Expand All @@ -288,6 +288,8 @@ export function TabList<T>(props: SpectrumTabListProps<T>): ReactNode {

let tabListclassName = classNames(styles, 'spectrum-TabsPanel-tabs');

const verticalWrap = props.wrap && orientation === 'vertical';

const tabContent = (
<div
{...stylePropsFinal}
Expand All @@ -301,7 +303,8 @@ export function TabList<T>(props: SpectrumTabListProps<T>): ReactNode {
{
'spectrum-Tabs--quiet': isQuiet,
'spectrum-Tabs--emphasized': isEmphasized,
['spectrum-Tabs--compact']: density === 'compact'
['spectrum-Tabs--compact']: density === 'compact',
'spectrum-Tabs--verticalWrap': verticalWrap
},
orientation === 'vertical' && styleProps.className
)
Expand Down
111 changes: 111 additions & 0 deletions packages/@react-spectrum/tabs/stories/Tabs.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,12 @@ OrientationVertical.story = {
name: 'orientation: vertical'
};

export const OrientationVerticalWrap: TabsStory = () => renderWithVerticalWrap({minWidth: 90, wrap: true});

OrientationVerticalWrap.story = {
name: 'orientation: vertical, wrap: true'
};

export const DensityCompact: TabsStory = () => render({density: 'compact'});

DensityCompact.story = {
Expand Down Expand Up @@ -742,6 +748,111 @@ function renderWithFalsyKey(props = {}) {
);
}

function renderWithVerticalWrap(props = {}) {
return (
<Tabs
orientation="vertical"
aria-label="Tab example"
maxWidth={500}
onSelectionChange={action('onSelectionChange')}>
<TabList {...props}>
<Item key="val1">User Profile Settings</Item>
<Item key="val2">Notification Preferences and yabba dabba doo yabba dabba doo yabba dabba doo</Item>
<Item key="val3">Tab 3</Item>
<Item key="val4">Tab 4</Item>
<Item key="val5">Tab 5</Item>
</TabList>
<TabPanels>
<Item key="val1">
<Heading>Tab Body 1</Heading>
<Text>
Dolore ex esse laboris elit magna esse sunt. Pariatur in veniam Lorem est occaecat do
magna nisi mollit ipsum sit adipisicing fugiat ex. Pariatur ullamco exercitation ea qui
adipisicing. Id cupidatat aute id ut excepteur exercitation magna pariatur. Mollit irure
irure reprehenderit pariatur eiusmod proident Lorem deserunt duis cillum mollit. Do
reprehenderit sit cupidatat quis laborum in do culpa nisi ipsum. Velit aliquip commodo
ea ipsum incididunt culpa nostrud deserunt incididunt exercitation. In quis proident sit
ad dolore tempor. Eiusmod pariatur quis commodo labore cupidatat cillum enim eiusmod
voluptate laborum culpa. Laborum cupidatat incididunt velit voluptate incididunt
occaecat quis do. Consequat adipisicing irure Lorem commodo officia sint id. Velit sit
magna aliquip eiusmod non id deserunt. Magna veniam ad consequat dolor cupidatat esse
enim Lorem ullamco. Anim excepteur consectetur id in. Mollit laboris duis labore enim
duis esse reprehenderit.
</Text>
</Item>
<Item key="val2">
<Heading>Tab Body 2</Heading>
<Text>
Dolore ex esse laboris elit magna esse sunt. Pariatur in veniam Lorem est occaecat do
magna nisi mollit ipsum sit adipisicing fugiat ex. Pariatur ullamco exercitation ea qui
adipisicing. Id cupidatat aute id ut excepteur exercitation magna pariatur. Mollit irure
irure reprehenderit pariatur eiusmod proident Lorem deserunt duis cillum mollit. Do
reprehenderit sit cupidatat quis laborum in do culpa nisi ipsum. Velit aliquip commodo
ea ipsum incididunt culpa nostrud deserunt incididunt exercitation. In quis proident sit
ad dolore tempor. Eiusmod pariatur quis commodo labore cupidatat cillum enim eiusmod
voluptate laborum culpa. Laborum cupidatat incididunt velit voluptate incididunt
occaecat quis do. Consequat adipisicing irure Lorem commodo officia sint id. Velit sit
magna aliquip eiusmod non id deserunt. Magna veniam ad consequat dolor cupidatat esse
enim Lorem ullamco. Anim excepteur consectetur id in. Mollit laboris duis labore enim
duis esse reprehenderit.
</Text>
</Item>
<Item key="val3">
<Heading>Tab Body 3</Heading>
<Text>
Dolore ex esse laboris elit magna esse sunt. Pariatur in veniam Lorem est occaecat do
magna nisi mollit ipsum sit adipisicing fugiat ex. Pariatur ullamco exercitation ea qui
adipisicing. Id cupidatat aute id ut excepteur exercitation magna pariatur. Mollit irure
irure reprehenderit pariatur eiusmod proident Lorem deserunt duis cillum mollit. Do
reprehenderit sit cupidatat quis laborum in do culpa nisi ipsum. Velit aliquip commodo
ea ipsum incididunt culpa nostrud deserunt incididunt exercitation. In quis proident sit
ad dolore tempor. Eiusmod pariatur quis commodo labore cupidatat cillum enim eiusmod
voluptate laborum culpa. Laborum cupidatat incididunt velit voluptate incididunt
occaecat quis do. Consequat adipisicing irure Lorem commodo officia sint id. Velit sit
magna aliquip eiusmod non id deserunt. Magna veniam ad consequat dolor cupidatat esse
enim Lorem ullamco. Anim excepteur consectetur id in. Mollit laboris duis labore enim
duis esse reprehenderit.
</Text>
</Item>
<Item key="val4">
<Heading>Tab Body 4</Heading>
<Text>
Dolore ex esse laboris elit magna esse sunt. Pariatur in veniam Lorem est occaecat do
magna nisi mollit ipsum sit adipisicing fugiat ex. Pariatur ullamco exercitation ea qui
adipisicing. Id cupidatat aute id ut excepteur exercitation magna pariatur. Mollit irure
irure reprehenderit pariatur eiusmod proident Lorem deserunt duis cillum mollit. Do
reprehenderit sit cupidatat quis laborum in do culpa nisi ipsum. Velit aliquip commodo
ea ipsum incididunt culpa nostrud deserunt incididunt exercitation. In quis proident sit
ad dolore tempor. Eiusmod pariatur quis commodo labore cupidatat cillum enim eiusmod
voluptate laborum culpa. Laborum cupidatat incididunt velit voluptate incididunt
occaecat quis do. Consequat adipisicing irure Lorem commodo officia sint id. Velit sit
magna aliquip eiusmod non id deserunt. Magna veniam ad consequat dolor cupidatat esse
enim Lorem ullamco. Anim excepteur consectetur id in. Mollit laboris duis labore enim
duis esse reprehenderit.
</Text>
</Item>
<Item key="val5">
<Heading>Tab Body 5</Heading>
<Text>
Dolore ex esse laboris elit magna esse sunt. Pariatur in veniam Lorem est occaecat do
magna nisi mollit ipsum sit adipisicing fugiat ex. Pariatur ullamco exercitation ea qui
adipisicing. Id cupidatat aute id ut excepteur exercitation magna pariatur. Mollit irure
irure reprehenderit pariatur eiusmod proident Lorem deserunt duis cillum mollit. Do
reprehenderit sit cupidatat quis laborum in do culpa nisi ipsum. Velit aliquip commodo
ea ipsum incididunt culpa nostrud deserunt incididunt exercitation. In quis proident sit
ad dolore tempor. Eiusmod pariatur quis commodo labore cupidatat cillum enim eiusmod
voluptate laborum culpa. Laborum cupidatat incididunt velit voluptate incididunt
occaecat quis do. Consequat adipisicing irure Lorem commodo officia sint id. Velit sit
magna aliquip eiusmod non id deserunt. Magna veniam ad consequat dolor cupidatat esse
enim Lorem ullamco. Anim excepteur consectetur id in. Mollit laboris duis labore enim
duis esse reprehenderit.
</Text>
</Item>
</TabPanels>
</Tabs>
);
}

interface DynamicTabItem {
name: string,
children: ReactNode,
Expand Down
7 changes: 6 additions & 1 deletion packages/@react-types/tabs/src/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,12 @@ export interface SpectrumTabsProps<T> extends AriaTabListBase, Omit<SingleSelect

export interface SpectrumTabListProps<T> extends DOMProps, StyleProps {
/** The tab items to display. Item keys should match the key of the corresponding `<Item>` within the `<TabPanels>` element. */
children: CollectionChildren<T>
children: CollectionChildren<T>,
/**
* When `true`, tab labels will wrap if they exceed the TabList's width. Only supported in vertical orientation with `regular` density. For proper wrapping, set a `minWidth` on TabList.
* @default false
*/
wrap?: boolean
}

export interface SpectrumTabPanelsProps<T> extends DOMProps, StyleProps {
Expand Down