@udixio/ui-react 2.6.0 → 2.7.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 (130) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/dist/index.cjs +2 -2
  3. package/dist/index.js +2451 -2126
  4. package/dist/lib/components/Button.d.ts.map +1 -1
  5. package/dist/lib/components/Card.d.ts.map +1 -1
  6. package/dist/lib/components/Fab.d.ts +1 -1
  7. package/dist/lib/components/Fab.d.ts.map +1 -1
  8. package/dist/lib/components/FabMenu.d.ts +9 -0
  9. package/dist/lib/components/FabMenu.d.ts.map +1 -0
  10. package/dist/lib/components/IconButton.d.ts.map +1 -1
  11. package/dist/lib/components/NavigationRail.d.ts.map +1 -1
  12. package/dist/lib/components/NavigationRailItem.d.ts.map +1 -1
  13. package/dist/lib/components/Tab.d.ts.map +1 -1
  14. package/dist/lib/components/ToolTip.d.ts.map +1 -1
  15. package/dist/lib/components/index.d.ts +1 -0
  16. package/dist/lib/components/index.d.ts.map +1 -1
  17. package/dist/lib/effects/State.d.ts +26 -0
  18. package/dist/lib/effects/State.d.ts.map +1 -0
  19. package/dist/lib/effects/index.d.ts +1 -0
  20. package/dist/lib/effects/index.d.ts.map +1 -1
  21. package/dist/lib/effects/ripple/RippleEffect.d.ts.map +1 -1
  22. package/dist/lib/interfaces/button.interface.d.ts +4 -1
  23. package/dist/lib/interfaces/button.interface.d.ts.map +1 -1
  24. package/dist/lib/interfaces/fab-menu.interface.d.ts +12 -0
  25. package/dist/lib/interfaces/fab-menu.interface.d.ts.map +1 -0
  26. package/dist/lib/interfaces/fab.interface.d.ts +2 -2
  27. package/dist/lib/interfaces/fab.interface.d.ts.map +1 -1
  28. package/dist/lib/interfaces/index.d.ts +1 -0
  29. package/dist/lib/interfaces/index.d.ts.map +1 -1
  30. package/dist/lib/interfaces/side-sheet.interface.d.ts +1 -1
  31. package/dist/lib/interfaces/side-sheet.interface.d.ts.map +1 -1
  32. package/dist/lib/styles/button.style.d.ts +43 -3
  33. package/dist/lib/styles/button.style.d.ts.map +1 -1
  34. package/dist/lib/styles/card.style.d.ts +9 -1
  35. package/dist/lib/styles/card.style.d.ts.map +1 -1
  36. package/dist/lib/styles/carousel-item.style.d.ts +11 -1
  37. package/dist/lib/styles/carousel-item.style.d.ts.map +1 -1
  38. package/dist/lib/styles/carousel.style.d.ts +16 -1
  39. package/dist/lib/styles/carousel.style.d.ts.map +1 -1
  40. package/dist/lib/styles/divider.style.d.ts +8 -2
  41. package/dist/lib/styles/divider.style.d.ts.map +1 -1
  42. package/dist/lib/styles/fab-menu.style.d.ts +83 -0
  43. package/dist/lib/styles/fab-menu.style.d.ts.map +1 -0
  44. package/dist/lib/styles/fab.style.d.ts +29 -5
  45. package/dist/lib/styles/fab.style.d.ts.map +1 -1
  46. package/dist/lib/styles/icon-button.style.d.ts +37 -1
  47. package/dist/lib/styles/icon-button.style.d.ts.map +1 -1
  48. package/dist/lib/styles/index.d.ts +2 -0
  49. package/dist/lib/styles/index.d.ts.map +1 -1
  50. package/dist/lib/styles/navigation-rail-item.style.d.ts +11 -1
  51. package/dist/lib/styles/navigation-rail-item.style.d.ts.map +1 -1
  52. package/dist/lib/styles/navigation-rail.style.d.ts +31 -1
  53. package/dist/lib/styles/navigation-rail.style.d.ts.map +1 -1
  54. package/dist/lib/styles/progress-indicator.style.d.ts +12 -1
  55. package/dist/lib/styles/progress-indicator.style.d.ts.map +1 -1
  56. package/dist/lib/styles/side-sheet.style.d.ts +20 -3
  57. package/dist/lib/styles/side-sheet.style.d.ts.map +1 -1
  58. package/dist/lib/styles/slider.style.d.ts +21 -2
  59. package/dist/lib/styles/slider.style.d.ts.map +1 -1
  60. package/dist/lib/styles/snackbar.style.d.ts +14 -3
  61. package/dist/lib/styles/snackbar.style.d.ts.map +1 -1
  62. package/dist/lib/styles/switch.style.d.ts +14 -2
  63. package/dist/lib/styles/switch.style.d.ts.map +1 -1
  64. package/dist/lib/styles/tab.style.d.ts +12 -2
  65. package/dist/lib/styles/tab.style.d.ts.map +1 -1
  66. package/dist/lib/styles/tabs.style.d.ts +17 -2
  67. package/dist/lib/styles/tabs.style.d.ts.map +1 -1
  68. package/dist/lib/styles/text-field.style.d.ts +23 -2
  69. package/dist/lib/styles/text-field.style.d.ts.map +1 -1
  70. package/dist/lib/styles/tooltip.style.d.ts +20 -3
  71. package/dist/lib/styles/tooltip.style.d.ts.map +1 -1
  72. package/dist/lib/utils/styles/get-classname.d.ts +3 -0
  73. package/dist/lib/utils/styles/get-classname.d.ts.map +1 -1
  74. package/dist/lib/utils/styles/index.d.ts +1 -0
  75. package/dist/lib/utils/styles/index.d.ts.map +1 -1
  76. package/dist/lib/utils/styles/use-classnames.d.ts +6 -0
  77. package/dist/lib/utils/styles/use-classnames.d.ts.map +1 -0
  78. package/package.json +2 -2
  79. package/src/lib/components/Button.tsx +54 -20
  80. package/src/lib/components/Card.tsx +11 -9
  81. package/src/lib/components/Carousel.tsx +2 -2
  82. package/src/lib/components/CarouselItem.tsx +2 -2
  83. package/src/lib/components/Divider.tsx +2 -2
  84. package/src/lib/components/Fab.tsx +22 -21
  85. package/src/lib/components/FabMenu.tsx +229 -0
  86. package/src/lib/components/IconButton.tsx +24 -30
  87. package/src/lib/components/NavigationRail.tsx +7 -4
  88. package/src/lib/components/NavigationRailItem.tsx +13 -4
  89. package/src/lib/components/ProgressIndicator.tsx +2 -2
  90. package/src/lib/components/SideSheet.tsx +2 -2
  91. package/src/lib/components/Slider.tsx +2 -2
  92. package/src/lib/components/Snackbar.tsx +2 -2
  93. package/src/lib/components/Switch.tsx +2 -2
  94. package/src/lib/components/Tab.tsx +11 -11
  95. package/src/lib/components/Tabs.tsx +2 -2
  96. package/src/lib/components/TextField.tsx +2 -2
  97. package/src/lib/components/ToolTip.tsx +9 -3
  98. package/src/lib/components/index.ts +1 -0
  99. package/src/lib/effects/State.tsx +83 -0
  100. package/src/lib/effects/index.ts +1 -0
  101. package/src/lib/effects/ripple/RippleEffect.tsx +40 -27
  102. package/src/lib/interfaces/button.interface.ts +5 -1
  103. package/src/lib/interfaces/fab-menu.interface.ts +12 -0
  104. package/src/lib/interfaces/fab.interface.ts +8 -2
  105. package/src/lib/interfaces/index.ts +1 -0
  106. package/src/lib/interfaces/side-sheet.interface.tsx +1 -1
  107. package/src/lib/styles/button.style.ts +127 -136
  108. package/src/lib/styles/card.style.ts +22 -17
  109. package/src/lib/styles/carousel-item.style.ts +23 -9
  110. package/src/lib/styles/carousel.style.ts +17 -5
  111. package/src/lib/styles/divider.style.ts +27 -13
  112. package/src/lib/styles/fab-menu.style.ts +28 -0
  113. package/src/lib/styles/fab.style.ts +41 -43
  114. package/src/lib/styles/icon-button.style.ts +160 -149
  115. package/src/lib/styles/index.ts +2 -0
  116. package/src/lib/styles/navigation-rail-item.style.ts +49 -40
  117. package/src/lib/styles/navigation-rail.style.ts +31 -15
  118. package/src/lib/styles/progress-indicator.style.ts +49 -36
  119. package/src/lib/styles/side-sheet.style.ts +41 -27
  120. package/src/lib/styles/slider.style.ts +37 -23
  121. package/src/lib/styles/snackbar.style.ts +22 -10
  122. package/src/lib/styles/switch.style.ts +61 -45
  123. package/src/lib/styles/tab.style.ts +76 -66
  124. package/src/lib/styles/tabs.style.ts +19 -10
  125. package/src/lib/styles/text-field.style.ts +108 -97
  126. package/src/lib/styles/tooltip.style.ts +42 -33
  127. package/src/lib/utils/styles/get-classname.ts +23 -0
  128. package/src/lib/utils/styles/index.ts +1 -0
  129. package/src/lib/utils/styles/use-classnames.ts +25 -0
  130. package/src/tests/useClassNames.spec.tsx +82 -0
