Skip to content

Commit

Permalink
Tabs: tweak sizing and overflow behavior of TabList (#64371)
Browse files Browse the repository at this point in the history
* Tweak sizing and overflow behavior of TabList.

* Add size and overflow playground story.

* Add "scroll into view" behavior to selected tabs.

* fit-content only on horizontal orientation

* Reduce specificity of `fit-content` to make it easier to override.

* centered label only when orientation is horizontal

* Remove unused file.

* Fix inspector controls tabs.

* Fix font library modal tabs.

* Fix style-book tabs.

* fix typo

* Add changelog entry.

* fix emotion being weird ugh

* Prevent unwanted focusable container in Firefox.

* Add fade effect.

* Fix IntersectionObserver logic.

* Feature detect IntersectionObserver to prevent tests from failing.

* Add a bit of tolerance for scroll state detection.

* Fix vertical indicator.

* Better handling of vertical overflow.

* Add a bit of scroll margin for better "scroll into view" experience.

* Horizontal fade should only happen on horizontal direction.

* Adjust for offset parent scroll state in `getElementOffsetRect`.

* Better "scroll into view" positioning heuristics ("nearest").

* Invert use of before and after to remove z-index and fix related issues.

* Make vertical indicator light blue as discussed.

* Undo most overrides in pattern/media vertical tabs.

* Clean up outdated styles previously needed for label wrapping.

* Revert vertical indicator changes and some indicator patterns/media tabs styles

* Revert vertical indicator bug fix

* Add changelog entry

* Remove outdated style.

* Address feedback

* Fix scroll bug

* Improve automatic tab scrolling behavior.

* Tweaks to prevent unit test failure and minor cleanup.

* Undo unnecessary changes.

* Improved story

* Fix scroll jumping bug.

* Scroll to active tab instead of selected (support `selectOnMove=false`).

* Fix minor visual glitch with overflow fade out indicators.

* Misc tweaks

* Fix.

* Fix changelog

* Fix changelog but it's actually true

* Fix changelog

* Make Story Book tabs nicer.

* Temp fix for scrollbar issue in Style Book tabs.

* Fix scroll bug and clean up a little.

* Simplify and clean up a bit more.

* Fix merge issues.

* Fix merge issues again.

* Make inserter patterns/media changes more minimal

* Fix outdated comment

* Fix another typo in comment.

* Minor cleanup.

* Fix bad automatic merge.

* ugh, fix again

Co-authored-by: DaniGuardiola <[email protected]>
Co-authored-by: tyxla <[email protected]>
Co-authored-by: ciampo <[email protected]>
Co-authored-by: jasmussen <[email protected]>
Co-authored-by: jameskoster <[email protected]>
Co-authored-by: afercia <[email protected]>
  • Loading branch information
7 people authored Sep 30, 2024
1 parent b7bf133 commit 37bceff
Show file tree
Hide file tree
Showing 15 changed files with 346 additions and 185 deletions.
28 changes: 0 additions & 28 deletions packages/block-editor/src/components/inserter/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -257,39 +257,11 @@ $block-inserter-tabs-height: 44px;
svg {
fill: var(--wp-admin-theme-color);
}

&::after {
content: "";
display: block;
outline: none;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
border-radius: $radius-small;
opacity: 0.04;
background: var(--wp-admin-theme-color);
height: 100%;
}
}

&:focus-visible,
&:focus:not(:disabled) {
border-radius: $radius-small;
box-shadow: 0 0 0 var(--wp-admin-border-width-focus) var(--wp-admin-theme-color);
// Windows high contrast mode.
outline: 2px solid transparent;
outline-offset: 0;
}

&::before {
display: none;
}

&::after {
display: none;
}
}
}

