cozy-ui 60.3.0 → 60.4.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.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,11 @@
1
+ # [60.4.0](https://github.com/cozy/cozy-ui/compare/v60.3.0...v60.4.0) (2022-01-20)
2
+
3
+
4
+ ### Features
5
+
6
+ * Add new BottomSheet component ([7064202](https://github.com/cozy/cozy-ui/commit/7064202))
7
+ * Replace the Viewer BottomSheet by the new one ([184b5af](https://github.com/cozy/cozy-ui/commit/184b5af))
8
+
1
9
  # [60.3.0](https://github.com/cozy/cozy-ui/compare/v60.2.0...v60.3.0) (2022-01-19)
2
10
 
3
11
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cozy-ui",
3
- "version": "60.3.0",
3
+ "version": "60.4.0",
4
4
  "description": "Cozy apps UI SDK",
5
5
  "main": "./index.js",
6
6
  "bin": {
@@ -0,0 +1,190 @@
1
+ import React, { useState, useEffect, useRef, useMemo } from 'react'
2
+ import PropTypes from 'prop-types'
3
+ import { BottomSheet as MuiBottomSheet } from 'mui-bottom-sheet'
4
+
5
+ import Stack from 'cozy-ui/transpiled/react/Stack'
6
+ import Paper from 'cozy-ui/transpiled/react/Paper'
7
+
8
+ const makeStyles = ({ isTopPosition }) => ({
9
+ root: {
10
+ borderTopLeftRadius: '1rem',
11
+ borderTopRightRadius: '1rem',
12
+ transition: 'border-radius 0.5s',
13
+ zIndex: 'var(--zIndex-drawer)',
14
+ boxShadow: '0 6px 16px 0 rgba(0, 0, 0, 0.5)',
15
+ backgroundColor: 'var(--paperBackgroundColor)',
16
+ ...(isTopPosition && {
17
+ borderTopLeftRadius: 0,
18
+ borderTopRightRadius: 0,
19
+ boxShadow: '0 0 1px 0 rgba(0, 0, 0, 0.5)'
20
+ })
21
+ },
22
+ indicator: {
23
+ width: '4rem',
24
+ height: '0.25rem',
25
+ borderRadius: '99px',
26
+ backgroundColor: 'var(--secondaryTextColor)'
27
+ },
28
+ stack: {
29
+ backgroundColor: 'var(--defaultBackgroundColor)'
30
+ }
31
+ })
32
+
33
+ export const defaultBottomSheetSpringConfig = {
34
+ tension: 165,
35
+ friction: 17,
36
+ clamp: true
37
+ }
38
+
39
+ const defaultSettings = {
40
+ mediumHeightRatio: 0.33
41
+ }
42
+
43
+ const computeMaxHeight = toolbarProps => {
44
+ const { ref, height } = toolbarProps
45
+ let computedToolbarHeight = 1
46
+
47
+ if (height) {
48
+ computedToolbarHeight = height
49
+ } else if (ref && ref.current) {
50
+ computedToolbarHeight = ref.current.offsetHeight
51
+ }
52
+
53
+ return window.innerHeight - computedToolbarHeight
54
+ }
55
+
56
+ const BottomSheet = ({ toolbarProps, settings, children }) => {
57
+ const innerContentRef = useRef()
58
+ const headerRef = useRef()
59
+ const headerContentRef = useRef()
60
+ const [isTopPosition, setIsTopPosition] = useState(false)
61
+ const [peekHeights, setPeekHeights] = useState(null)
62
+ const [initPos, setInitPos] = useState(null)
63
+ const [bottomSpacerHeight, setBottomSpacerHeight] = useState(0)
64
+
65
+ const { mediumHeightRatio } = useMemo(() => settings || defaultSettings, [
66
+ settings
67
+ ])
68
+ const styles = useMemo(() => makeStyles({ isTopPosition }), [isTopPosition])
69
+
70
+ // hack to prevent pull-down-to-refresh behavior when dragging down the bottom sheet.
71
+ // Needed for iOS Safari
72
+ useEffect(() => {
73
+ document.body.style.overflow = 'hidden'
74
+ return () => {
75
+ document.body.style.overflow = 'auto'
76
+ }
77
+ }, [])
78
+
79
+ useEffect(() => {
80
+ const headerContent = headerContentRef.current
81
+ const maxHeight = computeMaxHeight(toolbarProps)
82
+ const mediumHeight = Math.round(maxHeight * mediumHeightRatio)
83
+
84
+ const actionButtonsHeight = headerContent
85
+ ? parseFloat(getComputedStyle(headerContent).getPropertyValue('height'))
86
+ : 0
87
+ const actionButtonsBottomMargin = headerContent
88
+ ? parseFloat(
89
+ getComputedStyle(headerContent).getPropertyValue('padding-bottom')
90
+ )
91
+ : 0
92
+ const minHeight =
93
+ headerRef.current.offsetHeight +
94
+ actionButtonsHeight +
95
+ actionButtonsBottomMargin
96
+
97
+ // Used so that the bottomSheet can be opened to the top,
98
+ // without stopping at the content height
99
+ const bottomSpacerHeight = maxHeight - innerContentRef.current.offsetHeight
100
+
101
+ setPeekHeights([minHeight, mediumHeight, maxHeight])
102
+ setInitPos(mediumHeight)
103
+ setBottomSpacerHeight(bottomSpacerHeight)
104
+ }, [
105
+ innerContentRef,
106
+ headerContentRef.current,
107
+ toolbarProps,
108
+ mediumHeightRatio
109
+ ])
110
+
111
+ const handleOnIndexChange = snapIndex => {
112
+ const maxHeightSnapIndex = peekHeights.length - 1
113
+
114
+ if (snapIndex === maxHeightSnapIndex && !isTopPosition) {
115
+ setIsTopPosition(true)
116
+ }
117
+ if (snapIndex !== maxHeightSnapIndex && isTopPosition) {
118
+ setIsTopPosition(false)
119
+ }
120
+ }
121
+
122
+ const overriddenChildren = React.Children.map(children, child => {
123
+ if (child.type.name === 'BottomSheetHeader') {
124
+ return React.cloneElement(child, { headerContentRef })
125
+ }
126
+ return child
127
+ })
128
+
129
+ return (
130
+ <MuiBottomSheet
131
+ peekHeights={peekHeights}
132
+ defaultHeight={initPos}
133
+ backdrop={false}
134
+ fullHeight={false}
135
+ onIndexChange={snapIndex => handleOnIndexChange(snapIndex)}
136
+ styles={{ root: styles.root }}
137
+ threshold={0}
138
+ // springConfig doc : https://www.react-spring.io/docs/hooks/api
139
+ springConfig={{
140
+ tension: defaultBottomSheetSpringConfig.tension,
141
+ friction: defaultBottomSheetSpringConfig.friction,
142
+ clamp: defaultBottomSheetSpringConfig.clamp
143
+ }}
144
+ disabledClosing={true}
145
+ snapPointSeekerMode="next"
146
+ >
147
+ <div ref={innerContentRef}>
148
+ <Paper
149
+ data-testid="bottomSheet-header"
150
+ className="u-w-100 u-h-2-half u-pos-relative u-flex u-flex-items-center u-flex-justify-center"
151
+ ref={headerRef}
152
+ elevation={0}
153
+ square
154
+ >
155
+ <div style={styles.indicator} />
156
+ </Paper>
157
+ <Stack
158
+ style={styles.stack}
159
+ className="u-flex u-flex-column u-ov-hidden"
160
+ spacing="s"
161
+ >
162
+ {overriddenChildren}
163
+ </Stack>
164
+ </div>
165
+ <div style={{ height: bottomSpacerHeight }} />
166
+ </MuiBottomSheet>
167
+ )
168
+ }
169
+
170
+ BottomSheet.defaultProps = {
171
+ classes: {},
172
+ toolbarProps: {}
173
+ }
174
+
175
+ BottomSheet.propTypes = {
176
+ /** Toolbar properties */
177
+ toolbarProps: PropTypes.shape({
178
+ /** React reference of the toolbar node */
179
+ ref: PropTypes.bool,
180
+ /** Toolbar height value */
181
+ height: PropTypes.func
182
+ }),
183
+ /** Settings that can be modified */
184
+ settings: PropTypes.shape({
185
+ /** Height of the middle snap point, expressed as a percentage of the viewport height */
186
+ mediumHeightRatio: PropTypes.number
187
+ })
188
+ }
189
+
190
+ export default React.memo(BottomSheet)
@@ -0,0 +1,23 @@
1
+ import React from 'react'
2
+ import cx from 'classnames'
3
+
4
+ import Paper from 'cozy-ui/transpiled/react/Paper'
5
+
6
+ const BottomSheetHeader = ({ className, headerContentRef, children }) => {
7
+ return (
8
+ <Paper
9
+ ref={headerContentRef}
10
+ className={cx('u-flex u-flex-items-center', className)}
11
+ elevation={0}
12
+ square
13
+ >
14
+ {children}
15
+ </Paper>
16
+ )
17
+ }
18
+
19
+ BottomSheetHeader.defaultProps = {
20
+ classes: {}
21
+ }
22
+
23
+ export default BottomSheetHeader
@@ -0,0 +1,35 @@
1
+ import React from 'react'
2
+ import PropTypes from 'prop-types'
3
+ import cx from 'classnames'
4
+
5
+ import Paper from 'cozy-ui/transpiled/react/Paper'
6
+
7
+ const BottomSheetItem = ({
8
+ children,
9
+ disableGutters,
10
+ disableElevation,
11
+ className,
12
+ ...props
13
+ }) => {
14
+ return (
15
+ <Paper
16
+ elevation={disableElevation ? 0 : 0} // need to set correct shadow values before setting a real elevation value
17
+ square
18
+ className={cx({ 'u-p-1': !disableGutters }, className)}
19
+ {...props}
20
+ >
21
+ {children}
22
+ </Paper>
23
+ )
24
+ }
25
+
26
+ BottomSheetItem.propTypes = {
27
+ /** CSS classes */
28
+ className: PropTypes.string,
29
+ /** Disables default padding */
30
+ disableGutters: PropTypes.bool,
31
+ /** Disables default paper elevation */
32
+ disableElevation: PropTypes.bool
33
+ }
34
+
35
+ export default React.memo(BottomSheetItem)
@@ -0,0 +1,33 @@
1
+ Displays content coming up from the bottom of the screen. The pane can be swiped to the top of the screen.
2
+
3
+ ```jsx
4
+ import BottomSheet, { BottomSheetItem, BottomSheetHeader } from 'cozy-ui/transpiled/react/BottomSheet'
5
+ import Button from 'cozy-ui/transpiled/react/Buttons'
6
+
7
+ // <-- only usefull for the documentation
8
+ initialState = { isBottomSheetDisplayed: isTesting() }
9
+ const showBottomSheet = () => setState({ isBottomSheetDisplayed: true })
10
+
11
+ const settings = { mediumHeightRatio: isTesting() ? 0.90 : 0.33 }
12
+ // -->
13
+
14
+ ;
15
+
16
+ <>
17
+ <Button label="Open BottomSheet" onClick={showBottomSheet} />
18
+ {state.isBottomSheetDisplayed && (
19
+ <BottomSheet settings={settings}>
20
+ <BottomSheetHeader className="u-ph-1 u-pb-1">
21
+ <Button className="u-mr-half" variant="secondary" label="Button 1" fullWidth />
22
+ <Button variant="secondary" label="Button 2" fullWidth />
23
+ </BottomSheetHeader>
24
+ <BottomSheetItem>
25
+ {content.ada.short}
26
+ </BottomSheetItem>
27
+ <BottomSheetItem disableElevation>
28
+ {content.ada.long}
29
+ </BottomSheetItem>
30
+ </BottomSheet>
31
+ )}
32
+ </>
33
+ ```
@@ -0,0 +1,3 @@
1
+ export { default } from './BottomSheet'
2
+ export { default as BottomSheetItem } from './BottomSheetItem'
3
+ export { default as BottomSheetHeader } from './BottomSheetHeader'
@@ -1,64 +1,26 @@
1
- import React, { forwardRef } from 'react'
1
+ import React from 'react'
2
2
  import PropTypes from 'prop-types'
3
- import cx from 'classnames'
4
- import { makeStyles } from '@material-ui/core/styles'
5
3
 
6
- import { isMobileApp } from 'cozy-device-helper'
4
+ import { BottomSheetItem } from '../../BottomSheet'
7
5
 
8
- import Paper from '../../Paper'
9
- import Typography from '../../Typography'
10
- import Stack from '../../Stack'
11
-
12
- import Sharing from './Sharing'
13
- import ForwardButton from './ForwardButton'
14
- import DownloadButton from './DownloadButton'
15
6
  import getPanelBlocks, { panelBlocksSpecs } from '../Panel/getPanelBlocks'
16
7
 
17
- const useStyles = makeStyles(theme => ({
18
- stack: {
19
- backgroundColor: theme.palette.background.default
20
- }
21
- }))
22
-
23
- const BottomSheetContent = forwardRef(
24
- ({ file, disableSharing, contactsFullname }, ref) => {
25
- const panelBlocks = getPanelBlocks({ panelBlocksSpecs, file })
26
- const FileActionButton = isMobileApp() ? ForwardButton : DownloadButton
27
- const styles = useStyles()
28
-
29
- return (
30
- <Stack
31
- spacing="s"
32
- className={cx('u-flex u-flex-column u-ov-hidden', styles.stack)}
33
- >
34
- <Paper
35
- className={'u-flex u-ph-1 u-pb-1'}
36
- elevation={2}
37
- square
38
- ref={ref}
39
- >
40
- {!disableSharing && <Sharing file={file} />}
41
- <FileActionButton file={file} />
42
- </Paper>
43
- {panelBlocks.map((PanelBlock, index) => (
44
- <Paper
45
- key={index}
46
- elevation={index === panelBlocks.length - 1 ? 0 : 2}
47
- square
48
- >
49
- <Typography variant="h4" className={'u-pv-1 u-ph-1'}>
50
- <PanelBlock file={file} contactsFullname={contactsFullname} />
51
- </Typography>
52
- </Paper>
53
- ))}
54
- </Stack>
55
- )
56
- }
57
- )
8
+ const BottomSheetContent = ({ file, contactsFullname }) => {
9
+ const panelBlocks = getPanelBlocks({ panelBlocksSpecs, file })
10
+
11
+ return panelBlocks.map((PanelBlock, index) => (
12
+ <BottomSheetItem
13
+ key={index}
14
+ disableElevation={index === panelBlocks.length - 1}
15
+ >
16
+ <PanelBlock file={file} contactsFullname={contactsFullname} />
17
+ </BottomSheetItem>
18
+ ))
19
+ }
58
20
 
59
21
  BottomSheetContent.propTypes = {
60
22
  file: PropTypes.object.isRequired,
61
- disableSharing: PropTypes.bool
23
+ contactsFullname: PropTypes.string
62
24
  }
63
25
 
64
26
  export default BottomSheetContent
@@ -1,16 +1,17 @@
1
- import React, { useRef } from 'react'
1
+ import React, { useMemo } from 'react'
2
2
  import PropTypes from 'prop-types'
3
3
  import { makeStyles } from '@material-ui/core/styles'
4
4
 
5
5
  import { isMobileApp } from 'cozy-device-helper'
6
6
  import { getReferencedBy, useQuery, models } from 'cozy-client'
7
7
 
8
+ import BottomSheet, { BottomSheetHeader } from '../../BottomSheet'
9
+
8
10
  import { buildContactByIdsQuery } from '../queries'
9
11
  import { isValidForPanel } from '../helpers'
10
12
  import Sharing from './Sharing'
11
13
  import ForwardButton from './ForwardButton'
12
14
  import DownloadButton from './DownloadButton'
13
- import BottomSheetWrapper from './BottomSheetWrapper'
14
15
  import BottomSheetContent from './BottomSheetContent'
15
16
 
16
17
  const {
@@ -32,7 +33,7 @@ const useStyles = makeStyles(theme => ({
32
33
  const FooterContent = ({ file, toolbarRef, disableSharing }) => {
33
34
  const styles = useStyles()
34
35
  const FileActionButton = isMobileApp() ? ForwardButton : DownloadButton
35
- const actionButtonsRef = useRef()
36
+ const toolbarProps = useMemo(() => ({ ref: toolbarRef }), [toolbarRef])
36
37
 
37
38
  const contactIds = getReferencedBy(file, 'io.cozy.contacts').map(
38
39
  ref => ref.id
@@ -52,18 +53,13 @@ const FooterContent = ({ file, toolbarRef, disableSharing }) => {
52
53
  (contactsFullname || contactIds.length === 0)
53
54
  ) {
54
55
  return (
55
- <BottomSheetWrapper
56
- file={file}
57
- actionButtonsRef={actionButtonsRef}
58
- toolbarRef={toolbarRef}
59
- >
60
- <BottomSheetContent
61
- file={file}
62
- disableSharing={disableSharing}
63
- contactsFullname={contactsFullname}
64
- ref={actionButtonsRef}
65
- />
66
- </BottomSheetWrapper>
56
+ <BottomSheet toolbarProps={toolbarProps}>
57
+ <BottomSheetHeader className="u-ph-1 u-pb-1">
58
+ {!disableSharing && <Sharing file={file} />}
59
+ <FileActionButton file={file} />
60
+ </BottomSheetHeader>
61
+ <BottomSheetContent file={file} contactsFullname={contactsFullname} />
62
+ </BottomSheet>
67
63
  )
68
64
  }
69
65
 
@@ -31,7 +31,6 @@ import Overlay from 'cozy-ui/transpiled/react/Overlay';
31
31
  import Button from 'cozy-ui/transpiled/react/Button';
32
32
  import DownloadIcon from 'cozy-ui/transpiled/react/Icons/Download';
33
33
  import ShareIcon from 'cozy-ui/transpiled/react/Icons/Share';
34
- import BottomSheetWrapper from 'cozy-ui/transpiled/react/Viewer/Footer/BottomSheetWrapper';
35
34
  import { isValidForPanel } from 'cozy-ui/transpiled/react/Viewer/helpers';
36
35
  import getPanelBlocks, { panelBlocksSpecs } from 'cozy-ui/transpiled/react/Viewer/Panel/getPanelBlocks';
37
36
 
package/react/index.js CHANGED
@@ -99,3 +99,4 @@ export { default as Fab } from './Fab'
99
99
  export { default as SquareAppIcon } from './SquareAppIcon'
100
100
  export { default as FileImageLoader } from './FileImageLoader'
101
101
  export { default as Radios } from './Radios'
102
+ export { default as BottomSheet, BottomSheetItem } from './BottomSheet'
@@ -0,0 +1,202 @@
1
+ import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
2
+ import _objectSpread from "@babel/runtime/helpers/objectSpread";
3
+ import React, { useState, useEffect, useRef, useMemo } from 'react';
4
+ import PropTypes from 'prop-types';
5
+ import { BottomSheet as MuiBottomSheet } from 'mui-bottom-sheet';
6
+ import Stack from 'cozy-ui/transpiled/react/Stack';
7
+ import Paper from 'cozy-ui/transpiled/react/Paper';
8
+
9
+ var makeStyles = function makeStyles(_ref) {
10
+ var isTopPosition = _ref.isTopPosition;
11
+ return {
12
+ root: _objectSpread({
13
+ borderTopLeftRadius: '1rem',
14
+ borderTopRightRadius: '1rem',
15
+ transition: 'border-radius 0.5s',
16
+ zIndex: 'var(--zIndex-drawer)',
17
+ boxShadow: '0 6px 16px 0 rgba(0, 0, 0, 0.5)',
18
+ backgroundColor: 'var(--paperBackgroundColor)'
19
+ }, isTopPosition && {
20
+ borderTopLeftRadius: 0,
21
+ borderTopRightRadius: 0,
22
+ boxShadow: '0 0 1px 0 rgba(0, 0, 0, 0.5)'
23
+ }),
24
+ indicator: {
25
+ width: '4rem',
26
+ height: '0.25rem',
27
+ borderRadius: '99px',
28
+ backgroundColor: 'var(--secondaryTextColor)'
29
+ },
30
+ stack: {
31
+ backgroundColor: 'var(--defaultBackgroundColor)'
32
+ }
33
+ };
34
+ };
35
+
36
+ export var defaultBottomSheetSpringConfig = {
37
+ tension: 165,
38
+ friction: 17,
39
+ clamp: true
40
+ };
41
+ var defaultSettings = {
42
+ mediumHeightRatio: 0.33
43
+ };
44
+
45
+ var computeMaxHeight = function computeMaxHeight(toolbarProps) {
46
+ var ref = toolbarProps.ref,
47
+ height = toolbarProps.height;
48
+ var computedToolbarHeight = 1;
49
+
50
+ if (height) {
51
+ computedToolbarHeight = height;
52
+ } else if (ref && ref.current) {
53
+ computedToolbarHeight = ref.current.offsetHeight;
54
+ }
55
+
56
+ return window.innerHeight - computedToolbarHeight;
57
+ };
58
+
59
+ var BottomSheet = function BottomSheet(_ref2) {
60
+ var toolbarProps = _ref2.toolbarProps,
61
+ settings = _ref2.settings,
62
+ children = _ref2.children;
63
+ var innerContentRef = useRef();
64
+ var headerRef = useRef();
65
+ var headerContentRef = useRef();
66
+
67
+ var _useState = useState(false),
68
+ _useState2 = _slicedToArray(_useState, 2),
69
+ isTopPosition = _useState2[0],
70
+ setIsTopPosition = _useState2[1];
71
+
72
+ var _useState3 = useState(null),
73
+ _useState4 = _slicedToArray(_useState3, 2),
74
+ peekHeights = _useState4[0],
75
+ setPeekHeights = _useState4[1];
76
+
77
+ var _useState5 = useState(null),
78
+ _useState6 = _slicedToArray(_useState5, 2),
79
+ initPos = _useState6[0],
80
+ setInitPos = _useState6[1];
81
+
82
+ var _useState7 = useState(0),
83
+ _useState8 = _slicedToArray(_useState7, 2),
84
+ bottomSpacerHeight = _useState8[0],
85
+ setBottomSpacerHeight = _useState8[1];
86
+
87
+ var _useMemo = useMemo(function () {
88
+ return settings || defaultSettings;
89
+ }, [settings]),
90
+ mediumHeightRatio = _useMemo.mediumHeightRatio;
91
+
92
+ var styles = useMemo(function () {
93
+ return makeStyles({
94
+ isTopPosition: isTopPosition
95
+ });
96
+ }, [isTopPosition]); // hack to prevent pull-down-to-refresh behavior when dragging down the bottom sheet.
97
+ // Needed for iOS Safari
98
+
99
+ useEffect(function () {
100
+ document.body.style.overflow = 'hidden';
101
+ return function () {
102
+ document.body.style.overflow = 'auto';
103
+ };
104
+ }, []);
105
+ useEffect(function () {
106
+ var headerContent = headerContentRef.current;
107
+ var maxHeight = computeMaxHeight(toolbarProps);
108
+ var mediumHeight = Math.round(maxHeight * mediumHeightRatio);
109
+ var actionButtonsHeight = headerContent ? parseFloat(getComputedStyle(headerContent).getPropertyValue('height')) : 0;
110
+ var actionButtonsBottomMargin = headerContent ? parseFloat(getComputedStyle(headerContent).getPropertyValue('padding-bottom')) : 0;
111
+ var minHeight = headerRef.current.offsetHeight + actionButtonsHeight + actionButtonsBottomMargin; // Used so that the bottomSheet can be opened to the top,
112
+ // without stopping at the content height
113
+
114
+ var bottomSpacerHeight = maxHeight - innerContentRef.current.offsetHeight;
115
+ setPeekHeights([minHeight, mediumHeight, maxHeight]);
116
+ setInitPos(mediumHeight);
117
+ setBottomSpacerHeight(bottomSpacerHeight);
118
+ }, [innerContentRef, headerContentRef.current, toolbarProps, mediumHeightRatio]);
119
+
120
+ var handleOnIndexChange = function handleOnIndexChange(snapIndex) {
121
+ var maxHeightSnapIndex = peekHeights.length - 1;
122
+
123
+ if (snapIndex === maxHeightSnapIndex && !isTopPosition) {
124
+ setIsTopPosition(true);
125
+ }
126
+
127
+ if (snapIndex !== maxHeightSnapIndex && isTopPosition) {
128
+ setIsTopPosition(false);
129
+ }
130
+ };
131
+
132
+ var overriddenChildren = React.Children.map(children, function (child) {
133
+ if (child.type.name === 'BottomSheetHeader') {
134
+ return React.cloneElement(child, {
135
+ headerContentRef: headerContentRef
136
+ });
137
+ }
138
+
139
+ return child;
140
+ });
141
+ return React.createElement(MuiBottomSheet, {
142
+ peekHeights: peekHeights,
143
+ defaultHeight: initPos,
144
+ backdrop: false,
145
+ fullHeight: false,
146
+ onIndexChange: function onIndexChange(snapIndex) {
147
+ return handleOnIndexChange(snapIndex);
148
+ },
149
+ styles: {
150
+ root: styles.root
151
+ },
152
+ threshold: 0 // springConfig doc : https://www.react-spring.io/docs/hooks/api
153
+ ,
154
+ springConfig: {
155
+ tension: defaultBottomSheetSpringConfig.tension,
156
+ friction: defaultBottomSheetSpringConfig.friction,
157
+ clamp: defaultBottomSheetSpringConfig.clamp
158
+ },
159
+ disabledClosing: true,
160
+ snapPointSeekerMode: "next"
161
+ }, React.createElement("div", {
162
+ ref: innerContentRef
163
+ }, React.createElement(Paper, {
164
+ "data-testid": "bottomSheet-header",
165
+ className: "u-w-100 u-h-2-half u-pos-relative u-flex u-flex-items-center u-flex-justify-center",
166
+ ref: headerRef,
167
+ elevation: 0,
168
+ square: true
169
+ }, React.createElement("div", {
170
+ style: styles.indicator
171
+ })), React.createElement(Stack, {
172
+ style: styles.stack,
173
+ className: "u-flex u-flex-column u-ov-hidden",
174
+ spacing: "s"
175
+ }, overriddenChildren)), React.createElement("div", {
176
+ style: {
177
+ height: bottomSpacerHeight
178
+ }
179
+ }));
180
+ };
181
+
182
+ BottomSheet.defaultProps = {
183
+ classes: {},
184
+ toolbarProps: {}
185
+ };
186
+ BottomSheet.propTypes = {
187
+ /** Toolbar properties */
188
+ toolbarProps: PropTypes.shape({
189
+ /** React reference of the toolbar node */
190
+ ref: PropTypes.bool,
191
+
192
+ /** Toolbar height value */
193
+ height: PropTypes.func
194
+ }),
195
+
196
+ /** Settings that can be modified */
197
+ settings: PropTypes.shape({
198
+ /** Height of the middle snap point, expressed as a percentage of the viewport height */
199
+ mediumHeightRatio: PropTypes.number
200
+ })
201
+ };
202
+ export default React.memo(BottomSheet);
@@ -0,0 +1,20 @@
1
+ import React from 'react';
2
+ import cx from 'classnames';
3
+ import Paper from 'cozy-ui/transpiled/react/Paper';
4
+
5
+ var BottomSheetHeader = function BottomSheetHeader(_ref) {
6
+ var className = _ref.className,
7
+ headerContentRef = _ref.headerContentRef,
8
+ children = _ref.children;
9
+ return React.createElement(Paper, {
10
+ ref: headerContentRef,
11
+ className: cx('u-flex u-flex-items-center', className),
12
+ elevation: 0,
13
+ square: true
14
+ }, children);
15
+ };
16
+
17
+ BottomSheetHeader.defaultProps = {
18
+ classes: {}
19
+ };
20
+ export default BottomSheetHeader;
@@ -0,0 +1,35 @@
1
+ import _extends from "@babel/runtime/helpers/extends";
2
+ import _objectWithoutProperties from "@babel/runtime/helpers/objectWithoutProperties";
3
+ import React from 'react';
4
+ import PropTypes from 'prop-types';
5
+ import cx from 'classnames';
6
+ import Paper from 'cozy-ui/transpiled/react/Paper';
7
+
8
+ var BottomSheetItem = function BottomSheetItem(_ref) {
9
+ var children = _ref.children,
10
+ disableGutters = _ref.disableGutters,
11
+ disableElevation = _ref.disableElevation,
12
+ className = _ref.className,
13
+ props = _objectWithoutProperties(_ref, ["children", "disableGutters", "disableElevation", "className"]);
14
+
15
+ return React.createElement(Paper, _extends({
16
+ elevation: disableElevation ? 0 : 0 // need to set correct shadow values before setting a real elevation value
17
+ ,
18
+ square: true,
19
+ className: cx({
20
+ 'u-p-1': !disableGutters
21
+ }, className)
22
+ }, props), children);
23
+ };
24
+
25
+ BottomSheetItem.propTypes = {
26
+ /** CSS classes */
27
+ className: PropTypes.string,
28
+
29
+ /** Disables default padding */
30
+ disableGutters: PropTypes.bool,
31
+
32
+ /** Disables default paper elevation */
33
+ disableElevation: PropTypes.bool
34
+ };
35
+ export default React.memo(BottomSheetItem);
@@ -0,0 +1,3 @@
1
+ export { default } from './BottomSheet';
2
+ export { default as BottomSheetItem } from './BottomSheetItem';
3
+ export { default as BottomSheetHeader } from './BottomSheetHeader';
@@ -1,60 +1,28 @@
1
- import React, { forwardRef } from 'react';
1
+ import React from 'react';
2
2
  import PropTypes from 'prop-types';
3
- import cx from 'classnames';
4
- import { makeStyles } from '@material-ui/core/styles';
5
- import { isMobileApp } from 'cozy-device-helper';
6
- import Paper from "cozy-ui/transpiled/react/Paper";
7
- import Typography from "cozy-ui/transpiled/react/Typography";
8
- import Stack from "cozy-ui/transpiled/react/Stack";
9
- import Sharing from "cozy-ui/transpiled/react/Viewer/Footer/Sharing";
10
- import ForwardButton from "cozy-ui/transpiled/react/Viewer/Footer/ForwardButton";
11
- import DownloadButton from "cozy-ui/transpiled/react/Viewer/Footer/DownloadButton";
3
+ import { BottomSheetItem } from "cozy-ui/transpiled/react/BottomSheet";
12
4
  import getPanelBlocks, { panelBlocksSpecs } from "cozy-ui/transpiled/react/Viewer/Panel/getPanelBlocks";
13
- var useStyles = makeStyles(function (theme) {
14
- return {
15
- stack: {
16
- backgroundColor: theme.palette.background.default
17
- }
18
- };
19
- });
20
- var BottomSheetContent = forwardRef(function (_ref, ref) {
5
+
6
+ var BottomSheetContent = function BottomSheetContent(_ref) {
21
7
  var file = _ref.file,
22
- disableSharing = _ref.disableSharing,
23
8
  contactsFullname = _ref.contactsFullname;
24
9
  var panelBlocks = getPanelBlocks({
25
10
  panelBlocksSpecs: panelBlocksSpecs,
26
11
  file: file
27
12
  });
28
- var FileActionButton = isMobileApp() ? ForwardButton : DownloadButton;
29
- var styles = useStyles();
30
- return React.createElement(Stack, {
31
- spacing: "s",
32
- className: cx('u-flex u-flex-column u-ov-hidden', styles.stack)
33
- }, React.createElement(Paper, {
34
- className: 'u-flex u-ph-1 u-pb-1',
35
- elevation: 2,
36
- square: true,
37
- ref: ref
38
- }, !disableSharing && React.createElement(Sharing, {
39
- file: file
40
- }), React.createElement(FileActionButton, {
41
- file: file
42
- })), panelBlocks.map(function (PanelBlock, index) {
43
- return React.createElement(Paper, {
13
+ return panelBlocks.map(function (PanelBlock, index) {
14
+ return React.createElement(BottomSheetItem, {
44
15
  key: index,
45
- elevation: index === panelBlocks.length - 1 ? 0 : 2,
46
- square: true
47
- }, React.createElement(Typography, {
48
- variant: "h4",
49
- className: 'u-pv-1 u-ph-1'
16
+ disableElevation: index === panelBlocks.length - 1
50
17
  }, React.createElement(PanelBlock, {
51
18
  file: file,
52
19
  contactsFullname: contactsFullname
53
- })));
54
- }));
55
- });
20
+ }));
21
+ });
22
+ };
23
+
56
24
  BottomSheetContent.propTypes = {
57
25
  file: PropTypes.object.isRequired,
58
- disableSharing: PropTypes.bool
26
+ contactsFullname: PropTypes.string
59
27
  };
60
28
  export default BottomSheetContent;
@@ -1,15 +1,15 @@
1
1
  import _objectSpread from "@babel/runtime/helpers/objectSpread";
2
- import React, { useRef } from 'react';
2
+ import React, { useMemo } from 'react';
3
3
  import PropTypes from 'prop-types';
4
4
  import { makeStyles } from '@material-ui/core/styles';
5
5
  import { isMobileApp } from 'cozy-device-helper';
6
6
  import { getReferencedBy, useQuery, models } from 'cozy-client';
7
+ import BottomSheet, { BottomSheetHeader } from "cozy-ui/transpiled/react/BottomSheet";
7
8
  import { buildContactByIdsQuery } from "cozy-ui/transpiled/react/Viewer/queries";
8
9
  import { isValidForPanel } from "cozy-ui/transpiled/react/Viewer/helpers";
9
10
  import Sharing from "cozy-ui/transpiled/react/Viewer/Footer/Sharing";
10
11
  import ForwardButton from "cozy-ui/transpiled/react/Viewer/Footer/ForwardButton";
11
12
  import DownloadButton from "cozy-ui/transpiled/react/Viewer/Footer/DownloadButton";
12
- import BottomSheetWrapper from "cozy-ui/transpiled/react/Viewer/Footer/BottomSheetWrapper";
13
13
  import BottomSheetContent from "cozy-ui/transpiled/react/Viewer/Footer/BottomSheetContent";
14
14
  var getDisplayName = models.contact.getDisplayName;
15
15
  var useStyles = makeStyles(function (theme) {
@@ -32,7 +32,11 @@ var FooterContent = function FooterContent(_ref) {
32
32
  disableSharing = _ref.disableSharing;
33
33
  var styles = useStyles();
34
34
  var FileActionButton = isMobileApp() ? ForwardButton : DownloadButton;
35
- var actionButtonsRef = useRef();
35
+ var toolbarProps = useMemo(function () {
36
+ return {
37
+ ref: toolbarRef
38
+ };
39
+ }, [toolbarRef]);
36
40
  var contactIds = getReferencedBy(file, 'io.cozy.contacts').map(function (ref) {
37
41
  return ref.id;
38
42
  });
@@ -50,15 +54,17 @@ var FooterContent = function FooterContent(_ref) {
50
54
  if (isValidForPanel({
51
55
  file: file
52
56
  }) && (contactsFullname || contactIds.length === 0)) {
53
- return React.createElement(BottomSheetWrapper, {
57
+ return React.createElement(BottomSheet, {
58
+ toolbarProps: toolbarProps
59
+ }, React.createElement(BottomSheetHeader, {
60
+ className: "u-ph-1 u-pb-1"
61
+ }, !disableSharing && React.createElement(Sharing, {
62
+ file: file
63
+ }), React.createElement(FileActionButton, {
64
+ file: file
65
+ })), React.createElement(BottomSheetContent, {
54
66
  file: file,
55
- actionButtonsRef: actionButtonsRef,
56
- toolbarRef: toolbarRef
57
- }, React.createElement(BottomSheetContent, {
58
- file: file,
59
- disableSharing: disableSharing,
60
- contactsFullname: contactsFullname,
61
- ref: actionButtonsRef
67
+ contactsFullname: contactsFullname
62
68
  }));
63
69
  }
64
70
 
@@ -76,4 +76,5 @@ export { default as ProgressionBanner } from './ProgressionBanner';
76
76
  export { default as Fab } from './Fab';
77
77
  export { default as SquareAppIcon } from './SquareAppIcon';
78
78
  export { default as FileImageLoader } from './FileImageLoader';
79
- export { default as Radios } from './Radios';
79
+ export { default as Radios } from './Radios';
80
+ export { default as BottomSheet, BottomSheetItem } from './BottomSheet';
@@ -1,121 +0,0 @@
1
- import React, { useState, useEffect, useRef } from 'react'
2
- import { BottomSheet } from 'mui-bottom-sheet'
3
- import { makeStyles } from '@material-ui/core/styles'
4
-
5
- const useStyles = ({ isTopPosition }) => ({
6
- root: {
7
- borderTopLeftRadius: isTopPosition ? 0 : '1rem',
8
- borderTopRightRadius: isTopPosition ? 0 : '1rem',
9
- transition: 'border-radius 0.5s',
10
- boxShadow: '0 6px 16px 0 rgba(0, 0, 0, 0.5)'
11
- }
12
- })
13
-
14
- const useClasses = makeStyles(theme => ({
15
- header: {
16
- height: '2.5rem',
17
- width: '100%',
18
- position: 'relative',
19
- display: 'flex',
20
- alignItems: 'center',
21
- justifyContent: 'center'
22
- },
23
- indicator: {
24
- width: '4rem',
25
- height: '0.25rem',
26
- borderRadius: '99px',
27
- backgroundColor: theme.palette.text.secondary
28
- }
29
- }))
30
-
31
- export const defaultBottomSheetSpringConfig = {
32
- tension: 165,
33
- friction: 17,
34
- clamp: true
35
- }
36
-
37
- const BottomSheetWrapper = ({
38
- file,
39
- actionButtonsRef,
40
- toolbarRef,
41
- children
42
- }) => {
43
- const [isTopPosition, setIsTopPosition] = useState(false)
44
- const [peekHeights, setPeekHeights] = useState(null)
45
- const [initPos, setInitPos] = useState(null)
46
- const [bottomSpacerHeight, setBottomSpacerHeight] = useState(0)
47
- const classes = useClasses()
48
- const styles = useStyles({ isTopPosition })
49
- const innerContentRef = useRef()
50
- const headerRef = useRef()
51
-
52
- const toolbar = toolbarRef.current
53
-
54
- useEffect(() => {
55
- const maxHeight = toolbar
56
- ? window.innerHeight - toolbar.offsetHeight
57
- : window.innerHeight
58
- const mediumHeight = Math.round(maxHeight * 0.33)
59
- const actionButtonsHeight = parseFloat(
60
- getComputedStyle(actionButtonsRef.current).getPropertyValue('height')
61
- )
62
- const actionButtonsBottomMargin = 16
63
- const minHeight =
64
- headerRef.current.offsetHeight +
65
- actionButtonsHeight +
66
- actionButtonsBottomMargin
67
-
68
- // Used so that the bottomSheet can be opened to the top,
69
- // without stopping at the content height
70
- const bottomSpacerHeight = maxHeight - innerContentRef.current.offsetHeight
71
-
72
- setPeekHeights([minHeight, mediumHeight, maxHeight])
73
- setInitPos(mediumHeight)
74
- setBottomSpacerHeight(bottomSpacerHeight)
75
- }, [toolbar, innerContentRef, file, actionButtonsRef])
76
-
77
- const handleOnIndexChange = snapIndex => {
78
- const maxHeightSnapIndex = peekHeights.length - 1
79
-
80
- if (snapIndex === maxHeightSnapIndex && !isTopPosition) {
81
- setIsTopPosition(true)
82
- }
83
- if (snapIndex !== maxHeightSnapIndex && isTopPosition) {
84
- setIsTopPosition(false)
85
- }
86
- }
87
-
88
- return (
89
- <BottomSheet
90
- peekHeights={peekHeights}
91
- defaultHeight={initPos}
92
- backdrop={false}
93
- fullHeight={false}
94
- onIndexChange={snapIndex => handleOnIndexChange(snapIndex)}
95
- styles={{ root: styles.root }}
96
- threshold={0}
97
- // springConfig doc : https://react-spring.io/common/configs
98
- springConfig={{
99
- tension: defaultBottomSheetSpringConfig.tension,
100
- friction: defaultBottomSheetSpringConfig.friction,
101
- clamp: defaultBottomSheetSpringConfig.clamp
102
- }}
103
- disabledClosing={true}
104
- snapPointSeekerMode="next"
105
- >
106
- <div ref={innerContentRef}>
107
- <div
108
- data-testid="bottomSheet-header"
109
- className={classes.header}
110
- ref={headerRef}
111
- >
112
- <div className={classes.indicator} />
113
- </div>
114
- {children}
115
- </div>
116
- <div style={{ height: bottomSpacerHeight }} />
117
- </BottomSheet>
118
- )
119
- }
120
-
121
- export default BottomSheetWrapper
@@ -1,136 +0,0 @@
1
- import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
2
- import React, { useState, useEffect, useRef } from 'react';
3
- import { BottomSheet } from 'mui-bottom-sheet';
4
- import { makeStyles } from '@material-ui/core/styles';
5
-
6
- var useStyles = function useStyles(_ref) {
7
- var isTopPosition = _ref.isTopPosition;
8
- return {
9
- root: {
10
- borderTopLeftRadius: isTopPosition ? 0 : '1rem',
11
- borderTopRightRadius: isTopPosition ? 0 : '1rem',
12
- transition: 'border-radius 0.5s',
13
- boxShadow: '0 6px 16px 0 rgba(0, 0, 0, 0.5)'
14
- }
15
- };
16
- };
17
-
18
- var useClasses = makeStyles(function (theme) {
19
- return {
20
- header: {
21
- height: '2.5rem',
22
- width: '100%',
23
- position: 'relative',
24
- display: 'flex',
25
- alignItems: 'center',
26
- justifyContent: 'center'
27
- },
28
- indicator: {
29
- width: '4rem',
30
- height: '0.25rem',
31
- borderRadius: '99px',
32
- backgroundColor: theme.palette.text.secondary
33
- }
34
- };
35
- });
36
- export var defaultBottomSheetSpringConfig = {
37
- tension: 165,
38
- friction: 17,
39
- clamp: true
40
- };
41
-
42
- var BottomSheetWrapper = function BottomSheetWrapper(_ref2) {
43
- var file = _ref2.file,
44
- actionButtonsRef = _ref2.actionButtonsRef,
45
- toolbarRef = _ref2.toolbarRef,
46
- children = _ref2.children;
47
-
48
- var _useState = useState(false),
49
- _useState2 = _slicedToArray(_useState, 2),
50
- isTopPosition = _useState2[0],
51
- setIsTopPosition = _useState2[1];
52
-
53
- var _useState3 = useState(null),
54
- _useState4 = _slicedToArray(_useState3, 2),
55
- peekHeights = _useState4[0],
56
- setPeekHeights = _useState4[1];
57
-
58
- var _useState5 = useState(null),
59
- _useState6 = _slicedToArray(_useState5, 2),
60
- initPos = _useState6[0],
61
- setInitPos = _useState6[1];
62
-
63
- var _useState7 = useState(0),
64
- _useState8 = _slicedToArray(_useState7, 2),
65
- bottomSpacerHeight = _useState8[0],
66
- setBottomSpacerHeight = _useState8[1];
67
-
68
- var classes = useClasses();
69
- var styles = useStyles({
70
- isTopPosition: isTopPosition
71
- });
72
- var innerContentRef = useRef();
73
- var headerRef = useRef();
74
- var toolbar = toolbarRef.current;
75
- useEffect(function () {
76
- var maxHeight = toolbar ? window.innerHeight - toolbar.offsetHeight : window.innerHeight;
77
- var mediumHeight = Math.round(maxHeight * 0.33);
78
- var actionButtonsHeight = parseFloat(getComputedStyle(actionButtonsRef.current).getPropertyValue('height'));
79
- var actionButtonsBottomMargin = 16;
80
- var minHeight = headerRef.current.offsetHeight + actionButtonsHeight + actionButtonsBottomMargin; // Used so that the bottomSheet can be opened to the top,
81
- // without stopping at the content height
82
-
83
- var bottomSpacerHeight = maxHeight - innerContentRef.current.offsetHeight;
84
- setPeekHeights([minHeight, mediumHeight, maxHeight]);
85
- setInitPos(mediumHeight);
86
- setBottomSpacerHeight(bottomSpacerHeight);
87
- }, [toolbar, innerContentRef, file, actionButtonsRef]);
88
-
89
- var handleOnIndexChange = function handleOnIndexChange(snapIndex) {
90
- var maxHeightSnapIndex = peekHeights.length - 1;
91
-
92
- if (snapIndex === maxHeightSnapIndex && !isTopPosition) {
93
- setIsTopPosition(true);
94
- }
95
-
96
- if (snapIndex !== maxHeightSnapIndex && isTopPosition) {
97
- setIsTopPosition(false);
98
- }
99
- };
100
-
101
- return React.createElement(BottomSheet, {
102
- peekHeights: peekHeights,
103
- defaultHeight: initPos,
104
- backdrop: false,
105
- fullHeight: false,
106
- onIndexChange: function onIndexChange(snapIndex) {
107
- return handleOnIndexChange(snapIndex);
108
- },
109
- styles: {
110
- root: styles.root
111
- },
112
- threshold: 0 // springConfig doc : https://react-spring.io/common/configs
113
- ,
114
- springConfig: {
115
- tension: defaultBottomSheetSpringConfig.tension,
116
- friction: defaultBottomSheetSpringConfig.friction,
117
- clamp: defaultBottomSheetSpringConfig.clamp
118
- },
119
- disabledClosing: true,
120
- snapPointSeekerMode: "next"
121
- }, React.createElement("div", {
122
- ref: innerContentRef
123
- }, React.createElement("div", {
124
- "data-testid": "bottomSheet-header",
125
- className: classes.header,
126
- ref: headerRef
127
- }, React.createElement("div", {
128
- className: classes.indicator
129
- })), children), React.createElement("div", {
130
- style: {
131
- height: bottomSpacerHeight
132
- }
133
- }));
134
- };
135
-
136
- export default BottomSheetWrapper;