@udixio/ui-react 2.10.13 → 2.10.14

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 (173) hide show
  1. package/package.json +4 -1
  2. package/.eslintrc.mjs +0 -22
  3. package/.storybook/main.ts +0 -20
  4. package/.storybook/preview.ts +0 -1
  5. package/CHANGELOG.md +0 -1144
  6. package/postcss.config.mjs +0 -5
  7. package/src/index.css +0 -4
  8. package/src/index.ts +0 -1
  9. package/src/lib/components/AnchorPositioner.tsx +0 -185
  10. package/src/lib/components/Button.tsx +0 -208
  11. package/src/lib/components/Card.tsx +0 -47
  12. package/src/lib/components/Carousel.tsx +0 -437
  13. package/src/lib/components/CarouselItem.tsx +0 -61
  14. package/src/lib/components/Checkbox.tsx +0 -120
  15. package/src/lib/components/Chip.tsx +0 -341
  16. package/src/lib/components/Chips.tsx +0 -331
  17. package/src/lib/components/ContextMenu.tsx +0 -109
  18. package/src/lib/components/DatePicker.tsx +0 -432
  19. package/src/lib/components/Divider.tsx +0 -20
  20. package/src/lib/components/Fab.tsx +0 -127
  21. package/src/lib/components/FabMenu.tsx +0 -239
  22. package/src/lib/components/IconButton.tsx +0 -146
  23. package/src/lib/components/Menu.tsx +0 -88
  24. package/src/lib/components/MenuGroup.tsx +0 -34
  25. package/src/lib/components/MenuHeadline.tsx +0 -9
  26. package/src/lib/components/MenuItem.tsx +0 -215
  27. package/src/lib/components/NavigationRail.tsx +0 -186
  28. package/src/lib/components/NavigationRailItem.tsx +0 -227
  29. package/src/lib/components/ProgressIndicator.tsx +0 -214
  30. package/src/lib/components/SideSheet.tsx +0 -135
  31. package/src/lib/components/Slider.tsx +0 -374
  32. package/src/lib/components/Snackbar.tsx +0 -77
  33. package/src/lib/components/Switch.tsx +0 -107
  34. package/src/lib/components/Tab.tsx +0 -123
  35. package/src/lib/components/TabGroup.tsx +0 -66
  36. package/src/lib/components/TabGroupContext.tsx +0 -16
  37. package/src/lib/components/TabPanel.tsx +0 -27
  38. package/src/lib/components/TabPanels.tsx +0 -76
  39. package/src/lib/components/Tabs.tsx +0 -105
  40. package/src/lib/components/TextField.tsx +0 -586
  41. package/src/lib/components/Tooltip.tsx +0 -217
  42. package/src/lib/components/index.ts +0 -34
  43. package/src/lib/config/config.interface.ts +0 -9
  44. package/src/lib/config/define-config.ts +0 -16
  45. package/src/lib/config/index.ts +0 -2
  46. package/src/lib/effects/AnimateOnScroll.ts +0 -391
  47. package/src/lib/effects/State.tsx +0 -90
  48. package/src/lib/effects/SyncedFixedWrapper.tsx +0 -62
  49. package/src/lib/effects/ThemeProvider.tsx +0 -174
  50. package/src/lib/effects/block-scroll.effect.tsx +0 -313
  51. package/src/lib/effects/custom-scroll/custom-scroll.effect.tsx +0 -407
  52. package/src/lib/effects/custom-scroll/custom-scroll.interface.ts +0 -29
  53. package/src/lib/effects/custom-scroll/custom-scroll.style.ts +0 -32
  54. package/src/lib/effects/custom-scroll/index.ts +0 -3
  55. package/src/lib/effects/index.ts +0 -7
  56. package/src/lib/effects/ripple/RippleEffect.tsx +0 -116
  57. package/src/lib/effects/ripple/index.tsx +0 -1
  58. package/src/lib/effects/scrollDriven.ts +0 -239
  59. package/src/lib/effects/smooth-scroll.effect.tsx +0 -112
  60. package/src/lib/effects/theme.worker.ts +0 -97
  61. package/src/lib/hooks/index.ts +0 -10
  62. package/src/lib/hooks/useTooltipTrigger.ts +0 -270
  63. package/src/lib/icon/icon.tsx +0 -125
  64. package/src/lib/icon/index.ts +0 -1
  65. package/src/lib/index.ts +0 -8
  66. package/src/lib/interfaces/button.interface.ts +0 -65
  67. package/src/lib/interfaces/card.interface.ts +0 -11
  68. package/src/lib/interfaces/carousel-item.interface.ts +0 -12
  69. package/src/lib/interfaces/carousel.interface.ts +0 -41
  70. package/src/lib/interfaces/checkbox.interface.ts +0 -39
  71. package/src/lib/interfaces/chip.interface.ts +0 -97
  72. package/src/lib/interfaces/chips.interface.ts +0 -37
  73. package/src/lib/interfaces/date-picker.interface.ts +0 -79
  74. package/src/lib/interfaces/divider.interface.ts +0 -7
  75. package/src/lib/interfaces/fab-menu.interface.ts +0 -12
  76. package/src/lib/interfaces/fab.interface.ts +0 -27
  77. package/src/lib/interfaces/icon-button.interface.ts +0 -38
  78. package/src/lib/interfaces/index.ts +0 -26
  79. package/src/lib/interfaces/menu-group.interface.ts +0 -13
  80. package/src/lib/interfaces/menu-item.interface.ts +0 -29
  81. package/src/lib/interfaces/menu.interface.ts +0 -19
  82. package/src/lib/interfaces/navigation-rail-item.interface.ts +0 -39
  83. package/src/lib/interfaces/navigation-rail.interface.ts +0 -39
  84. package/src/lib/interfaces/progress-indicator.interface.ts +0 -41
  85. package/src/lib/interfaces/side-sheet.interface.tsx +0 -28
  86. package/src/lib/interfaces/slider.interface.ts +0 -27
  87. package/src/lib/interfaces/snackbar.interface.ts +0 -13
  88. package/src/lib/interfaces/switch.interface.ts +0 -14
  89. package/src/lib/interfaces/tab-group.interface.ts +0 -13
  90. package/src/lib/interfaces/tab-panels.interface.ts +0 -21
  91. package/src/lib/interfaces/tab.interface.ts +0 -31
  92. package/src/lib/interfaces/tabs.interface.ts +0 -22
  93. package/src/lib/interfaces/text-field.interface.ts +0 -61
  94. package/src/lib/interfaces/tooltip.interface.ts +0 -61
  95. package/src/lib/styles/button.style.ts +0 -136
  96. package/src/lib/styles/card.style.ts +0 -29
  97. package/src/lib/styles/carousel-item.style.ts +0 -24
  98. package/src/lib/styles/carousel.style.ts +0 -22
  99. package/src/lib/styles/checkbox.style.ts +0 -64
  100. package/src/lib/styles/chip.style.ts +0 -62
  101. package/src/lib/styles/chips.style.ts +0 -20
  102. package/src/lib/styles/date-picker.style.ts +0 -43
  103. package/src/lib/styles/divider.style.ts +0 -31
  104. package/src/lib/styles/fab-menu.style.ts +0 -29
  105. package/src/lib/styles/fab.style.ts +0 -49
  106. package/src/lib/styles/icon-button.style.ts +0 -168
  107. package/src/lib/styles/index.ts +0 -25
  108. package/src/lib/styles/menu-group.style.ts +0 -34
  109. package/src/lib/styles/menu-headline.style.ts +0 -20
  110. package/src/lib/styles/menu-item.style.ts +0 -45
  111. package/src/lib/styles/menu.style.ts +0 -32
  112. package/src/lib/styles/navigation-rail-item.style.ts +0 -56
  113. package/src/lib/styles/navigation-rail.style.ts +0 -36
  114. package/src/lib/styles/progress-indicator.style.ts +0 -72
  115. package/src/lib/styles/side-sheet.style.ts +0 -45
  116. package/src/lib/styles/slider.style.ts +0 -41
  117. package/src/lib/styles/snackbar.style.ts +0 -26
  118. package/src/lib/styles/switch.style.ts +0 -67
  119. package/src/lib/styles/tab-panels.style.ts +0 -35
  120. package/src/lib/styles/tab.style.ts +0 -78
  121. package/src/lib/styles/tabs.style.ts +0 -22
  122. package/src/lib/styles/text-field.style.ts +0 -115
  123. package/src/lib/styles/tooltip.style.ts +0 -48
  124. package/src/lib/utils/component-helper.ts +0 -134
  125. package/src/lib/utils/component.ts +0 -34
  126. package/src/lib/utils/index.ts +0 -7
  127. package/src/lib/utils/string.ts +0 -9
  128. package/src/lib/utils/styles/classnames.ts +0 -49
  129. package/src/lib/utils/styles/get-classname.ts +0 -96
  130. package/src/lib/utils/styles/index.ts +0 -4
  131. package/src/lib/utils/styles/use-classnames.ts +0 -25
  132. package/src/stories/action/button.stories.tsx +0 -86
  133. package/src/stories/action/fab.stories.tsx +0 -54
  134. package/src/stories/action/icon-button.stories.tsx +0 -134
  135. package/src/stories/assets/accessibility.png +0 -0
  136. package/src/stories/assets/accessibility.svg +0 -5
  137. package/src/stories/assets/addon-library.png +0 -0
  138. package/src/stories/assets/assets.png +0 -0
  139. package/src/stories/assets/context.png +0 -0
  140. package/src/stories/assets/discord.svg +0 -15
  141. package/src/stories/assets/docs.png +0 -0
  142. package/src/stories/assets/figma-plugin.png +0 -0
  143. package/src/stories/assets/github.svg +0 -3
  144. package/src/stories/assets/share.png +0 -0
  145. package/src/stories/assets/styling.png +0 -0
  146. package/src/stories/assets/testing.png +0 -0
  147. package/src/stories/assets/theming.png +0 -0
  148. package/src/stories/assets/tutorials.svg +0 -12
  149. package/src/stories/assets/youtube.svg +0 -4
  150. package/src/stories/communication/ProgressIndicator.stories.tsx +0 -57
  151. package/src/stories/communication/SnackBar.stories.tsx +0 -32
  152. package/src/stories/communication/tool-tip.stories.tsx +0 -133
  153. package/src/stories/containment/card.stories.tsx +0 -42
  154. package/src/stories/containment/carousel.stories.tsx +0 -65
  155. package/src/stories/containment/divider.stories.tsx +0 -35
  156. package/src/stories/containment/slide-sheet.stories.tsx +0 -45
  157. package/src/stories/effect/smooth-scroll.stories.tsx +0 -54
  158. package/src/stories/navigation/navigation-rail/navigation-rail-item.stories.tsx +0 -65
  159. package/src/stories/navigation/navigation-rail/navigation-rail.stories.tsx +0 -122
  160. package/src/stories/navigation/tabs/tab.stories.tsx +0 -57
  161. package/src/stories/navigation/tabs/tabs.stories.tsx +0 -102
  162. package/src/stories/selection/slider.stories.tsx +0 -85
  163. package/src/stories/selection/switch.stories.tsx +0 -46
  164. package/src/stories/text-inputs/text-field.stories.tsx +0 -135
  165. package/src/tests/Button.spec.tsx +0 -67
  166. package/src/tests/useClassNames.spec.tsx +0 -82
  167. package/src/udixio.css +0 -120
  168. package/theme.config.ts +0 -7
  169. package/tsconfig.json +0 -16
  170. package/tsconfig.lib.json +0 -51
  171. package/tsconfig.spec.json +0 -37
  172. package/tsconfig.storybook.json +0 -38
  173. package/vite.config.ts +0 -96