@@ -1,11 +1,39 @@
1
1
  import { classNames, ReactProps } from '../utils';
2
2
  import { ButtonInterface } from '../interfaces';
3
- import { buttonStyle } from '../styles';
3
+ import { useButtonStyle } from '../styles';
4
4
  import { Icon } from '../icon';
5
5
  import { ProgressIndicator } from './ProgressIndicator';
6
- import { RippleEffect } from '../effects';
6
+ import { State } from '../effects';
7
7
  import React, { useEffect, useRef } from 'react';
8
8
 
9
+ /**
10
+ * Resolves variant aliases to their actual variant values
11
+ */
12
+ function resolveVariantAlias(
13
+ variant?:
14
+ | 'filled'
15
+ | 'elevated'
16
+ | 'tonal'
17
+ | 'outlined'
18
+ | 'text'
19
+ | 'primary'
20
+ | 'secondary',
21
+ ): 'filled' | 'elevated' | 'tonal' | 'outlined' | 'text' {
22
+ const aliasMap = {
23
+ primary: 'filled',
24
+ secondary: 'tonal',
25
+ } as const;
26
+
27
+ if (variant && variant in aliasMap) {
28
+ return aliasMap[variant as keyof typeof aliasMap];
29
+ }
30
+
31
+ return (
32
+ (variant as 'filled' | 'elevated' | 'tonal' | 'outlined' | 'text') ||
33
+ 'filled'
34
+ );
35
+ }
36
+
9
37
  /**
10
38
  * Buttons prompt most actions in a UI
11
39
  * @status beta
@@ -38,6 +66,7 @@ export const Button = ({
38
66
  'Button component requires either a label prop or children content',
39
67
  );
40
68
  }
69
+ variant = resolveVariantAlias(variant);
41
70
 
42
71
  const ElementType = href ? 'a' : 'button';
43
72
 
@@ -72,7 +101,7 @@ export const Button = ({
72
101
  onToggle(next);
73
102
  };
74
103
  }
75
- const styles = buttonStyle({
104
+ const styles = useButtonStyle({
76
105
  allowShapeTransformation,
77
106
  size,
78
107
  disableTextMargins,
@@ -109,25 +138,30 @@ export const Button = ({
109
138
  style={{ transition: transition.duration + 's' }}
110
139
  >
111
140
  <div className={styles.touchTarget}></div>
112
- <div
113
- className={styles.stateLayer}
141
+ <State
114
142
  style={{ transition: transition.duration + 's' }}
115
- >
116
- {!disabled && (
117
- <RippleEffect
118
- colorName={
119
- (variant === 'filled' && onToggle && 'on-surface-variant') ||
120
- (variant === 'filled' && !onToggle && 'on-primary') ||
121
- (variant === 'elevated' && 'primary') ||
122
- (variant === 'tonal' && 'on-secondary-container') ||
123
- (variant === 'outlined' && 'primary') ||
124
- (variant === 'text' && 'primary') ||
125
- ''
126
- }
127
- triggerRef={resolvedRef}
128
- />
143
+ className={styles.stateLayer}
144
+ colorName={classNames(
145
+ variant === 'filled' && {
146
+ 'on-surface-variant': !isActive && Boolean(onToggle),
147
+ 'on-primary': isActive || !onToggle,
148
+ },
149
+ variant === 'elevated' && {
150
+ 'on-primary': isActive && Boolean(onToggle),
151
+ primary: !isActive || !onToggle,
152
+ },
153
+ variant === 'tonal' && {
154
+ 'on-secondary': isActive && Boolean(onToggle),
155
+ 'on-secondary-container': !isActive || !onToggle,
156
+ },
157
+ variant === 'outlined' && {
158
+ 'inverse-on-surface': isActive && Boolean(onToggle),
159
+ 'on-surface-variant': !isActive || !onToggle,
160
+ },
161
+ variant === 'text' && 'primary',
129
162
  )}
130
- </div>
163
+ stateClassName={'state-ripple-group-[button]'}
164
+ />
131
165
 
132
166
  {iconPosition === 'left' && iconElement}
133
167
  {loading && (
@@ -1,9 +1,8 @@
1
1
  import { useRef } from 'react';
2
-
3
- import { RippleEffect } from '../effects/ripple';
4
2
  import { CardInterface } from '../interfaces';
5
- import { cardStyle } from '../styles';
3
+ import { useCardStyle } from '../styles';
6
4
  import { ReactProps } from '../utils';
5
+ import { State } from '../effects';
7
6
 
8
7
  /**
9
8
  * Cards display content and actions about a single subject
@@ -18,18 +17,21 @@ export const Card = ({
18
17
  ref,
19
18
  ...rest
20
19
  }: ReactProps<CardInterface>) => {
21
- const styles = cardStyle({ className, isInteractive, variant, children });
20
+ const styles = useCardStyle({ className, isInteractive, variant, children });
22
21
 
23
22
  const defaultRef = useRef<HTMLDivElement>(null);
24
23
  const resolvedRef = ref || defaultRef;
25
24
 
26
25
  return (
27
26
  <div {...rest} ref={resolvedRef} className={styles.card}>
28
- <div className={styles.stateLayer}>
29
- {isInteractive && (
30
- <RippleEffect colorName={'on-surface'} triggerRef={resolvedRef} />
31
- )}
32
- </div>
27
+ {isInteractive && (
28
+ <State
29
+ className={styles.stateLayer}
30
+ colorName={'on-surface'}
31
+ stateClassName={'state-ripple-group-[card]'}
32
+ />
33
+ )}
34
+
33
35
  {children}
34
36
  </div>
35
37
  );
@@ -2,7 +2,7 @@ import React, { useEffect, useLayoutEffect, useRef, useState } from 'react';
2
2
  import { animate } from 'motion/react';
3
3
  import { CarouselInterface, CarouselItemInterface } from '../interfaces';
4
4
 
5
- import { carouselStyle } from '../styles';
5
+ import { useCarouselStyle } from '../styles';
6
6
  import { CustomScroll } from '../effects';
7
7
  import { ReactProps } from '../utils';
8
8
  import { CarouselItem, normalize } from './CarouselItem';
@@ -40,7 +40,7 @@ export const Carousel = ({
40
40
 
41
41
  const [translateX, setTranslateX] = useState(0);
42
42
 
43
- const styles = carouselStyle({
43
+ const styles = useCarouselStyle({
44
44
  index,
45
45
  className,
46
46
  children,
@@ -1,6 +1,6 @@
1
1
  import React, { useRef } from 'react';
2
2
  import { CarouselItemInterface } from '../interfaces';
3
- import { carouselItemStyle } from '../styles';
3
+ import { useCarouselItemStyle } from '../styles';
4
4
  import { MotionProps } from '../utils';
5
5
 
6
6
  export const normalize = (
@@ -34,7 +34,7 @@ export const CarouselItem = ({
34
34
  const defaultRef = useRef(null);
35
35
  const ref: React.RefObject<null | HTMLDivElement> = optionalRef || defaultRef;
36
36
 
37
- const styles = carouselItemStyle({
37
+ const styles = useCarouselItemStyle({
38
38
  className,
39
39
  index,
40
40
  width,
@@ -1,4 +1,4 @@
1
- import { dividerStyle } from '../styles';
1
+ import { useDividerStyle } from '../styles';
2
2
  import { DividerInterface } from '../interfaces';
3
3
  import { ReactProps } from '../utils';
4
4
 
@@ -12,7 +12,7 @@ export const Divider = ({
12
12
  className,
13
13
  ...restProps
14
14
  }: ReactProps<DividerInterface>) => {
15
- const styles = dividerStyle({ orientation, className });
15
+ const styles = useDividerStyle({ orientation, className });
16
16
 
17
17
  return <hr className={styles.divider} {...restProps} />;
18
18
  };
@@ -1,13 +1,12 @@
1
- import { useRef } from 'react';
1
+ import React, { useRef } from 'react';
2
2
  import { Icon } from '../icon';
3
-
4
- import { RippleEffect } from '../effects/ripple';
5
3
  import { AnimatePresence, motion } from 'motion/react';
6
4
  import { FabInterface } from '../interfaces/fab.interface';
7
- import { fabStyle } from '../styles/fab.style';
5
+ import { useFabStyle } from '../styles/fab.style';
8
6
  import { classNames } from '../utils';
9
7
  import { ReactProps } from '../utils/component';
10
8
  import { ToolTip } from './ToolTip';
9
+ import { State } from '../effects';
11
10
 
12
11
  /**
13
12
  * Floating action buttons (FABs) help people take primary actions
@@ -22,7 +21,7 @@ export const Fab = ({
22
21
  href,
23
22
  type,
24
23
  icon,
25
- isExtended = false,
24
+ extended = false,
26
25
  ref,
27
26
  transition,
28
27
  children,
@@ -36,10 +35,10 @@ export const Fab = ({
36
35
  }
37
36
  const ElementType = href ? 'a' : 'button';
38
37
 
39
- const styles = fabStyle({
38
+ const styles = useFabStyle({
40
39
  href,
41
40
  icon,
42
- isExtended,
41
+ extended,
43
42
  label,
44
43
  size,
45
44
  variant,
@@ -84,28 +83,30 @@ export const Fab = ({
84
83
  {...(restProps as any)}
85
84
  ref={resolvedRef}
86
85
  href={href}
87
- aria-label={isExtended ? undefined : label}
86
+ aria-label={extended ? undefined : label}
88
87
  className={styles.fab}
89
88
  >
90
89
  <ToolTip
91
- trigger={isExtended ? null : undefined}
90
+ trigger={extended ? null : undefined}
92
91
  text={label}
93
92
  targetRef={resolvedRef}
94
93
  />
95
- <span className={styles.stateLayer}>
96
- <RippleEffect
97
- colorName={classNames({
98
- primary: variant == 'surface',
99
- 'on-primary-container': variant == 'primary',
100
- 'on-secondary-container': variant == 'secondary',
101
- 'on-tertiary-container': variant == 'tertiary',
102
- })}
103
- triggerRef={resolvedRef}
104
- />
105
- </span>
94
+ <State
95
+ style={{ transition: transition.duration + 's' }}
96
+ className={styles.stateLayer}
97
+ colorName={classNames({
98
+ 'on-primary': variant == 'primary',
99
+ 'on-secondary': variant == 'secondary',
100
+ 'on-tertiary': variant == 'tertiary',
101
+ 'on-primary-container': variant == 'primaryContainer',
102
+ 'on-secondary-container': variant == 'secondaryContainer',
103
+ 'on-tertiary-container': variant == 'tertiaryContainer',
104
+ })}
105
+ stateClassName={'state-ripple-group-[fab]'}
106
+ />
106
107
  <Icon icon={icon} className={styles.icon} />
107
108
  <AnimatePresence>
108
- {isExtended && (
109
+ {extended && (
109
110
  <motion.span
110
111
  variants={labelVariants}
111
112
  initial="hidden"
@@ -0,0 +1,229 @@
1
+ import React, { useRef, useState } from 'react';
2
+ import { FabMenuInterface } from '../interfaces/fab-menu.interface';
3
+ import { useFabMenuStyle } from '../styles/fab-menu.style';
4
+ import { ReactProps } from '../utils/component';
5
+ import { Fab } from './Fab';
6
+ import { Button } from './Button';
7
+ import { ButtonInterface } from '../interfaces';
8
+ import { classNames } from '../utils';
9
+ import { IconButton } from './IconButton';
10
+ import { faClose } from '@fortawesome/free-solid-svg-icons';
11
+ import { AnimatePresence, motion } from 'motion/react';
12
+
13
+ /**
14
+ * Floating action buttons (FABs) help people take primary actions
15
+ * @status beta
16
+ * @category Action
17
+ */
18
+ export const FabMenu = ({
19
+ className,
20
+ label,
21
+ variant = 'primary',
22
+ size = 'medium',
23
+ href,
24
+ type,
25
+ icon,
26
+ extended = false,
27
+ ref,
28
+ transition,
29
+ children,
30
+ open: openProp,
31
+ defaultOpen = false,
32
+ onOpenChange,
33
+ ...restProps
34
+ }: ReactProps<FabMenuInterface>) => {
35
+ transition = { duration: 0.3, ease: 'easeInOut', ...transition };
36
+
37
+ const defaultRef = useRef(null);
38
+ const resolvedRef = ref || defaultRef;
39
+
40
+ // Controlled/uncontrolled open state
41
+ const isControlled = typeof openProp === 'boolean';
42
+ const [internalOpen, setInternalOpen] = useState<boolean>(defaultOpen);
43
+ const open = isControlled ? (openProp as boolean) : internalOpen;
44
+ const setOpen = (next: boolean) => {
45
+ if (!isControlled) setInternalOpen(next);
46
+ onOpenChange?.(next);
47
+ };
48
+
49
+ const buttonChildren = React.Children.toArray(children).filter(
50
+ (child) => React.isValidElement(child) && child.type === Button,
51
+ );
52
+
53
+ const styles = useFabMenuStyle({
54
+ href,
55
+ icon,
56
+ extended,
57
+ label,
58
+ size,
59
+ variant,
60
+ className,
61
+ transition,
62
+ children: label,
63
+ open,
64
+ });
65
+
66
+ const MotionFab = motion.create(Fab);
67
+ const MotionIconButton = motion.create(IconButton);
68
+ const MotionButton = motion.create(Button);
69
+
70
+ const renderFab = (props) => (
71
+ <MotionFab
72
+ icon={icon}
73
+ extended={extended}
74
+ label={label}
75
+ variant={(variant + 'Container') as any}
76
+ size={size}
77
+ className={styles.fab + ' ' + (className ?? '')}
78
+ aria-expanded={open}
79
+ onClick={() => setOpen(true)}
80
+ style={{ transition: 'border-radius 0.3s ease-in-out' }}
81
+ transition={{
82
+ duration: transition.duration,
83
+ ease: 'easeInOut',
84
+ borderRadius: { duration: transition.duration, ease: 'easeInOut' },
85
+ background: { duration: transition.duration, ease: 'easeInOut' },
86
+ ...transition,
87
+ }}
88
+ {...props}
89
+ />
90
+ );
91
+
92
+ return (
93
+ <div className={styles.fabMenu} ref={resolvedRef} {...restProps}>
94
+ <AnimatePresence>
95
+ {open && (
96
+ <div className={styles.actions} role="menu" aria-hidden={!open}>
97
+ {(() => {
98
+ const total = buttonChildren.length;
99
+ return buttonChildren.map((child, index) => {
100
+ const childProps = (
101
+ child as React.ReactElement<ReactProps<ButtonInterface>>
102
+ ).props;
103
+ const reverseIndex = total - 1 - index; // inverser l'ordre d'animation
104
+ const delay = (transition?.delay ?? 0) + reverseIndex * 0.06; // délai échelonné inversé, un peu plus marqué
105
+
106
+ const variants = {
107
+ open: {
108
+ opacity: 1,
109
+ width: 'auto',
110
+ transition: {
111
+ ...transition,
112
+ delay,
113
+ opacity: {
114
+ delay: transition?.duration / 2 + delay,
115
+ },
116
+ },
117
+ },
118
+ close: {
119
+ opacity: 0,
120
+ width: 0,
121
+ transition: {
122
+ ...transition,
123
+ delay,
124
+ opacity: {
125
+ duration: transition?.duration / 2,
126
+ },
127
+ },
128
+ },
129
+ };
130
+
131
+ return (
132
+ <motion.div
133
+ initial={'close'}
134
+ animate={'open'}
135
+ className={'overflow-hidden'}
136
+ variants={variants}
137
+ transition={transition}
138
+ exit={'close'}
139
+ >
140
+ {React.cloneElement(
141
+ child as React.ReactElement<ReactProps<ButtonInterface>>,
142
+ {
143
+ key: index,
144
+ shape: 'rounded',
145
+ variant: 'filled',
146
+ className: () => ({
147
+ button: classNames('max-w-full overflow-hidden', {
148
+ 'px-0': !open,
149
+ 'bg-primary-container text-on-primary-container ':
150
+ variant === 'primary',
151
+ 'bg-secondary-container text-on-secondary-container':
152
+ variant === 'secondary',
153
+ 'bg-tertiary-container text-on-tertiary-container':
154
+ variant === 'tertiary',
155
+ }),
156
+ stateLayer: classNames({
157
+ 'state-on-primary-container': variant === 'primary',
158
+ 'state-on-secondary-container':
159
+ variant === 'secondary',
160
+ 'state-on-tertiary-container':
161
+ variant === 'tertiary',
162
+ }),
163
+ }),
164
+ },
165
+ )}
166
+ </motion.div>
167
+ );
168
+ });
169
+ })()}
170
+ </div>
171
+ )}
172
+ </AnimatePresence>
173
+
174
+ {renderFab({
175
+ className: 'invisible pointer-events-none',
176
+ })}
177
+ <div className={'absolute right-0 top-0'}>
178
+ {!open &&
179
+ renderFab({
180
+ className: '',
181
+ layout: true,
182
+ layoutId: 'fab-menu',
183
+ })}
184
+ {open && (
185
+ <>
186
+ <MotionIconButton
187
+ layout
188
+ layoutId="fab-menu"
189
+ variant={'filled'}
190
+ className={() => ({
191
+ iconButton: classNames('', {
192
+ 'bg-primary text-on-primary': variant === 'primary',
193
+ 'bg-secondary text-on-secondary': variant === 'secondary',
194
+ 'bg-tertiary text-on-tertiary': variant === 'tertiary',
195
+ }),
196
+ stateLayer: classNames({
197
+ '[--default-color:var(--color-on-primary)]':
198
+ variant === 'primary',
199
+ '[--default-color:var(--color-on-secondary)]':
200
+ variant === 'secondary',
201
+ '[--default-color:var(--color-on-tertiary)]':
202
+ variant === 'tertiary',
203
+ }),
204
+ })}
205
+ style={{ transition: 'border-radius 0.3s ease-in-out' }}
206
+ transition={{
207
+ duration: transition.duration,
208
+ ease: 'easeInOut',
209
+ borderRadius: {
210
+ duration: transition.duration,
211
+ ease: 'easeInOut',
212
+ },
213
+ background: {
214
+ duration: transition.duration,
215
+ ease: 'easeInOut',
216
+ },
217
+ ...transition,
218
+ }}
219
+ icon={faClose}
220
+ onClick={() => setOpen(false)}
221
+ >
222
+ Close
223
+ </MotionIconButton>
224
+ </>
225
+ )}
226
+ </div>
227
+ </div>
228
+ );
229
+ };
@@ -2,9 +2,9 @@ import React, { useEffect, useRef } from 'react';
2
2
 
