cozy-ui 82.14.0 → 83.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.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,31 @@
1
+ # [83.1.0](https://github.com/cozy/cozy-ui/compare/v83.0.0...v83.1.0) (2023-04-18)
2
+
3
+
4
+ ### Features
5
+
6
+ * Add success/fail animations to SquareAppIcon ([abbb4ed](https://github.com/cozy/cozy-ui/commit/abbb4ed))
7
+
8
+ # [83.0.0](https://github.com/cozy/cozy-ui/compare/v82.14.0...v83.0.0) (2023-04-17)
9
+
10
+
11
+ ### Features
12
+
13
+ * Update react-pdf from 4.0.5 to 5.7.2 ([fe9608e](https://github.com/cozy/cozy-ui/commit/fe9608e))
14
+ * **Viewer:** Navigate between pdf pages with keyboard ([d05f712](https://github.com/cozy/cozy-ui/commit/d05f712))
15
+
16
+
17
+ ### BREAKING CHANGES
18
+
19
+ * This update requires the two changes above in your application if you use the `Viewer` to display PDF. You can find more detail in `Viewer` documentation : https://docs.cozy.io/cozy-ui/react/#!/Viewer
20
+
21
+ Before :
22
+ - react-pdf alias : `react-pdf/dist/entry.webpack.js`
23
+ - public import for pdf worker : `react-pdf/dist/pdf.worker.entry.js`
24
+
25
+ After :
26
+ - react-pdf alias : `react-pdf/dist/esm/entry.webpack`
27
+ - public import for pdf worker : `react-pdf/dist/esm/pdf.worker.entry`
28
+
1
29
  # [82.14.0](https://github.com/cozy/cozy-ui/compare/v82.13.0...v82.14.0) (2023-04-13)
2
30
 
3
31
 
@@ -0,0 +1,41 @@
1
+ <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <style>
3
+ @-webkit-keyframes checkmark
4
+ {
5
+ 0% {
6
+ stroke-dashoffset: 100px
7
+ }
8
+
9
+ 100% {
10
+ stroke-dashoffset: 200px
11
+ }
12
+ }
13
+
14
+ @-ms-keyframes checkmark
15
+ {
16
+ 0% {
17
+ stroke-dashoffset: 100px
18
+ }
19
+
20
+ 100% {
21
+ stroke-dashoffset: 200px
22
+ }
23
+ }
24
+
25
+ @keyframes checkmark
26
+ {
27
+ 0% {
28
+ stroke-dashoffset: 100px
29
+ }
30
+
31
+ 100% {
32
+ stroke-dashoffset: 0px
33
+ }
34
+ }
35
+ path {
36
+ -webkit-animation: checkmark 1.0s ease-in-out backwards;
37
+ animation: checkmark 1.0s ease-in-out backwards
38
+ }
39
+ </style>
40
+ <path d="M1 11L4 14L15 3" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="stroke-dasharray:100px, 100px; stroke-dashoffset: 200px;"/>
41
+ </svg>
@@ -0,0 +1,41 @@
1
+ <svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <style>
3
+ @-webkit-keyframes checkmark
4
+ {
5
+ 0% {
6
+ stroke-dashoffset: 100px
7
+ }
8
+ 100% {
9
+ stroke-dashoffset: 200px
10
+ }
11
+ }
12
+ @-ms-keyframes checkmark
13
+ {
14
+ 0% {
15
+ stroke-dashoffset: 100px
16
+ }
17
+ 100% {
18
+ stroke-dashoffset: 200px
19
+ }
20
+ }
21
+ @keyframes checkmark
22
+ {
23
+ 0% {
24
+ stroke-dashoffset: 100px
25
+ }
26
+ 100% {
27
+ stroke-dashoffset: 0px
28
+ }
29
+ }
30
+ path.l1 {
31
+ -webkit-animation: checkmark 0.5s ease-in-out backwards;
32
+ animation: checkmark 0.5s ease-in-out backwards
33
+ }
34
+ path.l2 {
35
+ -webkit-animation: checkmark 0.5s ease-in-out 0.16s backwards;
36
+ animation: checkmark 0.5s ease-in-out 0.16s backwards
37
+ }
38
+ </style>
39
+ <path class="l1" d="M2 2L14 14" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="stroke-dasharray:100px, 100px; stroke-dashoffset: 200px;"/>
40
+ <path class="l2" d="M14 2L2 14" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="stroke-dasharray:100px, 100px; stroke-dashoffset: 200px;"/>
41
+ </svg>
package/jest.config.js CHANGED
@@ -11,7 +11,7 @@ module.exports = {
11
11
  'react-styleguidist.+\\.jsx?$': 'babel-jest',
12
12
  '^rsg-components(.*)$':
13
13
  '<rootDir>/node_modules/react-styleguidist/lib/client/rsg-components$1',
14
- 'react-pdf/dist/entry.webpack.js': 'react-pdf',
14
+ 'react-pdf/dist/esm/entry.webpack': 'react-pdf',
15
15
  '^cozy-client$': 'cozy-client/dist/index'
16
16
  },
17
17
  transformIgnorePatterns: ['node_modules/(?!(react-styleguidist)/)'],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cozy-ui",
3
- "version": "82.14.0",
3
+ "version": "83.1.0",
4
4
  "description": "Cozy apps UI SDK",
5
5
  "main": "./index.js",
6
6
  "bin": {
@@ -172,7 +172,7 @@
172
172
  "piwik-react-router": "0.12.1",
173
173
  "react-chartjs-2": "4.1.0",
174
174
  "react-markdown": "^4.0.8",
175
- "react-pdf": "^4.0.5",
175
+ "react-pdf": "^5.7.2",
176
176
  "react-popper": "^2.2.3",
177
177
  "react-remove-scroll": "^2.4.0",
178
178
  "react-select": "^4.3.0",
@@ -14,11 +14,10 @@ Use `makeActions` method and create (or use the predefined actions) to build the
14
14
 
15
15
  An action is a simple function that returns an object with specific keys:
16
16
 
17
- - **name** : `<string>` – Action's name
18
- - **action** : `<func>` – Method triggered when clicking the action
19
- - **isEnabled** : `<bool>` – Used to add `disable` effect (the action is still displayed)
20
- - **Component** : `<func>` – The returned component that manages the display
21
-
17
+ * **name** : `<string>` – Action's name
18
+ * **action** : `<func>` – Method triggered when clicking the action
19
+ * **isEnabled** : `<bool>` – Used to add `disable` effect (the action is still displayed)
20
+ * **Component** : `<func>` – The returned component that manages the display
22
21
 
23
22
  ```bash
24
23
  const expl = () => ({
@@ -83,7 +82,6 @@ const actions = makeActions([ modify, hr, call, customAction ])
83
82
  </DemoProvider>
84
83
  ```
85
84
 
86
-
87
85
  ### With a manual creation of the actions
88
86
 
89
87
  ```jsx
@@ -4,6 +4,7 @@ Display content coming up from the bottom of the screen. The pane can be swiped
4
4
  ### Usages
5
5
 
6
6
  * BottomSheet with header, text title and text content
7
+
7
8
  ```bash
8
9
  import BottomSheet, { BottomSheetHeader, BottomSheetItem, BottomSheetTitle } from 'cozy-ui/transpiled/react/BottomSheet'
9
10
 
@@ -19,6 +20,7 @@ import BottomSheet, { BottomSheetHeader, BottomSheetItem, BottomSheetTitle } fr
19
20
  ```
20
21
 
21
22
  * BottomSheet with list title and list content
23
+
22
24
  ```bash
23
25
  import BottomSheet, { BottomSheetItem, BottomSheetTitle } from 'cozy-ui/transpiled/react/BottomSheet'
24
26
 
@@ -14,7 +14,87 @@ module.exports = `<svg><defs>
14
14
  <path id="plus-small" d="M4 4V1a1 1 0 1 1 2 0v3h3a1 1 0 1 1 0 2H6v3a1 1 0 1 1-2 0V6H1a1 1 0 1 1 0-2h3z"/>
15
15
 
16
16
  <polygon id="plus-a" points="7 0 9 0 9 7 16 7 16 9 9 9 9 16 7 16 7 9 0 9 0 7 7 7"/>
17
- </defs><symbol id="bottom-select" viewBox="0 0 24 24">
17
+ </defs><symbol id="icon-check-animated" viewBox="0 0 16 16">
18
+ <style>
19
+ @-webkit-keyframes checkmark
20
+ {
21
+ 0% {
22
+ stroke-dashoffset: 100px
23
+ }
24
+
25
+ 100% {
26
+ stroke-dashoffset: 200px
27
+ }
28
+ }
29
+
30
+ @-ms-keyframes checkmark
31
+ {
32
+ 0% {
33
+ stroke-dashoffset: 100px
34
+ }
35
+
36
+ 100% {
37
+ stroke-dashoffset: 200px
38
+ }
39
+ }
40
+
41
+ @keyframes checkmark
42
+ {
43
+ 0% {
44
+ stroke-dashoffset: 100px
45
+ }
46
+
47
+ 100% {
48
+ stroke-dashoffset: 0px
49
+ }
50
+ }
51
+ path {
52
+ -webkit-animation: checkmark 1.0s ease-in-out backwards;
53
+ animation: checkmark 1.0s ease-in-out backwards
54
+ }
55
+ </style>
56
+ <path d="M1 11L4 14L15 3" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="stroke-dasharray:100px, 100px; stroke-dashoffset: 200px;"/>
57
+ </symbol><symbol id="icon-cross-animated" viewBox="0 0 16 16">
58
+ <style>
59
+ @-webkit-keyframes checkmark
60
+ {
61
+ 0% {
62
+ stroke-dashoffset: 100px
63
+ }
64
+ 100% {
65
+ stroke-dashoffset: 200px
66
+ }
67
+ }
68
+ @-ms-keyframes checkmark
69
+ {
70
+ 0% {
71
+ stroke-dashoffset: 100px
72
+ }
73
+ 100% {
74
+ stroke-dashoffset: 200px
75
+ }
76
+ }
77
+ @keyframes checkmark
78
+ {
79
+ 0% {
80
+ stroke-dashoffset: 100px
81
+ }
82
+ 100% {
83
+ stroke-dashoffset: 0px
84
+ }
85
+ }
86
+ path.l1 {
87
+ -webkit-animation: checkmark 0.5s ease-in-out backwards;
88
+ animation: checkmark 0.5s ease-in-out backwards
89
+ }
90
+ path.l2 {
91
+ -webkit-animation: checkmark 0.5s ease-in-out 0.16s backwards;
92
+ animation: checkmark 0.5s ease-in-out 0.16s backwards
93
+ }
94
+ </style>
95
+ <path class="l1" d="M2 2L14 14" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="stroke-dasharray:100px, 100px; stroke-dashoffset: 200px;"/>
96
+ <path class="l2" d="M14 2L2 14" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="stroke-dasharray:100px, 100px; stroke-dashoffset: 200px;"/>
97
+ </symbol><symbol id="bottom-select" viewBox="0 0 24 24">
18
98
  <g fill="#95999d" fill-rule="evenodd" transform="translate(12.285714, 12.000000) rotate(90.000000) translate(-12.285714, -12.000000)">
19
99
  <path d="M6.46026077,20.3174036 C5.84657974,20.9310847 5.84657974,21.9260582 6.46026077,22.5397392 C7.0739418,23.1534203 8.06891534,23.1534203 8.68259637,22.5397392 L18.1111678,13.1111678 C18.7248488,12.4974868 18.7248488,11.5025132 18.1111678,10.8888322 L8.68259637,1.46026077 C8.06891534,0.846579743 7.0739418,0.846579743 6.46026077,1.46026077 C5.84657974,2.0739418 5.84657974,3.06891534 6.46026077,3.68259637 L14.7776644,12 L6.46026077,20.3174036 Z"/>
20
100
  </g>
@@ -0,0 +1,29 @@
1
+ // Automatically created, please run `scripts/generate-svgr-icon.sh assets/icons/animated/icon-check-animated.svg` to regenerate;
2
+ import React from 'react'
3
+
4
+ function SvgIconCheckAnimated(props) {
5
+ return (
6
+ <svg viewBox="0 0 16 16" fill="none" {...props}>
7
+ <style>
8
+ {
9
+ '@-webkit-keyframes checkmark{0%{stroke-dashoffset:100px}to{stroke-dashoffset:200px}}@-ms-keyframes checkmark{0%{stroke-dashoffset:100px}to{stroke-dashoffset:200px}}@keyframes checkmark{0%{stroke-dashoffset:100px}to{stroke-dashoffset:0}}'
10
+ }
11
+ </style>
12
+ <path
13
+ d="M1 11l3 3L15 3"
14
+ stroke="#000"
15
+ strokeWidth={2}
16
+ strokeLinecap="round"
17
+ strokeLinejoin="round"
18
+ style={{
19
+ WebkitAnimation: 'checkmark 1s ease-in-out backwards',
20
+ animation: 'checkmark 1s ease-in-out backwards'
21
+ }}
22
+ strokeDasharray="100px,100px"
23
+ strokeDashoffset={200}
24
+ />
25
+ </svg>
26
+ )
27
+ }
28
+
29
+ export default SvgIconCheckAnimated
@@ -0,0 +1,44 @@
1
+ // Automatically created, please run `scripts/generate-svgr-icon.sh assets/icons/animated/icon-cross-animated.svg` to regenerate;
2
+ import React from 'react'
3
+
4
+ function SvgIconCrossAnimated(props) {
5
+ return (
6
+ <svg viewBox="0 0 16 16" fill="none" {...props}>
7
+ <style>
8
+ {
9
+ '@-webkit-keyframes checkmark{0%{stroke-dashoffset:100px}to{stroke-dashoffset:200px}}@-ms-keyframes checkmark{0%{stroke-dashoffset:100px}to{stroke-dashoffset:200px}}@keyframes checkmark{0%{stroke-dashoffset:100px}to{stroke-dashoffset:0}}'
10
+ }
11
+ </style>
12
+ <path
13
+ className="icon-cross-animated_svg__l1"
14
+ d="M2 2l12 12"
15
+ stroke="#000"
16
+ strokeWidth={2}
17
+ strokeLinecap="round"
18
+ strokeLinejoin="round"
19
+ style={{
20
+ WebkitAnimation: 'checkmark .5s ease-in-out backwards',
21
+ animation: 'checkmark .5s ease-in-out backwards'
22
+ }}
23
+ strokeDasharray="100px,100px"
24
+ strokeDashoffset={200}
25
+ />
26
+ <path
27
+ className="icon-cross-animated_svg__l2"
28
+ d="M14 2L2 14"
29
+ stroke="#000"
30
+ strokeWidth={2}
31
+ strokeLinecap="round"
32
+ strokeLinejoin="round"
33
+ style={{
34
+ WebkitAnimation: 'checkmark .5s ease-in-out .16s backwards',
35
+ animation: 'checkmark .5s ease-in-out .16s backwards'
36
+ }}
37
+ strokeDasharray="100px,100px"
38
+ strokeDashoffset={200}
39
+ />
40
+ </svg>
41
+ )
42
+ }
43
+
44
+ export default SvgIconCrossAnimated
@@ -13,12 +13,15 @@ import Button from 'cozy-ui/transpiled/react/Buttons'
13
13
  const theme = useCozyTheme()
14
14
  const app = { name: "Test App", slug: "testapp", type: "app" }
15
15
  const [isLoading, setLoading] = React.useState(false)
16
+ const [isError, setIsError] = React.useState(false)
17
+
16
18
 
17
19
 
18
20
  ;
19
21
 
20
22
  <>
21
- <Button className="u-mb-1" label="Toggle Loading" onClick={() => setLoading(!isLoading)} />
23
+ <Button className="u-mb-1 u-mr-1" label="Toggle Loading" onClick={() => setLoading(!isLoading)} />
24
+ <Button className="u-mb-1" label="Toggle Loading Error" onClick={() => setIsError(!isError)} />
22
25
 
23
26
  <Grid container spacing={1} style={{ background: `center / cover no-repeat url(${cloudWallpaper})` }}
24
27
  >
@@ -43,6 +46,9 @@ const [isLoading, setLoading] = React.useState(false)
43
46
  <Grid item>
44
47
  <SquareAppIcon IconContent={<Icon icon={CozyIcon} size="48" />} name="Loading" variant={isLoading ? 'loading' : 'default'} />
45
48
  </Grid>
49
+ <Grid item>
50
+ <SquareAppIcon IconContent={<Icon icon={CozyIcon} size="48" />} name="Loading" variant={isError ? 'error' : 'loading'} />
51
+ </Grid>
46
52
  <Grid item>
47
53
  <SquareAppIcon name="Shortcut" variant="shortcut" IconContent={<img
48
54
  src={`data:image/svg+xml;base64,${window.btoa(`<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
@@ -36,6 +36,9 @@ exports[`SquareAppIcon component should render an app correctly with the app nam
36
36
  <div
37
37
  class="styles__SquareAppIcon-icon-container___39MRl"
38
38
  >
39
+ <div
40
+ class="styles__onEnd___1O6Q7"
41
+ />
39
42
  <svg
40
43
  class="styles__c-app-icon___2_O40 styles__c-app-icon-default___3CEmt styles__icon___23x3R"
41
44
  height="100%"
@@ -100,6 +103,9 @@ exports[`SquareAppIcon component should render an app correctly with the given n
100
103
  <div
101
104
  class="styles__SquareAppIcon-icon-container___39MRl"
102
105
  >
106
+ <div
107
+ class="styles__onEnd___1O6Q7"
108
+ />
103
109
  <svg
104
110
  class="styles__c-app-icon___2_O40 styles__c-app-icon-default___3CEmt styles__icon___23x3R"
105
111
  height="100%"
@@ -164,6 +170,9 @@ exports[`SquareAppIcon component should render an app with the app slug if no na
164
170
  <div
165
171
  class="styles__SquareAppIcon-icon-container___39MRl"
166
172
  >
173
+ <div
174
+ class="styles__onEnd___1O6Q7"
175
+ />
167
176
  <svg
168
177
  class="styles__c-app-icon___2_O40 styles__c-app-icon-default___3CEmt styles__icon___23x3R"
169
178
  height="100%"
@@ -206,6 +215,9 @@ exports[`SquareAppIcon component should render correctly an app in add state 1`]
206
215
  <div
207
216
  class="styles__SquareAppIcon-icon-container___39MRl"
208
217
  >
218
+ <div
219
+ class="styles__onEnd___1O6Q7"
220
+ />
209
221
  <svg
210
222
  class="styles__icon___23x3R"
211
223
  height="16"
@@ -247,12 +259,37 @@ exports[`SquareAppIcon component should render correctly an app in error state 1
247
259
  <span
248
260
  class="MuiBadge-root"
249
261
  >
262
+ <div
263
+ class="styles__c-spinner___1snK7 styles__SquareAppIcon-spinner___o0LO1 u-m-0"
264
+ >
265
+ <svg
266
+ aria-busy="true"
267
+ class="styles__icon___23x3R styles__icon--spin___ybfC1"
268
+ height="16"
269
+ role="progressbar"
270
+ style="fill: var(--spinnerColor);"
271
+ viewBox="0 0 32 32"
272
+ width="16"
273
+ >
274
+ <path
275
+ d="M16 0a16 16 0 000 32 16 16 0 000-32m0 4a12 12 0 010 24 12 12 0 010-24"
276
+ opacity="0.25"
277
+ />
278
+ <path
279
+ d="M16 0a16 16 0 0116 16h-4A12 12 0 0016 4z"
280
+ />
281
+ </svg>
282
+
283
+ </div>
250
284
  <span
251
285
  class="MuiBadge-root styles__SquareAppIcon-wrapper___2SEuM makeStyles-shadow-33"
252
286
  >
253
287
  <div
254
288
  class="styles__SquareAppIcon-icon-container___39MRl"
255
289
  >
290
+ <div
291
+ class="styles__onEnd___1O6Q7"
292
+ />
256
293
  <svg
257
294
  class="styles__c-app-icon___2_O40 styles__c-app-icon-default___3CEmt styles__icon___23x3R"
258
295
  height="100%"
@@ -307,6 +344,9 @@ exports[`SquareAppIcon component should render correctly an app in ghost state 1
307
344
  <div
308
345
  class="styles__SquareAppIcon-icon-container___39MRl"
309
346
  >
347
+ <div
348
+ class="styles__onEnd___1O6Q7"
349
+ />
310
350
  <svg
311
351
  class="styles__c-app-icon___2_O40 styles__c-app-icon-default___3CEmt styles__icon___23x3R"
312
352
  height="100%"
@@ -349,6 +389,9 @@ exports[`SquareAppIcon component should render correctly an app in maintenance s
349
389
  <div
350
390
  class="styles__SquareAppIcon-icon-container___39MRl"
351
391
  >
392
+ <div
393
+ class="styles__onEnd___1O6Q7"
394
+ />
352
395
  <svg
353
396
  class="styles__c-app-icon___2_O40 styles__c-app-icon-default___3CEmt styles__icon___23x3R"
354
397
  height="100%"
@@ -458,6 +501,9 @@ exports[`SquareAppIcon component should render correctly an app with custom cont
458
501
  <div
459
502
  class="styles__SquareAppIcon-icon-container___39MRl"
460
503
  >
504
+ <div
505
+ class="styles__onEnd___1O6Q7"
506
+ />
461
507
  <svg
462
508
  class="styles__icon___23x3R"
463
509
  height="16"
@@ -1,19 +1,21 @@
1
- import React from 'react'
1
+ import React, { useEffect, useState } from 'react'
2
2
  import cx from 'classnames'
3
3
  import PropTypes from 'prop-types'
4
4
  import get from 'lodash/get'
5
5
 
6
- import { makeStyles } from '../styles'
7
6
  import AppIcon from '../AppIcon'
8
7
  import Badge from '../Badge'
8
+ import Icon from '../Icon'
9
+ import IconCheckAnimated from '../Icons/IconCheckAnimated'
9
10
  import InfosBadge from '../InfosBadge'
10
- import { nameToColor } from '../Avatar'
11
11
  import Spinner from '../Spinner'
12
+ import SvgIconCrossAnimated from '../Icons/IconCrossAnimated'
12
13
  import Typography from '../Typography'
13
- import Icon from '../Icon'
14
+ import iconOut from '../Icons/LinkOut'
14
15
  import iconPlus from '../Icons/Plus'
15
16
  import iconWarning from '../Icons/WarningCircle'
16
- import iconOut from '../Icons/LinkOut'
17
+ import { makeStyles } from '../styles'
18
+ import { nameToColor } from '../Avatar'
17
19
 
18
20
  import { color } from './constants.json'
19
21
  import styles from './styles.styl'
@@ -72,6 +74,23 @@ export const SquareAppIcon = ({
72
74
  const appName =
73
75
  name || get(appIconProps, 'app.name') || get(appIconProps, 'app') || ''
74
76
  const letter = appName[0] || ''
77
+ const prevVariant = React.useRef(variant)
78
+ const [animationState, setAnimationState] = useState()
79
+
80
+ const handleAnimationEnd = e => {
81
+ if (e.animationName.startsWith('end')) setAnimationState()
82
+ }
83
+
84
+ useEffect(() => {
85
+ const curr = prevVariant.current
86
+
87
+ if (curr === 'loading' && variant === 'error') setAnimationState('failed')
88
+
89
+ if (curr === 'loading' && (variant === 'default' || variant === undefined))
90
+ setAnimationState('success')
91
+
92
+ prevVariant.current = variant
93
+ }, [variant])
75
94
 
76
95
  return (
77
96
  <div data-testid="square-app-icon" className={cx(classes.tileWrapper)}>
@@ -82,7 +101,7 @@ export const SquareAppIcon = ({
82
101
  overlap="rectangular"
83
102
  invisible={variant !== 'shortcut'}
84
103
  >
85
- {['default', 'loading'].includes(variant) && (
104
+ {['default', 'loading', 'error'].includes(variant) && (
86
105
  <Spinner className={cx(styles['SquareAppIcon-spinner'], 'u-m-0')} />
87
106
  )}
88
107
  <Badge
@@ -124,6 +143,26 @@ export const SquareAppIcon = ({
124
143
  </Typography>
125
144
  ) : (
126
145
  <div className={styles['SquareAppIcon-icon-container']}>
146
+ <div
147
+ className={cx(
148
+ styles['onEnd'],
149
+ { [styles['isSuccess']]: animationState === 'success' },
150
+ { [styles['isFailed']]: animationState === 'failed' }
151
+ )}
152
+ onAnimationEnd={handleAnimationEnd}
153
+ >
154
+ {animationState && (
155
+ <Icon
156
+ size="32"
157
+ icon={
158
+ animationState === 'success'
159
+ ? IconCheckAnimated
160
+ : SvgIconCrossAnimated
161
+ }
162
+ />
163
+ )}
164
+ </div>
165
+
127
166
  {variant === 'add' ? (
128
167
  <Icon icon={iconPlus} color={color} />
129
168
  ) : IconContent ? (
@@ -55,7 +55,77 @@ $color = constants['color'] // hard-coded color, because the component is curren
55
55
  transform scale(0.8334)
56
56
 
57
57
  .SquareAppIcon-spinner
58
+ margin 0 !important
59
+
58
60
  svg
59
61
  position absolute
60
62
  height 100%
61
63
  width 100%
64
+
65
+ animation-duration = 1.50s
66
+ icon-duration = 0.2s
67
+ icon-start = 0.2s
68
+ border-radius-start = 50%
69
+ border-radius-end = rem(12)
70
+ opacity-start = 0
71
+ opacity-end = 1
72
+
73
+ .onEnd
74
+ align-items center
75
+ border-radius border-radius-start
76
+ display flex
77
+ height 100%
78
+ opacity opacity-start
79
+ position absolute
80
+ width 100%
81
+ z-index 1
82
+
83
+ svg
84
+ fill transparent !important
85
+
86
+ path
87
+ animation-duration icon-duration !important
88
+
89
+ path:first-of-type
90
+ animation-delay icon-start !important
91
+
92
+ // The second path is a part of the cross,
93
+ // since it has its own hardcoded animation delay we need to add it again (.16s)
94
+ path+path
95
+ animation-delay icon-start + .16s !important
96
+
97
+ *
98
+ stroke var(--white) !important
99
+
100
+ .onEnd.isFailed
101
+ --animationColor var(--errorColor)
102
+
103
+ .onEnd.isSuccess
104
+ --animationColor var(--successColor)
105
+
106
+ .isSuccess
107
+ .isFailed
108
+ animation end-animation animation-duration forwards
109
+
110
+ @keyframes end-animation {
111
+ 0% {
112
+ background-color transparent
113
+ border-radius border-radius-start
114
+ opacity opacity-start
115
+ }
116
+ 13.33% {
117
+ background-color var(--animationColor)
118
+ border-radius border-radius-end
119
+ opacity opacity-end
120
+ }
121
+ 66.67% {
122
+ background-color var(--animationColor)
123
+ border-radius border-radius-end
124
+ opacity opacity-end
125
+ }
126
+ 100% {
127
+ border-radius border-radius-end
128
+ opacity opacity-start
129
+ background-color transparent
130
+ }
131
+ }