@12-apps/ui 1.4.0 → 1.4.1

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 (53) hide show
  1. package/package.json +4 -4
  2. package/src/components/data-display/Carousel/Carousel.chrome.tsx +83 -0
  3. package/src/components/data-display/Carousel/Carousel.hooks.ts +88 -0
  4. package/src/components/data-display/Carousel/Carousel.parts.tsx +346 -0
  5. package/src/components/data-display/Carousel/Carousel.slide.tsx +190 -0
  6. package/src/components/data-display/Carousel/Carousel.styles.ts +86 -0
  7. package/src/components/data-display/Carousel/Carousel.tsx +84 -732
  8. package/src/components/data-display/HoverCard/HoverCard.animations.ts +73 -0
  9. package/src/components/data-display/HoverCard/HoverCard.content.tsx +143 -0
  10. package/src/components/data-display/HoverCard/HoverCard.hooks.ts +180 -0
  11. package/src/components/data-display/HoverCard/HoverCard.styles.ts +178 -0
  12. package/src/components/data-display/HoverCard/HoverCard.tsx +117 -631
  13. package/src/components/data-display/Sheet/Sheet.animations.ts +44 -0
  14. package/src/components/data-display/Sheet/Sheet.body.tsx +124 -0
  15. package/src/components/data-display/Sheet/Sheet.drag.ts +203 -0
  16. package/src/components/data-display/Sheet/Sheet.hooks.ts +318 -0
  17. package/src/components/data-display/Sheet/Sheet.parts.tsx +224 -0
  18. package/src/components/data-display/Sheet/Sheet.styles.ts +257 -0
  19. package/src/components/data-display/Sheet/Sheet.tsx +125 -948
  20. package/src/components/feedback/Modal/Modal.styles.ts +126 -0
  21. package/src/components/feedback/Modal/Modal.transitions.tsx +40 -0
  22. package/src/components/feedback/Modal/Modal.tsx +37 -242
  23. package/src/components/form/InputOTP/InputOTP.hooks.ts +104 -0
  24. package/src/components/form/InputOTP/InputOTP.styles.ts +97 -0
  25. package/src/components/form/InputOTP/InputOTP.tsx +74 -221
  26. package/src/components/form/Label/Label.parts.tsx +75 -0
  27. package/src/components/form/Label/Label.styles.ts +206 -0
  28. package/src/components/form/Label/Label.tsx +73 -325
  29. package/src/components/form/Menubar/Menubar.hooks.ts +41 -0
  30. package/src/components/form/Menubar/Menubar.item.tsx +121 -0
  31. package/src/components/form/Menubar/Menubar.separator.tsx +25 -0
  32. package/src/components/form/Menubar/Menubar.styles.ts +110 -0
  33. package/src/components/form/Menubar/Menubar.toolbar.tsx +103 -0
  34. package/src/components/form/Menubar/Menubar.tsx +64 -347
  35. package/src/components/form/RadioGroup/RadioGroup.animations.ts +48 -0
  36. package/src/components/form/RadioGroup/RadioGroup.styles.ts +305 -0
  37. package/src/components/form/RadioGroup/RadioGroup.tsx +81 -651
  38. package/src/components/form/RadioGroup/RadioGroup.variants.tsx +291 -0
  39. package/src/components/form/Slider/Slider.animations.ts +40 -0
  40. package/src/components/form/Slider/Slider.styles.ts +292 -0
  41. package/src/components/form/Slider/Slider.tsx +106 -357
  42. package/src/components/form/Switch/Switch.animations.ts +62 -0
  43. package/src/components/form/Switch/Switch.parts.tsx +213 -0
  44. package/src/components/form/Switch/Switch.styles.ts +355 -0
  45. package/src/components/form/Switch/Switch.tsx +87 -566
  46. package/src/components/typography/Blockquote/Blockquote.test.stories.tsx +7 -7
  47. package/src/components/typography/Heading/Heading.styles.ts +101 -0
  48. package/src/components/typography/Heading/Heading.tsx +48 -164
  49. package/src/components/utility/AnimatedIcon/AnimatedIcon.animations.ts +274 -0
  50. package/src/components/utility/AnimatedIcon/AnimatedIcon.styles.ts +231 -0
  51. package/src/components/utility/AnimatedIcon/AnimatedIcon.tsx +39 -559
  52. package/src/utils/index.ts +1 -0
  53. package/src/utils/withDefaults.ts +20 -0
