Skip to content

Commit

Permalink
feat(ld-tabs): tabs tablist tab tabpanellist tabpanel
Browse files Browse the repository at this point in the history
  • Loading branch information
borisdiakur authored and renet committed Sep 20, 2021
1 parent 292c295 commit acc5964
Show file tree
Hide file tree
Showing 12 changed files with 988 additions and 0 deletions.
1 change: 1 addition & 0 deletions src/docs/components/docs-example/docs-example.css
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@

> * {
margin: var(--ld-sp-24) var(--ld-sp-24) 0;
max-width: calc(100% - 2 * var(--ld-sp-24));
}
}
}
Expand Down
305 changes: 305 additions & 0 deletions src/liquid/components/ld-tabs/ld-tab.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,305 @@
.ld-tab {
--ld-tab-padding-x: 0.875rem;
--ld-tab-padding-y: 0.75rem;
--ld-tab-min-height: 2.5rem;
--ld-tab-color: var(--ld-col-rblck-default);
--ld-tab-bg-color: var(--ld-col-bg-lg);
--ld-tab-focus-color: var(--ld-col-rblck1);
--ld-tab-focus-bg-color: var(--ld-col-rblck4);
--ld-tab-hover-bg-color: var(--ld-col-rblck1);
--ld-tab-active-bg-color: var(--ld-col-rblck2);
--ld-tab-gap: 0.625rem;
--ld-tab-icon-size: 1.25rem;
position: relative;
font: var(--ld-typo-body-m);
font-weight: 700;
border: 0;
text-decoration: none;
user-select: none;
touch-action: manipulation;
display: grid;
grid-template-columns: minmax(0rem, var(--ld-sp-16)) max-content minmax(
0rem,
var(--ld-sp-16)
);
align-items: center;
text-align: center;
justify-content: center;
line-height: 1;
scroll-snap-align: start;
white-space: nowrap;
-webkit-touch-callout: none;
padding: var(--ld-tab-padding-y) var(--ld-tab-padding-x);
min-height: var(--ld-tab-min-height);
color: var(--ld-tab-color);
background-color: var(--ld-tab-bg-color);

&[aria-disabled='true'] {
--ld-tab-focus-bg-color: var(--ld-col-rblck3);
--ld-tab-focus-color: var(--ld-col-wht);

.ld-tab__content {
opacity: 0.25;
}
}

/* Selection indicator */
&::after {
content: '';
position: absolute;
inset: auto 0 0 0;
height: var(--ld-sp-2);
z-index: 1;
}

&[aria-selected='true'] {
color: var(--ld-tab-color-selected);

&::after {
background-color: var(--ld-tab-color-selected);
}
}

&:focus:focus-visible {
outline: none;
background-color: var(--ld-tab-focus-bg-color);

&:not(:active),
&[aria-disabled='true'] {
color: var(--ld-tab-focus-color);
}

&[aria-selected='true'] {
&:not(:active) {
color: var(--ld-tab-selected-focus-color);
}

&::after {
background-color: var(--ld-tab-selected-focus-color);
}
}

&:not([aria-selected='true'])::after {
background-color: inherit;
}
}

&:where(:not([aria-disabled='true'])) {
cursor: pointer;

@media (hover: hover) {
&:hover {
background-color: var(--ld-tab-hover-bg-color);

&:not([aria-selected='true'])::after {
background-color: inherit;
}
}
}
&:active:focus,
&:active:focus:focus-visible {
background-color: var(--ld-tab-active-bg-color);

&:not([aria-selected='true'])::after {
background-color: inherit;
}
}
}

.ld-tabs--sm & {
--ld-tab-padding-x: 0.625rem;
--ld-tab-padding-y: 0.5rem;
--ld-tab-min-height: 2rem;
--ld-tab-gap: 0.375rem;
--ld-tab-icon-size: 1rem;
font: var(--ld-typo-body-s);
}

.ld-tabs--lg & {
--ld-tab-padding-x: 1.3125rem;
--ld-tab-padding-y: 0.75rem;
--ld-tab-min-height: 3.125rem;
--ld-tab-gap: 0.875rem;
--ld-tab-icon-size: 1.5rem;
font: var(--ld-typo-body-l);
}

.ld-tabs--sm &,
.ld-tabs--lg & {
line-height: 1;
font-weight: 700;
}

:where(.ld-tabs--ghost) & {
--ld-tab-bg-color: transparent;
}

.ld-tabs--brand-color & {
--ld-tab-selected-focus-color: var(--ld-col-wht);

&[aria-selected='true'] {
color: var(--ld-col-wht);

&:focus,
&:focus:focus-visible {
&::after {
background-color: var(--ld-tab-color-selected);
}
}
}

&[aria-disabled='true'] {
opacity: 0.5;

.ld-tab__content {
opacity: 1;
}
}

&:not([aria-disabled='true']) {
--ld-tab-color: var(--ld-col-wht);
--ld-tab-focus-color: var(--ld-col-wht);
}

.ld-theme-ocean &,
[class*='ld-theme'] .ld-theme-ocean & {
--ld-tab-color-selected: var(--ld-thm-ocean-accent);
--ld-tab-bg-color: var(--ld-thm-ocean-bg-primary);
--ld-tab-focus-bg-color: var(--ld-col-rb-focus);
--ld-tab-focus-color: var(--ld-col-rb6);
--ld-tab-hover-bg-color: var(--ld-col-rb-hover);
--ld-tab-active-bg-color: var(--ld-col-rb-active);

&[aria-disabled='true'] {
--ld-tab-focus-color: var(--ld-col-rb5);
--ld-tab-focus-bg-color: var(--ld-col-rb6);
--ld-tab-color: var(--ld-col-rb3);
}
}

.ld-theme-tea &,
[class*='ld-theme'] .ld-theme-tea & {
--ld-tab-color-selected: var(--ld-thm-tea-accent);
--ld-tab-bg-color: var(--ld-thm-tea-bg-primary);
--ld-tab-focus-bg-color: var(--ld-col-rg-focus);
--ld-tab-focus-color: var(--ld-col-rg6);
--ld-tab-hover-bg-color: var(--ld-col-rg-hover);
--ld-tab-active-bg-color: var(--ld-col-rg-active);

&[aria-disabled='true'] {
--ld-tab-focus-color: var(--ld-col-rg5);
--ld-tab-focus-bg-color: var(--ld-col-rg6);
--ld-tab-color: var(--ld-col-rg3);
}
}

.ld-theme-bubblegum &,
[class*='ld-theme'] .ld-theme-bubblegum & {
--ld-tab-color-selected: var(--ld-thm-bubblegum-accent);
--ld-tab-bg-color: var(--ld-thm-bubblegum-bg-primary);
--ld-tab-focus-bg-color: var(--ld-col-rp-focus);
--ld-tab-focus-color: var(--ld-col-rp6);
--ld-tab-hover-bg-color: var(--ld-col-rp-hover);
--ld-tab-active-bg-color: var(--ld-col-rp-active);

&[aria-disabled='true'] {
--ld-tab-focus-color: var(--ld-col-rp5);
--ld-tab-focus-bg-color: var(--ld-col-rp6);
--ld-tab-color: var(--ld-col-rp3);
}
}

.ld-theme-shake &,
[class*='ld-theme'] .ld-theme-shake & {
--ld-tab-color-selected: var(--ld-thm-shake-accent);
--ld-tab-bg-color: var(--ld-thm-shake-bg-primary);
--ld-tab-focus-bg-color: var(--ld-col-rp-focus);
--ld-tab-focus-color: var(--ld-col-rp6);
--ld-tab-hover-bg-color: var(--ld-col-rp-hover);
--ld-tab-active-bg-color: var(--ld-col-rp-active);

&[aria-disabled='true'] {
--ld-tab-focus-color: var(--ld-col-rp5);
--ld-tab-focus-bg-color: var(--ld-col-rp6);
--ld-tab-color: var(--ld-col-rp3);
}
}

.ld-theme-solvent &,
[class*='ld-theme'] .ld-theme-solvent & {
--ld-tab-color-selected: var(--ld-thm-solvent-accent);
--ld-tab-bg-color: var(--ld-thm-solvent-bg-primary);
--ld-tab-focus-bg-color: var(--ld-col-rp-focus);
--ld-tab-focus-color: var(--ld-col-rp6);
--ld-tab-hover-bg-color: var(--ld-col-rp-hover);
--ld-tab-active-bg-color: var(--ld-col-rp-active);

&[aria-disabled='true'] {
--ld-tab-focus-color: var(--ld-col-rp5);
--ld-tab-focus-bg-color: var(--ld-col-rp6);
--ld-tab-color: var(--ld-col-rp3);
}
}
}
}

