@linagora/twake-mui 10.4.0 → 10.5.0

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.
Files changed (40) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/dist/components/BottomSheet/BottomSheet.stories.d.ts +23 -0
  3. package/dist/components/BottomSheet/BottomSheet.stories.js +139 -0
  4. package/dist/components/BottomSheet/BottomSheetHeader.d.ts +9 -0
  5. package/dist/components/BottomSheet/BottomSheetHeader.js +14 -0
  6. package/dist/components/BottomSheet/BottomSheetItem.d.ts +10 -0
  7. package/dist/components/BottomSheet/BottomSheetItem.js +18 -0
  8. package/dist/components/BottomSheet/BottomSheetTitle.d.ts +10 -0
  9. package/dist/components/BottomSheet/BottomSheetTitle.js +20 -0
  10. package/dist/components/BottomSheet/core/BottomSheetCore.d.ts +28 -0
  11. package/dist/components/BottomSheet/core/BottomSheetCore.js +118 -0
  12. package/dist/components/BottomSheet/core/helpers.d.ts +8 -0
  13. package/dist/components/BottomSheet/core/helpers.js +29 -0
  14. package/dist/components/BottomSheet/helpers.d.ts +14 -0
  15. package/dist/components/BottomSheet/helpers.js +95 -0
  16. package/dist/components/BottomSheet/index.d.ts +8 -0
  17. package/dist/components/BottomSheet/index.js +158 -0
  18. package/dist/components/BottomSheet/safeArea.d.ts +3 -0
  19. package/dist/components/BottomSheet/safeArea.js +10 -0
  20. package/dist/components/BottomSheet/styles.d.ts +25 -0
  21. package/dist/components/BottomSheet/styles.js +100 -0
  22. package/dist/components/BottomSheet/types.d.ts +77 -0
  23. package/dist/components/BottomSheet/types.js +1 -0
  24. package/dist/components/ContactPopover/AttendeeInfo.js +3 -3
  25. package/dist/components/ContactPopover/ContactPopoverCalendarAction.js +2 -2
  26. package/dist/components/ContactPopover/ContactPopoverChatAction.js +2 -2
  27. package/dist/components/ContactPopover/ContactPopoverEmailAction.js +2 -2
  28. package/dist/components/ContactPopover/ContactPopoverVideoAction.js +2 -2
  29. package/dist/components/SearchBar/DisableHighlight.js +1 -1
  30. package/dist/components/SearchBar/FocusHighlight.js +1 -1
  31. package/dist/components/SearchBar/SearchBarIconWrapper.js +1 -1
  32. package/dist/components/SearchBar/SearchBarRoot.js +4 -4
  33. package/dist/components/SpaceOverlay/OverlayFrame.js +17 -21
  34. package/dist/components/SpaceOverlay/SpaceOverlay.js +2 -2
  35. package/dist/index.d.ts +16 -1
  36. package/dist/index.js +8 -1
  37. package/dist/lib/overrides.js +21 -19
  38. package/package.json +4 -1
  39. package/dist/components/SpaceOverlay/index.d.ts +0 -8
  40. package/dist/components/SpaceOverlay/index.js +0 -4
