cozy-ui 99.0.3 → 99.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/.nvmrc CHANGED
@@ -1 +1 @@
1
- 16.13.0
1
+ 16.20.2
package/CHANGELOG.md CHANGED
@@ -1,3 +1,11 @@
1
+ ## [99.0.4](https://github.com/cozy/cozy-ui/compare/v99.0.3...v99.0.4) (2023-12-14)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * **BottomSheet:** Did not rerender correctly after a change to children ([4d97075](https://github.com/cozy/cozy-ui/commit/4d97075))
7
+ * **NestedSelect:** Remove useless hack to force rerender when in BottomSheet ([0cbe62f](https://github.com/cozy/cozy-ui/commit/0cbe62f))
8
+
1
9
  ## [99.0.3](https://github.com/cozy/cozy-ui/compare/v99.0.2...v99.0.3) (2023-12-13)
2
10
 
3
11
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cozy-ui",
3
- "version": "99.0.3",
3
+ "version": "99.0.4",
4
4
  "description": "Cozy apps UI SDK",
5
5
  "main": "./index.js",
6
6
  "bin": {
@@ -68,7 +68,7 @@
68
68
  "intersection-observer"
69
69
  ],
70
70
  "devDependencies": {
71
- "@argos-ci/cli": "0.4.4",
71
+ "@argos-ci/cli": "1.0.4",
72
72
  "@babel/cli": "7.17.6",
73
73
  "@babel/core": "7.17.8",
74
74
  "@babel/helper-builder-react-jsx": "7.16.7",
@@ -129,7 +129,7 @@
129
129
  "postcss-loader": "2.1.6",
130
130
  "pretty": "2.0.0",
131
131
  "prop-types": "15.7.2",
132
- "puppeteer": "18.2.0",
132
+ "puppeteer": "21.6.1",
133
133
  "react": "16.12.0",
134
134
  "react-dom": "16.12.0",
135
135
  "react-hot-loader": "^4.3.11",
@@ -9,7 +9,7 @@ import React, {
9
9
  } from 'react'
10
10
  import PropTypes from 'prop-types'
11
11
  import { BottomSheet as MuiBottomSheet } from 'mui-bottom-sheet'
12
- import { useTimeoutWhen } from 'rooks'
12
+ import { useMutationObserver, useTimeoutWhen } from 'rooks'
13
13
  import Fade from '@material-ui/core/Fade'
14
14
  import Portal from '@material-ui/core/Portal'
15
15
 
@@ -159,6 +159,7 @@ const BottomSheet = memo(
159
159
  const [bottomSpacerHeight, setBottomSpacerHeight] = useState(0)
160
160
  const [initPos, setInitPos] = useState(0)
161
161
  const prevInitPos = useRef()
162
+ const [forceRender, setForceRender] = useState(0)
162
163
 
163
164
  const hasToolbarProps = !!Object.keys(toolbarProps).length
164
165
  const isClosable = !!onClose || backdrop
@@ -199,6 +200,12 @@ const BottomSheet = memo(
199
200
  setBottomPosition({ snapIndex, isBottomPosition, setIsBottomPosition })
200
201
  }
201
202
 
203
+ // forces a rendering when one of the children has changed,
204
+ // typically after content loading or using content changer such as NestedSelect
205
+ useMutationObserver(innerContentRef, () => {
206
+ setForceRender(v => v + 1)
207
+ })
208
+
202
209
  // hack to prevent pull-down-to-refresh behavior when dragging down the bottom sheet.
203
210
  // Needed for iOS Safari
204
211
  useEffect(() => {
@@ -286,7 +293,7 @@ const BottomSheet = memo(
286
293
  backdrop,
287
294
  isClosable,
288
295
  offset,
289
- children // to recompute data if content changes
296
+ forceRender // to recompute data when content has changed
290
297
  ])
291
298
 
292
299
  useSetFlagshipUI(
@@ -1,4 +1,4 @@
1
- import React, { useState } from 'react'
1
+ import React from 'react'
2
2
  import cx from 'classnames'
3
3
 
4
4
  import Icon from '../Icon'
@@ -33,8 +33,6 @@ const HeaderComponent = ({ title, showBack, onClickBack }) => {
33
33
  }
34
34
 
35
35
  const SelfBottomSheet = props => {
36
- const [, setInnerContentHeight] = useState(0) // tricks to rerender BottomSheet
37
-
38
36
  return (
39
37
  <BottomSheet
40
38
  {...props?.componentsProps?.bottomsheet}
@@ -42,11 +40,7 @@ const SelfBottomSheet = props => {
42
40
  onClose={props.onClose}
43
41
  >
44
42
  <BottomSheetItem disableGutters>
45
- <NestedSelect
46
- HeaderComponent={HeaderComponent}
47
- setInnerContentHeight={setInnerContentHeight}
48
- {...props}
49
- />
43
+ <NestedSelect HeaderComponent={HeaderComponent} {...props} />
50
44
  </BottomSheetItem>
51
45
  </BottomSheet>
52
46
  )
@@ -1,4 +1,4 @@
1
- import React, { Component } from 'react'
1
+ import React, { useEffect, useState, useRef } from 'react'
2
2
  import PropTypes from 'prop-types'
3
3
  import omit from 'lodash/omit'
4
4
 
@@ -15,51 +15,56 @@ export { ItemRow }
15
15
  * will show the children of the chosen option instead of selecting
16
16
  * the option.
17
17
  */
18
- class NestedSelect extends Component {
19
- constructor(props) {
20
- super(props)
21
- this.innerRef = React.createRef()
22
- this.state = {
23
- history: [props.options],
24
- searchValue: '',
25
- searchResult: []
26
- }
27
- }
28
-
29
- componentWillUnmount() {
30
- this.unmounted = true
31
- }
18
+ const NestedSelect = ({
19
+ onSelect,
20
+ ContentComponent,
21
+ HeaderComponent,
22
+ canSelectParent,
23
+ isSelected,
24
+ title,
25
+ transformParentItem,
26
+ radioPosition,
27
+ ellipsis,
28
+ options,
29
+ searchOptions,
30
+ noDivider
31
+ }) => {
32
+ const innerRef = useRef()
33
+ const [state, setState] = useState({
34
+ history: [options],
35
+ searchValue: '',
36
+ searchResult: []
37
+ })
38
+ const [unmounted, setUnmounted] = useState(false)
32
39
 
33
- componentDidUpdate() {
34
- const { setInnerContentHeight } = this.props
35
-
36
- setInnerContentHeight?.(this.innerRef?.current?.offsetHeight)
37
- }
40
+ useEffect(() => {
41
+ return () => {
42
+ setUnmounted(true)
43
+ }
44
+ }, [])
38
45
 
39
- resetHistory() {
40
- if (this.unmounted) {
46
+ const resetHistory = () => {
47
+ if (unmounted) {
41
48
  return
42
49
  }
43
- this.setState({ history: [this.props.options] })
50
+ setState(state => ({ ...state, history: [options] }))
44
51
  }
45
52
 
46
- handleBack = () => {
47
- const [item, ...newHistory] = this.state.history
48
- this.setState({
49
- history: newHistory
50
- })
53
+ const handleBack = () => {
54
+ const [item, ...newHistory] = state.history
55
+
56
+ setState(state => ({ ...state, history: newHistory }))
57
+
51
58
  return item
52
59
  }
53
60
 
54
- handleNavToChildren = item => {
55
- const newHistory = [item, ...this.state.history]
56
- this.setState({
57
- history: newHistory
58
- })
61
+ const handleNavToChildren = item => {
62
+ const newHistory = [item, ...state.history]
63
+ setState(state => ({ ...state, history: newHistory }))
59
64
  }
60
65
 
61
- handleSelect = item => {
62
- this.props.onSelect(item)
66
+ const handleSelect = item => {
67
+ onSelect(item)
63
68
  // It is important to reset history if the NestedSelected is used
64
69
  // multiple times in a row without being dismounted. For example
65
70
  // if it displayed in Carousel that slides in the NestedSelect
@@ -68,128 +73,112 @@ class NestedSelect extends Component {
68
73
  // while the animation is running.
69
74
  // There is probably a better way to do this.
70
75
  setTimeout(() => {
71
- this.resetHistory()
76
+ resetHistory()
72
77
  }, 500)
73
78
  }
74
79
 
75
- handleClickItem = item => {
80
+ const handleClickItem = item => {
76
81
  if (item.children && item.children.length > 0) {
77
- this.handleNavToChildren(item)
82
+ handleNavToChildren(item)
78
83
  } else {
79
- this.handleSelect(item)
84
+ handleSelect(item)
80
85
  }
81
86
  }
82
87
 
83
- render() {
84
- const {
85
- ContentComponent,
86
- HeaderComponent,
87
- canSelectParent,
88
- isSelected,
89
- title,
90
- transformParentItem,
91
- radioPosition,
92
- ellipsis,
93
- options,
94
- searchOptions,
95
- noDivider
96
- } = this.props
97
- const { history, searchValue, searchResult } = this.state
88
+ const onChange = ev => {
89
+ const onSearch = searchOptions?.onSearch
98
90
 
99
- const current = history[0]
100
- const children = current.children || []
101
- const level = history.length - 1
102
- const isSelectedWithLevel = item => isSelected(item, level)
103
- const parentItem = transformParentItem(omit(current, 'children'))
91
+ if (onSearch) {
92
+ const searchValue = ev.target.value
93
+ const searchResult = onSearch(searchValue)
94
+ setState(state => ({ ...state, searchValue, searchResult }))
95
+ }
96
+ }
104
97
 
105
- const hasSearchResult = searchValue.length > 0
98
+ const current = state.history[0]
99
+ const children = current.children || []
100
+ const level = state.history.length - 1
101
+ const parentItem = transformParentItem(omit(current, 'children'))
106
102
 
107
- const onChange = ev => {
108
- const onSearch = searchOptions && searchOptions.onSearch
109
- if (onSearch) {
110
- const searchValue = ev.target.value
111
- const searchResult = onSearch(searchValue)
112
- this.setState({ searchValue, searchResult })
113
- }
114
- }
103
+ const hasSearchResult = state.searchValue?.length > 0
104
+ const isSelectedWithLevel = item => isSelected(item, level)
115
105
 
116
- return (
117
- <span ref={this.innerRef}>
118
- {HeaderComponent ? (
119
- <HeaderComponent
120
- title={current.title || title}
121
- showBack={history.length > 1}
122
- onClickBack={this.handleBack}
106
+ return (
107
+ <span ref={innerRef}>
108
+ {HeaderComponent ? (
109
+ <HeaderComponent
110
+ title={current.title || title}
111
+ showBack={state.history.length > 1}
112
+ onClickBack={handleBack}
113
+ />
114
+ ) : null}
115
+ {level > 0
116
+ ? current.header
117
+ ? current.header
118
+ : typeof options.childrenHeader === 'function'
119
+ ? options.childrenHeader(level)
120
+ : options.childrenHeader
121
+ : options.header}
122
+ <ContentComponent>
123
+ {canSelectParent && level > 0 ? (
124
+ <ItemRow
125
+ radioPosition={radioPosition}
126
+ item={parentItem}
127
+ onClick={handleClickItem}
128
+ isSelected={isSelectedWithLevel(parentItem)}
129
+ ellipsis={ellipsis}
130
+ noDivider={noDivider}
123
131
  />
124
132
  ) : null}
125
- {level > 0
126
- ? current.header
127
- ? current.header
128
- : typeof options.childrenHeader === 'function'
129
- ? options.childrenHeader(level)
130
- : options.childrenHeader
131
- : options.header}
132
- <ContentComponent>
133
- {canSelectParent && level > 0 ? (
134
- <ItemRow
135
- radioPosition={radioPosition}
136
- item={parentItem}
137
- onClick={this.handleClickItem}
138
- isSelected={isSelectedWithLevel(parentItem)}
139
- ellipsis={ellipsis}
140
- noDivider={noDivider}
133
+ {searchOptions && level === 0 && (
134
+ <div className="u-mh-1 u-mb-half">
135
+ <Input
136
+ placeholder={searchOptions.placeholderSearch}
137
+ onChange={onChange}
138
+ value={state.searchValue}
141
139
  />
142
- ) : null}
143
- {searchOptions && level === 0 && (
144
- <div className="u-mh-1 u-mb-half">
145
- <Input
146
- placeholder={searchOptions.placeholderSearch}
147
- onChange={onChange}
148
- value={searchValue}
149
- />
150
- </div>
151
- )}
140
+ </div>
141
+ )}
152
142
 
153
- {hasSearchResult ? (
154
- searchResult.length === 0 ? (
155
- <Typography
156
- variant="body1"
157
- className="u-flex u-flex-justify-center u-mb-1 "
158
- >
159
- {searchOptions.noDataLabel}
160
- </Typography>
161
- ) : (
162
- searchResult.map((item, index) => (
163
- <ItemRow
164
- radioPosition={radioPosition}
165
- key={item.key || item.title}
166
- item={item}
167
- onClick={this.handleClickItem}
168
- isSelected={isSelectedWithLevel(item)}
169
- isLast={index === searchResult.length - 1}
170
- ellipsis={ellipsis}
171
- noDivider={noDivider}
172
- />
173
- ))
174
- )
143
+ {hasSearchResult ? (
144
+ state.searchResult.length === 0 ? (
145
+ <Typography
146
+ variant="body1"
147
+ className="u-flex u-flex-justify-center u-mb-1 "
148
+ >
149
+ {searchOptions.noDataLabel}
150
+ </Typography>
175
151
  ) : (
176
- children.map((item, index) => (
152
+ state.searchResult.map((item, index) => (
177
153
  <ItemRow
178
154
  radioPosition={radioPosition}
179
155
  key={item.key || item.title}
180
156
  item={item}
181
- onClick={this.handleClickItem}
157
+ onClick={handleClickItem}
182
158
  isSelected={isSelectedWithLevel(item)}
183
- isLast={index === children.length - 1}
159
+ isLast={index === state.searchResult.length - 1}
184
160
  ellipsis={ellipsis}
185
161
  noDivider={noDivider}
186
162
  />
187
163
  ))
188
- )}
189
- </ContentComponent>
190
- </span>
191
- )
192
- }
164
+ )
165
+ ) : (
166
+ children.map((item, index) => (
167
+ <ItemRow
168
+ radioPosition={radioPosition}
169
+ key={item.key || item.title}
170
+ item={item}
171
+ onClick={handleClickItem}
172
+ isSelected={isSelectedWithLevel(item)}
173
+ isLast={index === children.length - 1}
174
+ ellipsis={ellipsis}
175
+ noDivider={noDivider}
176
+ />
177
+ ))
178
+ )}
179
+ </ContentComponent>
180
+ </span>
181
+ )
193
182
  }
194
183
 
195
184
  NestedSelect.defaultProps = {
@@ -154,10 +154,11 @@ const InteractiveExample = () => {
154
154
  return false
155
155
  }
156
156
 
157
- const searchOptions = {
157
+ const searchOptions = withHeaders => ({
158
158
  placeholderSearch: 'Placeholder Search',
159
159
  noDataLabel: 'No Data Found',
160
160
  onSearch: (value) => {
161
+ const options = makeOptions(withHeaders)
161
162
  return options.children.filter(o => o.description && o.description.toLowerCase().includes(value.toLowerCase()))
162
163
  },
163
164
  displaySearchResultItem: item =>
@@ -167,7 +168,7 @@ const InteractiveExample = () => {
167
168
  ellipsis
168
169
  />
169
170
  </ListItem>
170
- }
171
+ })
171
172
 
172
173
  const handleSelect = item => {
173
174
  setSelected(item)
@@ -203,7 +204,7 @@ const InteractiveExample = () => {
203
204
  radioPosition={variant.leftRadio ? 'left' : 'right'}
204
205
  title={variant.noTitle ? undefined : "Please select letter"}
205
206
  transformParentItem={transformParentItem}
206
- searchOptions={variant.withSearch ? searchOptions : undefined}
207
+ searchOptions={variant.withSearch ? searchOptions(variant.withHeaders) : undefined}
207
208
  ellipsis={variant.withEllipsis}
208
209
  componentsProps={{ bottomsheet: { skipAnimation: isTesting() } }}
209
210
  noDivider={variant.noDivider}
@@ -33,7 +33,7 @@ const prepareFS = async options => {
33
33
  * Returns { browser, page }
34
34
  */
35
35
  const prepareBrowser = async (puppeteer, options) => {
36
- const browser = await puppeteer.launch()
36
+ const browser = await puppeteer.launch({ headless: 'new' })
37
37
  const page = await browser.newPage()
38
38
  // Put Argos in user agent
39
39
  await page.setUserAgent(
@@ -44,7 +44,10 @@ const prepareBrowser = async (puppeteer, options) => {
44
44
  ])
45
45
  page.setViewport(options.viewport)
46
46
  await page.setDefaultNavigationTimeout(0)
47
- console.log('Browser opened and set up')
47
+ await page.evaluateOnNewDocument(theme => {
48
+ localStorage.clear()
49
+ localStorage.setItem('theme', theme)
50
+ }, options.theme)
48
51
  return { browser, page }
49
52
  }
50
53
 
@@ -19,13 +19,8 @@ const screenshotComponent = async (page, options) => {
19
19
  const { component, screenshotDir, viewport, theme } = options
20
20
  const { link, name } = component
21
21
 
22
- // Need to use page.goto twice to set localStorage correctly
23
- await page.goto(link, { waitUntil: 'load', timeout: 0 })
24
- await page.evaluate(theme => {
25
- localStorage.setItem('theme', theme)
26
- }, theme)
27
- await page.goto(link, { waitUntil: 'load', timeout: 0 })
28
- await sleep(100)
22
+ await page.goto(link)
23
+ await sleep(100) // to be sure the page is entirely loaded
29
24
 
30
25
  const getScreenshotName =
31
26
  options.getScreenshotName || defaultGetScreenshotName
@@ -1,6 +1,5 @@
1
1
  const fs = require('fs')
2
2
 
3
- const themes = require('../../theme/themes')
4
3
  const { parseViewportArgument } = require('./helpers')
5
4
  const fetchAllComponents = require('./fetchAllComponents')
6
5
  const screenshotComponent = require('./screenshotComponent')
@@ -32,7 +31,7 @@ const cacheToDisk = (fnToCache, options) =>
32
31
  return res
33
32
  }
34
33
 
35
- const screenshotReactStyleguide = async (page, args, config) => {
34
+ const screenshotReactStyleguide = async (page, args, config, theme) => {
36
35
  const cachedFetchAllComponents = cacheToDisk(fetchAllComponents, {
37
36
  cacheFile: args.cacheFile,
38
37
  onLoadCache: () =>
@@ -47,7 +46,7 @@ const screenshotReactStyleguide = async (page, args, config) => {
47
46
  )
48
47
  }
49
48
 
50
- console.log('Screenshotting components')
49
+ console.log('Screenshotting components...')
51
50
 
52
51
  for (const component of components) {
53
52
  const componentConfig = config[component.name] || {}
@@ -58,15 +57,13 @@ const screenshotReactStyleguide = async (page, args, config) => {
58
57
  ? parseViewportArgument(componentViewportSpec)
59
58
  : parseViewportArgument(args.viewport)
60
59
  await page.setViewport(componentViewport)
61
- for (const theme of Object.keys(themes)) {
62
- await screenshotComponent(page, {
63
- component,
64
- componentConfig,
65
- screenshotDir: args.screenshotDir,
66
- viewport: componentViewport,
67
- theme
68
- })
69
- }
60
+ await screenshotComponent(page, {
61
+ component,
62
+ componentConfig,
63
+ screenshotDir: args.screenshotDir,
64
+ viewport: componentViewport,
65
+ theme
66
+ })
70
67
  }
71
68
  }
72
69
 
@@ -5,6 +5,7 @@ const screenshotReactStyleguide = require('./screenshots/screenshotReactStylegui
5
5
  const screenshotKSSStyleguide = require('./screenshots/screenshotKSSStyleguide')
6
6
  const makeParser = require('./screenshots/parser')
7
7
  const { readConfig, parseViewportArgument } = require('./screenshots/helpers')
8
+ const themes = require('../theme/themes')
8
9
 
9
10
  let puppeteer
10
11
  try {
@@ -27,21 +28,36 @@ const main = async () => {
27
28
 
28
29
  const parsedViewport = parseViewportArgument(args.viewport)
29
30
 
31
+ console.log('\n⌛ Preparing screenshot directory...')
30
32
  await prepareFS({
31
33
  screenshotDir: args.screenshotDir,
32
34
  emptyScreenshotDir: args.emptyScreenshotDir
33
35
  })
34
- const { browser, page } = await prepareBrowser(puppeteer, {
35
- viewport: parsedViewport
36
- })
36
+ console.log('✅ Done. Screenshot directory prepared')
37
37
 
38
- if (args.mode == 'react') {
39
- await screenshotReactStyleguide(page, args, config)
40
- } else if (args.mode == 'kss') {
41
- await screenshotKSSStyleguide(page, args)
42
- }
38
+ for (const theme of Object.keys(themes)) {
39
+ console.log(`\n✨ Running process for '${theme}' theme...`)
40
+ console.log('\n⌛ Preparing browser...')
41
+
42
+ const { browser, page } = await prepareBrowser(puppeteer, {
43
+ viewport: parsedViewport,
44
+ theme
45
+ })
46
+
47
+ console.log('✅ Done. Browser opened and set up')
48
+ console.log('\n⌛ Preparing screenshots...')
43
49
 
44
- await browser.close()
50
+ if (args.mode == 'react') {
51
+ await screenshotReactStyleguide(page, args, config, theme)
52
+ } else if (args.mode == 'kss') {
53
+ await screenshotKSSStyleguide(page, args)
54
+ }
55
+
56
+ console.log(`✅ Done. Screenshots completed for '${theme}' theme.`)
57
+
58
+ await browser.close()
59
+ console.log('Browser closed')
60
+ }
45
61
  }
46
62
 
47
63
  if (require.main === module) {
@@ -14,7 +14,7 @@ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { va
14
14
  import React, { useState, useEffect, useRef, useCallback, forwardRef, memo, Fragment } from 'react';
15
15
  import PropTypes from 'prop-types';
16
16
  import { BottomSheet as MuiBottomSheet } from 'mui-bottom-sheet';
17
- import { useTimeoutWhen } from 'rooks';
17
+ import { useMutationObserver, useTimeoutWhen } from 'rooks';
18
18
  import Fade from '@material-ui/core/Fade';
19
19
  import Portal from '@material-ui/core/Portal';
20
20
  import { getFlagshipMetadata } from 'cozy-device-helper';
@@ -188,6 +188,12 @@ var BottomSheet = /*#__PURE__*/memo(function (_ref3) {
188
188
  setInitPos = _useState16[1];
189
189
 
190
190
  var prevInitPos = useRef();
191
+
192
+ var _useState17 = useState(0),
193
+ _useState18 = _slicedToArray(_useState17, 2),
194
+ forceRender = _useState18[0],
195
+ setForceRender = _useState18[1];
196
+
191
197
  var hasToolbarProps = !!Object.keys(toolbarProps).length;
192
198
  var isClosable = !!onClose || backdrop;
193
199
  var renderSaferHeight = initPos < prevInitPos.current ? prevInitPos.current - 16 : 0; // 16 because border radius
@@ -225,10 +231,17 @@ var BottomSheet = /*#__PURE__*/memo(function (_ref3) {
225
231
  isBottomPosition: isBottomPosition,
226
232
  setIsBottomPosition: setIsBottomPosition
227
233
  });
228
- }; // hack to prevent pull-down-to-refresh behavior when dragging down the bottom sheet.
229
- // Needed for iOS Safari
234
+ }; // forces a rendering when one of the children has changed,
235
+ // typically after content loading or using content changer such as NestedSelect
230
236
 
231
237
 
238
+ useMutationObserver(innerContentRef, function () {
239
+ setForceRender(function (v) {
240
+ return v + 1;
241
+ });
242
+ }); // hack to prevent pull-down-to-refresh behavior when dragging down the bottom sheet.
243
+ // Needed for iOS Safari
244
+
232
245
  useEffect(function () {
233
246
  document.body.style.overflow = 'hidden';
234
247
  return function () {
@@ -286,7 +299,7 @@ var BottomSheet = /*#__PURE__*/memo(function (_ref3) {
286
299
 
287
300
  setBottomSpacerHeight(bottomSpacerHeight); // eslint-disable-next-line react-hooks/exhaustive-deps
288
301
  }, [// initPos is missing, because we need the previous value
289
- innerContentRef, toolbarProps, mediumHeightRatio, mediumHeight, showBackdrop, backdrop, isClosable, offset, children // to recompute data if content changes
302
+ innerContentRef, toolbarProps, mediumHeightRatio, mediumHeight, showBackdrop, backdrop, isClosable, offset, forceRender // to recompute data when content has changed
290
303
  ]);
291
304
  useSetFlagshipUI({
292
305
  bottomTheme: 'dark'
@@ -1,6 +1,5 @@
1
1
  import _extends from "@babel/runtime/helpers/extends";
2
- import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
3
- import React, { useState } from 'react';
2
+ import React from 'react';
4
3
  import cx from 'classnames';
5
4
  import Icon from "cozy-ui/transpiled/react/Icon";
6
5
  import IconButton from "cozy-ui/transpiled/react/IconButton";
@@ -34,19 +33,13 @@ var HeaderComponent = function HeaderComponent(_ref) {
34
33
  var SelfBottomSheet = function SelfBottomSheet(props) {
35
34
  var _props$componentsProp;
36
35
 
37
- var _useState = useState(0),
38
- _useState2 = _slicedToArray(_useState, 2),
39
- setInnerContentHeight = _useState2[1]; // tricks to rerender BottomSheet
40
-
41
-
42
36
  return /*#__PURE__*/React.createElement(BottomSheet, _extends({}, props === null || props === void 0 ? void 0 : (_props$componentsProp = props.componentsProps) === null || _props$componentsProp === void 0 ? void 0 : _props$componentsProp.bottomsheet, {
43
37
  backdrop: true,
44
38
  onClose: props.onClose
45
39
  }), /*#__PURE__*/React.createElement(BottomSheetItem, {
46
40
  disableGutters: true
47
41
  }, /*#__PURE__*/React.createElement(NestedSelect, _extends({
48
- HeaderComponent: HeaderComponent,
49
- setInnerContentHeight: setInnerContentHeight
42
+ HeaderComponent: HeaderComponent
50
43
  }, props))));
51
44
  };
52
45
 
@@ -1,18 +1,13 @@
1
1
  import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
2
2
  import _toArray from "@babel/runtime/helpers/toArray";
3
- import _classCallCheck from "@babel/runtime/helpers/classCallCheck";
4
- import _createClass from "@babel/runtime/helpers/createClass";
5
- import _assertThisInitialized from "@babel/runtime/helpers/assertThisInitialized";
6
- import _inherits from "@babel/runtime/helpers/inherits";
7
- import _possibleConstructorReturn from "@babel/runtime/helpers/possibleConstructorReturn";
8
- import _getPrototypeOf from "@babel/runtime/helpers/getPrototypeOf";
9
3
  import _defineProperty from "@babel/runtime/helpers/defineProperty";
4
+ import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
10
5
 
11
- function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
6
+ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
12
7
 
13
- function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
8
+ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
14
9
 
15
- import React, { Component } from 'react';
10
+ import React, { useEffect, useState, useRef } from 'react';
16
11
  import PropTypes from 'prop-types';
17
12
  import omit from 'lodash/omit';
18
13
  import List from "cozy-ui/transpiled/react/List";
@@ -27,191 +22,170 @@ export { ItemRow };
27
22
  * the option.
28
23
  */
29
24
 
30
- var NestedSelect = /*#__PURE__*/function (_Component) {
31
- _inherits(NestedSelect, _Component);
32
-
33
- var _super = _createSuper(NestedSelect);
34
-
35
- function NestedSelect(props) {
36
- var _this;
37
-
38
- _classCallCheck(this, NestedSelect);
39
-
40
- _this = _super.call(this, props);
25
+ var NestedSelect = function NestedSelect(_ref) {
26
+ var _state$searchValue;
27
+
28
+ var onSelect = _ref.onSelect,
29
+ ContentComponent = _ref.ContentComponent,
30
+ HeaderComponent = _ref.HeaderComponent,
31
+ canSelectParent = _ref.canSelectParent,
32
+ isSelected = _ref.isSelected,
33
+ title = _ref.title,
34
+ transformParentItem = _ref.transformParentItem,
35
+ radioPosition = _ref.radioPosition,
36
+ ellipsis = _ref.ellipsis,
37
+ options = _ref.options,
38
+ searchOptions = _ref.searchOptions,
39
+ noDivider = _ref.noDivider;
40
+ var innerRef = useRef();
41
+
42
+ var _useState = useState({
43
+ history: [options],
44
+ searchValue: '',
45
+ searchResult: []
46
+ }),
47
+ _useState2 = _slicedToArray(_useState, 2),
48
+ state = _useState2[0],
49
+ setState = _useState2[1];
50
+
51
+ var _useState3 = useState(false),
52
+ _useState4 = _slicedToArray(_useState3, 2),
53
+ unmounted = _useState4[0],
54
+ setUnmounted = _useState4[1];
55
+
56
+ useEffect(function () {
57
+ return function () {
58
+ setUnmounted(true);
59
+ };
60
+ }, []);
41
61
 
42
- _defineProperty(_assertThisInitialized(_this), "handleBack", function () {
43
- var _this$state$history = _toArray(_this.state.history),
44
- item = _this$state$history[0],
45
- newHistory = _this$state$history.slice(1);
62
+ var resetHistory = function resetHistory() {
63
+ if (unmounted) {
64
+ return;
65
+ }
46
66
 
47
- _this.setState({
48
- history: newHistory
67
+ setState(function (state) {
68
+ return _objectSpread(_objectSpread({}, state), {}, {
69
+ history: [options]
49
70
  });
50
-
51
- return item;
52
71
  });
72
+ };
53
73
 
54
- _defineProperty(_assertThisInitialized(_this), "handleNavToChildren", function (item) {
55
- var newHistory = [item].concat(_toConsumableArray(_this.state.history));
74
+ var handleBack = function handleBack() {
75
+ var _state$history = _toArray(state.history),
76
+ item = _state$history[0],
77
+ newHistory = _state$history.slice(1);
56
78
 
57
- _this.setState({
79
+ setState(function (state) {
80
+ return _objectSpread(_objectSpread({}, state), {}, {
58
81
  history: newHistory
59
82
  });
60
83
  });
84
+ return item;
85
+ };
61
86
 
62
- _defineProperty(_assertThisInitialized(_this), "handleSelect", function (item) {
63
- _this.props.onSelect(item); // It is important to reset history if the NestedSelected is used
64
- // multiple times in a row without being dismounted. For example
65
- // if it displayed in Carousel that slides in the NestedSelect
66
- // and slides it out on selection.
67
- // But, we want in this case that the resetting does not happen
68
- // while the animation is running.
69
- // There is probably a better way to do this.
70
-
71
-
72
- setTimeout(function () {
73
- _this.resetHistory();
74
- }, 500);
75
- });
76
-
77
- _defineProperty(_assertThisInitialized(_this), "handleClickItem", function (item) {
78
- if (item.children && item.children.length > 0) {
79
- _this.handleNavToChildren(item);
80
- } else {
81
- _this.handleSelect(item);
82
- }
83
- });
84
-
85
- _this.innerRef = /*#__PURE__*/React.createRef();
86
- _this.state = {
87
- history: [props.options],
88
- searchValue: '',
89
- searchResult: []
90
- };
91
- return _this;
92
- }
93
-
94
- _createClass(NestedSelect, [{
95
- key: "componentWillUnmount",
96
- value: function componentWillUnmount() {
97
- this.unmounted = true;
98
- }
99
- }, {
100
- key: "componentDidUpdate",
101
- value: function componentDidUpdate() {
102
- var _this$innerRef, _this$innerRef$curren;
103
-
104
- var setInnerContentHeight = this.props.setInnerContentHeight;
105
- setInnerContentHeight === null || setInnerContentHeight === void 0 ? void 0 : setInnerContentHeight((_this$innerRef = this.innerRef) === null || _this$innerRef === void 0 ? void 0 : (_this$innerRef$curren = _this$innerRef.current) === null || _this$innerRef$curren === void 0 ? void 0 : _this$innerRef$curren.offsetHeight);
106
- }
107
- }, {
108
- key: "resetHistory",
109
- value: function resetHistory() {
110
- if (this.unmounted) {
111
- return;
112
- }
113
-
114
- this.setState({
115
- history: [this.props.options]
87
+ var handleNavToChildren = function handleNavToChildren(item) {
88
+ var newHistory = [item].concat(_toConsumableArray(state.history));
89
+ setState(function (state) {
90
+ return _objectSpread(_objectSpread({}, state), {}, {
91
+ history: newHistory
116
92
  });
93
+ });
94
+ };
95
+
96
+ var handleSelect = function handleSelect(item) {
97
+ onSelect(item); // It is important to reset history if the NestedSelected is used
98
+ // multiple times in a row without being dismounted. For example
99
+ // if it displayed in Carousel that slides in the NestedSelect
100
+ // and slides it out on selection.
101
+ // But, we want in this case that the resetting does not happen
102
+ // while the animation is running.
103
+ // There is probably a better way to do this.
104
+
105
+ setTimeout(function () {
106
+ resetHistory();
107
+ }, 500);
108
+ };
109
+
110
+ var handleClickItem = function handleClickItem(item) {
111
+ if (item.children && item.children.length > 0) {
112
+ handleNavToChildren(item);
113
+ } else {
114
+ handleSelect(item);
117
115
  }
118
- }, {
119
- key: "render",
120
- value: function render() {
121
- var _this2 = this;
122
-
123
- var _this$props = this.props,
124
- ContentComponent = _this$props.ContentComponent,
125
- HeaderComponent = _this$props.HeaderComponent,
126
- canSelectParent = _this$props.canSelectParent,
127
- isSelected = _this$props.isSelected,
128
- title = _this$props.title,
129
- transformParentItem = _this$props.transformParentItem,
130
- radioPosition = _this$props.radioPosition,
131
- ellipsis = _this$props.ellipsis,
132
- options = _this$props.options,
133
- searchOptions = _this$props.searchOptions,
134
- noDivider = _this$props.noDivider;
135
- var _this$state = this.state,
136
- history = _this$state.history,
137
- searchValue = _this$state.searchValue,
138
- searchResult = _this$state.searchResult;
139
- var current = history[0];
140
- var children = current.children || [];
141
- var level = history.length - 1;
142
-
143
- var isSelectedWithLevel = function isSelectedWithLevel(item) {
144
- return isSelected(item, level);
145
- };
146
-
147
- var parentItem = transformParentItem(omit(current, 'children'));
148
- var hasSearchResult = searchValue.length > 0;
149
-
150
- var onChange = function onChange(ev) {
151
- var onSearch = searchOptions && searchOptions.onSearch;
152
-
153
- if (onSearch) {
154
- var _searchValue = ev.target.value;
155
-
156
- var _searchResult = onSearch(_searchValue);
157
-
158
- _this2.setState({
159
- searchValue: _searchValue,
160
- searchResult: _searchResult
161
- });
162
- }
163
- };
164
-
165
- return /*#__PURE__*/React.createElement("span", {
166
- ref: this.innerRef
167
- }, HeaderComponent ? /*#__PURE__*/React.createElement(HeaderComponent, {
168
- title: current.title || title,
169
- showBack: history.length > 1,
170
- onClickBack: this.handleBack
171
- }) : null, level > 0 ? current.header ? current.header : typeof options.childrenHeader === 'function' ? options.childrenHeader(level) : options.childrenHeader : options.header, /*#__PURE__*/React.createElement(ContentComponent, null, canSelectParent && level > 0 ? /*#__PURE__*/React.createElement(ItemRow, {
172
- radioPosition: radioPosition,
173
- item: parentItem,
174
- onClick: this.handleClickItem,
175
- isSelected: isSelectedWithLevel(parentItem),
176
- ellipsis: ellipsis,
177
- noDivider: noDivider
178
- }) : null, searchOptions && level === 0 && /*#__PURE__*/React.createElement("div", {
179
- className: "u-mh-1 u-mb-half"
180
- }, /*#__PURE__*/React.createElement(Input, {
181
- placeholder: searchOptions.placeholderSearch,
182
- onChange: onChange,
183
- value: searchValue
184
- })), hasSearchResult ? searchResult.length === 0 ? /*#__PURE__*/React.createElement(Typography, {
185
- variant: "body1",
186
- className: "u-flex u-flex-justify-center u-mb-1 "
187
- }, searchOptions.noDataLabel) : searchResult.map(function (item, index) {
188
- return /*#__PURE__*/React.createElement(ItemRow, {
189
- radioPosition: radioPosition,
190
- key: item.key || item.title,
191
- item: item,
192
- onClick: _this2.handleClickItem,
193
- isSelected: isSelectedWithLevel(item),
194
- isLast: index === searchResult.length - 1,
195
- ellipsis: ellipsis,
196
- noDivider: noDivider
197
- });
198
- }) : children.map(function (item, index) {
199
- return /*#__PURE__*/React.createElement(ItemRow, {
200
- radioPosition: radioPosition,
201
- key: item.key || item.title,
202
- item: item,
203
- onClick: _this2.handleClickItem,
204
- isSelected: isSelectedWithLevel(item),
205
- isLast: index === children.length - 1,
206
- ellipsis: ellipsis,
207
- noDivider: noDivider
116
+ };
117
+
118
+ var onChange = function onChange(ev) {
119
+ var onSearch = searchOptions === null || searchOptions === void 0 ? void 0 : searchOptions.onSearch;
120
+
121
+ if (onSearch) {
122
+ var searchValue = ev.target.value;
123
+ var searchResult = onSearch(searchValue);
124
+ setState(function (state) {
125
+ return _objectSpread(_objectSpread({}, state), {}, {
126
+ searchValue: searchValue,
127
+ searchResult: searchResult
208
128
  });
209
- })));
129
+ });
210
130
  }
211
- }]);
212
-
213
- return NestedSelect;
214
- }(Component);
131
+ };
132
+
133
+ var current = state.history[0];
134
+ var children = current.children || [];
135
+ var level = state.history.length - 1;
136
+ var parentItem = transformParentItem(omit(current, 'children'));
137
+ var hasSearchResult = ((_state$searchValue = state.searchValue) === null || _state$searchValue === void 0 ? void 0 : _state$searchValue.length) > 0;
138
+
139
+ var isSelectedWithLevel = function isSelectedWithLevel(item) {
140
+ return isSelected(item, level);
141
+ };
142
+
143
+ return /*#__PURE__*/React.createElement("span", {
144
+ ref: innerRef
145
+ }, HeaderComponent ? /*#__PURE__*/React.createElement(HeaderComponent, {
146
+ title: current.title || title,
147
+ showBack: state.history.length > 1,
148
+ onClickBack: handleBack
149
+ }) : null, level > 0 ? current.header ? current.header : typeof options.childrenHeader === 'function' ? options.childrenHeader(level) : options.childrenHeader : options.header, /*#__PURE__*/React.createElement(ContentComponent, null, canSelectParent && level > 0 ? /*#__PURE__*/React.createElement(ItemRow, {
150
+ radioPosition: radioPosition,
151
+ item: parentItem,
152
+ onClick: handleClickItem,
153
+ isSelected: isSelectedWithLevel(parentItem),
154
+ ellipsis: ellipsis,
155
+ noDivider: noDivider
156
+ }) : null, searchOptions && level === 0 && /*#__PURE__*/React.createElement("div", {
157
+ className: "u-mh-1 u-mb-half"
158
+ }, /*#__PURE__*/React.createElement(Input, {
159
+ placeholder: searchOptions.placeholderSearch,
160
+ onChange: onChange,
161
+ value: state.searchValue
162
+ })), hasSearchResult ? state.searchResult.length === 0 ? /*#__PURE__*/React.createElement(Typography, {
163
+ variant: "body1",
164
+ className: "u-flex u-flex-justify-center u-mb-1 "
165
+ }, searchOptions.noDataLabel) : state.searchResult.map(function (item, index) {
166
+ return /*#__PURE__*/React.createElement(ItemRow, {
167
+ radioPosition: radioPosition,
168
+ key: item.key || item.title,
169
+ item: item,
170
+ onClick: handleClickItem,
171
+ isSelected: isSelectedWithLevel(item),
172
+ isLast: index === state.searchResult.length - 1,
173
+ ellipsis: ellipsis,
174
+ noDivider: noDivider
175
+ });
176
+ }) : children.map(function (item, index) {
177
+ return /*#__PURE__*/React.createElement(ItemRow, {
178
+ radioPosition: radioPosition,
179
+ key: item.key || item.title,
180
+ item: item,
181
+ onClick: handleClickItem,
182
+ isSelected: isSelectedWithLevel(item),
183
+ isLast: index === children.length - 1,
184
+ ellipsis: ellipsis,
185
+ noDivider: noDivider
186
+ });
187
+ })));
188
+ };
215
189
 
216
190
  NestedSelect.defaultProps = {
217
191
  ContentComponent: List,