cozy-ui-plus 5.3.1 → 6.1.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 (44) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/dist/CollectionField/index.js +2 -2
  3. package/dist/Contacts/AddModal/ContactForm/FieldInput.js +49 -20
  4. package/dist/Contacts/AddModal/ContactForm/FieldInputArray.js +5 -16
  5. package/dist/Contacts/AddModal/ContactForm/FieldInputLayout.js +2 -2
  6. package/dist/Contacts/AddModal/ContactForm/FieldInputWrapper.js +3 -1
  7. package/dist/Contacts/AddModal/ContactForm/RemoveButton.js +34 -0
  8. package/dist/Contacts/AddModal/ContactForm/fieldsConfig.js +3 -1
  9. package/dist/Contacts/AddModal/ContactForm/helpers.js +12 -2
  10. package/dist/Contacts/AddModal/ContactForm/index.js +14 -3
  11. package/dist/ContactsListModal/ContactsListModal.js +2 -6
  12. package/dist/ContactsListModal/MobileHeader.js +2 -6
  13. package/dist/Field/index.js +9 -10
  14. package/dist/ListItem/ListItemFile/ItemIcon.js +11 -4
  15. package/dist/Qualification/QualificationItem/index.js +10 -14
  16. package/dist/ShortcutTile/index.js +2 -2
  17. package/dist/SquareAppIcon/index.js +22 -21
  18. package/dist/providers/CozyTheme/index.js +0 -3
  19. package/dist/src/Contacts/AddModal/ContactForm/FieldInput.d.ts +3 -1
  20. package/dist/src/Contacts/AddModal/ContactForm/FieldInputWrapper.d.ts +2 -1
  21. package/dist/src/Contacts/AddModal/ContactForm/RemoveButton.d.ts +4 -0
  22. package/dist/src/providers/CozyTheme/index.d.ts +0 -3
  23. package/dist/stylesheet.css +0 -25
  24. package/package.json +4 -4
  25. package/src/CollectionField/index.jsx +2 -2
  26. package/src/Contacts/AddModal/ContactForm/FieldInput.jsx +29 -9
  27. package/src/Contacts/AddModal/ContactForm/FieldInputArray.jsx +3 -14
  28. package/src/Contacts/AddModal/ContactForm/FieldInputLayout.jsx +5 -3
  29. package/src/Contacts/AddModal/ContactForm/FieldInputWrapper.jsx +3 -1
  30. package/src/Contacts/AddModal/ContactForm/RemoveButton.jsx +18 -0
  31. package/src/Contacts/AddModal/ContactForm/fieldsConfig.jsx +3 -1
  32. package/src/Contacts/AddModal/ContactForm/helpers.js +11 -2
  33. package/src/Contacts/AddModal/ContactForm/helpers.spec.js +62 -0
  34. package/src/Contacts/AddModal/ContactForm/index.jsx +27 -14
  35. package/src/ContactsListModal/ContactsListModal.jsx +1 -4
  36. package/src/ContactsListModal/MobileHeader.jsx +20 -24
  37. package/src/Field/index.jsx +7 -6
  38. package/src/ListItem/ListItemFile/ItemIcon.jsx +15 -7
  39. package/src/Qualification/QualificationItem/index.jsx +11 -16
  40. package/src/ShortcutTile/index.tsx +1 -1
  41. package/src/SquareAppIcon/__snapshots__/SquareAppIcon.spec.js.snap +240 -271
  42. package/src/SquareAppIcon/index.jsx +96 -107
  43. package/src/providers/CozyTheme/index.jsx +0 -2
  44. package/src/Contacts/AddModal/ContactForm/styles.styl +0 -2
@@ -21,6 +21,8 @@ var _propTypes = _interopRequireDefault(require("prop-types"));
21
21
 
22
22
  var _react = _interopRequireWildcard(require("react"));
23
23
 
24
+ var _helpers = require("cozy-ui/transpiled/react/Avatar/helpers");
25
+
24
26
  var _Badge = _interopRequireDefault(require("cozy-ui/transpiled/react/Badge"));
25
27
 
26
28
  var _Icon = _interopRequireDefault(require("cozy-ui/transpiled/react/Icon"));