@@ -0,0 +1,158 @@
1
+ import { Backdrop, Portal } from '@mui/material';
2
+ import React, { memo, useCallback, useEffect, useRef, useState } from 'react';
3
+ import { useMutationObserver, useTimeoutWhen } from 'rooks';
4
+ import { ANIMATION_DURATION, computeBottomSpacer, computeMaxHeight, computeMediumHeight, computeMinHeight, getCssValue, makeOverriddenChildren, minimizeAndClose, setBottomPosition, setTopPosition } from './helpers';
5
+ import { BORDER_RADIUS, BottomSheetBounceSafer, BottomSheetContainer, BottomSheetHandleBar, BottomSheetIndicator, BottomSheetOffsetSafer, BottomSheetRenderSafer, BottomSheetRenderSaferFill, BottomSheetRoot, BottomSheetSpacer, BottomSheetStack } from './styles';
6
+ /** Shared default, so that effects depending on it do not run on every render */
7
+ const NO_TOOLBAR_PROPS = {};
8
+ const DEFAULT_MEDIUM_HEIGHT_RATIO = 0.75;
9
+ const SPRING_CONFIG = { tension: 165, friction: 17, clamp: true };
10
+ const BottomSheetContent = memo(function BottomSheetContent({ toolbarProps = NO_TOOLBAR_PROPS, settings, backdrop = false, skipAnimation, onClose, offset = 0, children }) {
11
+ const mediumHeight = settings?.mediumHeight ?? null;
12
+ const mediumHeightRatio = settings?.mediumHeightRatio ?? DEFAULT_MEDIUM_HEIGHT_RATIO;
13
+ const isOpenMin = settings?.isOpenMin ?? false;
14
+ const hasMinHeightOffset = settings?.hasMinHeightOffset ?? false;
15
+ const innerContentRef = useRef(null);
16
+ const headerRef = useRef(null);
17
+ const headerContentRef = useRef(null);
18
+ const [isTopPosition, setIsTopPosition] = useState(false);
19
+ const [isBottomPosition, setIsBottomPosition] = useState(false);
20
+ const [isHidden, setIsHidden] = useState(false);
21
+ const [showBackdrop, setShowBackdrop] = useState(backdrop);
22
+ const [peekHeights, setPeekHeights] = useState(null);
23
+ // Starts at the medium stop, the one the initial position is computed from
24
+ const [currentIndex, setCurrentIndex] = useState(1);
25
+ const [bottomSpacerHeight, setBottomSpacerHeight] = useState(0);
26
+ const [initPos, setInitPos] = useState(0);
27
+ const prevInitPos = useRef(0);
28
+ const [forceRender, setForceRender] = useState(0);
29
+ const hasToolbarProps = Object.keys(toolbarProps).length > 0;
30
+ const isClosable = !!onClose || backdrop;
31
+ const renderSaferHeight = initPos < prevInitPos.current ? prevInitPos.current - BORDER_RADIUS : 0;
32
+ const showRenderSafer = prevInitPos.current !== 0 && prevInitPos.current > initPos;
33
+ const overriddenChildren = makeOverriddenChildren(children, headerContentRef);
34
+ if (backdrop && !onClose) {
35
+ throw new Error('BottomSheet must have `onClose` method to work properly when setting `backdrop` to `true`');
36
+ }
37
+ const handleClose = useCallback(() => {
38
+ setShowBackdrop(false);
39
+ setIsHidden(true);
40
+ onClose?.();
41
+ }, [onClose]);
42
+ const handleIndexChange = (snapIndex) => {
43
+ setCurrentIndex(snapIndex);
44
+ setTopPosition({
45
+ snapIndex,
46
+ peekHeights: peekHeights ?? [],
47
+ isTopPosition,
48
+ setIsTopPosition
49
+ });
50
+ setBottomPosition({ snapIndex, isBottomPosition, setIsBottomPosition });
51
+ };
52
+ const handleBackdropClick = () => {
53
+ minimizeAndClose({
54
+ backdrop,
55
+ setCurrentIndex,
56
+ setIsTopPosition,
57
+ setIsBottomPosition,
58
+ handleClose
59
+ });
60
+ };
61
+ // Recomputes the stops when the content changes, after loading or navigating inside it
62
+ useMutationObserver(innerContentRef, () => {
63
+ setForceRender(value => value + 1);
64
+ });
65
+ // Prevents the pull-to-refresh of iOS Safari while dragging the sheet down
66
+ useEffect(() => {
67
+ document.body.style.overflow = 'hidden';
68
+ return () => {
69
+ document.body.style.overflow = 'auto';
70
+ };
71
+ }, []);
72
+ useTimeoutWhen(() => handleClose(), ANIMATION_DURATION, isClosable && isBottomPosition);
73
+ useEffect(() => {
74
+ const headerContent = headerContentRef.current;
75
+ const innerContentHeight = innerContentRef.current?.offsetHeight ?? 0;
76
+ const actionButtonsHeight = getCssValue(headerContent, 'height');
77
+ const actionButtonsBottomMargin = getCssValue(headerContent, 'padding-bottom');
78
+ const maxHeight = computeMaxHeight(toolbarProps);
79
+ const newBottomSpacerHeight = computeBottomSpacer({
80
+ backdrop,
81
+ maxHeight,
82
+ innerContentHeight,
83
+ toolbarProps,
84
+ offset
85
+ });
86
+ const minHeight = computeMinHeight({
87
+ isClosable,
88
+ isOpenMin,
89
+ headerRef,
90
+ offset: hasMinHeightOffset ? offset : 0,
91
+ actionButtonsHeight,
92
+ actionButtonsBottomMargin
93
+ });
94
+ const computedMediumHeight = isOpenMin && actionButtonsHeight > 0
95
+ ? minHeight + 1
96
+ : computeMediumHeight({
97
+ backdrop,
98
+ maxHeight,
99
+ mediumHeight,
100
+ mediumHeightRatio,
101
+ innerContentHeight,
102
+ bottomSpacerHeight: newBottomSpacerHeight,
103
+ offset
104
+ });
105
+ const newPeekHeights = [
106
+ ...new Set([minHeight, computedMediumHeight, maxHeight])
107
+ ];
108
+ const hasPeekHeightsChanged = peekHeights?.toString() !== newPeekHeights.toString();
109
+ // Lowers the sheet when its stops change while it is at the top
110
+ const snapIndex = hasPeekHeightsChanged && isTopPosition
111
+ ? currentIndex - 1 - (currentIndex - (newPeekHeights.length - 1))
112
+ : currentIndex;
113
+ setCurrentIndex(snapIndex);
114
+ setPeekHeights(newPeekHeights);
115
+ prevInitPos.current = initPos;
116
+ setInitPos(computedMediumHeight);
117
+ setTopPosition({
118
+ snapIndex,
119
+ peekHeights: newPeekHeights,
120
+ isTopPosition,
121
+ setIsTopPosition
122
+ });
123
+ // Lets the sheet open up to the top without stopping at the content height
124
+ setBottomSpacerHeight(newBottomSpacerHeight);
125
+ // initPos is left out on purpose: the effect needs its previous value
126
+ // eslint-disable-next-line react-hooks/exhaustive-deps
127
+ }, [
128
+ innerContentRef,
129
+ toolbarProps,
130
+ mediumHeightRatio,
131
+ mediumHeight,
132
+ showBackdrop,
133
+ backdrop,
134
+ isClosable,
135
+ offset,
136
+ forceRender
137
+ ]);
138
+ const content = (React.createElement(React.Fragment, null,
139
+ showBackdrop && React.createElement(Backdrop, { open: true, onClick: handleBackdropClick }),
140
+ React.createElement(BottomSheetRoot, { isTopPosition: isTopPosition, hasToolbar: hasToolbarProps, peekHeights: peekHeights, defaultHeight: initPos, fullHeight: !hasToolbarProps, currentIndex: currentIndex, onIndexChange: handleIndexChange, threshold: 0, springConfig: SPRING_CONFIG, disabledClosing: !onClose, hidden: isHidden, snapPointSeekerMode: "next", skipAnimation: skipAnimation },
141
+ React.createElement("div", { ref: innerContentRef },
142
+ React.createElement(BottomSheetHandleBar, { "data-testid": "bottomSheet-header", ref: headerRef, elevation: 0, square: true },
143
+ React.createElement(BottomSheetIndicator, null)),
144
+ React.createElement(BottomSheetStack, { spacing: 1.5 }, overriddenChildren)),
145
+ React.createElement(BottomSheetSpacer, { spacerHeight: bottomSpacerHeight })),
146
+ showRenderSafer && (React.createElement(BottomSheetRenderSafer, { saferHeight: renderSaferHeight },
147
+ React.createElement(BottomSheetRenderSaferFill, { elevation: 0, square: true }))),
148
+ !isBottomPosition && React.createElement(BottomSheetBounceSafer, null),
149
+ Boolean(offset) && (React.createElement(BottomSheetOffsetSafer, { offset: offset, isBottomPosition: isBottomPosition }))));
150
+ return showBackdrop ? (React.createElement(BottomSheetContainer, null, content)) : (content);
151
+ });
152
+ /**
153
+ * Panel coming up from the bottom of the screen, that the user can drag between a minimum, a
154
+ * medium and a full height. Rendered in a portal, like dialogs.
155
+ */
156
+ const BottomSheet = ({ portalProps, ...props }) => (React.createElement(Portal, { ...portalProps },
157
+ React.createElement(BottomSheetContent, { ...props })));
158
+ export default BottomSheet;
@@ -0,0 +1,3 @@
1
+ import { SafeAreaSide } from './types';
2
+ /** Returns the device safe area inset (notch, home indicator), in px */
3
+ export declare function getSafeAreaInset(side: SafeAreaSide): number;
@@ -0,0 +1,10 @@
1
+ /** Returns the device safe area inset (notch, home indicator), in px */
2
+ export function getSafeAreaInset(side) {
3
+ // env() is only resolved through a style, so a probe element reads it
4
+ const probe = document.createElement('div');
5
+ probe.style.paddingTop = `env(safe-area-inset-${side})`;
6
+ document.body.appendChild(probe);
7
+ const inset = parseFloat(getComputedStyle(probe).paddingTop) || 0;
8
+ probe.remove();
9
+ return inset;
10
+ }
@@ -0,0 +1,25 @@
1
+ import { Theme } from '@mui/material/styles';
2
+ export declare const BORDER_RADIUS = 16;
3
+ export declare const BottomSheetContainer: import("@emotion/styled").StyledComponent<import("@mui/system").MUIStyledCommonProps<Theme>, import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, {}>;
4
+ export declare const BottomSheetRoot: import("@emotion/styled").StyledComponent<import("./core/BottomSheetCore").BottomSheetCoreProps & import("@mui/system").MUIStyledCommonProps<Theme> & {
5
+ isTopPosition: boolean;
6
+ hasToolbar: boolean;
7
+ }, {}, {}>;
8
+ export declare const BottomSheetHandleBar: import("@emotion/styled").StyledComponent<import("@mui/material").PaperOwnProps & import("@mui/material/OverridableComponent").CommonProps & Omit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "style" | "square" | "className" | "elevation" | "children" | "classes" | "sx" | "variant"> & import("@mui/system").MUIStyledCommonProps<Theme>, {}, {}>;
9
+ export declare const BottomSheetIndicator: import("@emotion/styled").StyledComponent<import("@mui/system").MUIStyledCommonProps<Theme>, import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, {}>;
10
+ export declare const BottomSheetStack: import("@emotion/styled").StyledComponent<import("@mui/material").StackOwnProps & import("@mui/material/OverridableComponent").CommonProps & Omit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, keyof import("@mui/material/OverridableComponent").CommonProps | keyof import("@mui/material").StackOwnProps> & import("@mui/system").MUIStyledCommonProps<Theme>, {}, {}>;
11
+ export declare const BottomSheetSpacer: import("@emotion/styled").StyledComponent<import("@mui/system").MUIStyledCommonProps<Theme> & {
12
+ spacerHeight: number;
13
+ }, import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, {}>;
14
+ /** Covers the screen bottom while the sheet bounces up */
15
+ export declare const BottomSheetBounceSafer: import("@emotion/styled").StyledComponent<import("@mui/system").MUIStyledCommonProps<Theme>, import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, {}>;
16
+ /** Covers the offset area below the sheet */
17
+ export declare const BottomSheetOffsetSafer: import("@emotion/styled").StyledComponent<import("@mui/system").MUIStyledCommonProps<Theme> & {
18
+ offset: number;
19
+ isBottomPosition: boolean;
20
+ }, import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, {}>;
21
+ /** Hides the gap left under the sheet while it shrinks to a lower content height */
22
+ export declare const BottomSheetRenderSafer: import("@emotion/styled").StyledComponent<import("@mui/system").MUIStyledCommonProps<Theme> & {
23
+ saferHeight: number;
24
+ }, import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, {}>;
25
+ export declare const BottomSheetRenderSaferFill: import("@emotion/styled").StyledComponent<import("@mui/material").PaperOwnProps & import("@mui/material/OverridableComponent").CommonProps & Omit<import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "style" | "square" | "className" | "elevation" | "children" | "classes" | "sx" | "variant"> & import("@mui/system").MUIStyledCommonProps<Theme>, {}, {}>;
@@ -0,0 +1,100 @@
1
+ import { Paper, Stack } from '@mui/material';
2
+ import { keyframes, styled } from '@mui/material/styles';
3
+ import { BottomSheetCore } from './core/BottomSheetCore';
4
+ import { ANIMATION_DURATION } from './helpers';
5
+ export const BORDER_RADIUS = 16;
6
+ const BOUNCE_SAFER_HEIGHT = 50;
7
+ const fadeIn = keyframes({ from: { opacity: 0 }, to: { opacity: 1 } });
8
+ const collapse = keyframes({ from: { height: '100%' }, to: { height: 0 } });
9
+ export const BottomSheetContainer = styled('div')(({ theme }) => ({
10
+ position: 'fixed',
11
+ zIndex: theme.zIndex.modal,
12
+ inset: 0
13
+ }));
14
+ export const BottomSheetRoot = styled(BottomSheetCore, {
15
+ shouldForwardProp: prop => prop !== 'isTopPosition' && prop !== 'hasToolbar'
16
+ })(({ theme }) => ({
17
+ borderTopLeftRadius: BORDER_RADIUS,
18
+ borderTopRightRadius: BORDER_RADIUS,
19
+ transition: 'border-radius 0.5s',
20
+ boxShadow: '0 -0.5px 0px 0 rgba(0, 0, 0, 0.10), 0 -2px 2px 0 rgba(0, 0, 0, 0.02), 0 -4px 4px 0 rgba(0, 0, 0, 0.02), 0 -8px 8px 0 rgba(0, 0, 0, 0.02), 0 -16px 16px 0 rgba(0, 0, 0, 0.02)',
21
+ backgroundColor: theme.vars.palette.background.paper,
22
+ zIndex: theme.zIndex.modal,
23
+ variants: [
24
+ {
25
+ props: { isTopPosition: true },
26
+ style: {
27
+ borderTopLeftRadius: 0,
28
+ borderTopRightRadius: 0,
29
+ boxShadow: '0 -1px 0 0 rgba(255, 255, 255, 1)'
30
+ }
31
+ },
32
+ {
33
+ props: { isTopPosition: true, hasToolbar: true },
34
+ style: { boxShadow: '0 0 1px 0 rgba(0, 0, 0, 0.5)' }
35
+ }
36
+ ]
37
+ }));
38
+ export const BottomSheetHandleBar = styled(Paper)({
39
+ width: '100%',
40
+ height: '3rem',
41
+ position: 'relative',
42
+ display: 'flex',
43
+ alignItems: 'center',
44
+ justifyContent: 'center'
45
+ });
46
+ export const BottomSheetIndicator = styled('div')(({ theme }) => ({
47
+ width: '4rem',
48
+ height: '0.25rem',
49
+ borderRadius: 99,
50
+ backgroundColor: theme.vars.palette.text.secondary
51
+ }));
52
+ export const BottomSheetStack = styled(Stack)(({ theme }) => ({
53
+ overflow: 'hidden',
54
+ backgroundColor: theme.vars.palette.background.default
55
+ }));
56
+ export const BottomSheetSpacer = styled('div', {
57
+ shouldForwardProp: prop => prop !== 'spacerHeight'
58
+ })(({ spacerHeight }) => ({ height: spacerHeight }));
59
+ /** Covers the screen bottom while the sheet bounces up */
60
+ export const BottomSheetBounceSafer = styled('div')(({ theme }) => ({
61
+ height: BOUNCE_SAFER_HEIGHT,
62
+ width: '100%',
63
+ position: 'fixed',
64
+ bottom: 0,
65
+ left: 0,
66
+ backgroundColor: theme.vars.palette.background.paper,
67
+ animation: `${fadeIn} ${ANIMATION_DURATION}ms ${theme.transitions.easing.easeInOut}`
68
+ }));
69
+ /** Covers the offset area below the sheet */
70
+ export const BottomSheetOffsetSafer = styled('div', {
71
+ shouldForwardProp: prop => prop !== 'offset' && prop !== 'isBottomPosition'
72
+ })(({ theme, offset, isBottomPosition }) => ({
73
+ opacity: isBottomPosition ? 0 : 1,
74
+ height: offset,
75
+ width: '100%',
76
+ position: 'fixed',
77
+ bottom: 0,
78
+ left: 0,
79
+ backgroundColor: theme.vars.palette.background.paper,
80
+ zIndex: theme.zIndex.modal + 10,
81
+ transition: `opacity ${ANIMATION_DURATION}ms`,
82
+ animation: `${fadeIn} ${ANIMATION_DURATION}ms ${theme.transitions.easing.easeInOut}`
83
+ }));
84
+ /** Hides the gap left under the sheet while it shrinks to a lower content height */
85
+ export const BottomSheetRenderSafer = styled('div', {
86
+ shouldForwardProp: prop => prop !== 'saferHeight'
87
+ })(({ saferHeight }) => ({
88
+ height: saferHeight,
89
+ width: '100%',
90
+ position: 'fixed',
91
+ bottom: 0,
92
+ pointerEvents: 'none'
93
+ }));
94
+ export const BottomSheetRenderSaferFill = styled(Paper)({
95
+ position: 'absolute',
96
+ bottom: 0,
97
+ height: 0,
98
+ width: '100%',
99
+ animation: `${collapse} 1s`
100
+ });
@@ -0,0 +1,77 @@
1
+ import { PortalProps } from '@mui/material';
2
+ import React, { RefObject } from 'react';
3
+ export type SafeAreaSide = 'top' | 'bottom';
4
+ export interface BottomSheetToolbarProps {
5
+ /** Ref of the toolbar the sheet must stay under when fully open */
6
+ ref?: RefObject<HTMLElement | null>;
7
+ /** Height of that toolbar, in px, used instead of measuring `ref` */
8
+ height?: number;
9
+ }
10
+ export interface BottomSheetSettings {
11
+ /** Height of the middle stop, in px */
12
+ mediumHeight?: number | null;
13
+ /** Height of the middle stop, as a ratio of the available height */
14
+ mediumHeightRatio?: number;
15
+ /** Includes the offset in the minimum height */
16
+ hasMinHeightOffset?: boolean;
17
+ /** Opens the sheet at its minimum height, when it has a header */
18
+ isOpenMin?: boolean;
19
+ }
20
+ export interface BottomSheetProps {
21
+ /** Toolbar the sheet must stay under when fully open */
22
+ toolbarProps?: BottomSheetToolbarProps;
23
+ settings?: BottomSheetSettings;
24
+ /** Adds a backdrop, which requires `onClose` */
25
+ backdrop?: boolean;
26
+ /** Removes animations */
27
+ skipAnimation?: boolean;
28
+ /** Space kept at the bottom of the sheet, in px */
29
+ offset?: number;
30
+ /** Lets the user close the sheet by swiping it down */
31
+ onClose?: () => void;
32
+ portalProps?: Omit<PortalProps, 'children'>;
33
+ children?: React.ReactNode;
34
+ }
35
+ export type BottomSheetContentProps = Omit<BottomSheetProps, 'portalProps'>;
36
+ export interface MediumHeightParams {
37
+ backdrop: boolean;
38
+ maxHeight: number;
39
+ mediumHeight?: number | null;
40
+ mediumHeightRatio: number;
41
+ innerContentHeight: number;
42
+ bottomSpacerHeight: number;
43
+ offset: number;
44
+ }
45
+ export interface MinHeightParams {
46
+ isClosable: boolean;
47
+ isOpenMin: boolean;
48
+ headerRef: RefObject<HTMLElement | null>;
49
+ offset?: number;
50
+ actionButtonsHeight: number;
51
+ actionButtonsBottomMargin: number;
52
+ }
53
+ export interface TopPositionParams {
54
+ snapIndex: number;
55
+ peekHeights: number[];
56
+ isTopPosition: boolean;
57
+ setIsTopPosition: (isTopPosition: boolean) => void;
58
+ }
59
+ export interface BottomPositionParams {
60
+ snapIndex: number;
61
+ isBottomPosition: boolean;
62
+ setIsBottomPosition: (isBottomPosition: boolean) => void;
63
+ }
64
+ export interface MinimizeAndCloseParams {
65
+ backdrop: boolean;
66
+ setCurrentIndex: (index: number) => void;
67
+ setIsTopPosition: (isTopPosition: boolean) => void;
68
+ setIsBottomPosition: (isBottomPosition: boolean) => void;
69
+ handleClose: () => void;
70
+ }
71
+ export interface BottomSpacerParams {
72
+ backdrop: boolean;
73
+ maxHeight: number;
74
+ innerContentHeight: number;
75
+ toolbarProps?: BottomSheetToolbarProps;
76
+ offset: number;
77
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -1,6 +1,6 @@
1
1
  import { Icon } from '@linagora/twake-icons';
2
2
  import { Copy } from '@linagora/twake-icons';
3
- import { Box, IconButton, Typography, useTheme, alpha } from '@mui/material';
3
+ import { Box, IconButton, Typography, useTheme } from '@mui/material';
4
4
  import React, { useState } from 'react';
5
5
  import { useI18n } from 'twake-i18n';
6
6
  import { Avatar } from '../Avatar';
@@ -28,8 +28,8 @@ export const AttendeeInfo = ({ name, email, onEmailCopy }) => {
28
28
  name && name !== email ? (React.createElement(Typography, { variant: "body1", sx: { fontWeight: 500, wordBreak: 'break-word' } }, name)) : null,
29
29
  React.createElement(Box, { sx: { display: 'flex', alignItems: 'center', gap: 1 } },
30
30
  React.createElement(Typography, { variant: "body2", color: "text.secondary", sx: { wordBreak: 'break-word' } }, email),
31
- React.createElement(IconButton, { size: "small", onClick: () => void handleCopy(), sx: { p: 0.5, color: alpha(theme.palette.grey[900], 0.9) }, title: showCopied
31
+ React.createElement(IconButton, { size: "small", onClick: () => void handleCopy(), sx: { p: 0.5, color: 'text.primary' }, title: showCopied
32
32
  ? t('ContactPopover.copiedTooltip')
33
33
  : t('ContactPopover.copyTooltip') },
34
- React.createElement(Icon, { icon: Copy, size: 16, color: theme.palette.text.icon }))))));
34
+ React.createElement(Icon, { icon: Copy, size: 16, color: theme.vars.palette.text.icon }))))));
35
35
  };
