@catalystsoftware/ui 1.0.2 → 1.0.5

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 (157) hide show
  1. package/data/tailwind.config.js +261 -3821
  2. package/dist/components/catalyst-ui/buttons/burger.tsx +207 -0
  3. package/dist/components/catalyst-ui/core/data-display/timeline.tsx +210 -0
  4. package/dist/components/catalyst-ui/core/feedback/alert.tsx +491 -0
  5. package/dist/components/catalyst-ui/core/feedback/spinner-1.tsx +65 -0
  6. package/dist/components/catalyst-ui/core/feedback/toast.tsx +1857 -0
  7. package/dist/components/catalyst-ui/core/navigation/menu.tsx +164 -0
  8. package/dist/components/catalyst-ui/forms/toggle-class.tsx +176 -0
  9. package/dist/components/catalyst-ui/hooks/use-copy-to-clipboard.tsx +419 -0
  10. package/dist/components/catalyst-ui/hooks/use-counter.tsx +13 -0
  11. package/dist/components/catalyst-ui/hooks/use-event-listener.tsx +23 -0
  12. package/dist/components/catalyst-ui/hooks/use-export-markdown.tsx +47 -0
  13. package/dist/components/catalyst-ui/hooks/use-focus.tsx +17 -0
  14. package/dist/components/catalyst-ui/hooks/use-interval.tsx +23 -0
  15. package/dist/components/catalyst-ui/hooks/use-is-client.tsx +16 -0
  16. package/dist/components/catalyst-ui/hooks/use-media-query.tsx +19 -0
  17. package/dist/components/catalyst-ui/hooks/use-mobile.tsx +19 -0
  18. package/dist/components/catalyst-ui/hooks/use-resize-observer.tsx +81 -0
  19. package/dist/components/catalyst-ui/hooks/use-timeout.tsx +21 -0
  20. package/dist/components/catalyst-ui/hooks/use-timer.tsx +209 -0
  21. package/dist/components/catalyst-ui/hooks/use-toggle.tsx +12 -0
  22. package/dist/components/catalyst-ui/media/image.tsx +13 -0
  23. package/dist/components/catalyst-ui/overlays/dual-sidebar.tsx +4142 -0
  24. package/dist/components/catalyst-ui/overlays/sidebar-original.tsx +726 -0
  25. package/dist/components/catalyst-ui/primitives/accordion.tsx +250 -0
  26. package/dist/components/catalyst-ui/primitives/alert-dialog.tsx +126 -0
  27. package/dist/components/catalyst-ui/primitives/aspect-ratio.tsx +9 -0
  28. package/dist/components/catalyst-ui/primitives/avatar.tsx +296 -0
  29. package/dist/components/catalyst-ui/primitives/badge.tsx +57 -0
  30. package/dist/components/catalyst-ui/primitives/breadcrumb.tsx +101 -0
  31. package/dist/components/catalyst-ui/primitives/button.tsx +265 -0
  32. package/dist/components/catalyst-ui/primitives/calendar-v4.tsx +208 -0
  33. package/dist/components/catalyst-ui/primitives/calendar.tsx +295 -0
  34. package/dist/components/catalyst-ui/primitives/card.tsx +618 -0
  35. package/dist/components/catalyst-ui/primitives/carousel.tsx +238 -0
  36. package/dist/components/catalyst-ui/primitives/chart.tsx +347 -0
  37. package/dist/components/catalyst-ui/primitives/checkbox.tsx +225 -0
  38. package/dist/components/catalyst-ui/primitives/collapsible.tsx +212 -0
  39. package/dist/components/catalyst-ui/primitives/command.tsx +393 -0
  40. package/dist/components/catalyst-ui/primitives/context-menu.tsx +236 -0
  41. package/dist/components/catalyst-ui/primitives/dialog.tsx +471 -0
  42. package/dist/components/catalyst-ui/primitives/drawer.tsx +761 -0
  43. package/dist/components/catalyst-ui/primitives/dropdown-menu.tsx +290 -0
  44. package/dist/components/catalyst-ui/primitives/empty.tsx +104 -0
  45. package/dist/components/catalyst-ui/primitives/field.tsx +244 -0
  46. package/dist/components/catalyst-ui/primitives/hover-card.tsx +124 -0
  47. package/dist/components/catalyst-ui/primitives/input-otp.tsx +76 -0
  48. package/dist/components/catalyst-ui/primitives/input.tsx +64 -0
  49. package/dist/components/catalyst-ui/primitives/item.tsx +196 -0
  50. package/dist/components/catalyst-ui/primitives/kbd.tsx +75 -0
  51. package/dist/components/catalyst-ui/primitives/label.tsx +24 -0
  52. package/dist/components/catalyst-ui/primitives/navigation-menu.tsx +150 -0
  53. package/dist/components/catalyst-ui/primitives/pagination.tsx +198 -0
  54. package/dist/components/catalyst-ui/primitives/popover.tsx +232 -0
  55. package/dist/components/catalyst-ui/primitives/progress.tsx +34 -0
  56. package/dist/components/catalyst-ui/primitives/radio-group.tsx +43 -0
  57. package/dist/components/catalyst-ui/primitives/resizable.tsx +56 -0
  58. package/dist/components/catalyst-ui/primitives/select.tsx +155 -0
  59. package/dist/components/catalyst-ui/primitives/separator.tsx +74 -0
  60. package/dist/components/catalyst-ui/primitives/sheet.tsx +126 -0
  61. package/dist/components/catalyst-ui/primitives/skeleton.tsx +15 -0
  62. package/dist/components/catalyst-ui/primitives/slider.tsx +27 -0
  63. package/dist/components/catalyst-ui/primitives/switch.tsx +187 -0
  64. package/dist/components/catalyst-ui/primitives/tabs.tsx +335 -0
  65. package/dist/components/catalyst-ui/primitives/textarea.tsx +24 -0
  66. package/dist/components/catalyst-ui/primitives/toggle-group.tsx +55 -0
  67. package/dist/components/catalyst-ui/primitives/toggle.tsx +42 -0
  68. package/dist/components/catalyst-ui/primitives/tooltip.tsx +116 -0
  69. package/dist/components/catalyst-ui/utils/basic-auth.tsx +40 -0
  70. package/dist/components/catalyst-ui/utils/context-storage.tsx +19 -0
  71. package/dist/components/catalyst-ui/utils/cors-middleware.tsx +71 -0
  72. package/dist/components/catalyst-ui/utils/deferred-content.tsx +595 -0
  73. package/dist/components/catalyst-ui/utils/honeypot-middleware.tsx +38 -0
  74. package/dist/components/catalyst-ui/utils/incId.tsx +75 -0
  75. package/dist/components/catalyst-ui/utils/jwk-auth.tsx +36 -0
  76. package/dist/components/catalyst-ui/utils/request-id.tsx +14 -0
  77. package/dist/components/catalyst-ui/utils/secure-headers.tsx +37 -0
  78. package/dist/components/catalyst-ui/utils/server-timing.tsx +23 -0
  79. package/dist/components/catalyst-ui/utils/utils.ts +43 -0
  80. package/dist/components/catalyst-ui/utils/with-cookie.tsx +43 -0
  81. package/dist/components/catalyst-ui/x/accordian-x.tsx +428 -0
  82. package/dist/components/catalyst-ui/x/alert-x.tsx +413 -0
  83. package/dist/components/catalyst-ui/x/animated-text-x.tsx +2242 -0
  84. package/dist/components/catalyst-ui/x/avatar-x.tsx +515 -0
  85. package/dist/components/catalyst-ui/x/badge-x.tsx +670 -0
  86. package/dist/components/catalyst-ui/x/button-X.tsx +2857 -0
  87. package/dist/components/catalyst-ui/x/button-group-x.tsx +847 -0
  88. package/dist/components/catalyst-ui/x/calendar-x.tsx +1910 -0
  89. package/dist/components/catalyst-ui/x/card-x.tsx +2597 -0
  90. package/dist/components/catalyst-ui/x/checkbox-x.tsx +656 -0
  91. package/dist/components/catalyst-ui/x/collapsible-x.tsx +1360 -0
  92. package/dist/components/catalyst-ui/x/combobox-x.tsx +911 -0
  93. package/dist/components/catalyst-ui/x/data-table-x.tsx +1753 -0
  94. package/dist/components/catalyst-ui/x/date-picker-x.tsx +648 -0
  95. package/dist/components/catalyst-ui/x/dialog-x.tsx +659 -0
  96. package/dist/components/catalyst-ui/x/dropdown-menu-x.tsx +612 -0
  97. package/dist/components/catalyst-ui/x/hover-card-x.tsx +375 -0
  98. package/dist/components/catalyst-ui/x/icon-x.tsx +840 -0
  99. package/dist/components/catalyst-ui/x/input-mask-x.tsx +981 -0
  100. package/dist/components/catalyst-ui/x/input-otp-x.tsx +659 -0
  101. package/dist/components/catalyst-ui/x/loader-x.tsx +1757 -0
  102. package/dist/components/catalyst-ui/x/pagination-x.tsx +622 -0
  103. package/dist/components/catalyst-ui/x/popover-x.tsx +744 -0
  104. package/dist/components/catalyst-ui/x/radio-group-x.tsx +499 -0
  105. package/dist/components/catalyst-ui/x/select-x.tsx +1127 -0
  106. package/dist/components/catalyst-ui/x/sheet-x.tsx +668 -0
  107. package/dist/components/catalyst-ui/x/switch-x.tsx +681 -0
  108. package/dist/components/catalyst-ui/x/table-x.tsx +574 -0
  109. package/dist/components/catalyst-ui/x/tabs-x.tsx +839 -0
  110. package/dist/components/catalyst-ui/x/textarea-x.tsx +1263 -0
  111. package/dist/components/catalyst-ui/x/tooltip-x.tsx +396 -0
  112. package/dist/components/catalyst-ui/x/tracker-x.tsx +560 -0
  113. package/dist/data/bg-data.tsx +901 -0
  114. package/dist/data/buttons-data.tsx +2327 -0
  115. package/dist/data/charts-data.tsx +102 -0
  116. package/dist/data/chat-data.tsx +83 -0
  117. package/dist/data/code-data.tsx +1040 -0
  118. package/dist/data/comboboxes-data.tsx +1843 -0
  119. package/dist/data/command-data.tsx +1381 -0
  120. package/dist/data/core-data.tsx +15953 -0
  121. package/dist/data/crm-data.tsx +47 -0
  122. package/dist/data/data.tsx +159 -0
  123. package/dist/data/date-and-time-data.tsx +554 -0
  124. package/dist/data/dependencies.tsx +7 -0
  125. package/dist/data/ecommerce-data.tsx +1387 -0
  126. package/dist/data/forms-data.tsx +7890 -0
  127. package/dist/data/hooks-data.tsx +5487 -0
  128. package/dist/data/index.ts +34 -0
  129. package/dist/data/inputs-data.tsx +557 -0
  130. package/dist/data/interactive-data.tsx +5394 -0
  131. package/dist/data/lofi-data.tsx +18295 -0
  132. package/dist/data/marketing-data.tsx +2546 -0
  133. package/dist/data/media-data.tsx +1510 -0
  134. package/dist/data/motion-data.tsx +5801 -0
  135. package/dist/data/overlay-data.tsx +4136 -0
  136. package/dist/data/pdf-data.tsx +124 -0
  137. package/dist/data/pos-data.tsx +213 -0
  138. package/dist/data/postcss.config.js +6 -0
  139. package/dist/data/primitive-data.tsx +5170 -0
  140. package/dist/data/prompt-data.tsx +1226 -0
  141. package/dist/data/requiredLibs.ts +4 -0
  142. package/dist/data/sandbox-data.tsx +1 -0
  143. package/dist/data/sidebars-data.tsx +5421 -0
  144. package/dist/data/stacks-data.tsx +32 -0
  145. package/dist/data/table-data.tsx +706 -0
  146. package/dist/data/tailwind.config.js +270 -0
  147. package/dist/data/tailwind.config.ngin.js +3830 -0
  148. package/dist/data/tailwind.css +431 -0
  149. package/dist/data/tools-data.tsx +6910 -0
  150. package/dist/data/typography-data.tsx +2050 -0
  151. package/dist/data/utils-data.tsx +6500 -0
  152. package/dist/data/x-data.tsx +1171 -0
  153. package/dist/data.tsx +159 -0
  154. package/package.json +1 -1
  155. package/dist/index.d.ts +0 -3
  156. package/dist/index.d.ts.map +0 -1
  157. package/dist/index.js.map +0 -362