@@ -35,21 +37,17 @@ var _Plus = _interopRequireDefault(require("cozy-ui/transpiled/react/Icons/Plus"
35
37
 
36
38
  var _WarningCircle = _interopRequireDefault(require("cozy-ui/transpiled/react/Icons/WarningCircle"));
37
39
 
38
- var _InfosBadge = _interopRequireDefault(require("cozy-ui/transpiled/react/InfosBadge"));
39
-
40
40
  var _ListItemText = _interopRequireDefault(require("cozy-ui/transpiled/react/ListItemText"));
41
41
 
42
42
  var _Spinner = _interopRequireDefault(require("cozy-ui/transpiled/react/Spinner"));
43
43
 
44
44
  var _Typography = _interopRequireDefault(require("cozy-ui/transpiled/react/Typography"));
45
45
 
46
- var _helpers = require("cozy-ui/transpiled/react/legacy/Avatar/helpers");
47
-
48
46
  var _styles = require("cozy-ui/transpiled/react/styles");
49
47
 
50
48
  var _AppIcon = _interopRequireDefault(require("../AppIcon"));
51
49
 
52
- var _CozyTheme = _interopRequireWildcard(require("../providers/CozyTheme"));
50
+ var _CozyTheme = require("../providers/CozyTheme");
53
51
 
54
52
  var _excluded = ["display", "name", "variant", "IconContent", "description", "hideShortcutBadge"];
55
53
 
@@ -94,9 +92,6 @@ var useStyles = (0, _styles.makeStyles)(function (theme) {
94
92
  margin: '0.25rem 0.25rem 0 0.25rem',
95
93
  height: '2rem'
96
94
  }),
97
- nameInverted: {
98
- textShadow: theme.textShadows[1]
99
- },
100
95
  squareAppIconGhost: {
101
96
  backgroundColor: (0, _styles.alpha)(theme.palette.primary.main, theme.palette.action.ghostOpacity),
102
97
  border: "1px dashed ".concat((0, _styles.alpha)(theme.palette.primary.main, theme.palette.border.ghostOpacity))
@@ -157,7 +152,6 @@ var SquareAppIcon = function SquareAppIcon(_ref2) {
157
152
  appIconProps = (0, _objectWithoutProperties2.default)(_ref2, _excluded);
158
153
 
159
154
  var _useCozyTheme = (0, _CozyTheme.useCozyTheme)(),
160
- themeVariant = _useCozyTheme.variant,
161
155
  type = _useCozyTheme.type;
162
156
 
163
157
  var classes = useStyles();
@@ -179,25 +173,32 @@ var SquareAppIcon = function SquareAppIcon(_ref2) {
179
173
  var curr = prevVariant.current; // eslint-disable-next-line react-hooks/set-state-in-effect
180
174
 
181
175
  if (curr === 'loading' && variant === 'error') setAnimationState('failed');
182
- if (curr === 'loading' && (variant === 'default' || variant === undefined)) // eslint-disable-next-line react-hooks/set-state-in-effect
183
- setAnimationState('success');
176
+ if (curr === 'loading' && (variant === 'default' || variant === undefined)) setAnimationState('success');
184
177
  prevVariant.current = variant;
185
178
  }, [variant]);
186
179
  var exceptionVariant = ['ghost'];
187
- var squareTheme = exceptionVariant.includes(variant) ? themeVariant : 'normal';
188
180
  return /*#__PURE__*/_react.default.createElement("div", {
189
181
  "data-testid": "square-app-icon",
190
182
  className: (0, _classnames.default)(classes.tileWrapper, (0, _defineProperty2.default)({}, classes.detailedTileWrapper, display === 'detailed'))
191
- }, /*#__PURE__*/_react.default.createElement(_CozyTheme.default, {
192
- variant: squareTheme
193
- }, /*#__PURE__*/_react.default.createElement(_InfosBadge.default, {
194
- badgeContent: variant === 'shortcut' && !hideShortcutBadge ? /*#__PURE__*/_react.default.createElement(_Icon.default, {
183
+ }, /*#__PURE__*/_react.default.createElement(_Badge.default, {
184
+ badgeContent: variant === 'shortcut' && !hideShortcutBadge ? /*#__PURE__*/_react.default.createElement("div", {
185
+ className: "u-h-1-half u-miw-1-half u-bdrs-circle u-flex u-flex-items-center u-flex-justify-center",
186
+ style: {
187
+ backgroundColor: 'var(--paperBackgroundColor)',
188
+ color: 'var(--iconTextColor)',
189
+ boxShadow: 'var(--shadow3)'
190
+ }
191
+ }, /*#__PURE__*/_react.default.createElement(_Icon.default, {
195
192
  size: "10",
196
193
  icon: _LinkOut.default
197
- }) : null,
194
+ })) : null,
198
195
  className: (0, _classnames.default)((0, _defineProperty2.default)({}, 'u-mr-1', display === 'detailed')),
199
196
  overlap: "rectangular",
200
- invisible: variant !== 'shortcut' || hideShortcutBadge
197
+ invisible: variant !== 'shortcut' || hideShortcutBadge,
198
+ anchorOrigin: {
199
+ vertical: 'bottom',
200
+ horizontal: 'right'
201
+ }
201
202
  }, /*#__PURE__*/_react.default.createElement(SquareAppIconSpinner, {
202
203
  variant: variant,
203
204
  animationState: animationState
@@ -218,7 +219,7 @@ var SquareAppIcon = function SquareAppIcon(_ref2) {
218
219
  variant: "h2",
219
220
  align: "center"
220
221
  }, letter.toUpperCase()) : /*#__PURE__*/_react.default.createElement("div", {
221
- className: (0, _classnames.default)(styles['SquareAppIcon-icon-container'], (0, _defineProperty2.default)({}, styles['SquareAppIcon-icon-container-normal'], themeVariant === 'normal'))
222
+ className: (0, _classnames.default)(styles['SquareAppIcon-icon-container'], [styles['SquareAppIcon-icon-container-normal']])
222
223
  }, /*#__PURE__*/_react.default.createElement("div", {
223
224
  className: (0, _classnames.default)(styles['onEnd'], (0, _defineProperty2.default)({}, styles['isSuccess'], animationState === 'success'), (0, _defineProperty2.default)({}, styles['isFailed'], animationState === 'failed')),
224
225
  onAnimationEnd: handleAnimationEnd
@@ -230,11 +231,11 @@ var SquareAppIcon = function SquareAppIcon(_ref2) {
230
231
  color: "var(--primaryColor)"
231
232
  }) : IconContent ? IconContent : /*#__PURE__*/_react.default.createElement("div", {
232
233
  className: "u-w-2 u-h-2"
233
- }, /*#__PURE__*/_react.default.createElement(_AppIcon.default, appIconProps)))))), display === 'detailed' ? /*#__PURE__*/_react.default.createElement(_ListItemText.default, {
234
+ }, /*#__PURE__*/_react.default.createElement(_AppIcon.default, appIconProps))))), display === 'detailed' ? /*#__PURE__*/_react.default.createElement(_ListItemText.default, {
234
235
  primary: appName,
235
236
  secondary: description
236
237
  }) : /*#__PURE__*/_react.default.createElement(_Typography.default, {
237
- className: (0, _classnames.default)(classes.name, (0, _defineProperty2.default)({}, classes.nameInverted, themeVariant === 'inverted'), 'u-spacellipsis'),
238
+ className: (0, _classnames.default)(classes.name, 'u-spacellipsis'),
238
239
  variant: "h6",
239
240
  align: "center"
240
241
  }, appName));
@@ -39,8 +39,6 @@ var CozyTheme = function CozyTheme(_ref) {
39
39
  };
40
40
 
41
41
  CozyTheme.propTypes = {
42
- variant: _propTypes.default.oneOf(['normal', 'inverted']),
43
-
44
42
  /** Causes this element's children to appear as if they were direct children of the element's parent, ignoring the element itself. */
45
43
  ignoreItself: _propTypes.default.bool,
46
44
 
@@ -50,7 +48,6 @@ CozyTheme.propTypes = {
50
48
  children: _propTypes.default.node
51
49
  };
52
50
  CozyTheme.defaultProps = {
53
- variant: 'normal',
54
51
  ignoreCozySettings: false,
55
52
  ignoreItself: true
56
53
  };
@@ -1,5 +1,5 @@
1
1
  export default FieldInput;
2
- declare function FieldInput({ name, labelProps, className, attributes: { subFields, ...restAttributes }, contacts, contact, error, helperText, label, isInvisible }: {
2
+ declare function FieldInput({ name, labelProps, className, attributes: { subFields, ...restAttributes }, contacts, contact, error, onRemove, showRemove, helperText, label, isInvisible }: {
3
3
  name: any;
4
4
  labelProps: any;
5
5
  className: any;
@@ -10,6 +10,8 @@ declare function FieldInput({ name, labelProps, className, attributes: { subFiel
10
10
  contacts: any;
11
11
  contact: any;
12
12
  error: any;
13
+ onRemove: any;
14
+ showRemove: any;
13
15
  helperText: any;
14
16
  label: any;
15
17
  isInvisible: any;
@@ -1,11 +1,12 @@
1
1
  export default FieldInputWrapper;
2
- declare function FieldInputWrapper({ input, attributes: { component, layout, icon, isSecondary, validate, ...restAttributes }, variant, fullWidth, ...props }: {
2
+ declare function FieldInputWrapper({ input, attributes: { component, layout, isHalfWidth, icon, isSecondary, validate, ...restAttributes }, variant, fullWidth, ...props }: {
3
3
  [x: string]: any;
4
4
  input: any;
5
5
  attributes: {
6
6
  [x: string]: any;
7
7
  component: any;
8
8
  layout: any;
9
+ isHalfWidth: any;
9
10
  icon: any;
10
11
  isSecondary: any;
11
12
  validate: any;
@@ -0,0 +1,4 @@
1
+ export default RemoveButton;
2
+ declare function RemoveButton({ onRemove }: {
3
+ onRemove: any;
4
+ }): JSX.Element;
@@ -6,15 +6,12 @@ declare function CozyTheme({ ignoreCozySettings, ...props }: {
6
6
  }): JSX.Element;
7
7
  declare namespace CozyTheme {
8
8
  namespace propTypes {
9
- let variant: PropTypes.Requireable<string>;
10
9
  let ignoreItself: PropTypes.Requireable<boolean>;
11
10
  let ignoreCozySettings: PropTypes.Requireable<boolean>;
12
11
  let className: PropTypes.Requireable<string>;
13
12
  let children: PropTypes.Requireable<PropTypes.ReactNodeLike>;
14
13
  }
15
14
  namespace defaultProps {
16
- let variant_1: string;
17
- export { variant_1 as variant };
18
15
  let ignoreCozySettings_1: boolean;
19
16
  export { ignoreCozySettings_1 as ignoreCozySettings };
20
17
  let ignoreItself_1: boolean;
@@ -220,11 +220,6 @@
220
220
  }
221
221
  @media (max-width: 48rem) {
222
222
  }
223
- /* imported from styles.styl */
224
-
225
- .styles__contact-form-field__wrapper___13Usq {
226
- width: calc(100% - 3rem);
227
- }
228
223
  /* imported from styles.styl */
229
224
 
230
225
  .styles__container___w8t8I {
@@ -343,26 +338,6 @@ it overrides nothing so there's no need for
343
338
  }
344
339
  /* imported from styles.styl */
345
340
 
346
- .styles__c-label___24c92 {
347
- text-transform: uppercase;
348
- color: var(--secondaryTextColor);
349
- font-size: 0.813rem;
350
- font-weight: bold;
351
- line-height: 1rem;
352
- }
353
- .styles__c-label___24c92.styles__is-error___1gUPb {
354
- color: var(--errorColor);
355
- }
356
- .styles__c-label--block___1Zska {
357
- display: block;
358
- padding: 0.5rem 0;
359
- }
360
- @media (max-width: 48rem) {
361
- }
362
- @media (max-width: 48rem) {
363
- }
364
- /* imported from styles.styl */
365
-
366
341
  .styles__o-field___2B6P3 {
367
342
  position: relative;
368
343
  display: flex;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cozy-ui-plus",
3
- "version": "5.3.1",
3
+ "version": "6.1.0",
4
4
  "description": "Cozy-ui-plus is an extension of cozy-ui and provides components based on cozy-client",
5
5
  "main": "dist/index.js",
6
6
  "license": "MIT",
@@ -37,7 +37,7 @@
37
37
  "cozy-intent": "^2.31.1",
38
38
  "cozy-logger": "^1.18.1",
39
39
  "cozy-stack-client": "^60.21.1",
40
- "cozy-ui": "^135.0.0",
40
+ "cozy-ui": "^138.1.0",
41
41
  "jest": "30.3.0",
42
42
  "jest-canvas-mock": "2.3.1",
43
43
  "jest-environment-jsdom": "30.3.0",
@@ -68,10 +68,10 @@
68
68
  "cozy-device-helper": ">=2.0.0",
69
69
  "cozy-intent": ">=2.30.0",
70
70
  "cozy-logger": ">=1.17.0",
71
- "cozy-ui": ">=135.0.0",
71
+ "cozy-ui": ">=138.1.0",
72
72
  "react": "^16 || ^17 || ^18",
73
73
  "react-dom": "^16 || ^17 || ^18",
74
74
  "twake-i18n": ">=0.3.0"
75
75
  },
76
- "gitHead": "e726cac12603dffee9a88debf8618c47bc628082"
76
+ "gitHead": "0ac8873a7ba8909f3b02cb719d9fc05133bf5a1d"
77
77
  }
@@ -4,7 +4,7 @@ import React, { useRef } from 'react'
4
4
  import Icon from 'cozy-ui/transpiled/react/Icon'
5
5
  import CrossSmallIcon from 'cozy-ui/transpiled/react/Icons/CrossSmall'
6
6
  import PlusIcon from 'cozy-ui/transpiled/react/Icons/Plus'
7
- import Label from 'cozy-ui/transpiled/react/Label'
7
+ import InputLabel from 'cozy-ui/transpiled/react/InputLabel'
8
8
  import Stack from 'cozy-ui/transpiled/react/Stack'
9
9
  import Button from 'cozy-ui/transpiled/react/deprecated/Button'
10
10
 
@@ -70,7 +70,7 @@ const CollectionField = props => {
70
70
 
71
71
  return (
72
72
  <FieldContainer {...rest}>
73
- <Label>{label}</Label>
73
+ <InputLabel>{label}</InputLabel>
74
74
  <Stack>
75
75
  {values.length > 0 ? (
76
76
  <Stack spacing="s">
@@ -4,16 +4,32 @@ import PropTypes from 'prop-types'
4
4
  import React, { useState } from 'react'
5
5
  import { Field } from 'react-final-form'
6
6
 
7
+ import { useBreakpoints } from 'cozy-ui/transpiled/react/providers/Breakpoints'
7
8
  import { useI18n, useExtendI18n } from 'twake-i18n'
8
9
 
9
10
  import FieldInputWrapper from './FieldInputWrapper'
10
11
  import HasValueCondition from './HasValueCondition'
11
12
  import { RelatedContactList } from './RelatedContactList'
13
+ import RemoveButton from './RemoveButton'
12
14
  import { locales } from './locales'
13
- import styles from './styles.styl'
14
15
  import ContactAddressDialog from '../ContactAddressDialog'
15
16
  import { fieldInputAttributesTypes, labelPropTypes } from '../types'
16
17
 
18
+ const FieldAndRemove = ({ showRemove, onRemove, ...props }) => {
19
+ const { isMobile } = useBreakpoints()
20
+
21
+ if (isMobile) {
22
+ return (
23
+ <div className="u-flex u-flex-items-center u-w-100">
24
+ <Field {...props} />
25
+ {showRemove && <RemoveButton onRemove={onRemove} />}
26
+ </div>
27
+ )
28
+ }
29
+
30
+ return <Field {...props} />
31
+ }
32
+
17
33
  const FieldInput = ({
18
34
  name,
19
35
  labelProps,
@@ -22,6 +38,8 @@ const FieldInput = ({
22
38
  contacts,
23
39
  contact,
24
40
  error,
41
+ onRemove,
42
+ showRemove,
25
43
  helperText,
26
44
  label,
27
45
  isInvisible
@@ -33,6 +51,7 @@ const FieldInput = ({
33
51
  useState(false)
34
52
  useExtendI18n(locales)
35
53
  const { t } = useI18n()
54
+ const { isMobile } = useBreakpoints()
36
55
 
37
56
  const handleClick = () => {
38
57
  if (name.includes('address')) {
@@ -50,14 +69,12 @@ const FieldInput = ({
50
69
 
51
70
  return (
52
71
  <div
53
- className={cx(
54
- className,
55
- styles['contact-form-field__wrapper'],
56
- 'u-flex-column-s',
57
- { 'u-flex': !isInvisible, 'u-dn': isInvisible }
58
- )}
72
+ className={cx(className, 'u-flex-column-s u-flex-items-center u-w-100', {
73
+ 'u-flex': !isInvisible,
74
+ 'u-dn': isInvisible
75
+ })}
59
76
  >
60
- <Field
77
+ <FieldAndRemove
61
78
  error={error}
62
79
  helperText={helperText}
63
80
  label={label}
@@ -66,6 +83,8 @@ const FieldInput = ({
66
83
  name={name}
67
84
  contact={contact}
68
85
  component={FieldInputWrapper}
86
+ showRemove={showRemove}
87
+ onRemove={onRemove}
69
88
  onFocus={onFocus}
70
89
  onClick={handleClick}
71
90
  />
@@ -85,7 +104,7 @@ const FieldInput = ({
85
104
  )}
86
105
  {labelProps && (
87
106
  <HasValueCondition name={name} otherCondition={hasBeenFocused}>
88
- <div className="u-mt-half-s u-ml-half u-ml-0-s u-flex-shrink-0 u-w-auto u-miw-4">
107
+ <div className="u-mt-half-s u-ml-half u-ml-0-s u-flex-shrink-0 u-w-100-s u-w-auto u-miw-4">
89
108
  <Field
90
109
  attributes={labelProps}
91
110
  name={`${name}Label`}
@@ -97,6 +116,7 @@ const FieldInput = ({
97
116
  </div>
98
117
  </HasValueCondition>
99
118
  )}
119
+ {showRemove && !isMobile && <RemoveButton onRemove={onRemove} />}
100
120
  </div>
101
121
  )
102
122
  }
@@ -4,10 +4,7 @@ import { FieldArray } from 'react-final-form-arrays'
4
4
 
5
5
  import Button from 'cozy-ui/transpiled/react/Buttons'
6
6
  import Icon from 'cozy-ui/transpiled/react/Icon'
7
- import IconButton from 'cozy-ui/transpiled/react/IconButton'
8
- import CrossCircleIcon from 'cozy-ui/transpiled/react/Icons/CrossCircle'
9
7
  import PlusIcon from 'cozy-ui/transpiled/react/Icons/Plus'
10
- import ListItemIcon from 'cozy-ui/transpiled/react/ListItemIcon'
11
8
  import { useI18n, useExtendI18n } from 'twake-i18n'
12
9
 
13
10
  import FieldInput from './FieldInput'
@@ -53,22 +50,14 @@ const FieldInputArray = ({
53
50
  contacts={contacts}
54
51
  contact={contact}
55
52
  error={isError}
53
+ index={index}
54
+ showRemove={showRemove}
56
55
  helperText={isError ? errors[inputName] : null}
57
56
  name={inputName}
58
57
  label={t(`Contacts.AddModal.ContactForm.fields.${name}`)}
59
58
  labelProps={label}
59
+ onRemove={() => removeField(fields, index)}
60
60
  />
61
- {showRemove && (
62
- <ListItemIcon className="u-ml-half">
63
- <IconButton
64
- aria-label="delete"
65
- size="medium"
66
- onClick={() => removeField(fields, index)}
67
- >
68
- <Icon icon={CrossCircleIcon} />
69
- </IconButton>
70
- </ListItemIcon>
71
- )}
72
61
  </div>
73
62
  )
74
63
  })}
@@ -35,9 +35,11 @@ const FieldInputLayout = ({
35
35
  'u-dn': isSecondary && !showSecondaryFields
36
36
  })}
37
37
  >
38
- <div className="u-w-2-half">
39
- {icon && <Icon icon={icon} color="var(--iconTextColor)" />}
40
- </div>
38
+ {icon && (
39
+ <div className="u-w-2-half">
40
+ <Icon icon={icon} color="var(--iconTextColor)" />
41
+ </div>
42
+ )}
41
43
  <div className="u-w-100">
42
44
  {layout === 'array' ? (
43
45
  <FieldInputArray
@@ -13,11 +13,12 @@ const FieldInputWrapper = ({
13
13
  attributes: {
14
14
  component,
15
15
  layout,
16
+ isHalfWidth,
16
17
  icon,
17
18
  isSecondary,
18
19
  validate,
19
20
  ...restAttributes
20
- }, // ⚠️ `layout` `icon` `isSecondary` `validate` are removed from attributes to avoid DOM propagration, only used for business rules
21
+ }, // ⚠️ `layout` `isHalfWidth` `icon` `isSecondary` `validate` are removed from attributes to avoid DOM propagration, only used for business rules
21
22
  variant,
22
23
  fullWidth,
23
24
  ...props
@@ -37,6 +38,7 @@ const FieldInputWrapper = ({
37
38
  {...props}
38
39
  variant={variant}
39
40
  fullWidth={fullWidth}
41
+ size="small"
40
42
  minRows="2"
41
43
  />
42
44
  )
@@ -0,0 +1,18 @@
1
+ import React from 'react'
2
+
3
+ import Icon from 'cozy-ui/transpiled/react/Icon'
4
+ import IconButton from 'cozy-ui/transpiled/react/IconButton'
5
+ import CrossCircleIcon from 'cozy-ui/transpiled/react/Icons/CrossCircle'
6
+ import ListItemIcon from 'cozy-ui/transpiled/react/ListItemIcon'
7
+
8
+ const RemoveButton = ({ onRemove }) => {
9
+ return (
10
+ <ListItemIcon className="u-ml-half">
11
+ <IconButton aria-label="delete" size="medium" onClick={onRemove}>
12
+ <Icon icon={CrossCircleIcon} />
13
+ </IconButton>
14
+ </ListItemIcon>
15
+ )
16
+ }
17
+
18
+ export default RemoveButton
@@ -40,6 +40,7 @@ export const fields = [
40
40
  icon: null,
41
41
  type: 'text',
42
42
  layout: 'accordion',
43
+ isHalfWidth: true,
43
44
  subFields: [
44
45
  {
45
46
  name: 'additionalName',
@@ -56,7 +57,8 @@ export const fields = [
56
57
  {
57
58
  name: 'familyName',
58
59
  icon: null,
59
- type: 'text'
60
+ type: 'text',
61
+ isHalfWidth: true
60
62
  },
61
63
  {
62
64
  name: 'company',
@@ -460,17 +460,26 @@ export const makeFields = (customFields, defaultFields) => {
460
460
  return defaultFields
461
461
  }
462
462
 
463
- const fields = [...defaultFields]
463
+ let fields = [...defaultFields]
464
464
 
465
465
  customFields.forEach(customField => {
466
466
  const defaultField = fields.find(field => field.name === customField.name)
467
+
468
+ // If isRemoved is true, remove the field from the result
469
+ if (customField.isRemoved) {
470
+ if (defaultField) {
471
+ fields = fields.filter(field => field.name !== customField.name)
472
+ }
473
+ return
474
+ }
475
+
467
476
  const _field = defaultField || customField
468
477
 
469
478
  if (defaultField) {
470
479
  Object.assign(_field, customField)
471
480
  }
472
481
 
473
- if (_field.position) {
482
+ if (_field.position !== undefined) {
474
483
  if (defaultField) {
475
484
  const fieldIndex = fields.indexOf(defaultField)
476
485
  fields.splice(fieldIndex, 1)
@@ -441,6 +441,68 @@ describe('makeFields', () => {
441
441
  }
442
442
  ])
443
443
  })
444
+
445
+ it('should remove default field when custom field has isRemoved set to true', () => {
446
+ const defaultFields = [
447
+ { name: 'firstname' },
448
+ { name: 'lastname' },
449
+ { name: 'email' }
450
+ ]
451
+ const customFields = [{ name: 'lastname', isRemoved: true }]
452
+
453
+ const res = makeFields(customFields, defaultFields)
454
+
455
+ expect(res).toStrictEqual([{ name: 'firstname' }, { name: 'email' }])
456
+ })
457
+
458
+ it('should remove multiple default fields when multiple custom fields have isRemoved set to true', () => {
459
+ const defaultFields = [
460
+ { name: 'firstname' },
461
+ { name: 'lastname' },
462
+ { name: 'email' },
463
+ { name: 'phone' }
464
+ ]
465
+ const customFields = [
466
+ { name: 'lastname', isRemoved: true },
467
+ { name: 'phone', isRemoved: true }
468
+ ]
469
+
470
+ const res = makeFields(customFields, defaultFields)
471
+
472
+ expect(res).toStrictEqual([{ name: 'firstname' }, { name: 'email' }])
473
+ })
474
+
475
+ it('should ignore custom fields with isRemoved but no matching default field', () => {
476
+ const defaultFields = [{ name: 'firstname' }, { name: 'lastname' }]
477
+ const customFields = [{ name: 'nonexistent', isRemoved: true }]
478
+
479
+ const res = makeFields(customFields, defaultFields)
480
+
481
+ expect(res).toStrictEqual(defaultFields)
482
+ })
483
+
484
+ it('should handle mixed custom fields with isRemoved, position, and property overrides', () => {
485
+ const defaultFields = [
486
+ { name: 'firstname', type: 'text' },
487
+ { name: 'lastname', type: 'text' },
488
+ { name: 'email', type: 'email' },
489
+ { name: 'phone', type: 'tel' }
490
+ ]
491
+ const customFields = [
492
+ { name: 'lastname', isRemoved: true },
493
+ { name: 'email', isSecondary: true, position: 0 },
494
+ { name: 'middlename', position: 1 }
495
+ ]
496
+
497
+ const res = makeFields(customFields, defaultFields)
498
+
499
+ expect(res).toStrictEqual([
500
+ { name: 'email', type: 'email', isSecondary: true, position: 0 },
501
+ { name: 'middlename', position: 1 },
502
+ { name: 'firstname', type: 'text' },
503
+ { name: 'phone', type: 'tel' }
504
+ ])
505
+ })
444
506
  })
445
507
 
446
508
  describe('hasNoValues', () => {
@@ -3,7 +3,9 @@ import React, { useState } from 'react'
3
3
  import { Form } from 'react-final-form'
4
4
 
5
5
  import { getHasManyItems } from 'cozy-client/dist/associations/HasMany'
6
+ import Box from 'cozy-ui/transpiled/react/Box'
6
7
  import Button from 'cozy-ui/transpiled/react/Buttons'
8
+ import { useBreakpoints } from 'cozy-ui/transpiled/react/providers/Breakpoints'
7
9
  import { useI18n, useExtendI18n } from 'twake-i18n'
8
10
 
9
11
  import FieldInputLayout from './FieldInputLayout'
@@ -49,6 +51,7 @@ const ContactForm = ({ contacts, contact, customFieldsProps, onSubmit }) => {
49
51
  const { t } = useI18n()
50
52
  const { fields, makeCustomFieldsFormValues, makeCustomContactValues } =
51
53
  customFieldsProps
54
+ const { isMobile } = useBreakpoints()
52
55
 
53
56
  const _fields = makeFields(fields, defaultFields)
54
57
  const hasSecondaryFields = _fields.some(el => el.isSecondary)
@@ -90,20 +93,30 @@ const ContactForm = ({ contacts, contact, customFieldsProps, onSubmit }) => {
90
93
  onSubmit={handleSubmit}
91
94
  className="u-flex u-flex-column"
92
95
  >
93
- {_fields.map((attributes, index) => (
94
- <FieldInputLayout
95
- key={index}
96
- attributes={attributes}
97
- contacts={contacts}
98
- contact={contact}
99
- showSecondaryFields={showSecondaryFields}
100
- formProps={{
101
- valid,
102
- submitFailed,
103
- errors
104
- }}
105
- />
106
- ))}
96
+ <div className="u-flex u-flex-wrap u-flex-justify-between">
97
+ {_fields.map((attributes, index) => (
98
+ <Box
99
+ key={index}
100
+ width={
101
+ attributes.isHalfWidth && !isMobile
102
+ ? 'calc(50% - 0.5rem)'
103
+ : '100%'
104
+ }
105
+ >
106
+ <FieldInputLayout
107
+ attributes={attributes}
108
+ contacts={contacts}
109
+ contact={contact}
110
+ showSecondaryFields={showSecondaryFields}
111
+ formProps={{
112
+ valid,
113
+ submitFailed,
114
+ errors
115
+ }}
116
+ />
117
+ </Box>
118
+ ))}
119
+ </div>
107
120
  {hasSecondaryFields && !showSecondaryFields && (
108
121
  <div>
109
122
  <Button
@@ -22,7 +22,6 @@ import AddContactDialog from './AddContact/AddContactDialog'
22
22
  import ContactsListContent from './ContactsListContent'
23
23
  import MobileHeader from './MobileHeader'
24
24
  import styles from './styles.styl'
25
- import CozyTheme from '../providers/CozyTheme'
26
25
 
27
26
  const ContactsListModal = ({
28
27
  onItemClick,
@@ -64,9 +63,7 @@ const ContactsListModal = ({
64
63
 
65
64
  return (
66
65
  <TopAnchoredDialog {...dialogProps}>
67
- <CozyTheme variant={isMobile ? 'inverted' : 'normal'}>
68
- <DialogCloseButton onClick={dismissAction} />
69
- </CozyTheme>
66
+ <DialogCloseButton onClick={dismissAction} />
70
67
  <DialogTitle
71
68
  {...dialogTitleProps}
72
69
  className={cx(dialogTitleProps.className, {