@@ -4,6 +4,6 @@ import { IconButton, useTheme } from '@mui/material';
4
4
  import React from 'react';
5
5
  export const ContactPopoverCalendarAction = ({ url, disabled = false }) => {
6
6
  const theme = useTheme();
7
- return (React.createElement(IconButton, { href: url, target: "_blank", rel: "noopener noreferrer", size: "small", disabled: disabled, sx: { border: `1px solid ${theme.palette.divider}` } },
8
- React.createElement(Icon, { icon: CalendarToday, size: 20, color: theme.palette.text.icon })));
7
+ return (React.createElement(IconButton, { href: url, target: "_blank", rel: "noopener noreferrer", size: "small", disabled: disabled, sx: { border: `1px solid ${theme.vars.palette.divider}` } },
8
+ React.createElement(Icon, { icon: CalendarToday, size: 20, color: theme.vars.palette.text.icon })));
9
9
  };
@@ -4,6 +4,6 @@ import { IconButton, useTheme } from '@mui/material';
4
4
  import React from 'react';
5
5
  export const ContactPopoverChatAction = ({ url, disabled = false }) => {
6
6
  const theme = useTheme();
7
- return (React.createElement(IconButton, { href: url, target: "_blank", rel: "noopener noreferrer", size: "small", disabled: disabled, sx: { border: `1px solid ${theme.palette.divider}` } },
8
- React.createElement(Icon, { icon: Discuss, size: 20, color: theme.palette.text.icon })));
7
+ return (React.createElement(IconButton, { href: url, target: "_blank", rel: "noopener noreferrer", size: "small", disabled: disabled, sx: { border: `1px solid ${theme.vars.palette.divider}` } },
8
+ React.createElement(Icon, { icon: Discuss, size: 20, color: theme.vars.palette.text.icon })));
9
9
  };
