Skip to content

Commit

Permalink
feat(AppRoot): add layout (#5642)
Browse files Browse the repository at this point in the history
* feat(AppRoot): add `layout`
Добавляем новое свойство `layout: 'plain' | 'card'`

Изменяем вид Group при mode="card" и sizeX="compact"

- closed #3018

* fix: review by inomdzhon

Co-authored-by: Inomdzhon Mirdzhamolov <[email protected]>

---------

Co-authored-by: Inomdzhon Mirdzhamolov <[email protected]>
  • Loading branch information
SevereCloud and inomdzhon authored Aug 31, 2023
1 parent 894f035 commit 5520f4e
Show file tree
Hide file tree
Showing 15 changed files with 155 additions and 25 deletions.
34 changes: 29 additions & 5 deletions packages/vkui/src/components/AppRoot/AppRoot.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,25 @@ const vkuiSizeXClassNames = {
[SizeType.REGULAR]: 'vkui--sizeX-regular',
};

const vkuiLayoutClassNames = {
card: 'vkui--layout-card',
plain: 'vkui--layout-plain',
};

function containerClassNames(layout: AppRootProps['layout'], sizeX: SizeType | 'none'): string[] {
const classNames: string[] = [];

if (layout) {
classNames.push(vkuiLayoutClassNames[layout]);
}

if (sizeX !== SizeType.COMPACT) {
classNames.push(vkuiSizeXClassNames[sizeX]);
}

return classNames;
}

const INSET_CUSTOM_PROPERTY_PREFIX = `--vkui_internal--safe_area_inset_`;

// Используйте classList, но будьте осторожны
Expand All @@ -54,6 +73,7 @@ export interface AppRootProps extends React.HTMLAttributes<HTMLDivElement> {
* Это поведение можно отключить с помощью этого параметра.
*/
disableParentTransformForPositionFixedElements?: boolean;
layout?: 'card' | 'plain';
}

/**
Expand All @@ -68,6 +88,7 @@ export const AppRoot = ({
disableParentTransformForPositionFixedElements,
className,
safeAreaInsets,
layout,
...props
}: AppRootProps) => {
const isKeyboardInputActive = useKeyboardInputTracker();
Expand Down Expand Up @@ -180,18 +201,20 @@ export const AppRoot = ({
if (mode === 'partial') {
return noop;
}
const className = sizeX !== SizeType.COMPACT ? vkuiSizeXClassNames[sizeX] : null;

const classNames = containerClassNames(layout, sizeX);

const container = mode === 'embedded' ? rootRef.current?.parentElement : document!.body;

if (className === null || !container) {
if (!classNames.length || !container) {
return noop;
}

container.classList.add(className);
container.classList.add(...classNames);
return () => {
container.classList.remove(className);
container.classList.remove(...classNames);
};
}, [sizeX]);
}, [sizeX, layout]);

useIsomorphicLayoutEffect(() => {
if (mode !== 'full' || appearance === undefined) {
Expand All @@ -216,6 +239,7 @@ export const AppRoot = ({
keyboardInput: isKeyboardInputActive,
mode,
disablePortal,
layout,
}}
>
<ScrollController elRef={rootRef}>
Expand Down
1 change: 1 addition & 0 deletions packages/vkui/src/components/AppRoot/AppRootContext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export interface AppRootContextInterface {
mode?: 'partial' | 'embedded' | 'full';
keyboardInput?: boolean;
disablePortal?: boolean;
layout?: 'card' | 'plain';
}

export const AppRootContext = React.createContext<AppRootContextInterface>({
Expand Down
28 changes: 26 additions & 2 deletions packages/vkui/src/components/Group/Group.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,15 @@
}
}

.Group--sizeX-compact {
.Group--sizeX-compact,
.Group--sizeX-compact.Group--mode-card {
padding-left: 0;
padding-right: 0;
}

@media (--sizeX-compact) {
.Group--sizeX-none {
.Group--sizeX-none,
.Group--sizeX-none.Group--mode-card {
padding-left: 0;
padding-right: 0;
}
Expand All @@ -90,6 +92,18 @@
}
}

.Group--sizeX-compact.Group--mode-card:first-of-type {
border-radius: 0 0 var(--vkui--size_border_radius_paper--regular)
var(--vkui--size_border_radius_paper--regular);
}

@media (--sizeX-compact) {
.Group--sizeX-none.Group--mode-card:first-of-type {
border-radius: 0 0 var(--vkui--size_border_radius_paper--regular)
var(--vkui--size_border_radius_paper--regular);
}
}

/**
* Изменено с ::after на ::before
* потому что при ::after абсолютно позиционированный элемент накладывается
Expand Down Expand Up @@ -123,6 +137,16 @@
}
}

.Group--sizeX-compact.Group--mode-card::before {
box-shadow: none;
}

@media (--sizeX-compact) {
.Group--sizeX-none.Group--mode-card::before {
box-shadow: none;
}
}

.Group--mode-plain + .Group__separator,
.Group--mode-plain + .Group__separator + .Group__separator {
padding-top: 8px;
Expand Down
41 changes: 31 additions & 10 deletions packages/vkui/src/components/Group/Group.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { SizeType } from '../../lib/adaptivity';
import { Platform } from '../../lib/platform';
import { warnOnce } from '../../lib/warnOnce';
import { HTMLAttributesWithRootRef } from '../../types';
import { AppRootContext } from '../AppRoot/AppRootContext';
import { ModalRootContext } from '../ModalRoot/ModalRootContext';
import { RootComponent } from '../RootComponent/RootComponent';
import { Separator } from '../Separator/Separator';
Expand All @@ -29,6 +30,35 @@ const stylesPadding = {
m: styles['Group--padding-m'],
};

/**
* Вычисляем mode для Group.
*/
function useGroupMode(
forcedMode: GroupProps['mode'],
sizeX: SizeType | 'none',
isInsideModal: boolean,
): 'plain' | 'card' | 'none' {
const { layout } = React.useContext(AppRootContext);

if (forcedMode) {
return forcedMode;
}

if (isInsideModal) {
return 'plain';
}

if (layout) {
return layout;
}

if (sizeX !== 'none') {
return sizeX === SizeType.REGULAR ? 'card' : 'plain';
}

return 'none';
}

export interface GroupProps extends HTMLAttributesWithRootRef<HTMLElement> {
header?: React.ReactNode;
description?: React.ReactNode;
Expand Down Expand Up @@ -69,16 +99,7 @@ export const Group = ({
const platform = usePlatform();
const { sizeX = 'none' } = useAdaptivity();

let mode: GroupProps['mode'] | 'none' = modeProps;

if (!modeProps) {
// Подробнее в "none" можно прочитать в ADAPTIVITY_GUIDE.md
mode = isInsideModal ? 'plain' : 'none';
}

if (mode === 'none' && sizeX !== 'none') {
mode = sizeX === SizeType.REGULAR ? 'card' : 'plain';
}
const mode = useGroupMode(modeProps, sizeX, isInsideModal);

const isTabPanel = restProps.role === 'tabpanel';

Expand Down
2 changes: 1 addition & 1 deletion packages/vkui/src/components/Group/Readme.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Группа – базовый компонент для группировки контента по смыслу.

```jsx { "props": { "layout": false, "adaptivity": true } }
```jsx { "props": { "layout": false, "showLayoutSelect": true, "adaptivity": true } }
const MODAL_NAME = 'modal';

const Example = () => {
Expand Down
10 changes: 8 additions & 2 deletions packages/vkui/src/components/Panel/Panel.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -162,8 +162,8 @@
background-color: var(--vkui--color_background_content);
}

.Panel.Panel--sizeX-regular .Panel__in,
.Panel.Panel--sizeX-regular::before {
.Panel--sizeX-regular .Panel__in,
.Panel--sizeX-regular::before {
background-color: transparent;
}

Expand All @@ -173,3 +173,9 @@
background-color: transparent;
}
}

/* В AppRoot была установлена layout настройка */
.Panel--layoutSetting .Panel__in,
.Panel--layoutSetting::before {
background-color: transparent;
}
3 changes: 3 additions & 0 deletions packages/vkui/src/components/Panel/Panel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { SizeType } from '../../lib/adaptivity';
import { NavIdProps } from '../../lib/getNavId';
import { Platform } from '../../lib/platform';
import { HTMLAttributesWithRootRef } from '../../types';
import { AppRootContext } from '../AppRoot/AppRootContext';
import { RootComponent } from '../RootComponent/RootComponent';
import { TooltipContainer } from '../Tooltip/TooltipContainer';
import { Touch } from '../Touch/Touch';
Expand All @@ -27,6 +28,7 @@ export interface PanelProps extends HTMLAttributesWithRootRef<HTMLDivElement>, N
export const Panel = ({ centered = false, children, nav, ...restProps }: PanelProps) => {
const platform = usePlatform();
const { sizeX = 'none' } = useAdaptivity();
const { layout } = React.useContext(AppRootContext);

return (
<RootComponent
Expand All @@ -35,6 +37,7 @@ export const Panel = ({ centered = false, children, nav, ...restProps }: PanelPr
styles['Panel'],
sizeXClassNames[sizeX],
centered && 'vkuiInternalPanel--centered',
layout && styles['Panel--layoutSetting'],
)}
>
<Touch
Expand Down
2 changes: 1 addition & 1 deletion packages/vkui/src/components/SplitLayout/Readme.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Компонент-контейнер для реализации интерфейса с [многоколоночной структурой](#!/Adaptivity). Тесно связан со [SplitCol](#!/SplitCol).

```jsx { "props": { "layout": false, "showCustomPanelHeaderAfterProps": true, "adaptivity": true } }
```jsx { "props": { "layout": false, "showCustomPanelHeaderAfterProps": true, "showLayoutSelect": true, "adaptivity": true } }
const panels = ['panel 1', 'panel 2', 'panel 3'];
const modals = ['modal 1', 'modal 2'];

Expand Down
8 changes: 8 additions & 0 deletions packages/vkui/src/styles/common.css
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,11 @@
background: var(--vkui--color_background);
}
}

.vkui--layout-card {
background: var(--vkui--color_background);
}

.vkui--layout-plain {
background: var(--vkui--color_background_content);
}
2 changes: 2 additions & 0 deletions styleguide/Components/Playground/PlaygroundRenderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const PlaygroundRenderer = ({ name, preview, previewProps, tabBody, exampleIndex
iframe = true, // Рендерить пример в айфреме
adaptivity: _adaptivity, // Продвинутые контролеры настроек адаптивности
showCustomPanelHeaderAfterProps = false, // Контроллер настроек, связанных с пользовательским слотом `after` у `PanelHeader`
showLayoutSelect = false,
integration,
containerStyle,
config,
Expand All @@ -28,6 +29,7 @@ const PlaygroundRenderer = ({ name, preview, previewProps, tabBody, exampleIndex
<Settings
adaptivity={adaptivity}
showCustomPanelHeaderAfterProps={showCustomPanelHeaderAfterProps}
showLayoutSelect={showLayoutSelect}
/>
<div className="Playground__preview" {...wrapperProps} data-preview={name}>
{cloneElement(preview, {
Expand Down
4 changes: 2 additions & 2 deletions styleguide/Components/Preview.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,11 @@ const Layout = ({ children }) => {
);
};

const Config = ({ hasPointer, children, ...config }) => {
const Config = ({ hasPointer, layout, children, ...config }) => {
return (
<ConfigProvider {...config}>
<AdaptivityProvider hasPointer={hasPointer}>
<AppRoot>{children}</AppRoot>
<AppRoot layout={layout}>{children}</AppRoot>
</AdaptivityProvider>
</ConfigProvider>
);
Expand Down
10 changes: 9 additions & 1 deletion styleguide/Components/Setting/Setting.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,14 @@ export const Setting = ({
[],
);

const title =
options?.find((option) => {
if (typeof option === 'string' || typeof option === 'number') {
return false;
}
return option.value === value;
})?.title || value;

const labelJsx = <span className="Setting__label">{label}:&nbsp;</span>;

return (
Expand Down Expand Up @@ -69,7 +77,7 @@ export const Setting = ({
);
}}
>
{value}
{title}
<Icon16Dropdown />
</Link>
)}
Expand Down
25 changes: 25 additions & 0 deletions styleguide/Components/Settings/LayoutSelect.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import React from 'react';
import { Link } from '@vkui';
import { Setting } from '../Setting/Setting';

const layouts = [{ title: 'Не задано', value: undefined }, 'card', 'plain'];

export const LayoutSelect = ({ onChange, value }) => {
const onChangeValue = (changeValue) => {
onChange(changeValue);
};

return (
<Setting
hint={
<React.Fragment>
Свойство <Link href="#/AppRoot">AppRoot</Link>
</React.Fragment>
}
label="layout"
onChange={onChangeValue}
value={value}
options={layouts}
/>
);
};
9 changes: 8 additions & 1 deletion styleguide/Components/Settings/Settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@ import { StyleGuideContext } from '../StyleGuide/StyleGuideRenderer';
import { AppearanceSelect } from './AppearanceSelect';
import { HasCustomPanelHeaderAfter } from './HasCustomPanelHeaderAfter';
import { HasPointerCheckbox } from './HasPointerCheckbox';
import { LayoutSelect } from './LayoutSelect';
import { PlatformSelect } from './PlatformSelect';
import { ViewHeightSelect } from './ViewHeightSelect';
import { ViewWidthSelect } from './ViewWidthSelect';
import './Settings.css';

export const Settings = ({ adaptivity, showCustomPanelHeaderAfterProps }) => {
export const Settings = ({ adaptivity, showCustomPanelHeaderAfterProps, showLayoutSelect }) => {
const { sizeX } = useAdaptivityConditionalRender();
return (
<StyleGuideContext.Consumer>
Expand Down Expand Up @@ -58,6 +59,12 @@ export const Settings = ({ adaptivity, showCustomPanelHeaderAfterProps }) => {
)}
</Fragment>
)}
{showLayoutSelect && (
<LayoutSelect
onChange={(layout) => context.setContext({ layout })}
value={context.layout}
/>
)}
</div>
</div>
);
Expand Down
1 change: 1 addition & 0 deletions styleguide/Components/StyleGuide/StyleGuideRenderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ let initialState = {
styleguideAppearance: Appearance.LIGHT,
hasCustomPanelHeaderAfter: true,
transitionMotionEnabled: true,
layout: undefined,
};

try {
Expand Down

0 comments on commit 5520f4e

Please sign in to comment.