@duro-app/ui 0.38.1 → 0.39.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@duro-app/ui",
3
- "version": "0.38.1",
3
+ "version": "0.39.0",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -54,7 +54,7 @@
54
54
  }
55
55
  },
56
56
  "dependencies": {
57
- "@duro-app/tokens": "^0.38.1"
57
+ "@duro-app/tokens": "^0.39.0"
58
58
  },
59
59
  "devDependencies": {
60
60
  "@babel/preset-typescript": "^7.28.0",
@@ -2,6 +2,7 @@ import {css} from 'react-strict-dom'
2
2
  import {colors} from '@duro-app/tokens/tokens/colors.css'
3
3
  import {spacing, radii} from '@duro-app/tokens/tokens/spacing.css'
4
4
  import {typography} from '@duro-app/tokens/tokens/typography.css'
5
+ import {duration, easing} from '@duro-app/tokens/tokens/motion.css'
5
6
 
6
7
  export const styles = css.create({
7
8
  base: {
@@ -17,11 +18,20 @@ export const styles = css.create({
17
18
  borderWidth: 1,
18
19
  borderStyle: 'solid',
19
20
  cursor: 'pointer',
20
- transitionProperty: 'background-color, border-color, color, opacity',
21
- transitionDuration: '150ms',
22
- transitionTimingFunction: 'ease',
21
+ transitionProperty: 'background-color, border-color, color, opacity, transform',
22
+ transitionDuration: duration.fast,
23
+ transitionTimingFunction: easing.standard,
23
24
  textDecoration: 'none',
24
25
  whiteSpace: 'nowrap',
26
+ // Tactile press feedback. The scale is suppressed under reduced motion (and
27
+ // duration.fast collapses to 0ms there too), so it's inert for those users.
28
+ transform: {
29
+ default: 'scale(1)',
30
+ ':active': {
31
+ default: 'scale(0.97)',
32
+ '@media (prefers-reduced-motion: reduce)': 'scale(1)',
33
+ },
34
+ },
25
35
  outlineWidth: {
26
36
  default: 0,
27
37
  ':focus-visible': 2,
@@ -3,6 +3,7 @@ import {colors} from '@duro-app/tokens/tokens/colors.css'
3
3
  import {spacing, radii} from '@duro-app/tokens/tokens/spacing.css'
4
4
  import {typography} from '@duro-app/tokens/tokens/typography.css'
5
5
  import {shadows} from '@duro-app/tokens/tokens/shadows.css'
6
+ import {duration, easing} from '@duro-app/tokens/tokens/motion.css'
6
7
 
7
8
  export const styles = css.create({
8
9
  base: {
@@ -41,11 +42,16 @@ export const styles = css.create({
41
42
  },
42
43
  cursor: 'pointer',
43
44
  transitionProperty: 'background-color, border-color, transform',
44
- transitionDuration: '150ms',
45
- transitionTimingFunction: 'ease',
45
+ transitionDuration: duration.fast,
46
+ transitionTimingFunction: easing.standard,
47
+ // Lift on hover; suppressed under reduced motion so there's no positional
48
+ // shift (the token duration also collapses to 0ms there).
46
49
  transform: {
47
50
  default: 'translateY(0)',
48
- ':hover': 'translateY(-2px)',
51
+ ':hover': {
52
+ default: 'translateY(-2px)',
53
+ '@media (prefers-reduced-motion: reduce)': 'translateY(0)',
54
+ },
49
55
  },
50
56
  },
51
57
  // Sizes (padding)
@@ -2,12 +2,11 @@ import {css} from 'react-strict-dom'
2
2
  import {colors} from '@duro-app/tokens/tokens/colors.css'
3
3
  import {spacing} from '@duro-app/tokens/tokens/spacing.css'
4
4
  import {shadows} from '@duro-app/tokens/tokens/shadows.css'
5
+ import {duration, easing} from '@duro-app/tokens/tokens/motion.css'
5
6
 
6
- /** Apple-standard ease: aggressive deceleration, feels like "arriving" */
7
- const APPLE_EASE_OUT = 'cubic-bezier(0.32, 0.72, 0, 1)'
8
- const APPLE_EASE_IN = 'cubic-bezier(0.72, 0, 0.68, 0.28)'
9
-
10
- const OPEN_DURATION = '280ms'
7
+ // The "Apple ease" curves and the 280ms open now live in the shared motion
8
+ // tokens (easing.easeOut/easeIn, duration.slow). The 220ms close is specific to
9
+ // this panel's exit, so it stays local.
11
10
  const CLOSE_DURATION = '220ms'
12
11
 
13
12
  export const styles = css.create({
@@ -24,8 +23,8 @@ export const styles = css.create({
24
23
  from: {width: 0},
25
24
  to: {width: 360},
26
25
  }),
27
- animationDuration: OPEN_DURATION,
28
- animationTimingFunction: APPLE_EASE_OUT,
26
+ animationDuration: duration.slow,
27
+ animationTimingFunction: easing.easeOut,
29
28
  animationFillMode: 'both',
30
29
  },
31
30
  wrapperCloseSm: {
@@ -34,7 +33,7 @@ export const styles = css.create({
34
33
  to: {width: 0},
35
34
  }),
36
35
  animationDuration: CLOSE_DURATION,
37
- animationTimingFunction: APPLE_EASE_IN,
36
+ animationTimingFunction: easing.easeIn,
38
37
  animationFillMode: 'both',
39
38
  },
40
39
 
@@ -44,8 +43,8 @@ export const styles = css.create({
44
43
  from: {width: 0},
45
44
  to: {width: 480},
46
45
  }),
47
- animationDuration: OPEN_DURATION,
48
- animationTimingFunction: APPLE_EASE_OUT,
46
+ animationDuration: duration.slow,
47
+ animationTimingFunction: easing.easeOut,
49
48
  animationFillMode: 'both',
50
49
  },
51
50
  wrapperCloseMd: {
@@ -54,7 +53,7 @@ export const styles = css.create({
54
53
  to: {width: 0},
55
54
  }),
56
55
  animationDuration: CLOSE_DURATION,
57
- animationTimingFunction: APPLE_EASE_IN,
56
+ animationTimingFunction: easing.easeIn,
58
57
  animationFillMode: 'both',
59
58
  },
60
59
 
@@ -87,8 +86,8 @@ export const styles = css.create({
87
86
  opacity: 1,
88
87
  },
89
88
  }),
90
- animationDuration: OPEN_DURATION,
91
- animationTimingFunction: APPLE_EASE_OUT,
89
+ animationDuration: duration.slow,
90
+ animationTimingFunction: easing.easeOut,
92
91
  animationFillMode: 'both',
93
92
  },
94
93
  slideOut: {
@@ -103,7 +102,7 @@ export const styles = css.create({
103
102
  },
104
103
  }),
105
104
  animationDuration: CLOSE_DURATION,
106
- animationTimingFunction: APPLE_EASE_IN,
105
+ animationTimingFunction: easing.easeIn,
107
106
  animationFillMode: 'both',
108
107
  },
109
108
 
@@ -183,7 +182,8 @@ export const styles = css.create({
183
182
  padding: 0,
184
183
  flexShrink: 0,
185
184
  transitionProperty: 'background-color',
186
- transitionDuration: '150ms',
185
+ transitionDuration: duration.fast,
186
+ transitionTimingFunction: easing.standard,
187
187
  },
188
188
 
189
189
  inlineWrapper: {
@@ -33,3 +33,22 @@
33
33
  text-decoration: none;
34
34
  }
35
35
  }
36
+
37
+ /*
38
+ * Reduced-motion safety net. Neutralizes animation/transition timing globally
39
+ * for users who prefer reduced motion, covering every component (dialogs,
40
+ * drawers, detail panels, spinners, …) without touching their per-component
41
+ * tuned animations. Uses 0.01ms (not 0) so animationend/transitionend still
42
+ * fire and any state-driven mount/unmount logic completes. Kept outside
43
+ * `@layer reset` so its `!important` wins regardless of cascade layers.
44
+ */
45
+ @media (prefers-reduced-motion: reduce) {
46
+ *,
47
+ *::before,
48
+ *::after {
49
+ animation-duration: 0.01ms !important;
50
+ animation-iteration-count: 1 !important;
51
+ transition-duration: 0.01ms !important;
52
+ scroll-behavior: auto !important;
53
+ }
54
+ }