@@ -6,7 +6,7 @@ export const ContactPopoverEmailAction = ({ url, disabled = false }) => {
6
6
  const { t } = useI18n();
7
7
  return (React.createElement(Button, { href: url, target: "_blank", rel: "noopener noreferrer", variant: "outlined", size: "small", disabled: disabled, sx: {
8
8
  justifyContent: 'center',
9
- color: theme.palette.text.primary,
10
- borderColor: theme.palette.divider
9
+ color: theme.vars.palette.text.primary,
10
+ borderColor: theme.vars.palette.divider
11
11
  } }, t('ContactPopover.emailButton')));
12
12
  };
@@ -4,6 +4,6 @@ import { IconButton, useTheme } from '@mui/material';
4
4
  import React from 'react';
5
5
  export const ContactPopoverVideoAction = ({ url, disabled = false }) => {
6
6
  const theme = useTheme();
7
- return (React.createElement(IconButton, { href: url, target: "_blank", rel: "noopener noreferrer", size: "small", disabled: disabled, sx: { border: `1px solid ${theme.palette.divider}` } },
8
- React.createElement(Icon, { icon: Camera, size: 20, color: theme.palette.text.icon })));
7
+ return (React.createElement(IconButton, { href: url, target: "_blank", rel: "noopener noreferrer", size: "small", disabled: disabled, sx: { border: `1px solid ${theme.vars.palette.divider}` } },
8
+ React.createElement(Icon, { icon: Camera, size: 20, color: theme.vars.palette.text.icon })));
9
9
  };
