@vkontakte/vkui 6.1.1 → 6.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/components/Clickable/useState.d.ts.map +1 -1
- package/dist/cjs/components/Clickable/useState.js +7 -6
- package/dist/cjs/components/Clickable/useState.js.map +1 -1
- package/dist/cjs/components/CustomScrollView/CustomScrollView.d.ts.map +1 -1
- package/dist/cjs/components/CustomScrollView/CustomScrollView.js +8 -1
- package/dist/cjs/components/CustomScrollView/CustomScrollView.js.map +1 -1
- package/dist/cjs/components/FocusTrap/FocusTrap.d.ts +2 -2
- package/dist/cjs/components/FocusTrap/FocusTrap.d.ts.map +1 -1
- package/dist/cjs/components/FocusTrap/FocusTrap.js +36 -11
- package/dist/cjs/components/FocusTrap/FocusTrap.js.map +1 -1
- package/dist/cjs/components/Select/Select.d.ts +1 -1
- package/dist/cjs/components/Select/Select.d.ts.map +1 -1
- package/dist/cjs/components/Select/Select.js +12 -6
- package/dist/cjs/components/Select/Select.js.map +1 -1
- package/dist/cjs/components/Spacing/Spacing.d.ts +16 -5
- package/dist/cjs/components/Spacing/Spacing.d.ts.map +1 -1
- package/dist/cjs/components/Spacing/Spacing.js +38 -31
- package/dist/cjs/components/Spacing/Spacing.js.map +1 -1
- package/dist/cjs/components/ToolButton/ToolButton.d.ts +5 -0
- package/dist/cjs/components/ToolButton/ToolButton.d.ts.map +1 -1
- package/dist/cjs/components/ToolButton/ToolButton.js +2 -1
- package/dist/cjs/components/ToolButton/ToolButton.js.map +1 -1
- package/dist/cjs/hooks/useResizeObserver.d.ts +6 -0
- package/dist/cjs/hooks/useResizeObserver.d.ts.map +1 -0
- package/dist/cjs/hooks/useResizeObserver.js +32 -0
- package/dist/cjs/hooks/useResizeObserver.js.map +1 -0
- package/dist/cjs/lib/floating/customResizeObserver.d.ts.map +1 -1
- package/dist/cjs/lib/floating/customResizeObserver.js +2 -1
- package/dist/cjs/lib/floating/customResizeObserver.js.map +1 -1
- package/dist/cjs/lib/floating/useFloatingWithInteractions/useFloatingWithInteractions.d.ts.map +1 -1
- package/dist/cjs/lib/floating/useFloatingWithInteractions/useFloatingWithInteractions.js +11 -1
- package/dist/cjs/lib/floating/useFloatingWithInteractions/useFloatingWithInteractions.js.map +1 -1
- package/dist/components/Clickable/useState.d.ts.map +1 -1
- package/dist/components/Clickable/useState.js +7 -6
- package/dist/components/Clickable/useState.js.map +1 -1
- package/dist/components/CustomScrollView/CustomScrollView.d.ts.map +1 -1
- package/dist/components/CustomScrollView/CustomScrollView.js +8 -1
- package/dist/components/CustomScrollView/CustomScrollView.js.map +1 -1
- package/dist/components/FocusTrap/FocusTrap.d.ts +2 -2
- package/dist/components/FocusTrap/FocusTrap.d.ts.map +1 -1
- package/dist/components/FocusTrap/FocusTrap.js +37 -11
- package/dist/components/FocusTrap/FocusTrap.js.map +1 -1
- package/dist/components/Select/Select.d.ts +1 -1
- package/dist/components/Select/Select.d.ts.map +1 -1
- package/dist/components/Select/Select.js +12 -6
- package/dist/components/Select/Select.js.map +1 -1
- package/dist/components/Spacing/Spacing.d.ts +16 -5
- package/dist/components/Spacing/Spacing.d.ts.map +1 -1
- package/dist/components/Spacing/Spacing.js +33 -28
- package/dist/components/Spacing/Spacing.js.map +1 -1
- package/dist/components/ToolButton/ToolButton.d.ts +5 -0
- package/dist/components/ToolButton/ToolButton.d.ts.map +1 -1
- package/dist/components/ToolButton/ToolButton.js +2 -1
- package/dist/components/ToolButton/ToolButton.js.map +1 -1
- package/dist/components.css +4 -4
- package/dist/components.css.map +1 -1
- package/dist/components.js.tmp +461 -330
- package/dist/cssm/components/Clickable/useState.d.ts.map +1 -1
- package/dist/cssm/components/Clickable/useState.js +7 -6
- package/dist/cssm/components/Clickable/useState.js.map +1 -1
- package/dist/cssm/components/CustomScrollView/CustomScrollView.d.ts.map +1 -1
- package/dist/cssm/components/CustomScrollView/CustomScrollView.js +8 -1
- package/dist/cssm/components/CustomScrollView/CustomScrollView.js.map +1 -1
- package/dist/cssm/components/CustomScrollView/CustomScrollView.module.css +4 -0
- package/dist/cssm/components/FocusTrap/FocusTrap.d.ts +2 -2
- package/dist/cssm/components/FocusTrap/FocusTrap.d.ts.map +1 -1
- package/dist/cssm/components/FocusTrap/FocusTrap.js +37 -11
- package/dist/cssm/components/FocusTrap/FocusTrap.js.map +1 -1
- package/dist/cssm/components/Select/Select.d.ts +1 -1
- package/dist/cssm/components/Select/Select.d.ts.map +1 -1
- package/dist/cssm/components/Select/Select.js +8 -5
- package/dist/cssm/components/Select/Select.js.map +1 -1
- package/dist/cssm/components/Spacing/Spacing.d.ts +16 -5
- package/dist/cssm/components/Spacing/Spacing.d.ts.map +1 -1
- package/dist/cssm/components/Spacing/Spacing.js +31 -30
- package/dist/cssm/components/Spacing/Spacing.js.map +1 -1
- package/dist/cssm/components/Spacing/Spacing.module.css +44 -0
- package/dist/cssm/components/ToolButton/ToolButton.d.ts +5 -0
- package/dist/cssm/components/ToolButton/ToolButton.d.ts.map +1 -1
- package/dist/cssm/components/ToolButton/ToolButton.js +2 -1
- package/dist/cssm/components/ToolButton/ToolButton.js.map +1 -1
- package/dist/cssm/components/ToolButton/ToolButton.module.css +6 -20
- package/dist/cssm/hooks/useResizeObserver.d.ts +6 -0
- package/dist/cssm/hooks/useResizeObserver.d.ts.map +1 -0
- package/dist/cssm/hooks/useResizeObserver.js +23 -0
- package/dist/cssm/hooks/useResizeObserver.js.map +1 -0
- package/dist/cssm/lib/floating/customResizeObserver.d.ts.map +1 -1
- package/dist/cssm/lib/floating/customResizeObserver.js +2 -1
- package/dist/cssm/lib/floating/customResizeObserver.js.map +1 -1
- package/dist/cssm/lib/floating/useFloatingWithInteractions/useFloatingWithInteractions.d.ts.map +1 -1
- package/dist/cssm/lib/floating/useFloatingWithInteractions/useFloatingWithInteractions.js +11 -1
- package/dist/cssm/lib/floating/useFloatingWithInteractions/useFloatingWithInteractions.js.map +1 -1
- package/dist/cssm/styles/adaptivity.module.css +1 -2
- package/dist/hooks/useResizeObserver.d.ts +6 -0
- package/dist/hooks/useResizeObserver.d.ts.map +1 -0
- package/dist/hooks/useResizeObserver.js +23 -0
- package/dist/hooks/useResizeObserver.js.map +1 -0
- package/dist/lib/floating/customResizeObserver.d.ts.map +1 -1
- package/dist/lib/floating/customResizeObserver.js +2 -1
- package/dist/lib/floating/customResizeObserver.js.map +1 -1
- package/dist/lib/floating/useFloatingWithInteractions/useFloatingWithInteractions.d.ts.map +1 -1
- package/dist/lib/floating/useFloatingWithInteractions/useFloatingWithInteractions.js +11 -1
- package/dist/lib/floating/useFloatingWithInteractions/useFloatingWithInteractions.js.map +1 -1
- package/dist/vkui.css +4 -4
- package/dist/vkui.css.map +1 -1
- package/dist/vkui.js.tmp +461 -330
- package/package.json +1 -1
- package/src/components/Clickable/useState.tsx +16 -6
- package/src/components/CustomScrollView/CustomScrollView.module.css +4 -0
- package/src/components/CustomScrollView/CustomScrollView.tsx +7 -1
- package/src/components/FocusTrap/FocusTrap.tsx +54 -20
- package/src/components/Select/Select.tsx +12 -5
- package/src/components/Spacing/Spacing.module.css +44 -0
- package/src/components/Spacing/Spacing.tsx +38 -34
- package/src/components/ToolButton/ToolButton.module.css +4 -14
- package/src/components/ToolButton/ToolButton.tsx +7 -2
- package/src/hooks/useResizeObserver.ts +30 -0
- package/src/lib/floating/customResizeObserver.ts +10 -1
- package/src/lib/floating/useFloatingWithInteractions/useFloatingWithInteractions.ts +11 -1
- package/src/styles/adaptivity.module.css +1 -2
package/package.json
CHANGED
|
@@ -38,6 +38,13 @@ export interface StateProps {
|
|
|
38
38
|
hoverClassName?: string;
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
+
interface StateHookProps extends StateProps {
|
|
42
|
+
/**
|
|
43
|
+
* Блокирование активации состояний
|
|
44
|
+
*/
|
|
45
|
+
lockState: boolean;
|
|
46
|
+
}
|
|
47
|
+
|
|
41
48
|
export const DEFAULT_ACTIVE_EFFECT_DELAY = 600;
|
|
42
49
|
|
|
43
50
|
export const ACTIVE_DELAY = 70;
|
|
@@ -45,10 +52,10 @@ export const ACTIVE_DELAY = 70;
|
|
|
45
52
|
/**
|
|
46
53
|
* Управляет наведением на компонент, игнорирует тач события
|
|
47
54
|
*/
|
|
48
|
-
function useHover({ hovered, hoverClassName, hasHover = true }:
|
|
55
|
+
function useHover({ hovered, hoverClassName, hasHover = true, lockState }: StateHookProps) {
|
|
49
56
|
const [hoveredState, setHover] = React.useState(false);
|
|
50
57
|
|
|
51
|
-
const hover = hasHover && (hovered || hoveredState) ? hoverClassName : undefined;
|
|
58
|
+
const hover = hasHover && !lockState && (hovered || hoveredState) ? hoverClassName : undefined;
|
|
52
59
|
|
|
53
60
|
const onPointerEnter: React.PointerEventHandler<any> = (e) => {
|
|
54
61
|
if (e.pointerType === 'touch') {
|
|
@@ -77,13 +84,15 @@ function useActive({
|
|
|
77
84
|
activeClassName,
|
|
78
85
|
activeEffectDelay,
|
|
79
86
|
hasActive = true,
|
|
80
|
-
|
|
87
|
+
lockState,
|
|
88
|
+
}: StateHookProps) {
|
|
81
89
|
const [activatedState, setActivated] = useStateWithDelay(false);
|
|
82
90
|
|
|
83
91
|
// Список нажатий которые не требуется отменять
|
|
84
92
|
const pointersUp = React.useMemo(() => new Set<number>(), []);
|
|
85
93
|
|
|
86
|
-
const active =
|
|
94
|
+
const active =
|
|
95
|
+
hasActive && !lockState && (activated || activatedState) ? activeClassName : undefined;
|
|
87
96
|
|
|
88
97
|
const onPointerDown = () => setActivated(true, ACTIVE_DELAY);
|
|
89
98
|
const onPointerCancel: React.PointerEventHandler = (e) => {
|
|
@@ -133,8 +142,9 @@ export function useState({ hasHover, hasActive, ...restProps }: StateProps) {
|
|
|
133
142
|
const [lockState, setLockBubbling, setLockBubblingImmediate] = useLockState();
|
|
134
143
|
|
|
135
144
|
const props = {
|
|
136
|
-
hasHover
|
|
137
|
-
hasActive
|
|
145
|
+
hasHover,
|
|
146
|
+
hasActive,
|
|
147
|
+
lockState,
|
|
138
148
|
...restProps,
|
|
139
149
|
};
|
|
140
150
|
|
|
@@ -3,6 +3,7 @@ import { classNames } from '@vkontakte/vkjs';
|
|
|
3
3
|
import { useAdaptivity } from '../../hooks/useAdaptivity';
|
|
4
4
|
import { useEventListener } from '../../hooks/useEventListener';
|
|
5
5
|
import { useExternRef } from '../../hooks/useExternRef';
|
|
6
|
+
import { useResizeObserver } from '../../hooks/useResizeObserver';
|
|
6
7
|
import { useDOM } from '../../lib/dom';
|
|
7
8
|
import { useIsomorphicLayoutEffect } from '../../lib/useIsomorphicLayoutEffect';
|
|
8
9
|
import { stopPropagation } from '../../lib/utils';
|
|
@@ -57,6 +58,7 @@ export const CustomScrollView = ({
|
|
|
57
58
|
const trackerTop = React.useRef(0);
|
|
58
59
|
|
|
59
60
|
const boxRef = useExternRef(externalBoxRef);
|
|
61
|
+
const boxContentRef = React.useRef<HTMLDivElement>(null);
|
|
60
62
|
|
|
61
63
|
const barY = React.useRef<HTMLDivElement>(null);
|
|
62
64
|
const trackerY = React.useRef<HTMLDivElement>(null);
|
|
@@ -104,6 +106,8 @@ export const CustomScrollView = ({
|
|
|
104
106
|
}
|
|
105
107
|
}, [windowResize, window]);
|
|
106
108
|
|
|
109
|
+
useResizeObserver(boxContentRef, resize);
|
|
110
|
+
|
|
107
111
|
useIsomorphicLayoutEffect(() => {
|
|
108
112
|
let style = trackerY.current?.style;
|
|
109
113
|
let prop = '';
|
|
@@ -200,7 +204,9 @@ export const CustomScrollView = ({
|
|
|
200
204
|
{...restProps}
|
|
201
205
|
>
|
|
202
206
|
<div className={styles['CustomScrollView__box']} tabIndex={-1} ref={boxRef} onScroll={scroll}>
|
|
203
|
-
{
|
|
207
|
+
<div ref={boxContentRef} className={styles['CustomScrollView__box-content']}>
|
|
208
|
+
{children}
|
|
209
|
+
</div>
|
|
204
210
|
</div>
|
|
205
211
|
|
|
206
212
|
<div className={styles['CustomScrollView__barY']} ref={barY} onClick={stopPropagation}>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { AllHTMLAttributes, useContext, useRef } from 'react';
|
|
2
2
|
import { useExternRef } from '../../hooks/useExternRef';
|
|
3
3
|
import { FOCUSABLE_ELEMENTS_LIST, Keys, pressedKey } from '../../lib/accessibility';
|
|
4
4
|
import {
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
getActiveElementByAnotherElement,
|
|
7
7
|
getWindow,
|
|
8
8
|
isHTMLElement,
|
|
9
|
+
useDOM,
|
|
9
10
|
} from '../../lib/dom';
|
|
10
11
|
import { useIsomorphicLayoutEffect } from '../../lib/useIsomorphicLayoutEffect';
|
|
11
12
|
import { HasComponent, HasRootRef } from '../../types';
|
|
@@ -13,7 +14,7 @@ import { AppRootContext } from '../AppRoot/AppRootContext';
|
|
|
13
14
|
|
|
14
15
|
const FOCUSABLE_ELEMENTS: string = FOCUSABLE_ELEMENTS_LIST.join();
|
|
15
16
|
export interface FocusTrapProps<T extends HTMLElement = HTMLElement>
|
|
16
|
-
extends
|
|
17
|
+
extends AllHTMLAttributes<T>,
|
|
17
18
|
HasRootRef<T>,
|
|
18
19
|
HasComponent {
|
|
19
20
|
autoFocus?: boolean;
|
|
@@ -36,33 +37,66 @@ export const FocusTrap = <T extends HTMLElement = HTMLElement>({
|
|
|
36
37
|
...restProps
|
|
37
38
|
}: FocusTrapProps<T>) => {
|
|
38
39
|
const ref = useExternRef<T>(getRootRef);
|
|
40
|
+
const { document } = useDOM();
|
|
39
41
|
|
|
40
|
-
const { keyboardInput } =
|
|
41
|
-
const focusableNodesRef =
|
|
42
|
+
const { keyboardInput } = useContext(AppRootContext);
|
|
43
|
+
const focusableNodesRef = useRef<HTMLElement[]>([]);
|
|
44
|
+
|
|
45
|
+
const focusNodeByIndex = (nodeIndex: number) => {
|
|
46
|
+
const element = focusableNodesRef.current[nodeIndex];
|
|
47
|
+
|
|
48
|
+
if (element) {
|
|
49
|
+
element.focus();
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const recalculateFocusableNodesRef = (parentNode: HTMLElement) => {
|
|
54
|
+
// eslint-disable-next-line no-restricted-properties
|
|
55
|
+
const newFocusableElements = parentNode.querySelectorAll<HTMLElement>(FOCUSABLE_ELEMENTS);
|
|
56
|
+
|
|
57
|
+
const nodes: HTMLElement[] = [];
|
|
58
|
+
newFocusableElements.forEach((focusableEl) => {
|
|
59
|
+
const { display, visibility } = getComputedStyle(focusableEl);
|
|
60
|
+
if (display !== 'none' && visibility !== 'hidden') {
|
|
61
|
+
nodes.push(focusableEl);
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
if (nodes.length === 0) {
|
|
66
|
+
// Чтобы фокус был хотя бы на родителе
|
|
67
|
+
nodes.push(parentNode);
|
|
68
|
+
}
|
|
69
|
+
focusableNodesRef.current = nodes;
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
const onMutateParentHandler = (parentNode: HTMLElement) => {
|
|
73
|
+
recalculateFocusableNodesRef(parentNode);
|
|
74
|
+
|
|
75
|
+
if (document) {
|
|
76
|
+
const activeElement = document.activeElement as HTMLElement;
|
|
77
|
+
const currentElementIndex = Math.max(
|
|
78
|
+
document.activeElement ? focusableNodesRef.current.indexOf(activeElement) : -1,
|
|
79
|
+
0,
|
|
80
|
+
);
|
|
81
|
+
focusNodeByIndex(currentElementIndex);
|
|
82
|
+
}
|
|
83
|
+
};
|
|
42
84
|
|
|
43
85
|
useIsomorphicLayoutEffect(
|
|
44
86
|
function collectFocusableNodesRef() {
|
|
45
87
|
if (!ref.current) {
|
|
46
88
|
return;
|
|
47
89
|
}
|
|
48
|
-
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
if (display !== 'none' && visibility !== 'hidden') {
|
|
54
|
-
nodes.push(focusableEl);
|
|
55
|
-
}
|
|
90
|
+
const parentNode = ref.current;
|
|
91
|
+
const observer = new MutationObserver(() => onMutateParentHandler(parentNode));
|
|
92
|
+
observer.observe(ref.current, {
|
|
93
|
+
subtree: true,
|
|
94
|
+
childList: true,
|
|
56
95
|
});
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
// Чтобы фокус был хотя бы на родителе
|
|
60
|
-
nodes.push(ref.current);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
focusableNodesRef.current = nodes;
|
|
96
|
+
recalculateFocusableNodesRef(parentNode);
|
|
97
|
+
return () => observer.disconnect();
|
|
64
98
|
},
|
|
65
|
-
[
|
|
99
|
+
[ref],
|
|
66
100
|
);
|
|
67
101
|
|
|
68
102
|
useIsomorphicLayoutEffect(
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { classNames } from '@vkontakte/vkjs';
|
|
3
|
+
import { useAdaptivityConditionalRender } from '../../hooks/useAdaptivityConditionalRender';
|
|
3
4
|
import { HasOnlyExpectedProps } from '../../types';
|
|
4
5
|
import {
|
|
5
6
|
CustomSelect,
|
|
@@ -14,6 +15,7 @@ export type SelectType = 'default' | 'plain' | 'accent';
|
|
|
14
15
|
*/
|
|
15
16
|
export const Select = <OptionT extends CustomSelectOptionInterface>({
|
|
16
17
|
children,
|
|
18
|
+
className,
|
|
17
19
|
...props
|
|
18
20
|
}: SelectProps<OptionT>) => {
|
|
19
21
|
const {
|
|
@@ -45,15 +47,20 @@ export const Select = <OptionT extends CustomSelectOptionInterface>({
|
|
|
45
47
|
...restProps
|
|
46
48
|
} = props;
|
|
47
49
|
|
|
48
|
-
const
|
|
50
|
+
const { deviceType } = useAdaptivityConditionalRender();
|
|
49
51
|
|
|
50
52
|
const nativeProps: HasOnlyExpectedProps<typeof restProps, NativeSelectProps> = restProps;
|
|
51
53
|
|
|
52
54
|
return (
|
|
53
55
|
<React.Fragment>
|
|
54
|
-
{
|
|
55
|
-
|
|
56
|
-
|
|
56
|
+
{deviceType.desktop && (
|
|
57
|
+
<CustomSelect className={classNames(className, deviceType.desktop.className)} {...props} />
|
|
58
|
+
)}
|
|
59
|
+
{deviceType.mobile && (
|
|
60
|
+
<NativeSelect
|
|
61
|
+
className={classNames(className, deviceType.mobile.className)}
|
|
62
|
+
{...nativeProps}
|
|
63
|
+
>
|
|
57
64
|
{options.map(({ label, value }) => (
|
|
58
65
|
<option value={value} key={`${value}`}>
|
|
59
66
|
{label}
|
|
@@ -1,4 +1,48 @@
|
|
|
1
1
|
.Spacing {
|
|
2
|
+
--vkui_internal--Spacing_gap: 0;
|
|
3
|
+
|
|
2
4
|
position: relative;
|
|
5
|
+
block-size: var(--vkui_internal--Spacing_gap);
|
|
6
|
+
padding-block: calc(1px * var(--vkui_internal--Spacing_gap) / 2);
|
|
3
7
|
box-sizing: border-box;
|
|
4
8
|
}
|
|
9
|
+
|
|
10
|
+
.Spacing--3xs {
|
|
11
|
+
--vkui_internal--Spacing_gap: var(--vkui--spacing_size_3xs);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.Spacing--2xs {
|
|
15
|
+
--vkui_internal--Spacing_gap: var(--vkui--spacing_size_2xs);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
.Spacing--xs {
|
|
19
|
+
--vkui_internal--Spacing_gap: var(--vkui--spacing_size_xs);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.Spacing--s {
|
|
23
|
+
--vkui_internal--Spacing_gap: var(--vkui--spacing_size_s);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.Spacing--m {
|
|
27
|
+
--vkui_internal--Spacing_gap: var(--vkui--spacing_size_m);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.Spacing--l {
|
|
31
|
+
--vkui_internal--Spacing_gap: var(--vkui--spacing_size_l);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.Spacing--xl {
|
|
35
|
+
--vkui_internal--Spacing_gap: var(--vkui--spacing_size_xl);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.Spacing--2xl {
|
|
39
|
+
--vkui_internal--Spacing_gap: var(--vkui--spacing_size_2xl);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.Spacing--3xl {
|
|
43
|
+
--vkui_internal--Spacing_gap: var(--vkui--spacing_size_3xl);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.Spacing--4xl {
|
|
47
|
+
--vkui_internal--Spacing_gap: var(--vkui--spacing_size_4xl);
|
|
48
|
+
}
|
|
@@ -1,49 +1,53 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { classNames } from '@vkontakte/vkjs';
|
|
2
2
|
import { HTMLAttributesWithRootRef } from '../../types';
|
|
3
3
|
import { RootComponent } from '../RootComponent/RootComponent';
|
|
4
4
|
import styles from './Spacing.module.css';
|
|
5
5
|
|
|
6
|
-
export const
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
'
|
|
10
|
-
'
|
|
11
|
-
'
|
|
12
|
-
'
|
|
13
|
-
'
|
|
14
|
-
'
|
|
15
|
-
'
|
|
16
|
-
'
|
|
17
|
-
]
|
|
18
|
-
|
|
6
|
+
export const CUSTOM_CSS_TOKEN_FOR_USER_GAP = '--vkui_internal--Spacing_gap';
|
|
7
|
+
|
|
8
|
+
export const sizesClassNames = {
|
|
9
|
+
'3xs': styles['Spacing--3xs'],
|
|
10
|
+
'2xs': styles['Spacing--2xs'],
|
|
11
|
+
'xs': styles['Spacing--xs'],
|
|
12
|
+
's': styles['Spacing--s'],
|
|
13
|
+
'm': styles['Spacing--m'],
|
|
14
|
+
'l': styles['Spacing--l'],
|
|
15
|
+
'xl': styles['Spacing--xl'],
|
|
16
|
+
'2xl': styles['Spacing--2xl'],
|
|
17
|
+
'3xl': styles['Spacing--3xl'],
|
|
18
|
+
'4xl': styles['Spacing--4xl'],
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export type SpacingSize = keyof typeof sizesClassNames;
|
|
19
22
|
|
|
20
23
|
export interface SpacingProps extends HTMLAttributesWithRootRef<HTMLDivElement> {
|
|
21
24
|
/**
|
|
22
25
|
* Высота спэйсинга
|
|
23
26
|
*/
|
|
24
|
-
size?: number |
|
|
27
|
+
size?: number | SpacingSize;
|
|
25
28
|
}
|
|
26
29
|
/**
|
|
27
30
|
* @see https://vkcom.github.io/VKUI/#/Spacing
|
|
28
31
|
*/
|
|
29
|
-
export const Spacing = ({ size = 'm', style
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
export const Spacing = ({ size = 'm', style, className, ...restProps }: SpacingProps) => {
|
|
33
|
+
if (typeof size === 'string') {
|
|
34
|
+
className = className ? classNames(sizesClassNames[size], className) : sizesClassNames[size];
|
|
35
|
+
} else {
|
|
36
|
+
if (style) {
|
|
37
|
+
// @ts-expect-error: TS7053 В React.CSSProperties не учитывается Custom Properties
|
|
38
|
+
style[CUSTOM_CSS_TOKEN_FOR_USER_GAP] = size;
|
|
39
|
+
} else {
|
|
40
|
+
// @ts-expect-error: TS2353 В React.CSSProperties не учитывается Custom Properties
|
|
41
|
+
style = { [CUSTOM_CSS_TOKEN_FOR_USER_GAP]: size };
|
|
42
|
+
}
|
|
43
|
+
}
|
|
34
44
|
|
|
35
|
-
return
|
|
45
|
+
return (
|
|
46
|
+
<RootComponent
|
|
47
|
+
{...restProps}
|
|
48
|
+
style={style}
|
|
49
|
+
className={className}
|
|
50
|
+
baseClassName={styles['Spacing']}
|
|
51
|
+
/>
|
|
52
|
+
);
|
|
36
53
|
};
|
|
37
|
-
|
|
38
|
-
function getSizeStyle(size: number | Size): React.CSSProperties {
|
|
39
|
-
const sizeValue = getSizeValue(size);
|
|
40
|
-
|
|
41
|
-
return {
|
|
42
|
-
height: sizeValue,
|
|
43
|
-
padding: `calc(${sizeValue} / 2px) 0`,
|
|
44
|
-
};
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
function getSizeValue(size: number | Size): `var(--vkui--spacing_size_${Size})` | number {
|
|
48
|
-
return typeof size === 'string' ? `var(--vkui--spacing_size_${size})` : size;
|
|
49
|
-
}
|
|
@@ -48,24 +48,14 @@
|
|
|
48
48
|
flex-direction: column;
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
margin-inline-end: 4px;
|
|
51
|
+
.ToolButton--direction-row .ToolButton__text {
|
|
52
|
+
margin-inline-start: 4px;
|
|
54
53
|
}
|
|
55
54
|
|
|
56
|
-
.ToolButton--direction-
|
|
57
|
-
margin-
|
|
55
|
+
.ToolButton--direction-column .ToolButton__text {
|
|
56
|
+
margin-block-start: 4px;
|
|
58
57
|
}
|
|
59
58
|
|
|
60
|
-
.ToolButton--direction-column > * {
|
|
61
|
-
margin-block-end: 4px;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
.ToolButton--direction-column > *:last-child {
|
|
65
|
-
margin-block-end: 0;
|
|
66
|
-
}
|
|
67
|
-
/* stylelint-enable selector-max-universal */
|
|
68
|
-
|
|
69
59
|
/* ToolButton's backgrounds */
|
|
70
60
|
/* Mode = Primary */
|
|
71
61
|
.ToolButton--mode-primary.ToolButton--appearance-accent {
|
|
@@ -26,13 +26,18 @@ const stylesDirection = {
|
|
|
26
26
|
|
|
27
27
|
const sizeYClassNames = {
|
|
28
28
|
none: styles['ToolButton--sizeY-none'],
|
|
29
|
-
|
|
29
|
+
regular: styles['ToolButton--sizeY-regular'],
|
|
30
30
|
};
|
|
31
31
|
|
|
32
32
|
export interface ToolButtonProps extends TappableProps, AdaptiveIconRendererProps {
|
|
33
33
|
mode?: 'primary' | 'secondary' | 'tertiary' | 'outline';
|
|
34
34
|
appearance?: 'accent' | 'neutral';
|
|
35
35
|
direction?: 'row' | 'column';
|
|
36
|
+
/**
|
|
37
|
+
* Задаёт `50%` закругления для контейнера.
|
|
38
|
+
*
|
|
39
|
+
* > Note: игнорируется при передаче `children`.
|
|
40
|
+
*/
|
|
36
41
|
rounded?: boolean;
|
|
37
42
|
}
|
|
38
43
|
|
|
@@ -77,7 +82,7 @@ export const ToolButton = ({
|
|
|
77
82
|
{...restProps}
|
|
78
83
|
>
|
|
79
84
|
<AdaptiveIconRenderer IconCompact={IconCompact} IconRegular={IconRegular} />
|
|
80
|
-
{hasChildren && <span>{children}</span>}
|
|
85
|
+
{hasChildren && <span className={styles['ToolButton__text']}>{children}</span>}
|
|
81
86
|
</Tappable>
|
|
82
87
|
);
|
|
83
88
|
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { CustomResizeObserver } from '../lib/floating/customResizeObserver';
|
|
3
|
+
import { useIsomorphicLayoutEffect } from '../lib/useIsomorphicLayoutEffect';
|
|
4
|
+
import { useStableCallback } from './useStableCallback';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Хук вызывает переданный коллбэк при изменении размеров элемента.
|
|
8
|
+
*/
|
|
9
|
+
export function useResizeObserver(
|
|
10
|
+
ref: React.MutableRefObject<HTMLElement | null>,
|
|
11
|
+
callback: (element: HTMLElement) => void,
|
|
12
|
+
) {
|
|
13
|
+
const stableCallback = useStableCallback(callback);
|
|
14
|
+
|
|
15
|
+
useIsomorphicLayoutEffect(
|
|
16
|
+
function addResizeObserverHandler() {
|
|
17
|
+
/* istanbul ignore if: невозможный кейс (в SSR вызова этой функции не будет) */
|
|
18
|
+
if (!ref.current) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
const element = ref.current;
|
|
22
|
+
const observer = new CustomResizeObserver(() => stableCallback(element));
|
|
23
|
+
observer.observe(element);
|
|
24
|
+
observer.appendToTheDOM();
|
|
25
|
+
|
|
26
|
+
return () => observer.disconnect();
|
|
27
|
+
},
|
|
28
|
+
[ref],
|
|
29
|
+
);
|
|
30
|
+
}
|
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
const defaultIframeStyles: Pick<
|
|
2
2
|
CSSStyleDeclaration,
|
|
3
|
-
|
|
3
|
+
| 'position'
|
|
4
|
+
| 'left'
|
|
5
|
+
| 'top'
|
|
6
|
+
| 'zIndex'
|
|
7
|
+
| 'width'
|
|
8
|
+
| 'height'
|
|
9
|
+
| 'pointerEvents'
|
|
10
|
+
| 'opacity'
|
|
11
|
+
| 'border'
|
|
4
12
|
> = {
|
|
5
13
|
position: 'absolute',
|
|
6
14
|
left: '0',
|
|
@@ -10,6 +18,7 @@ const defaultIframeStyles: Pick<
|
|
|
10
18
|
height: '100%',
|
|
11
19
|
pointerEvents: 'none',
|
|
12
20
|
opacity: '0',
|
|
21
|
+
border: '0',
|
|
13
22
|
};
|
|
14
23
|
|
|
15
24
|
/*
|
|
@@ -91,7 +91,7 @@ export const useFloatingWithInteractions = <T extends HTMLElement = HTMLElement>
|
|
|
91
91
|
const commitShownLocalState = React.useCallback(
|
|
92
92
|
(nextShown: boolean, reason: ShownChangeReason) => {
|
|
93
93
|
setShownLocalState((prevState) => {
|
|
94
|
-
if (prevState.shown !== nextShown) {
|
|
94
|
+
if (prevState.shown !== nextShown || prevState.reason !== reason) {
|
|
95
95
|
return {
|
|
96
96
|
shown: nextShown,
|
|
97
97
|
reason,
|
|
@@ -118,6 +118,11 @@ export const useFloatingWithInteractions = <T extends HTMLElement = HTMLElement>
|
|
|
118
118
|
);
|
|
119
119
|
|
|
120
120
|
const handleFocusOnReference = useStableCallback(() => {
|
|
121
|
+
// Повторный вызов события фокуса - следствие клика на reference-элемент
|
|
122
|
+
if (shownLocalState.shown) {
|
|
123
|
+
commitShownLocalState(false, 'focus');
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
121
126
|
if (blockFocusRef.current) {
|
|
122
127
|
/* istanbul ignore next: в Jest не воспроизводится баг на вебе (cм. onRestoreFocus) */
|
|
123
128
|
blockFocusRef.current = false;
|
|
@@ -158,6 +163,11 @@ export const useFloatingWithInteractions = <T extends HTMLElement = HTMLElement>
|
|
|
158
163
|
});
|
|
159
164
|
|
|
160
165
|
const handleClickOnReference = useStableCallback(() => {
|
|
166
|
+
// Предыдущий триггер (фокус) уже вызвал открытие/закрытие всплывающего окна, игнорируем вызов
|
|
167
|
+
if (shownLocalState.reason === 'focus') {
|
|
168
|
+
commitShownLocalState(shownLocalState.shown, 'click');
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
161
171
|
commitShownLocalState(!shownLocalState.shown, 'click');
|
|
162
172
|
});
|
|
163
173
|
|
|
@@ -74,8 +74,7 @@ Note: В начале классов разделить (`-`), чтобы кра
|
|
|
74
74
|
|
|
75
75
|
.-deviceType--mobile-forced,
|
|
76
76
|
.-deviceType--desktop-forced {
|
|
77
|
-
/*
|
|
78
|
-
display: none !important;
|
|
77
|
+
/* Пустой класс для CSS Modules (см. CONTRIBUTING.md) */
|
|
79
78
|
}
|
|
80
79
|
|
|
81
80
|
@media (--desktop) {
|