@dss-kit/ui-kit 1.0.2 → 1.0.4
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/components/builders/Dialog/Dialog.const.d.ts +9 -0
- package/dist/components/builders/Dialog/Dialog.const.js +4 -0
- package/dist/components/builders/Dialog/Dialog.context.d.ts +12 -0
- package/dist/components/builders/{Modal/context.js → Dialog/Dialog.context.js} +5 -5
- package/dist/components/builders/Dialog/Dialog.parts.d.ts +11 -0
- package/dist/components/builders/Dialog/Dialog.parts.js +11 -0
- package/dist/components/builders/Dialog/Dialog.types.d.ts +44 -0
- package/dist/components/builders/Dialog/DialogCloseButton/DialogCloseButton.d.ts +10 -0
- package/dist/components/builders/Dialog/DialogCloseButton/DialogCloseButton.js +34 -0
- package/dist/components/builders/Dialog/DialogCloseButton/index.d.ts +2 -0
- package/dist/components/builders/{Modal/ModalFooter/ModalFooter.d.ts → Dialog/DialogFooter/DialogFooter.d.ts} +13 -22
- package/dist/components/builders/Dialog/DialogFooter/DialogFooter.js +48 -0
- package/dist/components/builders/Dialog/DialogFooter/index.d.ts +2 -0
- package/dist/components/builders/{Modal/ModalHeader/ModalHeader.d.ts → Dialog/DialogHeader/DialogHeader.d.ts} +10 -6
- package/dist/components/builders/Dialog/DialogHeader/DialogHeader.js +97 -0
- package/dist/components/builders/Dialog/DialogHeader/index.d.ts +2 -0
- package/dist/components/builders/{Modal/ModalMain/ModalMain.d.ts → Dialog/DialogMain/DialogMain.d.ts} +18 -17
- package/dist/components/builders/{Modal/ModalMain/ModalMain.js → Dialog/DialogMain/DialogMain.js} +39 -29
- package/dist/components/builders/Dialog/DialogMain/index.d.ts +2 -0
- package/dist/components/builders/Dialog/DialogMain/styles.d.ts +6 -0
- package/dist/components/builders/{Modal/ModalMain → Dialog/DialogMain}/styles.js +16 -0
- package/dist/components/builders/Dialog/hooks/index.d.ts +3 -0
- package/dist/components/builders/Dialog/hooks/useBackdropClose.d.ts +10 -0
- package/dist/components/builders/Dialog/hooks/useBackdropClose.js +15 -0
- package/dist/components/builders/Dialog/hooks/useBodyScrollLock.d.ts +6 -0
- package/dist/components/builders/Dialog/hooks/useBodyScrollLock.js +13 -0
- package/dist/components/builders/Dialog/hooks/useCloseOnEsc.d.ts +6 -0
- package/dist/components/builders/Dialog/hooks/useCloseOnEsc.js +21 -0
- package/dist/components/builders/Dialog/index.d.ts +10 -0
- package/dist/components/builders/Modal/Modal.d.ts +8 -28
- package/dist/components/builders/Modal/Modal.js +50 -78
- package/dist/components/builders/Modal/index.d.ts +6 -11
- package/dist/components/builders/Modal/index.js +7 -9
- package/dist/components/builders/Modal/styles.js +6 -7
- package/dist/components/builders/Sheet/Sheet.const.d.ts +50 -0
- package/dist/components/builders/Sheet/Sheet.const.js +38 -0
- package/dist/components/builders/Sheet/Sheet.d.ts +12 -0
- package/dist/components/builders/Sheet/Sheet.js +55 -0
- package/dist/components/builders/Sheet/Sheet.types.d.ts +82 -0
- package/dist/components/builders/Sheet/Sheet.utils.d.ts +34 -0
- package/dist/components/builders/Sheet/Sheet.utils.js +50 -0
- package/dist/components/builders/Sheet/SheetLayer.d.ts +22 -0
- package/dist/components/builders/Sheet/SheetLayer.js +115 -0
- package/dist/components/builders/Sheet/hooks/index.d.ts +2 -0
- package/dist/components/builders/Sheet/hooks/useSheetGesture.d.ts +24 -0
- package/dist/components/builders/Sheet/hooks/useSheetGesture.js +67 -0
- package/dist/components/builders/Sheet/hooks/useSheetMotion.d.ts +31 -0
- package/dist/components/builders/Sheet/hooks/useSheetMotion.js +74 -0
- package/dist/components/builders/Sheet/hooks/useSheetPointer.d.ts +31 -0
- package/dist/components/builders/Sheet/hooks/useSheetPointer.js +81 -0
- package/dist/components/builders/Sheet/index.d.ts +15 -0
- package/dist/components/builders/Sheet/index.js +9 -0
- package/dist/components/builders/Sheet/styles.d.ts +17 -0
- package/dist/components/builders/Sheet/styles.js +135 -0
- package/dist/components/builders/Table/TablePagination/TablePagination.js +1 -1
- package/dist/components/builders/Text/Text.d.ts +1 -1
- package/dist/components/builders/index.d.ts +1 -0
- package/dist/components/controls/Checkbox/Checkbox.js +6 -6
- package/dist/components/controls/Select/Select.js +6 -6
- package/dist/components/controls/Switch/Switch.d.ts +10 -6
- package/dist/components/controls/Switch/Switch.js +109 -86
- package/dist/components/controls/Switch/styles.d.ts +3 -2
- package/dist/components/controls/Switch/styles.js +76 -73
- package/dist/index.js +93 -91
- package/dist/ui-kit.cjs +8 -8
- package/dist/utils/hooks/useLatestRef.d.ts +6 -0
- package/dist/utils/hooks/useLatestRef.js +10 -0
- package/package.json +1 -1
- package/dist/components/builders/Modal/ModalFooter/ModalFooter.js +0 -35
- package/dist/components/builders/Modal/ModalFooter/index.d.ts +0 -2
- package/dist/components/builders/Modal/ModalHeader/ModalHeader.js +0 -86
- package/dist/components/builders/Modal/ModalHeader/index.d.ts +0 -2
- package/dist/components/builders/Modal/ModalMain/index.d.ts +0 -2
- package/dist/components/builders/Modal/ModalMain/styles.d.ts +0 -3
- package/dist/components/builders/Modal/context.d.ts +0 -8
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { MouseEvent } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Обработчики подложки (backdrop). `onClose` вызывается, только если и нажатие,
|
|
4
|
+
* и отпускание кнопки мыши пришлись на саму подложку: диалог не закроется, если
|
|
5
|
+
* выделение текста начали внутри окна, а отпустили снаружи.
|
|
6
|
+
*/
|
|
7
|
+
export declare function useBackdropClose(isEnabled: boolean, onClose: () => void): {
|
|
8
|
+
onMouseDown: (event: MouseEvent) => void;
|
|
9
|
+
onClick: (event: MouseEvent) => void;
|
|
10
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { useRef as s, useCallback as e } from "react";
|
|
2
|
+
function f(t, o) {
|
|
3
|
+
const c = s(!1), n = e((r) => {
|
|
4
|
+
c.current = r.target === r.currentTarget;
|
|
5
|
+
}, []), u = e(
|
|
6
|
+
(r) => {
|
|
7
|
+
t && r.target === r.currentTarget && c.current && o();
|
|
8
|
+
},
|
|
9
|
+
[t, o]
|
|
10
|
+
);
|
|
11
|
+
return { onMouseDown: n, onClick: u };
|
|
12
|
+
}
|
|
13
|
+
export {
|
|
14
|
+
f as useBackdropClose
|
|
15
|
+
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Блокирует прокрутку `body`, пока `isLocked` истинно. Блокировки всех
|
|
3
|
+
* диалогов считаются вместе: прокрутка возвращается, когда снята последняя,
|
|
4
|
+
* в каком бы порядке диалоги ни закрывались.
|
|
5
|
+
*/
|
|
6
|
+
export declare function useBodyScrollLock(isLocked: boolean): void;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { useEffect as f } from "react";
|
|
2
|
+
let o = 0, t = "";
|
|
3
|
+
function n(e) {
|
|
4
|
+
f(() => {
|
|
5
|
+
if (!(!e || typeof document > "u"))
|
|
6
|
+
return o === 0 && (t = document.body.style.overflow, document.body.style.overflow = "hidden"), o++, () => {
|
|
7
|
+
o--, o === 0 && (document.body.style.overflow = t);
|
|
8
|
+
};
|
|
9
|
+
}, [e]);
|
|
10
|
+
}
|
|
11
|
+
export {
|
|
12
|
+
n as useBodyScrollLock
|
|
13
|
+
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Вызывает `onClose` по нажатию Escape, если диалог открыт, `isEnabled`
|
|
3
|
+
* истинно и диалог верхний среди открытых. Диалог с `isEnabled = false` тоже
|
|
4
|
+
* занимает место в стеке: Escape над ним не закрывает диалоги ниже.
|
|
5
|
+
*/
|
|
6
|
+
export declare function useCloseOnEsc(isOpen: boolean, isEnabled: boolean, onClose: () => void): void;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { useEffect as r } from "react";
|
|
2
|
+
import { useLatestRef as i } from "../../../../utils/hooks/useLatestRef.js";
|
|
3
|
+
const e = [];
|
|
4
|
+
function c(n) {
|
|
5
|
+
if (n.key !== "Escape") return;
|
|
6
|
+
const t = e[e.length - 1]?.current;
|
|
7
|
+
t?.isEnabled && t.onClose();
|
|
8
|
+
}
|
|
9
|
+
function a(n, t, f) {
|
|
10
|
+
const o = i({ isEnabled: t, onClose: f });
|
|
11
|
+
r(() => {
|
|
12
|
+
if (!(!n || typeof document > "u"))
|
|
13
|
+
return e.length === 0 && document.addEventListener("keydown", c), e.push(o), () => {
|
|
14
|
+
const s = e.indexOf(o);
|
|
15
|
+
s !== -1 && e.splice(s, 1), e.length === 0 && document.removeEventListener("keydown", c);
|
|
16
|
+
};
|
|
17
|
+
}, [n, o]);
|
|
18
|
+
}
|
|
19
|
+
export {
|
|
20
|
+
a as useCloseOnEsc
|
|
21
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export { getDialogPartSelector } from './Dialog.const';
|
|
2
|
+
export { DialogContext } from './Dialog.context';
|
|
3
|
+
export type { DialogParts } from './Dialog.parts';
|
|
4
|
+
export { dialogParts } from './Dialog.parts';
|
|
5
|
+
export type { DialogProps } from './Dialog.types';
|
|
6
|
+
export { DialogCloseButton } from './DialogCloseButton';
|
|
7
|
+
export type { DialogFooterProps } from './DialogFooter';
|
|
8
|
+
export type { DialogHeaderProps } from './DialogHeader';
|
|
9
|
+
export type { DialogMainProps } from './DialogMain';
|
|
10
|
+
export { useBackdropClose, useBodyScrollLock, useCloseOnEsc, } from './hooks';
|
|
@@ -1,34 +1,14 @@
|
|
|
1
|
-
import { PropsWithChildren } from 'react';
|
|
2
1
|
import { Size } from '../../../types/tokens.types';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
/** Размер модального окна */
|
|
9
|
-
/** @default "md" */
|
|
2
|
+
import { DialogProps } from '../Dialog';
|
|
3
|
+
export interface ModalProps extends DialogProps {
|
|
4
|
+
/**
|
|
5
|
+
* Размер модального окна
|
|
6
|
+
* @default "md" */
|
|
10
7
|
size?: Extract<Size, "sm" | "md" | "lg">;
|
|
11
|
-
/**
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
/** Закрывать ли при нажатии ESC */
|
|
15
|
-
/** @default true */
|
|
16
|
-
closeOnEsc?: boolean;
|
|
17
|
-
/** Кастомный класс для overlay */
|
|
18
|
-
/** @default undefined */
|
|
19
|
-
overlayClassName?: string;
|
|
20
|
-
/** Кастомный класс для модального окна */
|
|
21
|
-
/** @default undefined */
|
|
8
|
+
/**
|
|
9
|
+
* Кастомный класс для модального окна
|
|
10
|
+
* @default undefined */
|
|
22
11
|
modalClassName?: string;
|
|
23
|
-
/** Кастомный класс для абсолютной кнопки закрытия (когда `showAbsoluteCloseButton`). */
|
|
24
|
-
/** @default undefined */
|
|
25
|
-
absoluteCloseButtonClassName?: string;
|
|
26
|
-
/** Отключать прокрутку body при открытии */
|
|
27
|
-
/** @default true */
|
|
28
|
-
disableBodyScroll?: boolean;
|
|
29
|
-
/** Показывать ли кнопку закрытия c абсолютным позиционированием внутри модального окна */
|
|
30
|
-
/** @default undefined */
|
|
31
|
-
showAbsoluteCloseButton?: boolean;
|
|
32
12
|
}
|
|
33
13
|
declare const Modal: import('react').ForwardRefExoticComponent<ModalProps & import('react').RefAttributes<HTMLDivElement>>;
|
|
34
14
|
export { Modal };
|
|
@@ -1,55 +1,38 @@
|
|
|
1
|
-
import { jsx as
|
|
2
|
-
import { cx as
|
|
3
|
-
import { forwardRef as
|
|
4
|
-
import
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
|
|
1
|
+
import { jsx as r, jsxs as v } from "react/jsx-runtime";
|
|
2
|
+
import { cx as i } from "@emotion/css";
|
|
3
|
+
import { forwardRef as M, useMemo as C } from "react";
|
|
4
|
+
import { styles as t } from "./styles.js";
|
|
5
|
+
import { useBodyScrollLock as D } from "../Dialog/hooks/useBodyScrollLock.js";
|
|
6
|
+
import { useCloseOnEsc as N } from "../Dialog/hooks/useCloseOnEsc.js";
|
|
7
|
+
import { useBackdropClose as _ } from "../Dialog/hooks/useBackdropClose.js";
|
|
8
|
+
import { Portal as w } from "../Portal/Portal.js";
|
|
9
|
+
import { DialogContext as B } from "../Dialog/Dialog.context.js";
|
|
10
|
+
import { DialogCloseButton as j } from "../Dialog/DialogCloseButton/DialogCloseButton.js";
|
|
11
|
+
import { Box as a } from "../Box/Box.js";
|
|
12
|
+
import { theme as c } from "../../../utils/theme/index.js";
|
|
13
|
+
const z = M(
|
|
12
14
|
({
|
|
13
|
-
isOpen:
|
|
14
|
-
onClose:
|
|
15
|
-
overlayClassName:
|
|
16
|
-
modalClassName:
|
|
17
|
-
absoluteCloseButtonClassName:
|
|
18
|
-
size:
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
15
|
+
isOpen: e,
|
|
16
|
+
onClose: o,
|
|
17
|
+
overlayClassName: s,
|
|
18
|
+
modalClassName: u,
|
|
19
|
+
absoluteCloseButtonClassName: f,
|
|
20
|
+
size: n = "md",
|
|
21
|
+
backgroundColor: p = c.color.fill.bg_primary,
|
|
22
|
+
closeOnBackdropClick: d = !0,
|
|
23
|
+
closeOnEsc: x = !0,
|
|
24
|
+
disableBodyScroll: y = !0,
|
|
25
|
+
showAbsoluteCloseButton: b,
|
|
26
|
+
showBorders: l = !0,
|
|
27
|
+
children: g
|
|
24
28
|
}, k) => {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
document.body.style.overflow = e;
|
|
30
|
-
};
|
|
31
|
-
}
|
|
32
|
-
}, [o, a]);
|
|
33
|
-
const n = d(
|
|
34
|
-
(e) => {
|
|
35
|
-
e.key === "Escape" && r();
|
|
36
|
-
},
|
|
37
|
-
[r]
|
|
38
|
-
);
|
|
39
|
-
p(() => {
|
|
40
|
-
if (typeof window < "u" && typeof document < "u" && u && o)
|
|
41
|
-
return document.addEventListener("keydown", n), () => document.removeEventListener("keydown", n);
|
|
42
|
-
}, [o, u, n]);
|
|
43
|
-
const c = N(!1), b = d((e) => {
|
|
44
|
-
c.current = e.target === e.currentTarget;
|
|
45
|
-
}, []), M = d(
|
|
46
|
-
(e) => {
|
|
47
|
-
m && e.target === e.currentTarget && c.current && r();
|
|
48
|
-
},
|
|
49
|
-
[m, r]
|
|
29
|
+
D(e && y), N(e, x, o);
|
|
30
|
+
const m = _(d, o), h = C(
|
|
31
|
+
() => ({ onClose: o, showBorders: l }),
|
|
32
|
+
[o, l]
|
|
50
33
|
);
|
|
51
|
-
return
|
|
52
|
-
|
|
34
|
+
return e ? /* @__PURE__ */ r(w, { children: /* @__PURE__ */ r(B.Provider, { value: h, children: /* @__PURE__ */ r(
|
|
35
|
+
a,
|
|
53
36
|
{
|
|
54
37
|
position: "fixed",
|
|
55
38
|
top: 0,
|
|
@@ -59,42 +42,31 @@ const j = D(
|
|
|
59
42
|
row: !0,
|
|
60
43
|
center: !0,
|
|
61
44
|
flex: 1,
|
|
62
|
-
onMouseDown:
|
|
63
|
-
onClick:
|
|
64
|
-
backgroundColor:
|
|
65
|
-
className:
|
|
45
|
+
onMouseDown: m.onMouseDown,
|
|
46
|
+
onClick: m.onClick,
|
|
47
|
+
backgroundColor: c.color.fill.bg_overlay_primary,
|
|
48
|
+
className: i(t.overlay, s),
|
|
66
49
|
zIndex: 1,
|
|
67
|
-
children: /* @__PURE__ */
|
|
68
|
-
|
|
50
|
+
children: /* @__PURE__ */ v(
|
|
51
|
+
a,
|
|
69
52
|
{
|
|
70
53
|
ref: k,
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
54
|
+
backgroundColor: p,
|
|
55
|
+
className: i(
|
|
56
|
+
t.modal,
|
|
57
|
+
t[`size_${n}`],
|
|
58
|
+
u
|
|
75
59
|
),
|
|
76
60
|
relative: !0,
|
|
77
61
|
children: [
|
|
78
|
-
|
|
79
|
-
|
|
62
|
+
b && /* @__PURE__ */ r(
|
|
63
|
+
j,
|
|
80
64
|
{
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
right: f.spacing.lg,
|
|
84
|
-
zIndex: 1,
|
|
85
|
-
children: /* @__PURE__ */ t(
|
|
86
|
-
_,
|
|
87
|
-
{
|
|
88
|
-
className: g,
|
|
89
|
-
onClick: r,
|
|
90
|
-
color: "neutral",
|
|
91
|
-
size: "xs",
|
|
92
|
-
children: /* @__PURE__ */ t(B, {})
|
|
93
|
-
}
|
|
94
|
-
)
|
|
65
|
+
absolute: !0,
|
|
66
|
+
className: f
|
|
95
67
|
}
|
|
96
68
|
),
|
|
97
|
-
|
|
69
|
+
g
|
|
98
70
|
]
|
|
99
71
|
}
|
|
100
72
|
)
|
|
@@ -102,7 +74,7 @@ const j = D(
|
|
|
102
74
|
) }) }) : null;
|
|
103
75
|
}
|
|
104
76
|
);
|
|
105
|
-
|
|
77
|
+
z.displayName = "Modal";
|
|
106
78
|
export {
|
|
107
|
-
|
|
79
|
+
z as Modal
|
|
108
80
|
};
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import { ReactNode, RefAttributes } from 'react';
|
|
2
|
+
import { DialogParts } from '../Dialog';
|
|
2
3
|
import { ModalProps } from './Modal';
|
|
3
|
-
import { ModalFooter } from './ModalFooter';
|
|
4
|
-
import { ModalHeader } from './ModalHeader';
|
|
5
|
-
import { ModalMain } from './ModalMain';
|
|
6
4
|
/**
|
|
7
5
|
* Тип составного компонента `Modal`.
|
|
8
6
|
*
|
|
@@ -14,15 +12,12 @@ import { ModalMain } from './ModalMain';
|
|
|
14
12
|
* NB: члены `Function` (apply/bind/call/…) TypeScript всё равно подмешивает
|
|
15
13
|
* к любому вызываемому значению — полностью убрать их без отказа от `<Modal>`
|
|
16
14
|
* нельзя.
|
|
15
|
+
*
|
|
16
|
+
* `Header` / `Main` / `Footer` — общие части диалогов (см. `../Dialog`),
|
|
17
|
+
* те же самые компоненты доступны как `Sheet.Header` / `Sheet.Main` / `Sheet.Footer`.
|
|
17
18
|
*/
|
|
18
|
-
type ModalComponent = ((props: ModalProps & RefAttributes<HTMLDivElement>) => ReactNode) &
|
|
19
|
-
Header: typeof ModalHeader;
|
|
20
|
-
Main: typeof ModalMain;
|
|
21
|
-
Footer: typeof ModalFooter;
|
|
22
|
-
};
|
|
19
|
+
type ModalComponent = ((props: ModalProps & RefAttributes<HTMLDivElement>) => ReactNode) & DialogParts;
|
|
23
20
|
declare const ModalWithSubComponents: ModalComponent;
|
|
24
21
|
export { ModalWithSubComponents as Modal };
|
|
25
22
|
export type { ModalProps };
|
|
26
|
-
export type { ModalFooterProps } from '
|
|
27
|
-
export type { ModalHeaderProps } from './ModalHeader';
|
|
28
|
-
export type { ModalMainProps } from './ModalMain';
|
|
23
|
+
export type { DialogFooterProps as ModalFooterProps, DialogHeaderProps as ModalHeaderProps, DialogMainProps as ModalMainProps, } from '../Dialog';
|
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
import { Modal as
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
o.Main = t;
|
|
8
|
-
o.Footer = m;
|
|
1
|
+
import { Modal as o } from "./Modal.js";
|
|
2
|
+
import { dialogParts as t } from "../Dialog/Dialog.parts.js";
|
|
3
|
+
const s = Object.assign(
|
|
4
|
+
o,
|
|
5
|
+
t
|
|
6
|
+
);
|
|
9
7
|
export {
|
|
10
|
-
|
|
8
|
+
s as Modal
|
|
11
9
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { css as i, keyframes as a } from "@emotion/css";
|
|
2
|
-
import { bp as
|
|
2
|
+
import { bp as t } from "../../../styles/utils/breakpoints.js";
|
|
3
3
|
import { theme as o } from "../../../utils/theme/index.js";
|
|
4
|
-
const
|
|
4
|
+
const s = a`
|
|
5
5
|
0% {
|
|
6
6
|
opacity: 0;
|
|
7
7
|
transform: scale(0.95);
|
|
@@ -10,20 +10,19 @@ const t = a`
|
|
|
10
10
|
opacity: 1;
|
|
11
11
|
transform: none;
|
|
12
12
|
}
|
|
13
|
-
`,
|
|
13
|
+
`, r = {
|
|
14
14
|
overlay: i({
|
|
15
15
|
backdropFilter: "blur(5px)"
|
|
16
16
|
}),
|
|
17
17
|
modal: i({
|
|
18
18
|
animationDuration: "0.2s",
|
|
19
19
|
animationTimingFunction: "ease-in-out",
|
|
20
|
-
animationName:
|
|
20
|
+
animationName: s,
|
|
21
21
|
maxWidth: `calc(100vw - ${o.spacing["3xl"]})`,
|
|
22
22
|
maxHeight: `calc(100vh - ${o.spacing["7xl"]} - ${o.spacing["7xl"]})`,
|
|
23
23
|
borderRadius: o.cornerRadius["2xl"],
|
|
24
|
-
backgroundColor: o.color.fill.bg_primary,
|
|
25
24
|
boxShadow: `0 4px 20px 0 ${o.color.effect.shadow_s}`,
|
|
26
|
-
[
|
|
25
|
+
[t.sm()]: {
|
|
27
26
|
flex: 1
|
|
28
27
|
}
|
|
29
28
|
}),
|
|
@@ -38,5 +37,5 @@ const t = a`
|
|
|
38
37
|
})
|
|
39
38
|
};
|
|
40
39
|
export {
|
|
41
|
-
|
|
40
|
+
r as styles
|
|
42
41
|
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { SheetPosition, SheetPositionConfig } from './Sheet.types';
|
|
2
|
+
/** Ось и направление закрытия каждой позиции */
|
|
3
|
+
export declare const SHEET_POSITION_CONFIG: Record<SheetPosition, SheetPositionConfig>;
|
|
4
|
+
/** Свойства указателя и размеров вдоль оси и поперёк неё */
|
|
5
|
+
export declare const SHEET_AXIS_KEYS: {
|
|
6
|
+
readonly x: {
|
|
7
|
+
readonly client: "clientX";
|
|
8
|
+
readonly crossClient: "clientY";
|
|
9
|
+
readonly size: "width";
|
|
10
|
+
};
|
|
11
|
+
readonly y: {
|
|
12
|
+
readonly client: "clientY";
|
|
13
|
+
readonly crossClient: "clientX";
|
|
14
|
+
readonly size: "height";
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
/** Порог закрытия по умолчанию: доля размера Sheet */
|
|
18
|
+
export declare const SHEET_DEFAULT_CLOSE_THRESHOLD = 0.4;
|
|
19
|
+
/** Скорость (px/s), с которой жест считается быстрым свайпом */
|
|
20
|
+
export declare const SHEET_FLICK_VELOCITY = 500;
|
|
21
|
+
/** Минимальный путь (px) быстрого свайпа, чтобы дрожание пальца не закрывало Sheet */
|
|
22
|
+
export declare const SHEET_FLICK_MIN_DISTANCE = 10;
|
|
23
|
+
/** Сдвиг указателя (px), после которого нажатие становится перетаскиванием */
|
|
24
|
+
export declare const SHEET_DRAG_START_THRESHOLD = 4;
|
|
25
|
+
/** Окно (мс) последних движений указателя для расчёта скорости */
|
|
26
|
+
export declare const SHEET_VELOCITY_WINDOW = 100;
|
|
27
|
+
/** Предел смещения (px) при перетягивании за границы, «резинка» */
|
|
28
|
+
export declare const SHEET_OVERDRAG_LIMIT = 48;
|
|
29
|
+
/** Высота зоны drag handle, px */
|
|
30
|
+
export declare const SHEET_HANDLE_HEIGHT = 16;
|
|
31
|
+
/** Имя CSS-переменной с активной долей экрана в режиме snap-points */
|
|
32
|
+
export declare const SHEET_SNAP_POINT_VAR = "--sheet-snap-point";
|
|
33
|
+
/**
|
|
34
|
+
* Пружина с критическим затуханием: без перелёта, ~0.35 с.
|
|
35
|
+
* Анимируемые значения — доли (0–1), поэтому пороги покоя мелкие.
|
|
36
|
+
*/
|
|
37
|
+
export declare const SHEET_SPRING: {
|
|
38
|
+
readonly type: "spring";
|
|
39
|
+
readonly stiffness: 400;
|
|
40
|
+
readonly damping: 40;
|
|
41
|
+
readonly restDelta: 0.0005;
|
|
42
|
+
readonly restSpeed: 0.01;
|
|
43
|
+
};
|
|
44
|
+
/** Зоны, за которые можно тянуть Sheet: drag handle и Sheet.Header */
|
|
45
|
+
export declare const SHEET_DRAG_ZONE_SELECTOR: string;
|
|
46
|
+
/**
|
|
47
|
+
* Элементы, нажатие на которые не начинает перетаскивание, даже внутри
|
|
48
|
+
* зоны перетаскивания. `data-sheet-no-drag` позволяет исключить свой элемент.
|
|
49
|
+
*/
|
|
50
|
+
export declare const SHEET_NO_DRAG_SELECTOR: string;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { getDialogPartSelector as t } from "../Dialog/Dialog.const.js";
|
|
2
|
+
const E = {
|
|
3
|
+
bottom: { axis: "y", direction: 1 }
|
|
4
|
+
}, n = {
|
|
5
|
+
x: { client: "clientX", crossClient: "clientY", size: "width" },
|
|
6
|
+
y: { client: "clientY", crossClient: "clientX", size: "height" }
|
|
7
|
+
}, o = 0.4, s = 500, _ = 10, S = 4, T = 100, c = 48, i = 16, H = "--sheet-snap-point", a = {
|
|
8
|
+
type: "spring",
|
|
9
|
+
stiffness: 400,
|
|
10
|
+
damping: 40,
|
|
11
|
+
restDelta: 5e-4,
|
|
12
|
+
restSpeed: 0.01
|
|
13
|
+
}, l = `[data-sheet-handle], ${t("header")}`, r = [
|
|
14
|
+
"button",
|
|
15
|
+
"a[href]",
|
|
16
|
+
"input",
|
|
17
|
+
"select",
|
|
18
|
+
"textarea",
|
|
19
|
+
"[contenteditable]:not([contenteditable='false'])",
|
|
20
|
+
"[role='button']",
|
|
21
|
+
"[role='link']",
|
|
22
|
+
"[data-sheet-no-drag]"
|
|
23
|
+
].join(", ");
|
|
24
|
+
export {
|
|
25
|
+
n as SHEET_AXIS_KEYS,
|
|
26
|
+
o as SHEET_DEFAULT_CLOSE_THRESHOLD,
|
|
27
|
+
S as SHEET_DRAG_START_THRESHOLD,
|
|
28
|
+
l as SHEET_DRAG_ZONE_SELECTOR,
|
|
29
|
+
_ as SHEET_FLICK_MIN_DISTANCE,
|
|
30
|
+
s as SHEET_FLICK_VELOCITY,
|
|
31
|
+
i as SHEET_HANDLE_HEIGHT,
|
|
32
|
+
r as SHEET_NO_DRAG_SELECTOR,
|
|
33
|
+
c as SHEET_OVERDRAG_LIMIT,
|
|
34
|
+
E as SHEET_POSITION_CONFIG,
|
|
35
|
+
H as SHEET_SNAP_POINT_VAR,
|
|
36
|
+
a as SHEET_SPRING,
|
|
37
|
+
T as SHEET_VELOCITY_WINDOW
|
|
38
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { SheetProps } from './Sheet.types';
|
|
2
|
+
/**
|
|
3
|
+
* Панель, выезжающая от края экрана, как bottom sheet в мобильных приложениях.
|
|
4
|
+
* Альтернатива `Modal` с теми же пропсами закрытия и теми же частями:
|
|
5
|
+
* `Sheet.Header`, `Sheet.Main`, `Sheet.Footer` — это `Modal.Header` и т.д.
|
|
6
|
+
*
|
|
7
|
+
* Закрывается свайпом за drag handle или Sheet.Header: при смещении больше
|
|
8
|
+
* `closeThreshold` или быстром свайпе. Размер — по содержимому, на весь экран
|
|
9
|
+
* (`sizeMode`) или по точкам фиксации (`snapPoints`).
|
|
10
|
+
*/
|
|
11
|
+
declare const Sheet: import('react').ForwardRefExoticComponent<SheetProps & import('react').RefAttributes<HTMLDivElement>>;
|
|
12
|
+
export { Sheet };
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { jsx as o } from "react/jsx-runtime";
|
|
2
|
+
import { forwardRef as g, useState as y, useMemo as R, useCallback as _ } from "react";
|
|
3
|
+
import { SHEET_DEFAULT_CLOSE_THRESHOLD as b } from "./Sheet.const.js";
|
|
4
|
+
import { normalizeSnapPoints as z } from "./Sheet.utils.js";
|
|
5
|
+
import { SheetLayer as D } from "./SheetLayer.js";
|
|
6
|
+
import { useBodyScrollLock as H } from "../Dialog/hooks/useBodyScrollLock.js";
|
|
7
|
+
import { useCloseOnEsc as T } from "../Dialog/hooks/useCloseOnEsc.js";
|
|
8
|
+
import { Portal as k } from "../Portal/Portal.js";
|
|
9
|
+
import { DialogContext as v } from "../Dialog/Dialog.context.js";
|
|
10
|
+
import { theme as j } from "../../../utils/theme/index.js";
|
|
11
|
+
const A = g(
|
|
12
|
+
({
|
|
13
|
+
isOpen: t,
|
|
14
|
+
onClose: r,
|
|
15
|
+
position: a = "bottom",
|
|
16
|
+
backgroundColor: l = j.color.fill.bg_primary,
|
|
17
|
+
sizeMode: s = "content",
|
|
18
|
+
snapPoints: f,
|
|
19
|
+
closeThreshold: c = b,
|
|
20
|
+
closeOnBackdropClick: u = !0,
|
|
21
|
+
closeOnEsc: p = !0,
|
|
22
|
+
closeOnDrag: d = !0,
|
|
23
|
+
disableBodyScroll: S = !0,
|
|
24
|
+
showBorders: m = !1,
|
|
25
|
+
...E
|
|
26
|
+
}, h) => {
|
|
27
|
+
const [e, i] = y(t);
|
|
28
|
+
t && !e && i(!0), H(e && S), T(t, p, r);
|
|
29
|
+
const n = z(f), x = n.length ? "snap" : s, L = R(
|
|
30
|
+
() => ({ onClose: r, showBorders: m }),
|
|
31
|
+
[r, m]
|
|
32
|
+
), P = _(() => i(!1), []);
|
|
33
|
+
return e ? /* @__PURE__ */ o(k, { children: /* @__PURE__ */ o(v.Provider, { value: L, children: /* @__PURE__ */ o(
|
|
34
|
+
D,
|
|
35
|
+
{
|
|
36
|
+
...E,
|
|
37
|
+
ref: h,
|
|
38
|
+
isOpen: t,
|
|
39
|
+
onClose: r,
|
|
40
|
+
onExited: P,
|
|
41
|
+
position: a,
|
|
42
|
+
backgroundColor: l,
|
|
43
|
+
sizing: x,
|
|
44
|
+
snapPoints: n,
|
|
45
|
+
closeThreshold: c,
|
|
46
|
+
closeOnBackdropClick: u,
|
|
47
|
+
closeOnDrag: d
|
|
48
|
+
}
|
|
49
|
+
) }) }) : null;
|
|
50
|
+
}
|
|
51
|
+
);
|
|
52
|
+
A.displayName = "Sheet";
|
|
53
|
+
export {
|
|
54
|
+
A as Sheet
|
|
55
|
+
};
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { DialogProps } from '../Dialog';
|
|
2
|
+
/**
|
|
3
|
+
* Край экрана, к которому прижат Sheet. Drag handle отображается на
|
|
4
|
+
* противоположном крае.
|
|
5
|
+
*
|
|
6
|
+
* Пока реализован только `bottom`. Чтобы добавить позицию (`top`, `left`,
|
|
7
|
+
* `right`), расширьте этот тип — TypeScript потребует описать её в
|
|
8
|
+
* `SHEET_POSITION_CONFIG` (ось и направление закрытия) и в `positionStyles`
|
|
9
|
+
* (прижатие к краю, скругления, размеры).
|
|
10
|
+
*/
|
|
11
|
+
export type SheetPosition = "bottom";
|
|
12
|
+
/**
|
|
13
|
+
* Режим размера:
|
|
14
|
+
* - `content` — по содержимому, но не больше плоскости экрана;
|
|
15
|
+
* - `full` — вся плоскость: для `bottom`/`top` вся высота экрана,
|
|
16
|
+
* для `left`/`right` — вся ширина.
|
|
17
|
+
*/
|
|
18
|
+
export type SheetSizeMode = "content" | "full";
|
|
19
|
+
/**
|
|
20
|
+
* Итоговый режим размера с учётом snap-points: если `snapPoints` заданы,
|
|
21
|
+
* размер определяют они, а `sizeMode` не учитывается.
|
|
22
|
+
* @internal
|
|
23
|
+
*/
|
|
24
|
+
export type SheetSizing = SheetSizeMode | "snap";
|
|
25
|
+
/** Ось, вдоль которой Sheet выезжает и перетаскивается. @internal */
|
|
26
|
+
export type SheetAxis = "x" | "y";
|
|
27
|
+
/** Геометрия позиции. @internal */
|
|
28
|
+
export interface SheetPositionConfig {
|
|
29
|
+
/** Ось выезда и перетаскивания */
|
|
30
|
+
axis: SheetAxis;
|
|
31
|
+
/**
|
|
32
|
+
* Направление закрытия вдоль оси: `1` — к концу оси (вниз, вправо),
|
|
33
|
+
* `-1` — к началу (вверх, влево). Drag handle стоит на крае, от которого
|
|
34
|
+
* Sheet уезжает при закрытии: для `1` это начало оси (верхний край у `bottom`).
|
|
35
|
+
*/
|
|
36
|
+
direction: 1 | -1;
|
|
37
|
+
}
|
|
38
|
+
export interface SheetProps extends DialogProps {
|
|
39
|
+
/**
|
|
40
|
+
* Край экрана, к которому прижат Sheet
|
|
41
|
+
* @default "bottom" */
|
|
42
|
+
position?: SheetPosition;
|
|
43
|
+
/**
|
|
44
|
+
* Режим размера: `content` — по содержимому (не больше экрана),
|
|
45
|
+
* `full` — на всю плоскость. Не учитывается, если заданы `snapPoints`.
|
|
46
|
+
* @default "content" */
|
|
47
|
+
sizeMode?: SheetSizeMode;
|
|
48
|
+
/**
|
|
49
|
+
* Точки фиксации размера — доли плоскости экрана в диапазоне (0, 1],
|
|
50
|
+
* например `[0.3, 0.5, 0.7, 1]`. Если заданы, Sheet имеет размер активной
|
|
51
|
+
* точки, при перетаскивании меняет его и при отпускании доводится до
|
|
52
|
+
* ближайшей точки (при быстром свайпе — до соседней по направлению свайпа).
|
|
53
|
+
* Значения вне (0, 1] отбрасываются.
|
|
54
|
+
* @default undefined */
|
|
55
|
+
snapPoints?: number[];
|
|
56
|
+
/**
|
|
57
|
+
* Точка фиксации при открытии
|
|
58
|
+
* @default наименьшая из `snapPoints` */
|
|
59
|
+
defaultSnapPoint?: number;
|
|
60
|
+
/** Callback смены точки фиксации после перетаскивания */
|
|
61
|
+
onSnapPointChange?: (snapPoint: number) => void;
|
|
62
|
+
/**
|
|
63
|
+
* Доля размера Sheet (0–1): если при отпускании Sheet сдвинут к закрытию
|
|
64
|
+
* больше чем на эту долю, он закрывается, иначе возвращается на место.
|
|
65
|
+
* Быстрый свайп закрывает Sheet независимо от порога.
|
|
66
|
+
* @default 0.4 */
|
|
67
|
+
closeThreshold?: number;
|
|
68
|
+
/**
|
|
69
|
+
* Закрывать ли свайпом. При `false` Sheet можно потянуть к закрытию только
|
|
70
|
+
* с сопротивлением, после отпускания он возвращается на место.
|
|
71
|
+
* Перемещение между `snapPoints` остаётся доступным.
|
|
72
|
+
* @default true */
|
|
73
|
+
closeOnDrag?: boolean;
|
|
74
|
+
/**
|
|
75
|
+
* Кастомный класс для панели Sheet
|
|
76
|
+
* @default undefined */
|
|
77
|
+
sheetClassName?: string;
|
|
78
|
+
/**
|
|
79
|
+
* Кастомный класс для зоны drag handle
|
|
80
|
+
* @default undefined */
|
|
81
|
+
handleClassName?: string;
|
|
82
|
+
}
|