.ld-tab__spacer {
display: inline-flex;
flex-shrink: 1;
width: 1rem;
}

.ld-tab__content {
display: grid;
grid-auto-flow: column;
gap: var(--ld-tab-gap);
align-items: center;

ld-icon,
.ld-icon {
svg {
width: var(--ld-tab-icon-size);
height: var(--ld-tab-icon-size);
}
}
}

/* .ld-theme-ocean -> default */
.ld-tab,
:where(.ld-theme-ocean) .ld-tab,
:where([class*='ld-theme'] .ld-theme-ocean) .ld-tab {
--ld-tab-color-selected: var(--ld-thm-ocean-bg-primary);
--ld-tab-selected-focus-color: var(--ld-col-rb2);
}

:where(.ld-theme-tea),
:where([class*='ld-theme'] .ld-theme-tea) {
.ld-tab {
--ld-tab-color-selected: var(--ld-thm-tea-bg-primary);
--ld-tab-selected-focus-color: var(--ld-col-rg2);
}
}

:where(.ld-theme-bubblegum),
:where([class*='ld-theme'] .ld-theme-bubblegum) {
.ld-tab {
--ld-tab-color-selected: var(--ld-thm-bubblegum-bg-primary);
--ld-tab-selected-focus-color: var(--ld-col-rp2);
}
}

