Skip to content

Commit

Permalink
Tabs: tweak sizing and overflow behavior of TabList (WordPress#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

0 comments on commit 37bceff

Please sign in to comment.