3
3
  import { Icon } from '../icon/icon';
4
4
  import { IconButtonInterface } from '../interfaces/icon-button.interface';
5
- import { iconButtonStyle } from '../styles/icon-button.style';
5
+ import { useIconButtonStyle } from '../styles/icon-button.style';
6
6
  import { ReactProps } from '../utils/component';
7
- import { RippleEffect } from '../effects';
7
+ import { State } from '../effects';
8
8
  import { classNames } from '../utils';
9
9
  import { ToolTip } from './ToolTip';
10
10
 
@@ -76,7 +76,7 @@ export const IconButton = ({
76
76
  // Détermine le type de l'élément à rendre : un bouton ou un lien
77
77
  const ElementType = href ? 'a' : 'button';
78
78
 
79
- const styles = iconButtonStyle({
79
+ const styles = useIconButtonStyle({
80
80
  transition,
81
81
  shape,
82
82
  allowShapeTransformation,
@@ -120,35 +120,29 @@ export const IconButton = ({
120
120
  ></ToolTip>
121
121
 
122
122
  <div className={styles.touchTarget} />
123
- <div
124
- className={styles.stateLayer}
123
+ <State
125
124
  style={{ transition: transition.duration + 's' }}
126
- >
127
- {!disabled && (
128
- <RippleEffect
129
- colorName={classNames(
130
- variant === 'standard' && {
131
- 'on-surface-variant': !isActive,
132
- primary: isActive,
133
- },
134
- variant === 'filled' && {
135
- primary: !isActive && Boolean(onToggle),
136
- 'inverse-on-surface': isActive || !onToggle,
137
- },
138
- variant === 'tonal' && {
139
- 'on-surface-variant': !isActive && Boolean(onToggle),
140
- 'on-secondary-container': isActive || !onToggle,
141
- },
142
- variant === 'outlined' && {
143
- 'on-surface-variant': !isActive,
144
- 'on-primary': isActive,
145
- },
146
- )}
147
- triggerRef={resolvedRef}
148
- />
125
+ className={styles.stateLayer}
126
+ colorName={classNames(
127
+ variant === 'standard' && {
128
+ 'on-surface-variant': !isActive,
129
+ 'on-primary': isActive,
130
+ },
131
+ variant === 'filled' && {
132
+ 'on-surface-variant': !isActive && Boolean(onToggle),
133
+ 'on-primary': isActive || !onToggle,
134
+ },
135
+ variant === 'tonal' && {
136
+ 'on-secondary': isActive && Boolean(onToggle),
137
+ 'on-secondary-container': !isActive || !onToggle,
138
+ },
139
+ variant === 'outlined' && {
140
+ 'inverse-on-surface': isActive && Boolean(onToggle),
141
+ 'on-surface-variant': !isActive || !onToggle,
142
+ },
149
143
  )}
150
- </div>
151
-
144
+ stateClassName={'state-ripple-group-[icon-button]'}
145
+ />
152
146
  {icon && <Icon icon={icon} className={styles.icon} />}
153
147
  </ElementType>
154
148
  );
@@ -8,12 +8,15 @@ import {
8
8
  RefObject,
9
9
  useEffect,
10
10
  useRef,
11
- useState
11
+ useState,
12
12
  } from 'react';
13
13
  import { ReactProps } from '../utils';
14
- import { NavigationRailItem, NavigationRailSection } from './NavigationRailItem';
14
+ import {
15
+ NavigationRailItem,
16
+ NavigationRailSection,
17
+ } from './NavigationRailItem';
15
18
  import { Fab } from './Fab';
16
- import { navigationRailStyle } from '../styles/navigation-rail.style';
19
+ import { useNavigationRailStyle } from '../styles/navigation-rail.style';
17
20
  import { NavigationRailInterface } from '../interfaces/navigation-rail.interface';
18
21
  import { FabInterface, NavigationRailItemInterface } from '../interfaces';
19
22
  import { faBars, faXmark } from '@fortawesome/free-solid-svg-icons';
@@ -96,7 +99,7 @@ export const NavigationRail = ({
96
99
  (child) => isValidElement(child) && child.type === Fab,
97
100
  );
98
101
 
99
- const styles = navigationRailStyle({
102
+ const styles = useNavigationRailStyle({
100
103
  children,
101
104
  onItemSelected,
102
105
  selectedItem,
@@ -1,10 +1,11 @@
1
1
  import React, { useEffect, useRef, useState } from 'react';
2
2
 
3
3
  import { Icon } from '../icon';
4
- import { ReactProps } from '../utils';
4
+ import { classNames, ReactProps } from '../utils';
5
5
  import { NavigationRailItemInterface } from '../interfaces';
6
- import { navigationRailItemStyle } from '../styles/navigation-rail-item.style';
6
+ import { useNavigationRailItemStyle } from '../styles/navigation-rail-item.style';
7
7
  import { AnimatePresence, motion } from 'motion/react';
8
+ import { State } from '../effects';
8
9
 
9
10
  /**
10
11
  * @status beta
@@ -80,7 +81,7 @@ export const NavigationRailItem = ({
80
81
  }
81
82
  };
82
83
 
83
- const styles = navigationRailItemStyle({
84
+ const styles = useNavigationRailItemStyle({
84
85
  isExtended,
85
86
  extendedOnly,
86
87
  className,
@@ -128,7 +129,15 @@ export const NavigationRailItem = ({
128
129
  transition={transition}
129
130
  className={styles.container}
130
131
  >
131
- <motion.div layout className={styles.stateLayer}></motion.div>
132
+ <State
133
+ style={{ transition: transition.duration + 's' }}
134
+ className={styles.stateLayer}
135
+ colorName={classNames({
136
+ 'on-surface': !isSelected,
137
+ 'on-secondary-container': isSelected,
138
+ })}
139
+ stateClassName={'state-ripple-group-[navigation-rail-item]'}
140
+ />
132
141
  {icon && (
133
142
  <Icon
134
143
  icon={isSelected ? iconSelected : icon}
@@ -2,7 +2,7 @@ import { useEffect, useState } from 'react';
2
2
  import { ProgressIndicatorInterface } from '../interfaces/progress-indicator.interface';
3
3
 
4
4
  import { motion } from 'motion/react';
5
- import { progressIndicatorStyle } from '../styles/progress-indicator.style';
5
+ import { useProgressIndicatorStyle } from '../styles/progress-indicator.style';
6
6
  import { ReactProps } from '../utils/component';
7
7
 
8
8
  /**
@@ -67,7 +67,7 @@ export const ProgressIndicator = ({
67
67
  return;
68
68
  }, [completedPercentage, transitionDuration]);
69
69
 
70
- const styles = progressIndicatorStyle({
70
+ const styles = useProgressIndicatorStyle({
71
71
  className,
72
72
  variant,
73
73
  value,