@@ -0,0 +1,231 @@
1
+ import { alpha } from '@mui/material';
2
+ import type { CSSObject, Theme } from '@mui/material';
3
+
4
+ import {
5
+ bounceAnimation,
6
+ breatheAnimation,
7
+ fadeInOutAnimation,
8
+ flipAnimation,
9
+ floatAnimation,
10
+ glowPulseAnimation,
11
+ heartbeatAnimation,
12
+ jelloAnimation,
13
+ morphAnimation,
14
+ neonFlickerAnimation,
15
+ pulseAnimation,
16
+ rippleAnimation,
17
+ rotateAnimation,
18
+ shakeAnimation,
19
+ spinAnimation,
20
+ swingAnimation,
21
+ translateAnimation,
22
+ wobbleAnimation,
23
+ } from './AnimatedIcon.animations';
24
+ import type { AnimationSize, AnimationVariant } from './AnimatedIcon.types';
25
+
26
+ export const sizeConfigs: Record<AnimationSize, { size: number; fontSize: number }> = {
27
+ sm: { size: 24, fontSize: 20 },
28
+ md: { size: 32, fontSize: 28 },
29
+ lg: { size: 48, fontSize: 44 },
30
+ xl: { size: 64, fontSize: 60 },
31
+ };
32
+
33
+ /**
34
+ * Every variant produces the same shorthand — keyframes, duration, easing,
35
+ * iteration count, delay — so only the three things that actually differ are
36
+ * tabulated. `scale` multiplies the caller's duration for the variants that
37
+ * read as slower than the rest.
38
+ */
39
+ const ANIMATIONS: Record<string, { keyframes: string; easing: string; scale: number }> = {
40
+ rotate: { keyframes: `${rotateAnimation}`, easing: 'linear', scale: 1 },
41
+ pulse: { keyframes: `${pulseAnimation}`, easing: 'ease-in-out', scale: 1 },
42
+ translate: { keyframes: `${translateAnimation}`, easing: 'ease-in-out', scale: 1 },
43
+ bounce: { keyframes: `${bounceAnimation}`, easing: 'ease-in-out', scale: 1 },
44
+ shake: { keyframes: `${shakeAnimation}`, easing: 'ease-in-out', scale: 1 },
45
+ flip: { keyframes: `${flipAnimation}`, easing: 'ease-in-out', scale: 1 },
46
+ spin: { keyframes: `${spinAnimation}`, easing: 'ease-in-out', scale: 1 },
47
+ fadeInOut: { keyframes: `${fadeInOutAnimation}`, easing: 'ease-in-out', scale: 1 },
48
+ heartbeat: { keyframes: `${heartbeatAnimation}`, easing: 'ease-in-out', scale: 1 },
49
+ wobble: { keyframes: `${wobbleAnimation}`, easing: 'ease-in-out', scale: 1 },
50
+ morph: { keyframes: `${morphAnimation}`, easing: 'ease-in-out', scale: 1 },
51
+ swing: { keyframes: `${swingAnimation}`, easing: 'ease-in-out', scale: 1 },
52
+ jello: { keyframes: `${jelloAnimation}`, easing: 'ease-in-out', scale: 1 },
53
+ float: { keyframes: `${floatAnimation}`, easing: 'ease-in-out', scale: 2 },
54
+ neonFlicker: { keyframes: `${neonFlickerAnimation}`, easing: 'ease-in-out', scale: 2 },
55
+ breathe: { keyframes: `${breatheAnimation}`, easing: 'ease-in-out', scale: 1.5 },
56
+ };
57
+
58
+ const animationFor = (
59
+ variant: AnimationVariant,
60
+ duration: number,
61
+ delay: number,
62
+ loop: boolean,
63
+ ) => {
64
+ const spec = ANIMATIONS[variant];
65
+ if (!spec) return 'none';
66
+
67
+ const iterationCount = loop ? 'infinite' : '1';
68
+ return `${spec.keyframes} ${duration * spec.scale}s ${spec.easing} ${iterationCount} ${delay > 0 ? `${delay}s` : '0s'}`;
69
+ };
70
+
71
+ const SHADOWS: Record<string, (theme: Theme) => string> = {
72
+ soft: (theme) => `0 4px 20px ${alpha(theme.palette.common.black, 0.15)}`,
73
+ hard: (theme) => `4px 4px 0px ${alpha(theme.palette.common.black, 0.25)}`,
74
+ elevated: (theme) =>
75
+ `0 10px 40px ${alpha(theme.palette.common.black, 0.2)}, 0 2px 10px ${alpha(theme.palette.common.black, 0.1)}`,
76
+ };
77
+
78
+ export interface IconStyleFlags {
79
+ $size: number;
80
+ $fontSize: number;
81
+ $animationVariant: AnimationVariant;
82
+ $duration: number;
83
+ $delay: number;
84
+ $loop: boolean;
85
+ $glow: boolean;
86
+ $glass: boolean;
87
+ $glowColor?: string;
88
+ $customColor?: string;
89
+ $metallic?: boolean;
90
+ $gradient?: boolean;
91
+ $shadow?: 'soft' | 'hard' | 'elevated' | 'none';
92
+ $ripple?: boolean;
93
+ $neon?: boolean;
94
+ $holographic?: boolean;
95
+ }
96
+
97
+ /**
98
+ * The four surface treatments that paint the icon themselves — metallic,
99
+ * gradient, neon and holographic — each run a second animation alongside the
100
+ * chosen one, so they all need the base animation string.
101
+ */
102
+ const effectStyles = (
103
+ theme: Theme,
104
+ flags: IconStyleFlags,
105
+ animation: string,
106
+ color: string,
107
+ ): CSSObject => {
108
+ const { $glass, $metallic, $gradient, $neon, $holographic } = flags;
109
+
110
+ return {
111
+ ...($glass && {
112
+ background: `linear-gradient(135deg, ${alpha(theme.palette.background.paper, 0.2)}, ${alpha(theme.palette.background.paper, 0.1)})`,
113
+ backdropFilter: 'blur(10px)',
114
+ border: `1px solid ${alpha(theme.palette.divider, 0.2)}`,
115
+ boxShadow: `inset 0 1px 1px ${alpha(theme.palette.common.white, 0.3)}, 0 8px 32px ${alpha(theme.palette.common.black, 0.1)}`,
116
+ }),
117
+ ...($metallic && {
118
+ background: `linear-gradient(145deg,
119
+ ${theme.palette.grey[300]} 0%,
120
+ ${theme.palette.grey[500]} 25%,
121
+ ${theme.palette.grey[400]} 50%,
122
+ ${theme.palette.grey[600]} 75%,
123
+ ${theme.palette.grey[400]} 100%)`,
124
+ backgroundSize: '200% 200%',
125
+ animation: `${animation}, ${breatheAnimation} 4s ease-in-out infinite`,
126
+ boxShadow: `inset 0 2px 4px ${alpha(theme.palette.common.white, 0.5)},
127
+ inset 0 -2px 4px ${alpha(theme.palette.common.black, 0.3)},
128
+ 0 4px 8px ${alpha(theme.palette.common.black, 0.2)}`,
129
+ }),
130
+ ...($gradient && {
131
+ background: `linear-gradient(135deg,
132
+ ${theme.palette.primary.main} 0%,
133
+ ${theme.palette.secondary.main} 100%)`,
134
+ backgroundSize: '200% 200%',
135
+ animation: `${animation}, ${breatheAnimation} 3s ease-in-out infinite`,
136
+ }),
137
+ ...($neon && {
138
+ color,
139
+ textShadow: `0 0 10px ${color}, 0 0 20px ${color}, 0 0 30px ${color}`,
140
+ filter: `brightness(1.2) contrast(1.2)`,
141
+ animation: `${animation}, ${neonFlickerAnimation} 3s ease-in-out infinite`,
142
+ }),
143
+ ...($holographic && {
144
+ background: `linear-gradient(45deg,
145
+ ${theme.palette.primary.main} 0%,
146
+ ${theme.palette.secondary.main} 25%,
147
+ ${theme.palette.error.main} 50%,
148
+ ${theme.palette.warning.main} 75%,
149
+ ${theme.palette.primary.main} 100%)`,
150
+ backgroundSize: '400% 400%',
151
+ animation: `${animation}, ${floatAnimation} 6s ease-in-out infinite`,
152
+ backgroundClip: 'text',
153
+ WebkitBackgroundClip: 'text',
154
+ WebkitTextFillColor: 'transparent',
155
+ filter: `hue-rotate(0deg)`,
156
+ '@keyframes hueRotate': {
157
+ '0%': { filter: 'hue-rotate(0deg)' },
158
+ '100%': { filter: 'hue-rotate(360deg)' },
159
+ },
160
+ '&::before': {
161
+ content: '""',
162
+ position: 'absolute' as const,
163
+ inset: -2,
164
+ borderRadius: '50%',
165
+ background: 'inherit',
166
+ filter: 'blur(10px)',
167
+ opacity: 0.5,
168
+ zIndex: -1,
169
+ },
170
+ }),
171
+ };
172
+ };
173
+
174
+ export const iconSx = (theme: Theme, flags: IconStyleFlags): CSSObject => {
175
+ const {
176
+ $size, $fontSize, $animationVariant, $duration, $delay, $loop,
177
+ $glow, $glowColor, $customColor, $shadow, $ripple, $neon,
178
+ } = flags;
179
+
180
+ const color = $customColor || theme.palette.primary.main;
181
+ const glowColor = $glowColor || color;
182
+ const animation = animationFor($animationVariant, $duration, $delay, $loop);
183
+
184
+ // Both selectors size the same glyph — MUI icons render an MuiSvgIcon-root,
185
+ // a bare child renders an svg.
186
+ const glyphSize = { fontSize: $fontSize, width: $fontSize, height: $fontSize };
187
+
188
+ return {
189
+ display: 'inline-flex',
190
+ alignItems: 'center',
191
+ justifyContent: 'center',
192
+ width: $size,
193
+ height: $size,
194
+ color,
195
+ animation,
196
+ position: 'relative' as const,
197
+ cursor: 'default',
198
+ borderRadius: '50%',
199
+ transition: 'all 0.3s ease',
200
+ boxShadow: SHADOWS[$shadow ?? 'none']?.(theme) ?? 'none',
201
+ ...($glow && {
202
+ '&::before': {
203
+ content: '""',
204
+ position: 'absolute' as const,
205
+ inset: -8,
206
+ borderRadius: '50%',
207
+ background: `radial-gradient(circle, ${alpha(glowColor, 0.3)} 0%, transparent 70%)`,
208
+ animation: `${glowPulseAnimation} ${$duration * 1.2}s ease-in-out infinite`,
209
+ zIndex: -1,
210
+ },
211
+ filter: `drop-shadow(0 0 8px ${alpha(glowColor, 0.5)})`,
212
+ }),
213
+ ...effectStyles(theme, flags, animation, color),
214
+ ...($ripple && {
215
+ '&::after': {
216
+ content: '""',
217
+ position: 'absolute' as const,
218
+ inset: 0,
219
+ borderRadius: '50%',
220
+ border: `2px solid ${color}`,
221
+ animation: `${rippleAnimation} ${$duration * 1.5}s ease-out infinite`,
222
+ },
223
+ }),
224
+ '& .MuiSvgIcon-root': glyphSize,
225
+ '& svg': glyphSize,
226
+ '&:hover': {
227
+ transform: 'scale(1.05)',
228
+ filter: $neon ? `brightness(1.4) contrast(1.3)` : undefined,
229
+ },
230
+ };
231
+ };