Skip to content

Commit

Permalink
feat: deprecate vk-bridge
Browse files Browse the repository at this point in the history
  • Loading branch information
inomdzhon committed Jul 18, 2023
1 parent ff5222e commit 614a9d4
Show file tree
Hide file tree
Showing 50 changed files with 662 additions and 156 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<a href="https://npmjs.com/package/@vkontakte/vkui"><img src="https://img.shields.io/npm/v/@vkontakte/vkui/latest.svg?maxAge=3600" alt="open latest version"></a>
</p>
<p align="center">
VKUI — это библиотека адаптивных React-компонентов, <br> для создания веб-приложений и <a href="https://dev.vk.com/mini-apps/overview">VK Mini Apps</a> в экосистеме ВКонтакте.<br>
VKUI — это библиотека адаптивных React-компонентов, <br> для создания веб-приложений.<br>
Библиотека основана на <a href="https://www.figma.com/@vk">дизайн-системе ВКонтакте</a> и реализует её интерфейсы для различных платформ.<br>
Релизы: <a href="https://github.com/VKCOM/VKUI/releases">https://github.com/VKCOM/VKUI/releases</a>.<br>
Гайд по миграции <a href="https://vkcom.github.io/VKUI/#/Migration">на версию 5</a>.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import * as React from 'react';
import { useGlobals } from '@storybook/manager-api';
import { IconButton, Icons } from '@storybook/components';
import { PARAM_KEY } from './constants';