@@ -0,0 +1,840 @@
1
+
2
+ import React, { useState } from 'react';
3
+ import { motion } from 'motion/react';
4
+ import { cn } from '~/components/catalyst-ui';
5
+
6
+ /**
7
+ * # IconX/MotionIcons Component Props Documentation
8
+
9
+ ### ============================ ICONX (Main Selector) ============================
10
+ - **icon**: "Burger" | "Close" | "Plus" | "Chevron" | "Arrow" | "Check" | "Dots" | "Play" | "Heart" (default: "Burger")
11
+ - **opened**: boolean (default: false) - controls the animated state of the icon
12
+ - **size**: "sm" | "md" | "lg" | "xl" (default: "md")
13
+ - **color**: string (default: "currentColor") - CSS color value
14
+ - **className**: string - additional CSS classes
15
+ - **...props**: additional HTML div props
16
+
17
+ **Size Reference:**
18
+ - `sm`: 16px (w-4 h-4)
19
+ - `md`: 24px (w-6 h-6)
20
+ - `lg`: 32px (w-8 h-8)
21
+ - `xl`: 40px (w-10 h-10)
22
+
23
+ **Line Height by Size:**
24
+ - `sm`: 2px
25
+ - `md`: 2px
26
+ - `lg`: 3px
27
+ - `xl`: 3px
28
+
29
+ ---
30
+
31
+ ### ============================ Burger =============================================
32
+ - **opened**: boolean (default: false) - when true, transforms to X shape
33
+ - **size**: "sm" | "md" | "lg" | "xl" (default: "md")
34
+ - **color**: string (default: "currentColor")
35
+ - **className**: string
36
+
37
+ **Animation:** Three horizontal lines transform into an X (cross) shape
38
+ - Top line: rotates 45° and moves to center
39
+ - Middle line: fades out (opacity 0)
40
+ - Bottom line: rotates -45° and moves to center
41
+
42
+ **Transition:** 0.3s with easeInOut
43
+
44
+ ---
45
+
46
+ ### ============================ Burger2 =================================================
47
+ - **opened**: boolean (default: false) - when true, transforms to X shape
48
+ - **size**: "sm" | "md" | "lg" | "xl" (default: "md")
49
+ - **color**: string (default: "currentColor")
50
+ - **className**: string
51
+ - **onToggle**: function(opened: boolean) - callback when state changes
52
+ - **aria-label**: string - accessibility label
53
+ - **disabled**: boolean - disables interaction
54
+
55
+ **Animation:** CSS-only version (no Framer Motion) - same visual effect as Burger
56
+ **Transition:** 0.3s with ease-in-out
57
+
58
+ ---
59
+
60
+ ## ============================ Close ===================================================================
61
+ - **opened**: boolean (default: false) - when true, rotates the X shape
62
+ - **size**: "sm" | "md" | "lg" | "xl" (default: "md")
63
+ - **color**: string (default: "currentColor")
64
+ - **className**: string
65
+
66
+ **Animation:** Two intersecting lines that rotate
67
+ - Line 1: rotates from 0° to 45° when opened
68
+ - Line 2: rotates from 0° to -45° when opened
69
+ - Creates an X shape that can spin
70
+
71
+ **Transition:** 0.3s with easeInOut
72
+
73
+ ---
74
+
75
+ ## ============================ Plus ====================================================================
76
+ - **opened**: boolean (default: false) - when true, rotates 90°
77
+ - **size**: "sm" | "md" | "lg" | "xl" (default: "md")
78
+ - **color**: string (default: "currentColor")
79
+ - **className**: string
80
+
81
+ **Animation:** Plus sign that rotates
82
+ - Horizontal line: rotates 90° (becomes vertical)
83
+ - Vertical line: rotates 90° (becomes horizontal)
84
+ - Creates a rotation effect
85
+
86
+ **Transition:** 0.3s with easeInOut
87
+
88
+ ---
89
+
90
+ ## ============================ Chevron =================================================================
91
+ - **opened**: boolean (default: false) - when true, changes direction from down to up
92
+ - **size**: "sm" | "md" | "lg" | "xl" (default: "md")
93
+ - **color**: string (default: "currentColor")
94
+ - **className**: string
95
+
96
+ **Animation:** V-shaped chevron that flips direction
97
+ - Left line: rotates from -45° to 45° when opened
98
+ - Right line: rotates from 45° to -45° when opened
99
+ - Chevron down (∨) becomes chevron up (∧)
100
+
101
+ - **Transition:** 0.3s with easeInOut
102
+ - **Transform Origin:** Right center for left line, left center for right line
103
+
104
+ ---
105
+
106
+ ## ============================ Arrow ===================================================================
107
+ - **opened**: boolean (default: false) - when true, arrow points backward
108
+ - **size**: "sm" | "md" | "lg" | "xl" (default: "md")
109
+ - **color**: string (default: "currentColor")
110
+ - **className**: string
111
+
112
+ **Animation:** Right-pointing arrow that flips to left
113
+ - Shaft: moves 30% to the right when opened
114
+ - Upper arrowhead: rotates from -45° to -135° when opened
115
+ - Lower arrowhead: rotates from 45° to 135° when opened
116
+ - Arrow right (→) becomes arrow left (←)
117
+
118
+ - **Transition:** 0.3s with easeInOut
119
+ - **Transform Origin:** Right center for arrowhead lines
120
+
121
+ ---
122
+
123
+ ## ============================ Check ===================================================================
124
+ - **opened**: boolean (default: false) - when true, draws checkmark
125
+ - **size**: "sm" | "md" | "lg" | "xl" (default: "md")
126
+ - **color**: string (default: "currentColor")
127
+ - **className**: string
128
+
129
+ **Animation:** Checkmark that draws in sequentially
130
+ - Short line: scales from 0 to 1 (draws in)
131
+ - Long line: scales from 0 to 1 with 0.1s delay (draws in after short line)
132
+ - Creates classic checkmark (✓) drawing effect
133
+
134
+ - **Transition:** 0.3s with easeOut, second line has 0.1s delay
135
+ - **Transform Origin:** Left center for both lines
136
+ - **Initial State:** scaleX: 0 (invisible)
137
+
138
+ ---
139
+
140
+ ## ============================ Dots ====================================================================
141
+ - **opened**: boolean (default: false) - when true, dots animate
142
+ - **size**: "sm" | "md" | "lg" | "xl" (default: "md")
143
+ - **color**: string (default: "currentColor")
144
+ - **className**: string
145
+
146
+ **Animation:** Three dots that bounce in sequence (loading animation)
147
+ - Each dot: scales to 1.5x and moves up 4px, then returns
148
+ - Sequential animation with 0.1s delay between each dot
149
+ - Creates wave/bounce loading effect
150
+
151
+ - **Transition:** 0.5s with easeInOut
152
+ - **Delays:** Dot 1: 0s, Dot 2: 0.1s, Dot 3: 0.2s
153
+
154
+ **Dot Sizes by Size:**
155
+ - `sm`: 3px
156
+ - `md`: 4px
157
+ - `lg`: 5px
158
+ - `xl`: 6px
159
+
160
+ ---
161
+
162
+ ## ============================ Play ====================================================================
163
+ - **opened**: boolean (default: false) - when true, changes to pause
164
+ - **size**: "sm" | "md" | "lg" | "xl" (default: "md")
165
+ - **color**: string (default: "currentColor")
166
+ - **className**: string
167
+
168
+ **Animation:** Play triangle morphs into pause bars
169
+ - Play state: Single triangle path (▶)
170
+ - Pause state: Two vertical bars (⏸)
171
+ - Smooth SVG path morphing
172
+
173
+ - **Transition:** 0.3s with easeInOut
174
+ - **Implementation:** Uses SVG with animated path data
175
+
176
+ ---
177
+
178
+ ## ============================ Heart ===================================================================
179
+ - **opened**: boolean (default: false) - when true, fills the heart
180
+ - **size**: "sm" | "md" | "lg" | "xl" (default: "md")
181
+ - **color**: string (default: "currentColor")
182
+ - **className**: string
183
+
184
+ **Animation:** Heart outline that fills and scales
185
+ - Closed state: Outline only (stroke)
186
+ - Opened state: Filled heart with scale animation [1, 1.2, 1]
187
+ - Creates "like" animation effect
188
+
189
+ - **Transition:** 0.3s with easeInOut
190
+ - **Implementation:** Uses SVG with stroke and fill animation
191
+ - **Scale Effect:** Brief 20% increase when filling
192
+
193
+ ---
194
+
195
+ ## Usage Examples
196
+
197
+ ### Basic Usage
198
+ ```jsx
199
+ import { IconX } from './icon-x';
200
+
201
+ // Using IconX selector
202
+ <IconX icon="Burger" opened={isOpen} size="md" />
203
+ <IconX icon="Heart" opened={isLiked} color="#ff0000" />
204
+ <IconX icon="Play" opened={isPlaying} size="lg" />
205
+ ```
206
+
207
+ ### With State Management
208
+ ```jsx
209
+ const [isOpen, setIsOpen] = useState(false);
210
+
211
+ <button onClick={() => setIsOpen(!isOpen)}>
212
+ <IconX icon="Burger" opened={isOpen} size="md" />
213
+ </button>
214
+ ```
215
+
216
+ ### Direct Component Import
217
+ ```jsx
218
+ import { Burger, Heart, Play, Check } from './icon-x';
219
+
220
+ <Burger opened={isMenuOpen} size="lg" color="blue" />
221
+ <Heart opened={isLiked} color="red" />
222
+ <Play opened={isPlaying} />
223
+ <Check opened={isComplete} size="sm" />
224
+ ```
225
+
226
+ ### With Custom Styling
227
+ ```jsx
228
+ <IconX
229
+ icon="Chevron"
230
+ opened={isExpanded}
231
+ size="md"
232
+ color="currentColor"
233
+ className="text-blue-500 hover:text-blue-700"
234
+ />
235
+ ```
236
+
237
+ ### All Sizes Demo
238
+ ```jsx
239
+ <div className="flex gap-4">
240
+ <IconX icon="Burger" opened={isOpen} size="sm" />
241
+ <IconX icon="Burger" opened={isOpen} size="md" />
242
+ <IconX icon="Burger" opened={isOpen} size="lg" />
243
+ <IconX icon="Burger" opened={isOpen} size="xl" />
244
+ </div>
245
+ ```
246
+
247
+ ### Toggle Button Pattern
248
+ ```jsx
249
+ const [states, setStates] = useState({
250
+ menu: false,
251
+ liked: false,
252
+ playing: false,
253
+ });
254
+
255
+ <button onClick={() => setStates(s => ({ ...s, menu: !s.menu }))}>
256
+ <IconX icon="Burger" opened={states.menu} />
257
+ </button>
258
+
259
+ <button onClick={() => setStates(s => ({ ...s, liked: !s.liked }))}>
260
+ <IconX icon="Heart" opened={states.liked} color="red" />
261
+ </button>
262
+
263
+ <button onClick={() => setStates(s => ({ ...s, playing: !s.playing }))}>
264
+ <IconX icon="Play" opened={states.playing} />
265
+ </button>
266
+ ```
267
+
268
+ ---
269
+
270
+ ## Animation States Reference
271
+
272
+ | Icon | Closed State | Opened State | Use Case |
273
+ |------|--------------|--------------|----------|
274
+ | Burger | ≡ (three lines) | ✕ (X shape) | Menu toggle |
275
+ | Burger2 | ≡ (three lines) | ✕ (X shape) | Menu toggle (CSS only) |
276
+ | Close | ✕ (upright X) | ✕ (rotated X) | Close/dismiss with rotation |
277
+ | Plus | + (plus) | + (rotated 90°) | Add/expand toggle |
278
+ | Chevron | ∨ (down) | ∧ (up) | Dropdown/accordion |
279
+ | Arrow | → (right) | ← (left) | Navigation/back |
280
+ | Check | (empty) | ✓ (checkmark) | Task completion |
281
+ | Dots | ··· (static) | ··· (bouncing) | Loading indicator |
282
+ | Play | ▶ (play) | ⏸ (pause) | Media control |
283
+ | Heart | ♡ (outline) | ♥ (filled) | Like/favorite |
284
+
285
+ ---
286
+
287
+ ## Technical Notes
288
+
289
+ 1. **Dependencies:**
290
+ - Framer Motion (`motion/react`) for all components except Burger2
291
+ - Burger2 uses pure CSS transitions (no motion dependency)
292
+
293
+ 2. **Performance:**
294
+ - All animations use transform/opacity for GPU acceleration
295
+ - 60fps smooth animations
296
+ - Lightweight (~2-3 KB per icon)
297
+
298
+ 3. **Accessibility:**
299
+ - Icons inherit currentColor by default
300
+ - Works with focus states
301
+ - Burger2 supports aria-label and disabled props
302
+
303
+ 4. **Customization:**
304
+ - All icons respect CSS color inheritance
305
+ - Sizes are responsive (rem-based)
306
+ - Can override with className prop
307
+ - Supports dark mode via color prop
308
+
309
+ 5. **Browser Support:**
310
+ - Modern browsers (Chrome, Firefox, Safari, Edge)
311
+ - Requires CSS transforms and CSS transitions support
312
+ - SVG support required for Play and Heart icons
313
+ */
314
+
315
+ export function IconX({ icon, ...props }) {
316
+ switch (icon) {
317
+ case 'Burger':
318
+ return <Burger {...props} />;
319
+ case 'Close':
320
+ return <Close {...props} />;
321
+ case 'Plus':
322
+ return <Plus {...props} />;
323
+ case 'Chevron':
324
+ return <Chevron {...props} />;
325
+ case 'Arrow':
326
+ return <Arrow {...props} />;
327
+ case 'Check':
328
+ return <Check {...props} />;
329
+ case 'Dots':
330
+ return <Dots {...props} />;
331
+ case 'Play':
332
+ return <Play {...props} />;
333
+ case 'Heart':
334
+ return <Heart {...props} />;
335
+ default:
336
+ return <Burger2 {...props} />;
337
+ }
338
+ }
339
+
340
+ // Shared props interface
341
+ interface IconProps {
342
+ opened?: boolean;
343
+ size?: 'sm' | 'md' | 'lg' | 'xl';
344
+ color?: string;
345
+ className?: string;
346
+ }
347
+
348
+ const sizeClasses = {
349
+ sm: 'w-4 h-4',
350
+ md: 'w-6 h-6',
351
+ lg: 'w-8 h-8',
352
+ xl: 'w-10 h-10'
353
+ };
354
+
355
+ const lineHeight = {
356
+ sm: '2px',
357
+ md: '2px',
358
+ lg: '3px',
359
+ xl: '3px'
360
+ };
361
+
362
+ interface BurgerMenuProps {
363
+ opened?: boolean;
364
+ onToggle?: (opened: boolean) => void;
365
+ size?: 'sm' | 'md' | 'lg' | 'xl';
366
+ color?: string;
367
+ className?: string;
368
+ 'aria-label'?: string;
369
+ disabled?: boolean;
370
+ }
371
+
372
+ function Burger2({ opened = false, size = 'md', color = 'currentColor', }: BurgerMenuProps) {
373
+ const isOpened = opened
374
+
375
+ const sizeClasses = {
376
+ sm: 'w-4 h-4',
377
+ md: 'w-6 h-6',
378
+ lg: 'w-8 h-8',
379
+ xl: 'w-10 h-10'
380
+ };
381
+
382
+ const lineHeight = {
383
+ sm: '2px',
384
+ md: '2px',
385
+ lg: '3px',
386
+ xl: '3px'
387
+ };
388
+
389
+ return (
390
+ <div className={cn("relative", sizeClasses[size])}>
391
+ <span
392
+ className={cn("absolute left-0 block transition-all duration-300 ease-in-out rounded-full", "bg-current")}
393
+ style={{
394
+ width: '100%',
395
+ height: lineHeight[size],
396
+ color: color,
397
+ top: isOpened ? '50%' : '20%',
398
+ transform: isOpened ? 'translateY(-50%) rotate(45deg)' : 'translateY(-50%) rotate(0deg)'
399
+ }}
400
+ />
401
+ <span
402
+ className={cn(
403
+ "absolute left-0 block transition-all duration-300 ease-in-out rounded-full",
404
+ "bg-current"
405
+ )}
406
+ style={{
407
+ width: '100%',
408
+ height: lineHeight[size],
409
+ color: color,
410
+ top: '50%',
411
+ opacity: isOpened ? 0 : 1,
412
+ transform: 'translateY(-50%)'
413
+ }}
414
+ />
415
+ <span
416
+ className={cn(
417
+ "absolute left-0 block transition-all duration-300 ease-in-out rounded-full",
418
+ "bg-current"
419
+ )}
420
+ style={{
421
+ width: '100%',
422
+ height: lineHeight[size],
423
+ color: color,
424
+ bottom: isOpened ? '50%' : '20%',
425
+ transform: isOpened ? 'translateY(50%) rotate(-45deg)' : 'translateY(50%) rotate(0deg)'
426
+ }}
427
+ />
428
+ </div>
429
+ );
430
+ }
431
+ function Burger({ opened = false, size = 'md', color = 'currentColor', className }: IconProps) {
432
+ return (
433
+ <div className={cn("relative", sizeClasses[size], className)}>
434
+ <motion.span
435
+ className="absolute left-0 block rounded-full bg-current"
436
+ style={{ width: '100%', height: lineHeight[size], color }}
437
+ animate={{
438
+ top: opened ? '50%' : '20%',
439
+ rotate: opened ? 45 : 0,
440
+ y: '-50%'
441
+ }}
442
+ transition={{ duration: 0.3, ease: 'easeInOut' }}
443
+ />
444
+ <motion.span
445
+ className="absolute left-0 top-1/2 block rounded-full bg-current"
446
+ style={{ width: '100%', height: lineHeight[size], color, y: '-50%' }}
447
+ animate={{ opacity: opened ? 0 : 1 }}
448
+ transition={{ duration: 0.3, ease: 'easeInOut' }}
449
+ />
450
+ <motion.span
451
+ className="absolute left-0 block rounded-full bg-current"
452
+ style={{ width: '100%', height: lineHeight[size], color }}
453
+ animate={{
454
+ bottom: opened ? '50%' : '20%',
455
+ rotate: opened ? -45 : 0,
456
+ y: '50%'
457
+ }}
458
+ transition={{ duration: 0.3, ease: 'easeInOut' }}
459
+ />
460
+ </div>
461
+ );
462
+ }
463
+
464
+ function Close({ opened = false, size = 'md', color = 'currentColor', className }: IconProps) {
465
+ return (
466
+ <div className={cn("relative", sizeClasses[size], className)}>
467
+ <motion.span
468
+ className="absolute left-0 top-1/2 block rounded-full bg-current"
469
+ style={{ width: '100%', height: lineHeight[size], color }}
470
+ animate={{ rotate: opened ? 45 : 0, y: '-50%' }}
471
+ transition={{ duration: 0.3, ease: 'easeInOut' }}
472
+ />
473
+ <motion.span
474
+ className="absolute left-0 top-1/2 block rounded-full bg-current"
475
+ style={{ width: '100%', height: lineHeight[size], color }}
476
+ animate={{ rotate: opened ? -45 : 0, y: '-50%' }}
477
+ transition={{ duration: 0.3, ease: 'easeInOut' }}
478
+ />
479
+ </div>
480
+ );
481
+ }
482
+
483
+ function Plus({ opened = false, size = 'md', color = 'currentColor', className }: IconProps) {
484
+ return (
485
+ <div className={cn("relative", sizeClasses[size], className)}>
486
+ <motion.span
487
+ className="absolute left-0 top-1/2 block rounded-full bg-current"
488
+ style={{ width: '100%', height: lineHeight[size], color }}
489
+ animate={{ rotate: opened ? 90 : 0, y: '-50%' }}
490
+ transition={{ duration: 0.3, ease: 'easeInOut' }}
491
+ />
492
+ <motion.span
493
+ className="absolute left-1/2 top-0 block rounded-full bg-current"
494
+ style={{ width: lineHeight[size], height: '100%', color }}
495
+ animate={{ rotate: opened ? 90 : 0, x: '-50%' }}
496
+ transition={{ duration: 0.3, ease: 'easeInOut' }}
497
+ />
498
+ </div>
499
+ );
500
+ }
501
+
502
+ function Chevron({ opened = false, size = 'md', color = 'currentColor', className }: IconProps) {
503
+ return (
504
+ <div className={cn("relative", sizeClasses[size], className)}>
505
+ <motion.span
506
+ className="absolute block rounded-full bg-current"
507
+ style={{
508
+ width: '50%',
509
+ height: lineHeight[size],
510
+ color,
511
+ left: '10%',
512
+ top: '50%',
513
+ transformOrigin: 'right center'
514
+ }}
515
+ animate={{
516
+ rotate: opened ? 45 : -45,
517
+ y: '-50%'
518
+ }}
519
+ transition={{ duration: 0.3, ease: 'easeInOut' }}
520
+ />
521
+ <motion.span
522
+ className="absolute block rounded-full bg-current"
523
+ style={{
524
+ width: '50%',
525
+ height: lineHeight[size],
526
+ color,
527
+ right: '10%',
528
+ top: '50%',
529
+ transformOrigin: 'left center'
530
+ }}
531
+ animate={{
532
+ rotate: opened ? -45 : 45,
533
+ y: '-50%'
534
+ }}
535
+ transition={{ duration: 0.3, ease: 'easeInOut' }}
536
+ />
537
+ </div>
538
+ );
539
+ }
540
+
541
+ function Arrow({ opened = false, size = 'md', color = 'currentColor', className }: IconProps) {
542
+ return (
543
+ <div className={cn("relative", sizeClasses[size], className)}>
544
+ <motion.span
545
+ className="absolute left-0 top-1/2 block rounded-full bg-current"
546
+ style={{ width: '70%', height: lineHeight[size], color }}
547
+ animate={{
548
+ x: opened ? '30%' : '0%',
549
+ y: '-50%'
550
+ }}
551
+ transition={{ duration: 0.3, ease: 'easeInOut' }}
552
+ />
553
+ <motion.span
554
+ className="absolute block rounded-full bg-current"
555
+ style={{
556
+ width: '40%',
557
+ height: lineHeight[size],
558
+ color,
559
+ right: '5%',
560
+ top: '50%',
561
+ transformOrigin: 'right center'
562
+ }}
563
+ animate={{
564
+ rotate: opened ? -135 : -45,
565
+ y: '-50%'
566
+ }}
567
+ transition={{ duration: 0.3, ease: 'easeInOut' }}
568
+ />
569
+ <motion.span
570
+ className="absolute block rounded-full bg-current"
571
+ style={{
572
+ width: '40%',
573
+ height: lineHeight[size],
574
+ color,
575
+ right: '5%',
576
+ top: '50%',
577
+ transformOrigin: 'right center'
578
+ }}
579
+ animate={{
580
+ rotate: opened ? 135 : 45,
581
+ y: '-50%'
582
+ }}
583
+ transition={{ duration: 0.3, ease: 'easeInOut' }}
584
+ />
585
+ </div>
586
+ );
587
+ }
588
+
589
+ function Check({ opened = false, size = 'md', color = 'currentColor', className }: IconProps) {
590
+ return (
591
+ <div className={cn("relative", sizeClasses[size], className)}>
592
+ <motion.span
593
+ className="absolute block rounded-full bg-current"
594
+ style={{
595
+ width: '40%',
596
+ height: lineHeight[size],
597
+ color,
598
+ left: '10%',
599
+ top: '60%',
600
+ transformOrigin: 'left center'
601
+ }}
602
+ initial={{ rotate: -45, scaleX: 0 }}
603
+ animate={{
604
+ rotate: -45,
605
+ scaleX: opened ? 1 : 0,
606
+ y: '-50%'
607
+ }}
608
+ transition={{ duration: 0.3, ease: 'easeOut' }}
609
+ />
610
+ <motion.span
611
+ className="absolute block rounded-full bg-current"
612
+ style={{
613
+ width: '60%',
614
+ height: lineHeight[size],
615
+ color,
616
+ left: '27%',
617
+ top: '50%',
618
+ transformOrigin: 'left center'
619
+ }}
620
+ initial={{ rotate: 45, scaleX: 0 }}
621
+ animate={{
622
+ rotate: 45,
623
+ scaleX: opened ? 1 : 0,
624
+ y: '-50%'
625
+ }}
626
+ transition={{ duration: 0.3, ease: 'easeOut', delay: 0.1 }}
627
+ />
628
+ </div>
629
+ );
630
+ }
631
+
632
+ function Dots({ opened = false, size = 'md', color = 'currentColor', className }: IconProps) {
633
+ const dotSize = {
634
+ sm: '3px',
635
+ md: '4px',
636
+ lg: '5px',
637
+ xl: '6px'
638
+ };
639
+
640
+ return (
641
+ <div className={cn("relative flex items-center justify-center gap-1", sizeClasses[size], className)}>
642
+ <motion.span
643
+ className="block rounded-full bg-current"
644
+ style={{
645
+ width: dotSize[size],
646
+ height: dotSize[size],
647
+ color
648
+ }}
649
+ animate={{
650
+ scale: opened ? [1, 1.5, 1] : 1,
651
+ y: opened ? [0, -4, 0] : 0
652
+ }}
653
+ transition={{ duration: 0.5, ease: 'easeInOut' }}
654
+ />
655
+ <motion.span
656
+ className="block rounded-full bg-current"
657
+ style={{
658
+ width: dotSize[size],
659
+ height: dotSize[size],
660
+ color
661
+ }}
662
+ animate={{
663
+ scale: opened ? [1, 1.5, 1] : 1,
664
+ y: opened ? [0, -4, 0] : 0
665
+ }}
666
+ transition={{ duration: 0.5, ease: 'easeInOut', delay: 0.1 }}
667
+ />
668
+ <motion.span
669
+ className="block rounded-full bg-current"
670
+ style={{
671
+ width: dotSize[size],
672
+ height: dotSize[size],
673
+ color
674
+ }}
675
+ animate={{
676
+ scale: opened ? [1, 1.5, 1] : 1,
677
+ y: opened ? [0, -4, 0] : 0
678
+ }}
679
+ transition={{ duration: 0.5, ease: 'easeInOut', delay: 0.2 }}
680
+ />
681
+ </div>
682
+ );
683
+ }
684
+
685
+ function Play({ opened = false, size = 'md', color = 'currentColor', className }: IconProps) {
686
+ return (
687
+ <div className={cn("relative", sizeClasses[size], className)}>
688
+ <svg viewBox="0 0 24 24" className="w-full h-full" style={{ color }}>
689
+ <motion.path
690
+ d={opened ? "M6 4h4v16H6V4zm8 0h4v16h-4V4z" : "M8 5v14l11-7z"}
691
+ fill="currentColor"
692
+ animate={{ d: opened ? "M6 4h4v16H6V4zm8 0h4v16h-4V4z" : "M8 5v14l11-7z" }}
693
+ transition={{ duration: 0.3, ease: 'easeInOut' }}
694
+ />
695
+ </svg>
696
+ </div>
697
+ );
698
+ }
699
+
700
+ function Heart({ opened = false, size = 'md', color = 'currentColor', className }: IconProps) {
701
+ return (
702
+ <div className={cn("relative", sizeClasses[size], className)}>
703
+ <svg viewBox="0 0 24 24" className="w-full h-full" style={{ color }}>
704
+ <motion.path
705
+ d="M12 21.35l-1.45-1.32C5.4 15.36 2 12.28 2 8.5 2 5.42 4.42 3 7.5 3c1.74 0 3.41.81 4.5 2.09C13.09 3.81 14.76 3 16.5 3 19.58 3 22 5.42 22 8.5c0 3.78-3.4 6.86-8.55 11.54L12 21.35z"
706
+ fill={opened ? 'currentColor' : 'none'}
707
+ stroke="currentColor"
708
+ strokeWidth="2"
709
+ animate={{
710
+ scale: opened ? [1, 1.2, 1] : 1,
711
+ fill: opened ? 'currentColor' : 'none'
712
+ }}
713
+ transition={{ duration: 0.3, ease: 'easeInOut' }}
714
+ />
715
+ </svg>
716
+ </div>
717
+ );
718
+ }
719
+
720
+
721
+ export function MotionIconsDemo() {
722
+ const [states, setStates] = useState({
723
+ burger: false,
724
+ close: false,
725
+ plus: false,
726
+ chevron: false,
727
+ arrow: false,
728
+ check: false,
729
+ dots: false,
730
+ play: false,
731
+ heart: false
732
+ });
733
+
734
+ const toggleIcon = (icon) => {
735
+ setStates(prev => ({ ...prev, [icon]: !prev[icon] }));
736
+ };
737
+
738
+ const icons = [
739
+ { name: 'burger', label: 'Burger Menu' },
740
+ { name: 'close', label: 'Close (X)' },
741
+ { name: 'plus', label: 'Plus' },
742
+ { name: 'chevron', label: 'Chevron' },
743
+ { name: 'arrow', label: 'Arrow' },
744
+ { name: 'check', label: 'Check' },
745
+ { name: 'dots', label: 'Loading Dots' },
746
+ { name: 'play', label: 'Play/Pause' },
747
+ { name: 'heart', label: 'Heart' }
748
+ ];
749
+
750
+ return (
751
+ <div className="min-h-screen bg-gradient-to-br from-slate-50 to-slate-100 dark:from-slate-900 dark:to-slate-800 p-8">
752
+ <div className="max-w-6xl mx-auto space-y-8">
753
+ <div className="text-center space-y-2">
754
+ <h1 className="text-4xl font-bold text-slate-900 dark:text-white">
755
+ MotionIcons
756
+ </h1>
757
+ <p className="text-lg text-slate-600 dark:text-slate-400">
758
+ Animated icon components built with Motion/React
759
+ </p>
760
+ </div>
761
+
762
+ <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
763
+ {icons.map(({ name, label }) => (
764
+ <div
765
+ key={name}
766
+ className="bg-white dark:bg-slate-800 rounded-xl shadow-lg p-6 space-y-4 border border-slate-200 dark:border-slate-700"
767
+ >
768
+ <div className="flex items-center justify-between">
769
+ <h3 className="text-lg font-semibold text-slate-900 dark:text-white">
770
+ {label}
771
+ </h3>
772
+ <code className="text-xs bg-slate-100 dark:bg-slate-700 px-2 py-1 rounded text-slate-600 dark:text-slate-300">
773
+ {name}
774
+ </code>
775
+ </div>
776
+
777
+ <div className="flex items-center justify-center gap-8 py-8">
778
+ {['sm', 'md', 'lg', 'xl'].map(size => (
779
+ <div key={size} className="flex flex-col items-center gap-2">
780
+ <button
781
+ onClick={() => toggleIcon(name)}
782
+ className="p-4 rounded-lg bg-slate-100 dark:bg-slate-700 hover:bg-slate-200 dark:hover:bg-slate-600 transition-colors"
783
+ aria-label={`Toggle ${label}`}
784
+ >
785
+ <MotionIcons
786
+ icon={name}
787
+ opened={states[name]}
788
+ size={size}
789
+ color="currentColor"
790
+ className="text-slate-900 dark:text-white"
791
+ />
792
+ </button>
793
+ <span className="text-xs text-slate-500 dark:text-slate-400">
794
+ {size}
795
+ </span>
796
+ </div>
797
+ ))}
798
+ </div>
799
+
800
+ <div className="text-center">
801
+ <button
802
+ onClick={() => toggleIcon(name)}
803
+ className="text-sm text-blue-600 dark:text-blue-400 hover:underline"
804
+ >
805
+ Click icons to toggle
806
+ </button>
807
+ </div>
808
+ </div>
809
+ ))}
810
+ </div>
811
+
812
+ <div className="bg-white dark:bg-slate-800 rounded-xl shadow-lg p-6 border border-slate-200 dark:border-slate-700">
813
+ <h2 className="text-xl font-bold text-slate-900 dark:text-white mb-4">
814
+ Usage Example
815
+ </h2>
816
+ <pre className="bg-slate-100 dark:bg-slate-900 p-4 rounded-lg overflow-x-auto text-sm">
817
+ <code className="text-slate-900 dark:text-slate-100">{`import { MotionIcons } from './motion-icons';
818
+
819
+ // Use any icon with the icon prop
820
+ <MotionIcons
821
+ icon="burger"
822
+ opened={isOpen}
823
+ size="md"
824
+ color="currentColor"
825
+ />
826
+
827
+ // Or import specific icons
828
+ import { Burger, Close, Plus, Heart } from './motion-icons';
829
+
830
+ <Burger opened={isOpen} size="lg" />
831
+ <Close opened={isOpen} />
832
+ <Plus opened={isOpen} size="sm" />
833
+ <Heart opened={isLiked} color="red" />`}</code>
834
+ </pre>
835
+ </div>
836
+ </div>
837
+ </div>
838
+ );
839
+ }
840
+