Skip to content
Merged
Show file tree
Hide file tree
Changes from 11 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
5 changes: 5 additions & 0 deletions .changeset/every-cows-do.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@drivenets/design-system': minor
---

Add `DsTabs` component
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ type BasePositioning = NonNullable<Menu.RootProps['positioning']>;
/**
* Positioning options for dropdown menu
*/
export type DsDropdownMenuPositioning = Pick<BasePositioning, 'placement' | 'gutter' | 'sameWidth'>;
export type DsDropdownMenuPositioning = Pick<
BasePositioning,
'placement' | 'gutter' | 'sameWidth' | 'getAnchorRect'
>;

/**
* DEPRECATED: Legacy dropdown menu option configuration
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
$animation-duration: 0.2s;
$animation-translate: -4px;

.tabContent {
padding: var(--spacing-standard) 0;
animation: fadeIn $animation-duration ease-in;
}

@keyframes fadeIn {
from {
opacity: 0;
transform: translateY($animation-translate);
}
to {
opacity: 1;
transform: translateY(0);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { Tabs } from '@ark-ui/react/tabs';
import classNames from 'classnames';
import type { DsTabsContentProps } from '../../ds-tabs.types';
import styles from './ds-tabs-content.module.scss';

export const DsTabsContent = ({ value, className, style, children }: DsTabsContentProps) => {
return (
<Tabs.Content value={value} className={classNames(styles.tabContent, className)} style={style}>
{children}
</Tabs.Content>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { DsTabsContent } from './ds-tabs-content';
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
$indicator-border-radius: 4px;
$indicator-thickness: 2px;
$indicator-offset: -4px;
$transition-duration: 0.2s;

.indicator {
position: absolute;
background: var(--color-background-selected);
transition:
left $transition-duration ease-in-out,
top $transition-duration ease-in-out,
width $transition-duration ease-in-out,
height $transition-duration ease-in-out,
opacity $transition-duration ease-in-out;
border-radius: $indicator-border-radius;
pointer-events: none;

[data-orientation='horizontal'] & {
bottom: $indicator-offset;
height: $indicator-thickness;
left: var(--left);
width: var(--width);
}

[data-orientation='vertical'] & {
left: 0;
width: $indicator-thickness;
top: var(--top);
height: var(--height);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
$border-width: 1px;

.tabList {
display: flex;
position: relative;
}

.tabList-horizontal {
flex-direction: row;
align-items: center;
border-bottom: $border-width solid var(--color-border-main);
gap: var(--spacing-xs);
}

.tabList-vertical {
flex-direction: column;
align-items: stretch;
border-right: $border-width solid var(--color-border-main);
}

.tabList-vertical-medium {
gap: var(--spacing-xs);
}

.tabList-vertical-small {
gap: var(--spacing-3xs);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { Tabs } from '@ark-ui/react/tabs';
import classNames from 'classnames';
import { useTabsContext } from '../../context/ds-tabs-context';
import type { DsTabsListProps } from '../../ds-tabs.types';
import styles from './ds-tabs-list.module.scss';
import indicatorStyles from './ds-tabs-indicator.module.scss';

export const DsTabsList = ({ className, style, children }: DsTabsListProps) => {
const { orientation, size } = useTabsContext();

return (
<Tabs.List
className={classNames(
styles.tabList,
styles[`tabList-${orientation}`],
styles[`tabList-${orientation}-${size}`],
className,
)}
style={style}
>
{children}
<Tabs.Indicator className={indicatorStyles.indicator} />
</Tabs.List>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { DsTabsList } from './ds-tabs-list';
Original file line number Diff line number Diff line change
@@ -0,0 +1,247 @@
@use '../../../../styles/typography';

$tab-border-width: 1px;
$badge-height: 20px;
$menu-content-width: 142px;
$transition-duration: 0.2s;
$disabled-opacity: 0.5;

.tabItem {
@include typography.body-sm-reg;
display: inline-flex;
align-items: center;
background: var(--color-background);
border-radius: var(--exo-spacing-2x-small);
cursor: pointer;
transition:
background-color $transition-duration,
color $transition-duration,
border-color $transition-duration;
position: relative;
color: var(--color-font-main);
border: $tab-border-width solid transparent;
white-space: nowrap;

&:hover:not(:disabled):not([aria-selected='true']) {
background: var(--color-background-secondary);

.badge {
background: var(--color-background-tertiary);
}
}

&:active:not(:disabled):not([aria-selected='true']) {
background: var(--color-background-tertiary);

.badge {
background: var(--color-background-secondary);
}
}

&:focus-visible:not(:disabled):not([aria-selected='true']) {
border-color: var(--color-border-action-hover);
background: var(--color-background-secondary);
outline: none;

.badge {
background: var(--color-background-tertiary);
}
}

&:disabled {
cursor: not-allowed;
opacity: $disabled-opacity;
color: var(--color-font-disabled);
}

&[aria-selected='true'] {
@include typography.body-sm-md;
color: var(--color-background-selected);
background: var(--color-background);

.icon {
color: var(--color-background-selected);
}

.badge {
background: var(--color-background-action-secondary-hover);
color: var(--color-background-selected);
}

&:hover:not(:disabled) {
background: var(--color-background-selected-weak);
}

&:active:not(:disabled) {
background: var(--color-background-selected-weak);
}

&:focus-visible:not(:disabled) {
border-color: var(--color-background-selected);
background: var(--color-background-selected-weak);
outline: none;
}
}
}

.tabItem-horizontal {
flex-direction: row;
justify-content: center;
gap: var(--spacing-3xs);
flex: 0 0 auto;
width: auto;

&.tabItem-medium {
padding: var(--spacing-xs) var(--spacing-sm);
}

&.tabItem-small {
padding: var(--spacing-2xs) var(--spacing-sm);
}
}

.tabItem-vertical {
flex-direction: row;
justify-content: flex-start;
gap: var(--spacing-3xs);
width: 100%;

&.tabItem-medium {
padding: var(--spacing-sm) var(--spacing-standard);
padding-left: var(--spacing-xs);
border-radius: var(--exo-spacing-2x-small) 0 0 var(--exo-spacing-2x-small);
}

&.tabItem-small {
padding: var(--spacing-xs) var(--spacing-standard);
padding-left: var(--spacing-xs);
border-radius: var(--exo-spacing-2x-small) 0 0 var(--exo-spacing-2x-small);
}
}

.icon {
display: flex;
align-items: center;
justify-content: center;
color: var(--color-font-secondary);
flex-shrink: 0;
}

.label {
@include typography.body-sm-reg;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
flex: 1 1 auto;
min-width: 0;
text-align: left;

[aria-selected='true'] & {
@include typography.body-sm-md;
}
}

.tabWrapper {
display: inline-flex;
align-items: stretch;
position: relative;
gap: 0;
}

.menuTrigger {
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
color: var(--color-font-main) !important;
cursor: pointer;
border-radius: var(--exo-spacing-2x-small);
transition:
background-color $transition-duration,
color $transition-duration;

&:hover {
background: var(--color-background-action-secondary);
color: var(--color-font-main);
}

&:active {
background: var(--color-background-tertiary);
}

&:focus-visible {
outline: var(--spacing-4xs) solid var(--color-border-action-hover);
outline-offset: var(--spacing-4xs);
}

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

&:hover {
background: var(--color-background);
}
}

[disabled] & {
opacity: $disabled-opacity;
cursor: not-allowed;
pointer-events: none;
}
}

.badge {
@include typography.body-xs-reg;
display: flex;
align-items: center;
justify-content: center;
height: $badge-height;
padding: 0 var(--spacing-2xs);
border-radius: var(--spacing-lg);
background: var(--color-background-secondary);
color: var(--color-font-main);
line-height: var(--line-height-xs);
flex-shrink: 0;
}

.menuContent {
background: var(--color-background);
border: $tab-border-width solid var(--color-border-secondary);
border-radius: var(--exo-spacing-2x-small);
box-shadow: 0 5px 15px 0 rgba(0, 0, 0, 0.15);
padding: var(--spacing-3xs);
width: $menu-content-width;
}

.menuItem {
@include typography.body-sm-reg;
display: flex;
align-items: center;
padding: var(--spacing-3xs);
border-radius: var(--exo-spacing-2x-small);
cursor: pointer;
color: var(--color-font-main);
background: var(--color-background);
transition: background-color $transition-duration;
user-select: none;
white-space: nowrap;

&:hover {
background: var(--color-background-secondary);
}

&:active {
background: var(--color-background-tertiary);
}

&[data-disabled] {
opacity: $disabled-opacity;
cursor: not-allowed;
pointer-events: none;
}
}

.menuItemLabel {
flex: 1;
min-width: 0;
line-height: var(--line-height-sm);
}
Loading