Expand Down
78 changes: 0 additions & 78 deletions packages/block-editor/src/components/inserter/tabs.js

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
.show-icon-labels {
.block-editor-block-inspector__tabs [role="tablist"] {
.components-button {
justify-content: center;
}
}
.block-editor-block-inspector__tabs [role="tablist"] {
width: 100%;
}
1 change: 1 addition & 0 deletions packages/components/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

### Enhancements

- `Tabs`: handle horizontal overflow and large tab lists gracefully ([#64371](https://github.com/WordPress/gutenberg/pull/64371)).
- `BorderBoxControl`: promote to stable ([#65586](https://github.com/WordPress/gutenberg/pull/65586)).
- `MenuGroup`: Simplify the MenuGroup styles within dropdown menus. ([#65561](https://github.com/WordPress/gutenberg/pull/65561)).
- `DatePicker`: Use compact button size. ([#65653](https://github.com/WordPress/gutenberg/pull/65653)).
Expand Down
106 changes: 106 additions & 0 deletions packages/components/src/tabs/stories/index.story.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,112 @@ const Template: StoryFn< typeof Tabs > = ( props ) => {

export const Default = Template.bind( {} );

export const SizeAndOverflowPlayground: StoryFn< typeof Tabs > = ( props ) => {
const [ fullWidth, setFullWidth ] = useState( false );
return (
<div>
<div style={ { maxWidth: '40rem', marginBottom: '1rem' } }>
<p>
This story helps understand how the TabList component
behaves under different conditions. The container below
(with the dotted red border) can be horizontally resized,
and it has a bit of padding to be out of the way of the
TabList.
</p>
<p>
The button will toggle between full width (adding{ ' ' }
<code>width: 100%</code>) and the default width.
</p>
<p>Try the following:</p>
<ul>
<li>
<strong>Small container</strong> that causes tabs to
overflow with scroll.
</li>
<li>
<strong>Large container</strong> that exceeds the normal
width of the tabs.
<ul>
<li>
<strong>
With <code>width: 100%</code>
</strong>{ ' ' }
set on the TabList (tabs fill up the space).
</li>
<li>
<strong>
Without <code>width: 100%</code>
</strong>{ ' ' }
(defaults to <code>auto</code>) set on the
TabList (tabs take up space proportional to
their content).
</li>
</ul>
</li>
</ul>
</div>
<Button
style={ { marginBottom: '1rem' } }
variant="primary"
onClick={ () => setFullWidth( ! fullWidth ) }
>
{ fullWidth
? 'Remove width: 100% from TabList'
: 'Set width: 100% in TabList' }
</Button>
<Tabs { ...props }>
<div
style={ {
width: '20rem',
border: '2px dotted red',
padding: '1rem',
resize: 'horizontal',
overflow: 'auto',
} }
>
<Tabs.TabList
style={ {
maxWidth: '100%',
width: fullWidth ? '100%' : undefined,
} }
>
<Tabs.Tab tabId="tab1">
Label with multiple words
</Tabs.Tab>
<Tabs.Tab tabId="tab2">Short</Tabs.Tab>
<Tabs.Tab tabId="tab3">
Hippopotomonstrosesquippedaliophobia
</Tabs.Tab>
<Tabs.Tab tabId="tab4">Tab 4</Tabs.Tab>
<Tabs.Tab tabId="tab5">Tab 5</Tabs.Tab>
</Tabs.TabList>
</div>
<Tabs.TabPanel tabId="tab1">
<p>Selected tab: Tab 1</p>
<p>(Label with multiple words)</p>
</Tabs.TabPanel>
<Tabs.TabPanel tabId="tab2">
<p>Selected tab: Tab 2</p>
<p>(Short)</p>
</Tabs.TabPanel>
<Tabs.TabPanel tabId="tab3">
<p>Selected tab: Tab 3</p>
<p>(Hippopotomonstrosesquippedaliophobia)</p>
</Tabs.TabPanel>
<Tabs.TabPanel tabId="tab4">
<p>Selected tab: Tab 4</p>
</Tabs.TabPanel>
<Tabs.TabPanel tabId="tab5">
<p>Selected tab: Tab 5</p>
</Tabs.TabPanel>
</Tabs>
</div>
);
};
SizeAndOverflowPlayground.args = {
defaultTabId: 'tab4',
};

const VerticalTemplate: StoryFn< typeof Tabs > = ( props ) => {
return (
<Tabs orientation="vertical" { ...props }>
Expand Down
74 changes: 54 additions & 20 deletions packages/components/src/tabs/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,32 +16,40 @@ export const TabListWrapper = styled.div`
align-items: stretch;
flex-direction: row;
text-align: center;
overflow-x: auto;
&[aria-orientation='vertical'] {
flex-direction: column;
text-align: start;
}
@media not ( prefers-reduced-motion ) {
&.is-animation-enabled::after {
transition-property: transform;
transition-duration: 0.2s;
transition-timing-function: ease-out;
}
:where( [aria-orientation='horizontal'] ) {
width: fit-content;
}
--direction-factor: 1;
--direction-origin-x: left;
--direction-start: left;
--direction-end: right;
--indicator-start: var( --indicator-left );
&:dir( rtl ) {
--direction-factor: -1;
--direction-origin-x: right;
--direction-start: right;
--direction-end: left;
--indicator-start: var( --indicator-right );
}
&::after {
@media not ( prefers-reduced-motion ) {
&.is-animation-enabled::before {
transition-property: transform;
transition-duration: 0.2s;
transition-timing-function: ease-out;
}
}
&::before {
content: '';
position: absolute;
pointer-events: none;
transform-origin: var( --direction-origin-x ) top;
transform-origin: var( --direction-start ) top;
// Windows high contrast mode.
outline: 2px solid transparent;
Expand All @@ -52,7 +60,31 @@ export const TabListWrapper = styled.div`
when scaling in the transform, see: https://stackoverflow.com/a/52159123 */
--antialiasing-factor: 100;
&:not( [aria-orientation='vertical'] ) {
&::after {
--fade-width: 4rem;
--fade-gradient-base: transparent 0%, black var( --fade-width );
--fade-gradient-composed: var( --fade-gradient-base ), black 60%,
transparent 50%;
&.is-overflowing-first {
mask-image: linear-gradient(
to var( --direction-end ),
var( --fade-gradient-base )
);
}
&.is-overflowing-last {
mask-image: linear-gradient(
to var( --direction-start ),
var( --fade-gradient-base )
);
}
&.is-overflowing-first.is-overflowing-last {
mask-image: linear-gradient(
to right,
var( --fade-gradient-composed )
),
linear-gradient( to left, var( --fade-gradient-composed ) );
}
&::before {
bottom: 0;
height: 0;
width: calc( var( --antialiasing-factor ) * 1px );
Expand All @@ -71,8 +103,7 @@ export const TabListWrapper = styled.div`
${ COLORS.theme.accent };
}
}
&[aria-orientation='vertical']::after {
z-index: -1;
&[aria-orientation='vertical']::before {
top: 0;
left: 0;
width: 100%;
Expand All @@ -87,14 +118,14 @@ export const TabListWrapper = styled.div`

export const Tab = styled( Ariakit.Tab )`
& {
scroll-margin: 24px;
flex-grow: 1;
flex-shrink: 0;
display: inline-flex;
align-items: center;
position: relative;
border-radius: 0;
min-height: ${ space(
12
) }; // Avoid fixed height to allow for long strings that go in multiple lines.
height: auto;
height: ${ space( 12 ) };
background: transparent;
border: none;
box-shadow: none;
Expand All @@ -104,7 +135,6 @@ export const Tab = styled( Ariakit.Tab )`
margin-left: 0;
font-weight: 500;
text-align: inherit;
hyphens: auto;
color: ${ COLORS.theme.foreground };
&[aria-disabled='true'] {
Expand All @@ -123,7 +153,7 @@ export const Tab = styled( Ariakit.Tab )`
}
// Focus.
&::before {
&::after {
content: '';
position: absolute;
top: ${ space( 3 ) };
Expand All @@ -146,7 +176,7 @@ export const Tab = styled( Ariakit.Tab )`
}
}
&:focus-visible::before {
&:focus-visible::after {
opacity: 1;
}
}
Expand All @@ -156,6 +186,10 @@ export const Tab = styled( Ariakit.Tab )`
10
) }; // Avoid fixed height to allow for long strings that go in multiple lines.
}
[aria-orientation='horizontal'] & {
justify-content: center;
}
`;

export const TabPanel = styled( Ariakit.TabPanel )`
Expand Down
Loading

1 comment on commit 37bceff

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Flaky tests detected in 37bceff.
Some tests passed with failed attempts. The failures may not be related to this commit but are still reported for visibility. See the documentation for more information.

🔍 Workflow run URL: https://github.com/WordPress/gutenberg/actions/runs/11112808635
📝 Reported issues:

Please sign in to comment.