export const HasCustomPanelHeaderAfter = () => {
const [globals, updateGlobals] = useGlobals();
const active = globals[PARAM_KEY];

const toggle = React.useCallback(() => {
updateGlobals({ [PARAM_KEY]: !active });
}, [updateGlobals, active]);

return (
<IconButton active={active} key="customPanelHeaderAfter" onClick={toggle}>
<Icons icon="browser" />
&nbsp; hasCustomPanelHeaderAfter
</IconButton>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export const ADDON_ID = 'storybook/customPanelHeaderAfter';
export const PARAM_KEY = 'hasCustomPanelHeaderAfter';
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
function managerEntries(entry = []) {
return [...entry, require.resolve('./register.ts')];
}

module.exports = {
managerEntries,
};
12 changes: 12 additions & 0 deletions packages/vkui/.storybook/addons/customPanelHeaderAfter/register.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { addons, types } from '@storybook/manager-api';
import { HasCustomPanelHeaderAfter } from './HasCustomPanelHeaderAfter';
import { ADDON_ID } from './constants';

addons.register(ADDON_ID, () => {
addons.add(ADDON_ID, {
title: 'CustomPanelHeaderAfter',
type: types.TOOL,
match: ({ viewMode }) => !!(viewMode && viewMode.match(/^(story|docs)$/)),
render: HasCustomPanelHeaderAfter,
});
});
1 change: 1 addition & 0 deletions packages/vkui/.storybook/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const config: StorybookConfig = {
'@project-tools/storybook-addon-cartesian',
'./addons/appearance',
'./addons/pointer',
'./addons/customPanelHeaderAfter',
'storybook-addon-swc',
],
framework: {
Expand Down
14 changes: 4 additions & 10 deletions packages/vkui/.storybook/preview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import '../src/styles/adaptivity.module.css';

import { Preview } from '@storybook/react';
import { BREAKPOINTS } from '../src/lib/adaptivity';
import { Platform, Appearance, WebviewType } from '../src';
import { Platform, Appearance } from '../src';
import { withVKUIWrapper } from '../src/storybook/VKUIDecorators';

interface CustomViewPortItem {
Expand Down Expand Up @@ -66,15 +66,9 @@ const preview: Preview = {
dynamicTitle: true,
},
},
webviewType: {
name: 'WebviewType',
defaultValue: WebviewType.INTERNAL,
toolbar: {
icon: 'component',
items: [WebviewType.INTERNAL, WebviewType.VKAPPS],
title: 'WebviewType',
dynamicTitle: true,
},
hasCustomPanelHeaderAfter: {
description: 'Hide "after" prop of PanelHeader for custom floating "after" element',
defaultValue: false,
},
},
argTypes: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@ import * as React from 'react';
import { hasMouse as _hasPointer } from '@vkontakte/vkjs';
import { BridgeAdaptivity, useBridgeAdaptivity } from '../../hooks/useBridgeAdaptivity';
import { BREAKPOINTS, SizeType, ViewHeight, ViewWidth } from '../../lib/adaptivity';
import { warnOnce } from '../../lib/warnOnce';
import { HasChildren } from '../../types';
import { AdaptivityContext, type AdaptivityProps } from './AdaptivityContext';

const warn = warnOnce('AdaptivityProvider');

export interface AdaptivityProviderProps extends AdaptivityProps, HasChildren {}

/**
Expand All @@ -19,7 +22,27 @@ export const AdaptivityProvider = ({
hasHover,
children,
}: AdaptivityProviderProps) => {
const bridge = useBridgeAdaptivity();
// TODO [>=6]: удалить использование хука (#5049)
/* eslint-disable @typescript-eslint/naming-convention */
const LEGACY_isPerhapsPropsByBridgeTypeAdaptive =
viewWidth !== undefined &&
viewHeight !== undefined &&
sizeX !== undefined &&
sizeY !== undefined;
const LEGACY_isPerhapsPropsByBridgeTypeForceMobile =
viewWidth !== undefined && sizeX !== undefined && sizeY !== undefined;
const LEGACY_disableInternalUseBridgeAdaptivity =
LEGACY_isPerhapsPropsByBridgeTypeAdaptive || LEGACY_isPerhapsPropsByBridgeTypeForceMobile;
const LEGACY_bridge = useBridgeAdaptivity(LEGACY_disableInternalUseBridgeAdaptivity);
/* eslint-enable @typescript-eslint/naming-convention */

if (process.env.NODE_ENVIRONMENT === 'development') {
// TODO [>=6]: удалить warn
if (!LEGACY_disableInternalUseBridgeAdaptivity) {
warn("[@vkontakte/vk-bridge's deprecated] Если вы используете VK Bridge, то используйте хук `useAdaptivity()` из @vkontakte/vk-bridge-react и результат передайте в компонент (см. https://github.com/VKCOM/VKUI/issues/5049)"); // prettier-ignore
}
}

const adaptivity = React.useMemo(
() =>
calculateAdaptivity(
Expand All @@ -31,20 +54,22 @@ export const AdaptivityProvider = ({
hasPointer,
hasHover,
},
bridge,
LEGACY_bridge,
),
[viewWidth, viewHeight, sizeX, sizeY, hasPointer, hasHover, bridge],
[viewWidth, viewHeight, sizeX, sizeY, hasPointer, hasHover, LEGACY_bridge],
);

return <AdaptivityContext.Provider value={adaptivity}>{children}</AdaptivityContext.Provider>;
};

function calculateAdaptivity(
{ viewWidth, viewHeight, sizeX, sizeY, hasPointer, hasHover }: AdaptivityProps,
bridge: BridgeAdaptivity,
LEGACY_bridge: BridgeAdaptivity, // eslint-disable-line @typescript-eslint/naming-convention
) {
if (bridge.type === 'adaptive') {
const { viewportWidth, viewportHeight } = bridge;
// TODO [>=6]: удалить блок кода c использованием LEGACY_bridge (#5049)
// https://github.com/VKCOM/VKUI/blob/v5.5.5/packages/vkui/src/components/AdaptivityProvider/AdaptivityProvider.tsx#L46-L92
if (LEGACY_bridge.type === 'adaptive') {
const { viewportWidth, viewportHeight } = LEGACY_bridge;

if (viewportWidth >= BREAKPOINTS.DESKTOP) {
viewWidth = ViewWidth.DESKTOP;
Expand Down Expand Up @@ -80,11 +105,14 @@ function calculateAdaptivity(
} else {
sizeY = SizeType.REGULAR;
}
} else if (bridge.type === 'force_mobile' || bridge.type === 'force_mobile_compact') {
} else if (
LEGACY_bridge.type === 'force_mobile' ||
LEGACY_bridge.type === 'force_mobile_compact'
) {
viewWidth = ViewWidth.MOBILE;
sizeX = SizeType.COMPACT;

if (bridge.type === 'force_mobile_compact') {
if (LEGACY_bridge.type === 'force_mobile_compact') {
sizeY = SizeType.COMPACT;
} else {
sizeY = SizeType.REGULAR;
Expand Down
27 changes: 23 additions & 4 deletions packages/vkui/src/components/AppRoot/AppRoot.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import * as React from 'react';
import { IconSettingsProvider } from '@vkontakte/icons';
import { Insets } from '@vkontakte/vk-bridge';
import { classNames, noop } from '@vkontakte/vkjs';
import { useAdaptivity } from '../../hooks/useAdaptivity';
import { useAppearance } from '../../hooks/useAppearance';
Expand All @@ -10,10 +9,20 @@ import { SizeType } from '../../lib/adaptivity';
import { useDOM } from '../../lib/dom';
import { isRefObject } from '../../lib/isRefObject';
import { useIsomorphicLayoutEffect } from '../../lib/useIsomorphicLayoutEffect';
import { warnOnce } from '../../lib/warnOnce';
import { AppRootContext } from './AppRootContext';
import { ElementScrollController, GlobalScrollController } from './ScrollContext';
import styles from './AppRoot.module.css';

const warn = warnOnce('AppRoot');

export type SafeAreaInsets = {
top?: number;
right?: number;
bottom?: number;
left?: number;
};

const vkuiSizeXClassNames = {
none: 'vkui--sizeX-none',
[SizeType.REGULAR]: 'vkui--sizeX-regular',
Expand All @@ -29,6 +38,7 @@ export interface AppRootProps extends React.HTMLAttributes<HTMLDivElement> {
mode?: 'partial' | 'embedded' | 'full';
window?: Window;
scroll?: 'global' | 'contain';
safeAreaInsets?: SafeAreaInsets;
/**
* Кастомный root-элемент портала
*/
Expand All @@ -47,17 +57,26 @@ export const AppRoot = ({
portalRoot: portalRootProp = null,
disablePortal,
className,
safeAreaInsets,
...props
}: AppRootProps) => {
const isKeyboardInputActive = useKeyboardInputTracker();
const rootRef = React.useRef<HTMLDivElement | null>(null);
const [portalRoot, setPortalRoot] = React.useState<HTMLElement | null>(null);
const { document } = useDOM();
const insets = useInsets();
const deprecatedInsets = useInsets(!safeAreaInsets);
const insets = safeAreaInsets ? safeAreaInsets : deprecatedInsets;
const appearance = useAppearance();

const { hasPointer, sizeX = 'none' } = useAdaptivity();

if (process.env.NODE_ENVIRONMENT === 'development') {
if (!safeAreaInsets) {
// TODO [>=6]: удалить warn
warn("[@vkontakte/vk-bridge's deprecated] Если вы используете VK Bridge, то используйте хук `useInsets()` из @vkontakte/vk-bridge-react и результат передайте в параметр `safeAreaInsets` (см. https://github.com/VKCOM/VKUI/issues/5049)"); // prettier-ignore
}
}

// setup portal
useIsomorphicLayoutEffect(() => {
let portal: HTMLElement | null = null;
Expand Down Expand Up @@ -115,7 +134,7 @@ export const AppRoot = ({

const parent = rootRef.current.parentElement;

let key: keyof Insets;
let key: keyof SafeAreaInsets;
for (key in insets) {
if (insets.hasOwnProperty(key) && typeof insets[key] === 'number') {
const inset = insets[key];
Expand All @@ -126,7 +145,7 @@ export const AppRoot = ({
}

return () => {
let key: keyof Insets;
let key: keyof SafeAreaInsets;
for (key in insets) {
if (insets.hasOwnProperty(key)) {
parent.style.removeProperty(INSET_CUSTOM_PROPERTY_PREFIX + key);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as React from 'react';
import { AppearanceType } from '@vkontakte/vk-bridge';
import { usePlatform } from '../../hooks/usePlatform';
import type { AppearanceType } from '../../lib/appearance';
import { TokensClassProvider } from '../../lib/tokensClassProvider';
import { ConfigProviderOverride } from '../ConfigProvider/ConfigProviderOverride';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ describe('ConfigProvider', () => {
it('provides config context', () => {
const config = {
appearance: Appearance.LIGHT,
webviewType: WebviewType.INTERNAL,
hasCustomPanelHeaderAfter: false,
transitionMotionEnabled: false,
};
const ConfigUser = () => {
Expand All @@ -24,7 +24,8 @@ describe('ConfigProvider', () => {
isWebView: false,
locale: 'ru',
appearance: Appearance.LIGHT,
webviewType: WebviewType.INTERNAL,
hasCustomPanelHeaderAfter: false,
customPanelHeaderAfterMinWidth: 90,
transitionMotionEnabled: false,
});
return null;
Expand All @@ -35,6 +36,59 @@ describe('ConfigProvider', () => {
</ConfigProvider>,
);
});
// TODO [>=6] Удалить этот тест на бэкпорт
describe('[deprecated] test webviewType backport', () => {
it('convert WebviewType.INTERNAL to hasCustomPanelHeaderAfter={false}', () => {
const config = {
appearance: Appearance.LIGHT,
webviewType: WebviewType.INTERNAL,
transitionMotionEnabled: false,
};
const ConfigUser = () => {
expect(useContext(ConfigProviderContext)).toEqual({
platform: Platform.ANDROID,
isWebView: false,
locale: 'ru',
appearance: Appearance.LIGHT,
webviewType: WebviewType.INTERNAL,
hasCustomPanelHeaderAfter: false,
customPanelHeaderAfterMinWidth: 90,
transitionMotionEnabled: false,
});
return null;
};
render(
<ConfigProvider {...config}>
<ConfigUser />
</ConfigProvider>,
);
});
it('convert WebviewType.VKAPPS to hasCustomPanelHeaderAfter={true}', () => {
const config = {
appearance: Appearance.LIGHT,
webviewType: WebviewType.VKAPPS,
transitionMotionEnabled: false,
};
const ConfigUser = () => {
expect(useContext(ConfigProviderContext)).toEqual({
platform: Platform.ANDROID,
isWebView: false,
locale: 'ru',
appearance: Appearance.LIGHT,
webviewType: WebviewType.VKAPPS,
hasCustomPanelHeaderAfter: true,
customPanelHeaderAfterMinWidth: 90,
transitionMotionEnabled: false,
});
return null;
};
render(
<ConfigProvider {...config}>
<ConfigUser />
</ConfigProvider>,
);
});
});
describe('inherits properties from parent ConfigProvider context', () => {
let config: ConfigProviderContextInterface | undefined;
const ReadConfig = () => {
Expand All @@ -45,14 +99,20 @@ describe('ConfigProvider', () => {
const defaultConfig: ConfigProviderContextInterface = {
platform: Platform.VKCOM,
appearance: Appearance.DARK,
// TODO [>=6] Удалить webviewType
webviewType: WebviewType.INTERNAL,
hasCustomPanelHeaderAfter: true,
customPanelHeaderAfterMinWidth: 90,
transitionMotionEnabled: false,
isWebView: true,
locale: 'en',
};
it.each([
['platform', Platform.ANDROID],
// TODO [>=6] Удалить webviewType
['webviewType', WebviewType.VKAPPS],
['hasCustomPanelHeaderAfter', false],
['customPanelHeaderAfterMinWidth', 100],
['transitionMotionEnabled', true],
['isWebView', false],
['platform', Appearance.LIGHT],
Expand Down
Loading

0 comments on commit 614a9d4

Please sign in to comment.