@@ -1,5 +1,5 @@
1
1
  import { styled } from '@mui/material';
2
2
  import { Highlight } from './Highlight';
3
3
  export const DisableHighlight = styled(Highlight)(({ theme }) => ({
4
- backgroundColor: theme.palette.action.disabled
4
+ backgroundColor: theme.vars.palette.action.disabled
5
5
  }));
@@ -2,5 +2,5 @@ import { styled } from '@mui/material';
2
2
  import { Highlight } from './Highlight';
3
3
  export const FocusHighlight = styled(Highlight)(({ theme }) => ({
4
4
  pointerEvents: 'none',
5
- backgroundColor: theme.palette.action.hover
5
+ backgroundColor: theme.vars.palette.action.hover
6
6
  }));
@@ -1,6 +1,6 @@
1
1
  import { styled } from '@mui/material';
2
2
  export const SearchBarIconWrapper = styled('div')(({ theme }) => ({
3
- color: theme.palette.text.secondary,
3
+ color: theme.vars.palette.text.secondary,
4
4
  padding: '0 1rem',
5
5
  display: 'flex'
6
6
  }));
@@ -15,10 +15,10 @@ export const SearchBarRoot = styled(Paper, {
15
15
  borderStyle: 'solid',
16
16
  borderWidth: 1,
17
17
  paddingRight: '0.5rem',
18
- borderColor: isFocused ? theme.palette.primary.main : 'transparent',
18
+ borderColor: isFocused ? theme.vars.palette.primary.main : 'transparent',
19
19
  backgroundColor: isFocused
20
- ? theme.palette.background.paper
21
- : theme.palette.background.default,
20
+ ? theme.vars.palette.background.paper
21
+ : theme.vars.palette.background.default,
22
22
  transition: theme.transitions.create(['border-color', 'background-color']),
23
23
  '&:hover': {
24
24
  '&:not(.Mui-disabled):not(.SearchBar-focused)': {
@@ -29,7 +29,7 @@ export const SearchBarRoot = styled(Paper, {
29
29
  },
30
30
  '&.Mui-disabled': {
31
31
  '& .SearchBar-icon': {
32
- color: theme.palette.text.disabled
32
+ color: theme.vars.palette.text.disabled
33
33
  },
34
34
  '& .SearchBar-disableHighlight': {
35
35
  opacity: 1
@@ -1,24 +1,20 @@
1
- import { Box } from '@mui/material';
2
- import React, { useLayoutEffect, useRef } from 'react';
3
- import { createPortal } from 'react-dom';
1
+ import { Box, Portal } from '@mui/material';
2
+ import React from 'react';
4
3
  export const OverlayFrame = ({ name, src, title, sandbox, allow, clipPath }) => {
5
- const ref = useRef(null);
6
4
  const empty = clipPath.startsWith('inset(');
7
- // Set by hand: it changes with every move of a menu, a class per value
8
- // would pile up.
9
- useLayoutEffect(() => {
10
- if (ref.current)
11
- ref.current.style.clipPath = clipPath;
12
- }, [clipPath, ref]);
13
- return createPortal(React.createElement(Box, { component: "iframe", ref: ref, name: name, src: src, title: title, sandbox: sandbox, allow: allow, "aria-hidden": empty || undefined, tabIndex: empty ? -1 : undefined, sx: {
14
- position: 'fixed',
15
- inset: 0,
16
- width: '100%',
17
- height: '100%',
18
- border: 0,
19
- background: 'transparent',
20
- // A frame whose colour scheme differs from the page is painted opaque
21
- colorScheme: 'normal',
22
- zIndex: theme => theme.zIndex.modal - 1
23
- } }), document.body);
5
+ return (React.createElement(Portal, null,
6
+ React.createElement(Box, { component: "iframe", name: name, src: src, title: title, sandbox: sandbox, allow: allow, "aria-hidden": empty || undefined, tabIndex: empty ? -1 : undefined,
7
+ // Inline: it changes with every move of a menu, a class per value
8
+ // would pile up
9
+ style: { clipPath }, sx: {
10
+ position: 'fixed',
11
+ inset: 0,
12
+ width: '100%',
13
+ height: '100%',
14
+ border: 0,
15
+ background: 'transparent',
16
+ // A frame whose colour scheme differs from the page is painted opaque
17
+ colorScheme: 'normal',
18
+ zIndex: theme => theme.zIndex.modal - 1
19
+ } })));
24
20
  };
@@ -1,5 +1,5 @@
1
+ import { Portal } from '@mui/material';
1
2
  import React, { createContext, useContext, useSyncExternalStore } from 'react';
2
- import { createPortal } from 'react-dom';
3
3
  const SpaceOverlayContext = createContext(null);
4
4
  export const SpaceOverlayProvider = ({ overlay, children }) => (React.createElement(SpaceOverlayContext.Provider, { value: overlay }, children));
5
5
  const NO_OVERLAY = () => () => undefined;
@@ -31,7 +31,7 @@ export const OverlayPortal = ({ children }) => {
31
31
  if (status === 'connecting')
32
32
  return null;
33
33
  const body = status === 'connected' ? (overlay?.getBody() ?? null) : null;
34
- return React.createElement(React.Fragment, null, body === null ? children : createPortal(children, body));
34
+ return (React.createElement(Portal, { container: body, disablePortal: body === null }, children));
35
35
  };
36
36
  /**
37
37
  * Theme options sending every dialog and temporary drawer to the overlay, so
package/dist/index.d.ts CHANGED
@@ -8,6 +8,10 @@ export { radius } from './lib/radius';
8
8
  export { TwakeMuiThemeProvider } from './components/ThemeProvider';
9
9
  export { Avatar, default as AvatarDefault } from './components/Avatar';
10
10
  export { Button, default as ButtonDefault } from './components/Button';
11
+ export { default as BottomSheet } from './components/BottomSheet';
12
+ export { default as BottomSheetItem } from './components/BottomSheet/BottomSheetItem';
13
+ export { default as BottomSheetHeader } from './components/BottomSheet/BottomSheetHeader';
14
+ export { default as BottomSheetTitle } from './components/BottomSheet/BottomSheetTitle';
11
15
  export { default as Chip } from './components/Chip';
12
16
  export { Dialog, default as DialogDefault } from './components/Dialog';
13
17
  export { ContactPopover, default as ContactPopoverDefault } from './components/ContactPopover';
@@ -41,11 +45,18 @@ export { default as AccordionExpandIcon } from './components/AccordionExpandIcon
41
45
  export { default as VirtualizedTable } from './components/VirtualizedTable';
42
46
  export { VirtuosoMockContext } from 'react-virtuoso';
43
47
  export { useBreakpoints } from './hooks/useBreakpoints';
44
- export * from './components/SpaceOverlay';
48
+ export { connectSpaceOverlay, computeOverlayRegion } from './components/SpaceOverlay/spaceOverlay';
49
+ export { OverlayPortal, SpaceOverlayProvider, overlayThemeOptions, useOverlayWindow } from './components/SpaceOverlay/SpaceOverlay';
50
+ export { overlayClipPath, overlayRegionMessage, parseOverlayRegion, parseOverlayRegionMessage } from './components/SpaceOverlay/region';
51
+ export { OverlayFrame } from './components/SpaceOverlay/OverlayFrame';
45
52
  export type { TwakeTheme } from './lib/theme';
46
53
  export type { PaletteJson } from './lib/types';
47
54
  export type { AvatarProps } from './components/Avatar';
48
55
  export type { ButtonProps } from './components/Button';
56
+ export type { BottomSheetProps, BottomSheetSettings, BottomSheetToolbarProps } from './components/BottomSheet/types';
57
+ export type { BottomSheetItemProps } from './components/BottomSheet/BottomSheetItem';
58
+ export type { BottomSheetHeaderProps } from './components/BottomSheet/BottomSheetHeader';
59
+ export type { BottomSheetTitleProps } from './components/BottomSheet/BottomSheetTitle';
49
60
  export type { ContactPopoverProps } from './components/ContactPopover';
50
61
  export { ContactPopoverActions, ContactPopoverChatAction, ContactPopoverVideoAction, ContactPopoverCalendarAction, ContactPopoverEmailAction } from './components/ContactPopover';
51
62
  export type { ContactPopoverActionsProps } from './components/ContactPopover/ContactPopoverActions';
@@ -54,6 +65,10 @@ export type { ContactPopoverVideoActionProps } from './components/ContactPopover
54
65
  export type { ContactPopoverCalendarActionProps } from './components/ContactPopover/ContactPopoverCalendarAction';
55
66
  export type { ContactPopoverEmailActionProps } from './components/ContactPopover/ContactPopoverEmailAction';
56
67
  export type { ChipProps } from './components/Chip';
68
+ export type { SpaceOverlay, SpaceOverlayStatus } from './components/SpaceOverlay/spaceOverlay';
69
+ export type { SpaceOverlayProviderProps } from './components/SpaceOverlay/SpaceOverlay';
70
+ export type { OverlayBox, OverlayRegion } from './components/SpaceOverlay/region';
71
+ export type { OverlayFrameProps } from './components/SpaceOverlay/OverlayFrame';
57
72
  export type { DialogProps, DialogSize } from './components/Dialog';
58
73
  export type { PointerAlertProps, PointerAlertDirection } from './components/PointerAlert';
59
74
  export type { EmptyProps, EmptyIconSize, EmptyComponentsProps } from './components/Empty';
package/dist/index.js CHANGED
@@ -11,6 +11,10 @@ export { radius } from './lib/radius';
11
11
  export { TwakeMuiThemeProvider } from './components/ThemeProvider';
12
12
  export { Avatar, default as AvatarDefault } from './components/Avatar';
13
13
  export { Button, default as ButtonDefault } from './components/Button';
14
+ export { default as BottomSheet } from './components/BottomSheet';
15
+ export { default as BottomSheetItem } from './components/BottomSheet/BottomSheetItem';
16
+ export { default as BottomSheetHeader } from './components/BottomSheet/BottomSheetHeader';
17
+ export { default as BottomSheetTitle } from './components/BottomSheet/BottomSheetTitle';
14
18
  export { default as Chip } from './components/Chip';
15
19
  export { Dialog, default as DialogDefault } from './components/Dialog';
16
20
  export { ContactPopover, default as ContactPopoverDefault } from './components/ContactPopover';
@@ -44,5 +48,8 @@ export { default as AccordionExpandIcon } from './components/AccordionExpandIcon
44
48
  export { default as VirtualizedTable } from './components/VirtualizedTable';
45
49
  export { VirtuosoMockContext } from 'react-virtuoso';
46
50
  export { useBreakpoints } from './hooks/useBreakpoints';
47
- export * from './components/SpaceOverlay';
51
+ export { connectSpaceOverlay, computeOverlayRegion } from './components/SpaceOverlay/spaceOverlay';
52
+ export { OverlayPortal, SpaceOverlayProvider, overlayThemeOptions, useOverlayWindow } from './components/SpaceOverlay/SpaceOverlay';
53
+ export { overlayClipPath, overlayRegionMessage, parseOverlayRegion, parseOverlayRegionMessage } from './components/SpaceOverlay/region';
54
+ export { OverlayFrame } from './components/SpaceOverlay/OverlayFrame';
48
55
  export { ContactPopoverActions, ContactPopoverChatAction, ContactPopoverVideoAction, ContactPopoverCalendarAction, ContactPopoverEmailAction } from './components/ContactPopover';