:where(.ld-theme-shake),
:where([class*='ld-theme'] .ld-theme-shake) {
.ld-tab {
--ld-tab-color-selected: var(--ld-thm-shake-bg-primary);
--ld-tab-selected-focus-color: var(--ld-col-rp2);
}
}

:where(.ld-theme-solvent),
:where([class*='ld-theme'] .ld-theme-solvent) {
.ld-tab {
--ld-tab-color-selected: var(--ld-thm-solvent-bg-primary);
--ld-tab-selected-focus-color: var(--ld-col-rp2);
}
}
79 changes: 79 additions & 0 deletions src/liquid/components/ld-tabs/ld-tab.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import '../../components' // type definitions for type checks and intelliSense
import {
Component,
Element,
Event,
EventEmitter,
h,
Prop,
Watch,
} from '@stencil/core'

/**
* @virtualProp ref - reference to component
* @virtualProp {string | number} key - for tracking the node's identity when working with lists
*/
@Component({
tag: 'ld-tab',
styleUrl: 'ld-tab.css',
shadow: false,
})
export class LdTab {
@Element() el: HTMLElement

/**
* If present, this boolean attribute indicates that the tab is selected.
*/
@Prop({ mutable: true, reflect: true }) selected?: boolean

/**
* Disables the tab.
*/
@Prop() disabled?: boolean

/**
* Emitted with the id of the selected tab.
*/
@Event() tabChange: EventEmitter<string>

private handleTabClick(ev) {
ev.preventDefault()

if (this.disabled) return

if (ev.currentTarget.getAttribute('aria-selected')) return

this.selected = true
}

@Watch('selected')
emitEvent(newSelected: boolean, oldSelected: boolean) {
if (!newSelected || newSelected === oldSelected) return

const index = Array.prototype.indexOf.call(
this.el.closest('.ld-tablist__scroll-container').children,
this.el
)

this.tabChange.emit(index)
}

render() {
return (
<button
class="ld-tab"
role="tab"
aria-selected={this.selected ? 'true' : undefined}
aria-disabled={this.disabled ? 'true' : undefined}
onClick={this.handleTabClick.bind(this)}
tabindex={this.selected ? undefined : '-1'}
>
<span class="ld-tab__spacer"></span>
<span class="ld-tab__content">
<slot></slot>
</span>
<span class="ld-tab__spacer"></span>
</button>
)
}
}
Loading

0 comments on commit acc5964

Please sign in to comment.