Skip to content
Draft
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
5 changes: 5 additions & 0 deletions .changeset/bright-wolves-change.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@alfalab/core-components-tabs': patch
---

Сплит внутреннего компонента десктоп / мобайл
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
import React from 'react';

import { type TabListProps } from '../../typings';
import { ScrollableContainerDesktop } from '../scrollable-container/Component.desktop';

import { PrimaryTabList } from './Component';

import styles from './index.module.css';

export const PrimaryTabListDesktop = ({ size = 'm', ...restProps }: TabListProps) => (
<PrimaryTabList {...restProps} size={size} styles={styles} platform='desktop' />
<PrimaryTabList
{...restProps}
ScrollableContainer={ScrollableContainerDesktop}
size={size}
styles={styles}
platform='desktop'
/>
);
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from 'react';

import { type TabListProps } from '../../typings';
import { ScrollableContainerMobile } from '../scrollable-container/Component.mobile';

import { PrimaryTabList } from './Component';

Expand All @@ -15,5 +16,10 @@ const styles = {
export type PrimaryTabListMobileProps = Omit<TabListProps, 'size' | 'collapsedTabsIds'>;

export const PrimaryTabListMobile = (props: PrimaryTabListMobileProps) => (
<PrimaryTabList {...props} styles={styles} platform='mobile' />
<PrimaryTabList
{...props}
ScrollableContainer={ScrollableContainerMobile}
styles={styles}
platform='mobile'
/>
);
4 changes: 2 additions & 2 deletions packages/tabs/src/components/primary-tablist/Component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import { fnUtils } from '@alfalab/core-components-shared';

import { useTabs } from '../../hooks/use-tabs';
import { type PlatformProps, type Styles, type TabListProps } from '../../typings';
import { ScrollableContainer } from '../scrollable-container';
import { Title } from '../title';

export const PrimaryTabList = ({
Expand All @@ -26,13 +25,15 @@ export const PrimaryTabList = ({
inlineStyle,
showSkeleton,
skeletonProps,
ScrollableContainer,
}: TabListProps & Styles & PlatformProps) => {
const lineRef = useRef<HTMLDivElement>(null);

const { selectedTab, focusedTab, getTabListItemProps } = useTabs({
titles,
selectedId,
onChange,
ScrollableContainer,
});

// расчет размера и положения нижней полосы
Expand Down Expand Up @@ -102,7 +103,6 @@ export const PrimaryTabList = ({
fullWidthScroll={fullWidthScroll}
view='primary'
size={textStyle ? undefined : size}
platform={platform}
inlineStyle={inlineStyle}
showSkeleton={showSkeleton}
>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,64 +1,19 @@
import React, { type ReactNode, useEffect, useRef, useState } from 'react';
import React, { useEffect, useRef, useState } from 'react';
import cn from 'classnames';
import { compute } from 'compute-scroll-into-view';

import { type PlatformProps, type TabsProps } from '../../typings';
import { type TabsProps } from '../../typings';
import { ScrollControls } from '../scroll-controls';

import { type ScrollableContainerProps } from './Component.responsive';

import styles from './index.module.css';

/**
* Дополнительная прокрутка при клике на не поместившийся таб
*/
const ADDITIONAL_SCROLL_LEFT_VALUE = 50;

export type ScrollableContainerProps = {
/**
* Дополнительный класс враппера контейнера
*/
containerWrapperClassName?: string;

/**
* Дополнительный класс контейнера
*/
containerClassName?: string;

/**
* Дополнительный класс кнопок прокрутки
*/
scrollControlsClassName?: string;

/**
* Дочерние компоненты
*/
children: ReactNode;

/**
* Активный элемент (всегда будет в видимой области)
*/
activeChild: HTMLElement | null;

/**
* Внешний вид заголовков табов
*/
view: Exclude<TabsProps['view'], undefined>;

/**
* Размер
*/
size: TabsProps['size'];

/**
* Дополнительные инлайн стили для заголовка
*/
inlineStyle?: React.CSSProperties;

/**
* Показать скелетон
*/
showSkeleton?: boolean;
};

const isOverflown = (
{ clientWidth, scrollWidth }: HTMLDivElement,
controlsNode: HTMLDivElement | null,
Expand All @@ -68,7 +23,7 @@ const isOverflown = (
return scrollWidth > clientWidth + controlsWidth;
};

export const ScrollableContainer = ({
export const ScrollableContainerDesktop = ({
containerWrapperClassName,
containerClassName,
scrollControlsClassName,
Expand All @@ -77,10 +32,9 @@ export const ScrollableContainer = ({
fullWidthScroll,
view,
size,
platform,
inlineStyle,
showSkeleton,
}: ScrollableContainerProps & Pick<TabsProps, 'fullWidthScroll'> & PlatformProps) => {
}: ScrollableContainerProps & Pick<TabsProps, 'fullWidthScroll'>) => {
const containerRef = useRef<HTMLDivElement>(null);
const controlsRef = useRef<HTMLDivElement>(null);
const [overflown, setOverflown] = useState(false);
Expand Down Expand Up @@ -109,7 +63,7 @@ export const ScrollableContainer = ({
const scrollableNode = containerRef.current;
const tabsContainer = scrollableNode?.firstElementChild;

if (platform === 'desktop' && scrollableNode && tabsContainer && window.ResizeObserver) {
if (scrollableNode && tabsContainer && window.ResizeObserver) {
const observerCb = () => {
if (isOverflown(scrollableNode, controlsRef.current)) {
setOverflown(true);
Expand All @@ -127,7 +81,7 @@ export const ScrollableContainer = ({
}

return () => {};
}, [platform]);
}, []);

return (
<div
Expand All @@ -142,7 +96,7 @@ export const ScrollableContainer = ({
>
{children}
</div>
{overflown && platform === 'desktop' ? (
{overflown ? (
<ScrollControls
className={scrollControlsClassName}
ref={controlsRef}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import React, { useEffect, useRef } from 'react';
import cn from 'classnames';
import { compute } from 'compute-scroll-into-view';

import { type TabsProps } from '../../typings';

import { type ScrollableContainerProps } from './Component.responsive';

import styles from './index.module.css';

/**
* Дополнительная прокрутка при клике на не поместившийся таб
*/
const ADDITIONAL_SCROLL_LEFT_VALUE = 50;

export const ScrollableContainerMobile = ({
containerWrapperClassName,
containerClassName,
children,
activeChild,
fullWidthScroll,
inlineStyle,
}: ScrollableContainerProps & Pick<TabsProps, 'fullWidthScroll'>) => {
const containerRef = useRef<HTMLDivElement>(null);

useEffect(() => {
if (activeChild) {
const actions = compute(activeChild, {
scrollMode: 'if-needed',
block: 'nearest',
inline: 'nearest',
boundary: (parent) => !parent.isSameNode(containerRef.current),
});

// TODO: animate?
actions.forEach(({ el, left }) => {
// eslint-disable-next-line no-param-reassign
el.scrollLeft =
el.scrollLeft > left
? left - ADDITIONAL_SCROLL_LEFT_VALUE
: left + ADDITIONAL_SCROLL_LEFT_VALUE;
});
}
}, [activeChild]);

return (
<div
className={cn(styles.scrollableContainerWrapper, containerWrapperClassName)}
style={inlineStyle}
>
<div
ref={containerRef}
className={cn(styles.container, containerClassName, {
[styles.fullWidthScroll]: fullWidthScroll,
})}
>
{children}
</div>
</div>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import React, { type ReactNode } from 'react';

import { type PlatformProps, type TabsProps } from '../../typings';

import { ScrollableContainerDesktop } from './Component.desktop';
import { ScrollableContainerMobile } from './Component.mobile';

export type ScrollableContainerProps = {
/**
* Дополнительный класс враппера контейнера
*/
containerWrapperClassName?: string;

/**
* Дополнительный класс контейнера
*/
containerClassName?: string;

/**
* Дополнительный класс кнопок прокрутки
*/
scrollControlsClassName?: string;

/**
* Дочерние компоненты
*/
children: ReactNode;

/**
* Активный элемент (всегда будет в видимой области)
*/
activeChild: HTMLElement | null;

/**
* Внешний вид заголовков табов
*/
view: Exclude<TabsProps['view'], undefined>;

/**
* Размер
*/
size: TabsProps['size'];

/**
* Дополнительные инлайн стили для заголовка
*/
inlineStyle?: React.CSSProperties;

/**
* Показать скелетон
*/
showSkeleton?: boolean;
};

export const ScrollableContainer = ({
platform,
...restProps
}: ScrollableContainerProps & Pick<TabsProps, 'fullWidthScroll'> & PlatformProps) => {
if (platform === 'desktop') {
return <ScrollableContainerDesktop {...restProps} />;
}

return <ScrollableContainerMobile {...restProps} />;
};
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export * from './Component';
export * from './Component.responsive';
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import cn from 'classnames';
import { TagDesktop } from '@alfalab/core-components-tag/desktop';

import { type SecondaryTabListProps } from '../../typings';
import { ScrollableContainerDesktop } from '../scrollable-container/Component.desktop';

import { SecondaryTabList } from './Component';

Expand All @@ -20,6 +21,7 @@ export const SecondaryTabListDesktop = ({
<SecondaryTabList
{...restProps}
TagComponent={TagDesktop}
ScrollableContainer={ScrollableContainerDesktop}
size={size}
styles={styles}
className={cn(className, styles.desktop, {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import cn from 'classnames';
import { TagMobile } from '@alfalab/core-components-tag/mobile';

import { type SecondaryTabListProps } from '../../typings';
import { ScrollableContainerMobile } from '../scrollable-container/Component.mobile';

import { SecondaryTabList } from './Component';

Expand All @@ -26,6 +27,7 @@ export const SecondaryTabListMobile = ({
<SecondaryTabList
{...restProps}
TagComponent={TagMobile}
ScrollableContainer={ScrollableContainerMobile}
styles={styles}
className={cn(className, styles.mobile, {
[styles.transparentView]: tagView === 'transparent',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { Skeleton } from '@alfalab/core-components-skeleton';

import { useTabs } from '../../hooks/use-tabs';
import { type PlatformProps, type SecondaryTabListProps, type Styles } from '../../typings';
import { ScrollableContainer } from '../scrollable-container';

function getBorderRadius(
shape?: SecondaryTabListProps['tagShape'],
Expand Down Expand Up @@ -41,11 +40,13 @@ export const SecondaryTabList = ({
inlineStyle,
showSkeleton,
skeletonProps,
ScrollableContainer,
}: SecondaryTabListProps & Styles & PlatformProps) => {
const { focusedTab, selectedTab, getTabListItemProps } = useTabs({
titles,
selectedId,
onChange,
ScrollableContainer,
});

const renderContent = () => {
Expand Down Expand Up @@ -109,7 +110,6 @@ export const SecondaryTabList = ({
fullWidthScroll={fullWidthScroll}
view='secondary'
size={size}
platform={platform}
inlineStyle={inlineStyle}
showSkeleton={showSkeleton}
>
Expand Down
Loading
Loading