@@ -1,215 +0,0 @@
1
- import React, { useEffect, useRef, useState } from 'react';
2
- import { Icon } from '../icon';
3
- import { classNames, ReactProps } from '../utils';
4
- import { MenuItemInterface } from '../interfaces/menu-item.interface';
5
- import { useMenuItemStyle } from '../styles/menu-item.style';
6
- import { faCheck, faChevronRight } from '@fortawesome/free-solid-svg-icons';
7
- import { AnchorPositioner } from './AnchorPositioner';
8
- import { State } from '../effects';
9
-
10
- /**
11
- * Single item within a Menu.
12
- * @status beta
13
- * @category Selection
14
- */
15
- export const MenuItem = ({
16
- label,
17
- children,
18
- leadingIcon,
19
- trailingIcon,
20
- disabled,
21
- variant = 'standard',
22
- href,
23
- onClick,
24
- onToggle,
25
- activated = false,
26
- className,
27
- ...restProps
28
- }: ReactProps<MenuItemInterface>) => {
29
- /* Extract subMenu from children if present */
30
- let subMenuElement: React.ReactNode = null;
31
- const contentChildren: React.ReactNode[] = [];
32
-
33
- React.Children.forEach(children, (child) => {
34
- // Check for Menu component via name (development) or if it has displayName 'Menu'
35
- // We accept a child that is valid element and looks like a Menu.
36
- if (
37
- React.isValidElement(child) &&
38
- ((child.type as any)?.name === 'Menu' ||
39
- (child.type as any)?.displayName === 'Menu')
40
- ) {
41
- subMenuElement = child;
42
- } else {
43
- contentChildren.push(child);
44
- }
45
- });
46
-
47
- const labelContent = contentChildren.length > 0 ? contentChildren : label;
48
-
49
- const [isSubMenuOpen, setIsSubMenuOpen] = useState(false);
50
- const [isActive, setIsActive] = useState(activated);
51
-
52
- if (isActive) {
53
- leadingIcon = faCheck;
54
- }
55
-
56
- const itemRef = useRef<HTMLButtonElement | HTMLAnchorElement>(null);
57
- const closeTimerRef = useRef<any>(null);
58
-
59
- useEffect(() => {
60
- setIsActive(activated);
61
- }, [activated]);
62
-
63
- const styles = useMenuItemStyle({
64
- variant,
65
- disabled,
66
- className,
67
- activated: isActive,
68
- isActive,
69
- });
70
-
71
- const handleClick = (e: React.MouseEvent) => {
72
- console.log('refrefd', disabled, subMenuElement, onToggle);
73
- if (disabled) {
74
- e.preventDefault();
75
- return;
76
- }
77
-
78
- if (subMenuElement) {
79
- e.stopPropagation();
80
- return;
81
- }
82
-
83
- if (onToggle) {
84
- setIsActive(!isActive);
85
- onToggle(!isActive);
86
- } else {
87
- console.log('click', onClick);
88
- onClick?.(e);
89
- }
90
- };
91
-
92
- const handleMouseEnter = () => {
93
- if (closeTimerRef.current) {
94
- clearTimeout(closeTimerRef.current);
95
- closeTimerRef.current = null;
96
- }
97
- if (!disabled && subMenuElement) {
98
- setIsSubMenuOpen(true);
99
- }
100
- };
101
-
102
- const handleMouseLeave = () => {
103
- if (subMenuElement) {
104
- closeTimerRef.current = setTimeout(() => {
105
- setIsSubMenuOpen(false);
106
- }, 150); // Delay to allow diagonal movement
107
- }
108
- };
109
-
110
- React.useEffect(() => {
111
- return () => {
112
- if (closeTimerRef.current) {
113
- clearTimeout(closeTimerRef.current);
114
- }
115
- };
116
- }, []);
117
-
118
- const effectiveTrailingIcon =
119
- trailingIcon ?? (subMenuElement ? faChevronRight : undefined);
120
-
121
- const ElementType = href ? 'a' : 'button';
122
-
123
- return (
124
- <ElementType
125
- ref={itemRef as any}
126
- href={href}
127
- className={styles.menuItem}
128
- onClick={handleClick}
129
- onMouseEnter={handleMouseEnter}
130
- onMouseLeave={handleMouseLeave}
131
- role="option"
132
- aria-haspopup={!!subMenuElement}
133
- aria-expanded={isSubMenuOpen}
134
- aria-pressed={onToggle ? isActive : undefined}
135
- tabIndex={disabled ? -1 : 0}
136
- disabled={!href ? disabled : undefined}
137
- onKeyDown={(e) => {
138
- if (e.key === 'Enter' || e.key === ' ') {
139
- e.preventDefault();
140
- if (subMenuElement) {
141
- setIsSubMenuOpen(!isSubMenuOpen);
142
- } else {
143
- handleClick(e as any);
144
- }
145
- }
146
- if (e.key === 'ArrowRight' && subMenuElement) {
147
- setIsSubMenuOpen(true);
148
- e.stopPropagation();
149
- }
150
- if (e.key === 'ArrowLeft' && isSubMenuOpen) {
151
- setIsSubMenuOpen(false);
152
- e.stopPropagation();
153
- }
154
- }}
155
- {...(restProps as any)}
156
- >
157
- <State
158
- className="absolute inset-0 pointer-events-none"
159
- colorName={classNames(
160
- // Match text color for state layer usually
161
- variant === 'vibrant' || isActive
162
- ? 'on-tertiary-container'
163
- : 'on-secondary-container',
164
- )}
165
- stateClassName={'state-ripple-group-[menu-item]'}
166
- />
167
-
168
- {leadingIcon && (
169
- <div
170
- className={classNames(
171
- styles.itemIcon,
172
- styles.leadingIcon,
173
- 'z-10 relative',
174
- )}
175
- >
176
- {React.isValidElement(leadingIcon) ? (
177
- leadingIcon
178
- ) : (
179
- <Icon icon={leadingIcon} />
180
- )}
181
- </div>
182
- )}
183
- <span className={classNames(styles.itemLabel, 'z-10 relative')}>
184
- {labelContent}
185
- </span>
186
- {effectiveTrailingIcon && (
187
- <div
188
- className={classNames(
189
- styles.itemIcon,
190
- styles.trailingIcon,
191
- 'z-10 relative',
192
- )}
193
- >
194
- {React.isValidElement(effectiveTrailingIcon) ? (
195
- effectiveTrailingIcon
196
- ) : (
197
- <Icon icon={effectiveTrailingIcon} />
198
- )}
199
- </div>
200
- )}
201
-
202
- {subMenuElement && isSubMenuOpen && (
203
- <AnchorPositioner
204
- anchorRef={itemRef}
205
- position="inline-end span-block-end"
206
- hoverOpen={true}
207
- >
208
- <div onMouseEnter={handleMouseEnter} onMouseLeave={handleMouseLeave}>
209
- {subMenuElement}
210
- </div>
211
- </AnchorPositioner>
212
- )}
213
- </ElementType>
214
- );
215
- };
@@ -1,186 +0,0 @@
1
- import {
2
- Children,
3
- cloneElement,
4
- Fragment,
5
- isValidElement,
6
- ReactElement,
7
- ReactNode,
8
- RefObject,
9
- useEffect,
10
- useRef,
11
- useState,
12
- } from 'react';
13
- import { ReactProps } from '../utils';
14
- import {
15
- NavigationRailItem,
16
- NavigationRailSection,
17
- } from './NavigationRailItem';
18
- import { Fab } from './Fab';
19
- import { useNavigationRailStyle } from '../styles/navigation-rail.style';
20
- import { NavigationRailInterface } from '../interfaces/navigation-rail.interface';
21
- import { FabInterface, NavigationRailItemInterface } from '../interfaces';
22
- import { faBars, faXmark } from '@fortawesome/free-solid-svg-icons';
23
- import { IconButton } from './IconButton';
24
-
25
- /**
26
- * Navigation rails let people switch between UI views on mid-sized devices
27
- * @status beta
28
- * @category Navigation
29
- * @devx
30
- * - Treats `NavigationRailItem`, `NavigationRailSection`, and `Fab` specially.
31
- * - Selection is index-based; provide `selectedItem` for controlled usage.
32
- * @limitations
33
- * - `extended` is not fully controlled (prop changes after mount aren’t synced).
34
- * - Keyboard navigation/roving tabindex is not implemented.
35
- */
36
- export const NavigationRail = ({
37
- variant = 'standard',
38
- onItemSelected,
39
- children,
40
- className,
41
- selectedItem: externalSelectedItem,
42
- extended,
43
- alignment = 'top',
44
- menu = {
45
- closed: {
46
- icon: faBars,
47
- label: 'Open menu',
48
- },
49
- opened: {
50
- icon: faXmark,
51
- label: 'Close menu',
52
- },
53
- },
54
- style,
55
- onExtendedChange,
56
- transition,
57
- setSelectedItem: externalSetSelectedItem,
58
- }: ReactProps<NavigationRailInterface>) => {
59
- const [internalSelectedItem, internalSetSelectedItem] = useState<
60
- number | null
61
- >(null);
62
-
63
- const [isExtended, setIsExtended] = useState(extended);
64
-
65
- let selectedItem: number | null;
66
- if (externalSelectedItem == 0 || externalSelectedItem != undefined) {
67
- selectedItem = externalSelectedItem;
68
- } else {
69
- selectedItem = internalSelectedItem;
70
- }
71
-
72
- const setSelectedItem = externalSetSelectedItem || internalSetSelectedItem;
73
-
74
- const ref = useRef<HTMLDivElement | null>(null);
75
-
76
- const handleOnItemSelected = (
77
- args: { index: number } & Pick<
78
- ReactProps<NavigationRailItemInterface>,
79
- 'label' | 'icon'
80
- > & {
81
- ref: RefObject<any>;
82
- },
83
- ) => {
84
- onItemSelected?.(args);
85
- };
86
-
87
- function flattenChildren(children: ReactNode): ReactNode[] {
88
- const flatChildren: ReactNode[] = [];
89
- Children.forEach(children, (child) => {
90
- if (
91
- isValidElement<{ children?: ReactNode }>(child) &&
92
- child.type === Fragment
93
- ) {
94
- flatChildren.push(...flattenChildren(child.props.children));
95
- } else {
96
- flatChildren.push(child);
97
- }
98
- });
99
- return flatChildren;
100
- }
101
-
102
- const childrenArray = flattenChildren(children);
103
-
104
- const fab = childrenArray.filter(
105
- (child) => isValidElement(child) && child.type === Fab,
106
- );
107
-
108
- const styles = useNavigationRailStyle({
109
- children,
110
- onItemSelected,
111
- selectedItem,
112
- setSelectedItem,
113
- className,
114
- variant,
115
- extended: isExtended,
116
- isExtended,
117
- alignment,
118
- menu,
119
- transition,
120
- onExtendedChange,
121
- });
122
- transition = { duration: 0.3, ...transition };
123
- const extendedOnly = useRef(false);
124
- extendedOnly.current = false;
125
-
126
- useEffect(() => {
127
- onExtendedChange?.(isExtended ?? false);
128
- }, [isExtended]);
129
-
130
- return (
131
- <div
132
- style={{ transition: transition.duration + 's', ...style }}
133
- ref={ref}
134
- className={styles.navigationRail}
135
- >
136
- <div className={styles.header}>
137
- <IconButton
138
- onClick={() => setIsExtended(!isExtended)}
139
- label={isExtended ? menu?.opened.label : menu?.closed.label}
140
- className={styles.menuIcon}
141
- icon={!isExtended ? menu?.closed.icon : menu.opened.icon}
142
- />
143
- {fab.length > 0 &&
144
- cloneElement(fab[0] as ReactElement<ReactProps<FabInterface>>, {
145
- transition: transition,
146
- isExtended: isExtended,
147
- className: '!shadow-none mx-5 ' + (fab[0] as any).props.className,
148
- })}
149
- </div>
150
-
151
- <div className={styles.segments}>
152
- {(() => {
153
- let itemIndex = 0;
154
- return childrenArray.map((child) => {
155
- if (isValidElement(child) && child.type === NavigationRailItem) {
156
- return cloneElement(
157
- child as ReactElement<ReactProps<NavigationRailItemInterface>>,
158
- {
159
- key: itemIndex,
160
- index: itemIndex++, // Utilise et incrémente le compteur dédié
161
- variant: isExtended ? 'horizontal' : 'vertical',
162
- selectedItem,
163
- setSelectedItem: setSelectedItem,
164
- onItemSelected: handleOnItemSelected,
165
- transition,
166
- extendedOnly: extendedOnly.current,
167
- isExtended,
168
- },
169
- );
170
- }
171
- if (isValidElement(child) && child.type === Fab) {
172
- return null;
173
- }
174
- if (isValidElement(child) && child.type === NavigationRailSection) {
175
- extendedOnly.current = true;
176
- if (!isExtended) return null;
177
- return cloneElement(child as ReactElement<{ label: string }>, {});
178
- }
179
- return child;
180
- });
181
- })()}
182
- </div>
183
- <div className={'flex-1 max-h-[160px]'}></div>
184
- </div>
185
- );
186
- };
@@ -1,227 +0,0 @@
1
- import React, { useEffect, useRef, useState } from 'react';
2
-
3
- import { Icon } from '../icon';
4
- import { classNames, ReactProps } from '../utils';
5
- import { NavigationRailItemInterface } from '../interfaces';
6
- import { useNavigationRailItemStyle } from '../styles/navigation-rail-item.style';
7
- import { AnimatePresence, motion } from 'motion/react';
8
- import { State } from '../effects';
9
-
10
- /**
11
- * @status beta
12
- * @parent NavigationRail
13
- * @devx
14
- * - Section labels only render when the rail is extended.
15
- */
16
- export const NavigationRailSection = ({ label }: { label: string }) => {
17
- return (
18
- <div className={' h-9 flex items-center mx-9 mt-3'}>
19
- <p className={'text-label-large text-on-surface-variant'}>{label}</p>
20
- </div>
21
- );
22
- };
23
-
24
- /**
25
- * @status beta
26
- * @parent NavigationRail
27
- * @devx
28
- * - Selection is index-based and provided by the parent rail.
29
- * - `extendedOnly` hides items when the rail is collapsed.
30
- * @a11y
31
- * - Uses `role="tab"` but no roving tabindex or aria-controls wiring.
32
- */
33
- export const NavigationRailItem = ({
34
- className,
35
- onClick,
36
- label,
37
- variant = 'vertical',
38
- href,
39
- icon,
40
- selectedItem,
41
- setSelectedItem,
42
- index,
43
- onItemSelected,
44
- selected = false,
45
- ref,
46
- transition,
47
- isExtended,
48
- iconSelected,
49
- style,
50
- extendedOnly,
51
- children,
52
- ...restProps
53
- }: ReactProps<NavigationRailItemInterface>) => {
54
- if (children) label = children;
55
-
56
- const defaultRef = useRef<any>(null);
57
- const resolvedRef = ref || defaultRef;
58
-
59
- const [isSelected, setIsSelected] = useState<boolean>(selected);
60
-
61
- useEffect(() => {
62
- if (selected && selectedItem == null) {
63
- setIsSelected(true);
64
- } else {
65
- setIsSelected(selectedItem == index && index != null);
66
- }
67
- }, [selectedItem]);
68
-
69
- useEffect(() => {
70
- if (selectedItem == index && onItemSelected) {
71
- onItemSelected({
72
- ref: resolvedRef as any,
73
- index: index || 0,
74
- label,
75
- icon,
76
- });
77
- }
78
- }, [selectedItem]);
79
-
80
- const ElementType = href ? 'a' : 'button';
81
-
82
- const handleClick = (e: React.MouseEvent<any>) => {
83
- if (setSelectedItem) {
84
- setSelectedItem(index ?? null);
85
- }
86
- if (onClick) {
87
- onClick(e);
88
- }
89
- };
90
-
91
- const styles = useNavigationRailItemStyle({
92
- isExtended,
93
- extendedOnly,
94
- className,
95
- onItemSelected,
96
- selectedItem,
97
- index,
98
- transition,
99
- selected: isSelected,
100
- variant,
101
- icon,
102
- label,
103
- isSelected,
104
- setSelectedItem,
105
- href: href as any,
106
- children: label,
107
- iconSelected,
108
- });
109
-
110
- transition = { duration: 0.3, ...transition };
111
-
112
- if (extendedOnly && !isExtended) return null;
113
-
114
- return (
115
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
116
- // @ts-expect-error
117
- <ElementType
118
- {...restProps}
119
- role="tab"
120
- aria-selected={isSelected}
121
- ref={resolvedRef}
122
- href={href}
123
- className={styles.navigationRailItem}
124
- onClick={handleClick}
125
- style={{ transition: transition.duration + 's', ...style }}
126
- >
127
- <motion.div
128
- style={{
129
- transition:
130
- variant == 'horizontal'
131
- ? transition.duration +
132
- `s, gap ${transition.duration! / 2}s ${transition.duration! - transition.duration! / 2}s`
133
- : transition.duration +
134
- `s, gap ${transition.duration! / 3}s ${transition.duration! - transition.duration! / 3}s`,
135
- }}
136
- transition={transition}
137
- className={styles.container}
138
- >
139
- <State
140
- style={{ transition: transition.duration + 's' }}
141
- className={styles.stateLayer}
142
- colorName={classNames({
143
- 'on-surface': !isSelected,
144
- 'on-secondary-container': isSelected,
145
- })}
146
- stateClassName={'state-ripple-group-[navigation-rail-item]'}
147
- />
148
- {icon && (
149
- <Icon
150
- icon={isSelected ? iconSelected : icon}
151
- className={styles.icon}
152
- />
153
- )}
154
- <AnimatePresence>
155
- {variant == 'horizontal' &&
156
- (() => {
157
- const initial = {
158
- width: 0,
159
- opacity: 0,
160
- transition: {
161
- ...transition,
162
- },
163
- };
164
- const animate = {
165
- width: 'auto',
166
- opacity: 1,
167
- transition: {
168
- ...transition,
169
- opacity: {
170
- duration: transition.duration! / 2,
171
- delay: transition.duration! - transition.duration! / 2,
172
- },
173
- },
174
- };
175
- return (
176
- <motion.span
177
- initial={initial}
178
- animate={animate}
179
- exit={initial}
180
- className={styles.label}
181
- >
182
- {label}
183
- </motion.span>
184
- );
185
- })()}
186
- </AnimatePresence>
187
- </motion.div>
188
- <AnimatePresence>
189
- {variant == 'vertical' &&
190
- (() => {
191
- const initial = {
192
- height: 0,
193
- opacity: 0,
194
- transition: {
195
- ...transition,
196
- opacity: {
197
- duration: 0,
198
- },
199
- },
200
- };
201
- const animate = {
202
- height: 'auto',
203
- opacity: 1,
204
- transition: {
205
- ...transition,
206
- opacity: {
207
- duration: transition.duration! / 3,
208
- delay: transition.duration! - transition.duration! / 3,
209
- },
210
- },
211
- };
212
- return (
213
- <motion.span
214
- initial={animate}
215
- animate={animate}
216
- exit={initial}
217
- className={styles.label}
218
- transition={transition}
219
- >
220
- {label}
221
- </motion.span>
222
- );
223
- })()}
224
- </AnimatePresence>
225
- </ElementType>
226
- );
227
- };