@ranimontagna/agent-toolkit 0.1.5 → 0.1.6

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 (27) hide show
  1. package/README.md +42 -8
  2. package/package.json +1 -1
  3. package/skills/frontend/react/react-patterns/LICENSE +21 -0
  4. package/skills/frontend/react/react-patterns/NOTICE.md +11 -0
  5. package/skills/frontend/react/react-patterns/SKILL.md +341 -0
  6. package/skills/frontend/react/react-performance/LICENSE +21 -0
  7. package/skills/frontend/react/react-performance/NOTICE.md +11 -0
  8. package/skills/frontend/react/react-performance/SKILL.md +574 -0
  9. package/skills/frontend/react/react-testing/LICENSE +21 -0
  10. package/skills/frontend/react/react-testing/NOTICE.md +11 -0
  11. package/skills/frontend/react/react-testing/SKILL.md +423 -0
  12. package/skills/frontend/react-native/react-native-expert/LICENSE +21 -0
  13. package/skills/frontend/react-native/react-native-expert/NOTICE.md +11 -0
  14. package/skills/frontend/react-native/react-native-expert/SKILL.md +187 -0
  15. package/skills/frontend/react-native/react-native-expert/references/expo-router.md +187 -0
  16. package/skills/frontend/react-native/react-native-expert/references/list-optimization.md +204 -0
  17. package/skills/frontend/react-native/react-native-expert/references/platform-handling.md +188 -0
  18. package/skills/frontend/react-native/react-native-expert/references/project-structure.md +171 -0
  19. package/skills/frontend/react-native/react-native-expert/references/storage-hooks.md +173 -0
  20. package/skills/frontend/react-native/react-native-unistyles-v3/LICENSE +21 -0
  21. package/skills/frontend/react-native/react-native-unistyles-v3/NOTICE.md +11 -0
  22. package/skills/frontend/react-native/react-native-unistyles-v3/SKILL.md +159 -0
  23. package/skills/frontend/react-native/react-native-unistyles-v3/references/api-reference.md +495 -0
  24. package/skills/frontend/react-native/react-native-unistyles-v3/references/common-issues.md +389 -0
  25. package/skills/frontend/react-native/react-native-unistyles-v3/references/setup-guide.md +217 -0
  26. package/skills/frontend/react-native/react-native-unistyles-v3/references/styling-patterns.md +705 -0
  27. package/skills/frontend/react-native/react-native-unistyles-v3/references/third-party-integration.md +318 -0
@@ -0,0 +1,705 @@
1
+ # Styling Patterns
2
+
3
+ Comprehensive patterns and code examples for react-native-unistyles v3.
4
+
5
+ ## Basic Stylesheet
6
+
7
+ ### Static styles (no theme)
8
+
9
+ ```tsx
10
+ import { StyleSheet } from 'react-native-unistyles'
11
+
12
+ const styles = StyleSheet.create({
13
+ container: {
14
+ flex: 1,
15
+ padding: 16,
16
+ justifyContent: 'center',
17
+ },
18
+ title: {
19
+ fontSize: 24,
20
+ fontWeight: 'bold',
21
+ },
22
+ })
23
+ ```
24
+
25
+ ### Theme-aware styles (zero re-renders)
26
+
27
+ ```tsx
28
+ const styles = StyleSheet.create(theme => ({
29
+ container: {
30
+ flex: 1,
31
+ backgroundColor: theme.colors.background,
32
+ padding: theme.spacing.md,
33
+ },
34
+ title: {
35
+ color: theme.colors.text,
36
+ fontSize: theme.fontSize.lg,
37
+ },
38
+ }))
39
+ ```
40
+
41
+ ### Theme + runtime styles (zero re-renders)
42
+
43
+ ```tsx
44
+ const styles = StyleSheet.create((theme, rt) => ({
45
+ container: {
46
+ flex: 1,
47
+ backgroundColor: theme.colors.background,
48
+ paddingTop: rt.insets.top,
49
+ paddingBottom: rt.insets.bottom,
50
+ },
51
+ hero: {
52
+ width: rt.screen.width,
53
+ height: rt.screen.height * 0.4,
54
+ },
55
+ }))
56
+ ```
57
+
58
+ ---
59
+
60
+ ## Dynamic Functions
61
+
62
+ Pass arguments to styles at the call site. Arguments must be serializable.
63
+
64
+ ```tsx
65
+ const styles = StyleSheet.create(theme => ({
66
+ // Single argument
67
+ avatar: (size: number) => ({
68
+ width: size,
69
+ height: size,
70
+ borderRadius: size / 2,
71
+ }),
72
+
73
+ // Multiple arguments
74
+ badge: (color: string, isActive: boolean) => ({
75
+ backgroundColor: isActive ? color : theme.colors.disabled,
76
+ opacity: isActive ? 1 : 0.5,
77
+ }),
78
+
79
+ // Conditional with theme
80
+ card: (elevation: number) => ({
81
+ backgroundColor: theme.colors.surface,
82
+ borderRadius: theme.radius.md,
83
+ shadowOpacity: elevation * 0.1,
84
+ shadowRadius: elevation * 2,
85
+ }),
86
+ }))
87
+
88
+ // Usage in JSX:
89
+ <Image style={styles.avatar(48)} />
90
+ <View style={styles.badge('#ff0000', true)} />
91
+ <View style={styles.card(3)} />
92
+ ```
93
+
94
+ ---
95
+
96
+ ## Breakpoint-Based Responsive Styles
97
+
98
+ Register breakpoints in `StyleSheet.configure`, then use breakpoint names as keys in style values:
99
+
100
+ ```tsx
101
+ StyleSheet.configure({
102
+ breakpoints: { xs: 0, sm: 576, md: 768, lg: 992, xl: 1200 }
103
+ })
104
+
105
+ const styles = StyleSheet.create(theme => ({
106
+ container: {
107
+ padding: {
108
+ xs: 8,
109
+ sm: 16,
110
+ md: 24,
111
+ lg: 32,
112
+ },
113
+ flexDirection: {
114
+ xs: 'column',
115
+ md: 'row',
116
+ },
117
+ },
118
+ sidebar: {
119
+ display: {
120
+ xs: 'none',
121
+ md: 'flex',
122
+ },
123
+ width: {
124
+ md: 250,
125
+ lg: 300,
126
+ },
127
+ },
128
+ }))
129
+ ```
130
+
131
+ ### Nested breakpoints (transform, shadowOffset)
132
+
133
+ For properties expecting objects (like `transform` or `shadowOffset`), use breakpoints at the nested level:
134
+
135
+ ```tsx
136
+ const styles = StyleSheet.create({
137
+ box: {
138
+ transform: [
139
+ { translateX: { xs: 0, md: 50 } },
140
+ { scale: { xs: 0.8, lg: 1 } },
141
+ ],
142
+ shadowOffset: {
143
+ width: { xs: 1, md: 2 },
144
+ height: { xs: 1, md: 4 },
145
+ },
146
+ },
147
+ })
148
+ ```
149
+
150
+ ### Built-in breakpoints: landscape / portrait
151
+
152
+ Unistyles has built-in `landscape` and `portrait` breakpoints:
153
+
154
+ ```tsx
155
+ const styles = StyleSheet.create({
156
+ grid: {
157
+ flexDirection: {
158
+ portrait: 'column',
159
+ landscape: 'row',
160
+ },
161
+ gap: {
162
+ portrait: 8,
163
+ landscape: 16,
164
+ },
165
+ },
166
+ })
167
+ ```
168
+
169
+ ---
170
+
171
+ ## Variants
172
+
173
+ Variants allow conditional style groups selected at the component level.
174
+
175
+ ### Basic variants
176
+
177
+ ```tsx
178
+ const styles = StyleSheet.create(theme => ({
179
+ button: {
180
+ borderRadius: theme.radius.md,
181
+ variants: {
182
+ size: {
183
+ small: { paddingVertical: 4, paddingHorizontal: 8 },
184
+ medium: { paddingVertical: 8, paddingHorizontal: 16 },
185
+ large: { paddingVertical: 12, paddingHorizontal: 24 },
186
+ },
187
+ variant: {
188
+ filled: { backgroundColor: theme.colors.primary },
189
+ outlined: { borderWidth: 1, borderColor: theme.colors.primary },
190
+ ghost: { backgroundColor: 'transparent' },
191
+ },
192
+ },
193
+ },
194
+ }))
195
+
196
+ const Button = ({ size = 'medium', variant = 'filled', children }) => {
197
+ styles.useVariants({ size, variant })
198
+ return <TouchableOpacity style={styles.button}><Text>{children}</Text></TouchableOpacity>
199
+ }
200
+ ```
201
+
202
+ ### Boolean variants
203
+
204
+ ```tsx
205
+ const styles = StyleSheet.create(theme => ({
206
+ card: {
207
+ padding: theme.spacing.md,
208
+ variants: {
209
+ elevated: {
210
+ true: { shadowOpacity: 0.2, shadowRadius: 4, elevation: 3 },
211
+ false: { shadowOpacity: 0 },
212
+ },
213
+ disabled: {
214
+ true: { opacity: 0.5 },
215
+ },
216
+ },
217
+ },
218
+ }))
219
+
220
+ styles.useVariants({ elevated: true, disabled: false })
221
+ ```
222
+
223
+ ### Default variant values
224
+
225
+ Use the `default` key for a fallback when no variant is selected:
226
+
227
+ ```tsx
228
+ const styles = StyleSheet.create(theme => ({
229
+ text: {
230
+ variants: {
231
+ weight: {
232
+ default: { fontWeight: 'normal' },
233
+ bold: { fontWeight: 'bold' },
234
+ light: { fontWeight: '300' },
235
+ },
236
+ },
237
+ },
238
+ }))
239
+
240
+ // No variant selected → uses 'default'
241
+ styles.useVariants({})
242
+ ```
243
+
244
+ ### Compound variants
245
+
246
+ Apply styles only when multiple variant values match simultaneously:
247
+
248
+ ```tsx
249
+ const styles = StyleSheet.create(theme => ({
250
+ button: {
251
+ variants: {
252
+ size: {
253
+ small: { padding: 4 },
254
+ large: { padding: 16 },
255
+ },
256
+ color: {
257
+ primary: { backgroundColor: theme.colors.primary },
258
+ danger: { backgroundColor: theme.colors.danger },
259
+ },
260
+ },
261
+ compoundVariants: [
262
+ {
263
+ size: 'large',
264
+ color: 'danger',
265
+ styles: { borderWidth: 3, borderColor: 'red' },
266
+ },
267
+ ],
268
+ },
269
+ }))
270
+ ```
271
+
272
+ ### TypeScript inference with UnistylesVariants
273
+
274
+ ```tsx
275
+ import type { UnistylesVariants } from 'react-native-unistyles'
276
+
277
+ const styles = StyleSheet.create(theme => ({
278
+ chip: {
279
+ variants: {
280
+ size: { sm: { height: 24 }, md: { height: 32 }, lg: { height: 40 } },
281
+ color: { primary: { backgroundColor: 'blue' }, secondary: { backgroundColor: 'gray' } },
282
+ },
283
+ },
284
+ }))
285
+
286
+ type ChipVariants = UnistylesVariants<typeof styles>
287
+ // { size?: 'sm' | 'md' | 'lg'; color?: 'primary' | 'secondary' }
288
+
289
+ type ChipProps = { label: string } & ChipVariants
290
+
291
+ const Chip = ({ label, ...variants }: ChipProps) => {
292
+ styles.useVariants(variants)
293
+ return <View style={styles.chip}><Text>{label}</Text></View>
294
+ }
295
+ ```
296
+
297
+ ---
298
+
299
+ ## Media Queries
300
+
301
+ Use `mq` for fine-grained width/height-based responsive values:
302
+
303
+ ```tsx
304
+ import { mq, StyleSheet } from 'react-native-unistyles'
305
+
306
+ const styles = StyleSheet.create({
307
+ container: {
308
+ padding: {
309
+ [mq.only.width(null, 576)]: 8, // width <= 576
310
+ [mq.only.width(576, 768)]: 16, // 576 < width <= 768
311
+ [mq.only.width(768)]: 24, // width > 768
312
+ },
313
+ },
314
+ sidebar: {
315
+ display: {
316
+ [mq.only.width(null, 768)]: 'none',
317
+ [mq.only.width(768)]: 'flex',
318
+ },
319
+ },
320
+ })
321
+ ```
322
+
323
+ ### Mixing breakpoint names and pixel values
324
+
325
+ ```tsx
326
+ mq.only.width('sm', 'lg') // between sm and lg breakpoints
327
+ mq.only.width(320, 768) // between 320px and 768px
328
+ mq.only.height(400) // height > 400px
329
+ ```
330
+
331
+ ### Combined width + height
332
+
333
+ ```tsx
334
+ const styles = StyleSheet.create({
335
+ panel: {
336
+ flexDirection: {
337
+ [mq.width(null, 768).and.height(null, 500)]: 'column', // small screen
338
+ [mq.width(768).and.height(500)]: 'row', // large screen
339
+ },
340
+ },
341
+ })
342
+ ```
343
+
344
+ ---
345
+
346
+ ## Style Merging
347
+
348
+ **NEVER spread styles.** Always use array syntax.
349
+
350
+ ```tsx
351
+ // Combine multiple styles
352
+ <View style={[styles.container, styles.centered]} />
353
+
354
+ // Conditional styles
355
+ <View style={[styles.button, isActive && styles.active]} />
356
+
357
+ // Inline overrides
358
+ <View style={[styles.card, { marginTop: 20 }]} />
359
+
360
+ // Dynamic function + static
361
+ <View style={[styles.box(100), styles.shadow]} />
362
+ ```
363
+
364
+ ---
365
+
366
+ ## Theme Management
367
+
368
+ ### Setting up themes
369
+
370
+ ```tsx
371
+ const lightTheme = {
372
+ colors: {
373
+ background: '#ffffff',
374
+ text: '#000000',
375
+ primary: '#007bff',
376
+ },
377
+ spacing: { xs: 4, sm: 8, md: 16, lg: 24, xl: 32 },
378
+ }
379
+
380
+ const darkTheme = {
381
+ colors: {
382
+ background: '#1a1a1a',
383
+ text: '#ffffff',
384
+ primary: '#4dabf7',
385
+ },
386
+ spacing: { xs: 4, sm: 8, md: 16, lg: 24, xl: 32 },
387
+ }
388
+
389
+ StyleSheet.configure({
390
+ themes: { light: lightTheme, dark: darkTheme },
391
+ settings: { initialTheme: 'light' },
392
+ })
393
+ ```
394
+
395
+ ### Adaptive themes (auto light/dark)
396
+
397
+ ```tsx
398
+ StyleSheet.configure({
399
+ themes: { light: lightTheme, dark: darkTheme },
400
+ settings: { adaptiveThemes: true }, // auto-switches based on OS setting
401
+ })
402
+ ```
403
+
404
+ Requires themes named exactly `light` and `dark`.
405
+
406
+ ### Switching themes programmatically
407
+
408
+ ```tsx
409
+ import { UnistylesRuntime } from 'react-native-unistyles'
410
+
411
+ // Switch to specific theme
412
+ UnistylesRuntime.setTheme('dark')
413
+
414
+ // Toggle
415
+ const toggle = () => {
416
+ UnistylesRuntime.setTheme(
417
+ UnistylesRuntime.themeName === 'light' ? 'dark' : 'light'
418
+ )
419
+ }
420
+ ```
421
+
422
+ ### Updating theme values at runtime
423
+
424
+ ```tsx
425
+ UnistylesRuntime.updateTheme('light', current => ({
426
+ ...current,
427
+ colors: { ...current.colors, primary: '#ff6600' }
428
+ }))
429
+ ```
430
+
431
+ ### ScopedTheme for subtree overrides
432
+
433
+ ```tsx
434
+ import { ScopedTheme } from 'react-native-unistyles'
435
+
436
+ // Force dark theme for a section
437
+ <ScopedTheme name="dark">
438
+ <DarkCard />
439
+ <DarkFooter />
440
+ </ScopedTheme>
441
+
442
+ // Invert: light→dark, dark→light
443
+ <ScopedTheme invertedAdaptive>
444
+ <InvertedSection />
445
+ </ScopedTheme>
446
+ ```
447
+
448
+ ---
449
+
450
+ ## Responsive Components (Display / Hide)
451
+
452
+ ```tsx
453
+ import { Display, Hide, mq } from 'react-native-unistyles'
454
+
455
+ const Layout = () => (
456
+ <View style={styles.row}>
457
+ {/* Only show on tablet+ */}
458
+ <Display mq={mq.only.width(768)}>
459
+ <Sidebar />
460
+ </Display>
461
+
462
+ <MainContent />
463
+
464
+ {/* Hide mobile nav on tablet+ */}
465
+ <Hide mq={mq.only.width(768)}>
466
+ <BottomNav />
467
+ </Hide>
468
+ </View>
469
+ )
470
+ ```
471
+
472
+ ---
473
+
474
+ ## Web-Specific Features
475
+
476
+ ### _web property
477
+
478
+ Add web-only styles using the `_web` key:
479
+
480
+ ```tsx
481
+ const styles = StyleSheet.create(theme => ({
482
+ button: {
483
+ padding: 16,
484
+ _web: {
485
+ cursor: 'pointer',
486
+ transition: 'background-color 0.2s ease',
487
+ outline: 'none',
488
+ },
489
+ },
490
+ }))
491
+ ```
492
+
493
+ ### Pseudo-classes
494
+
495
+ ```tsx
496
+ const styles = StyleSheet.create(theme => ({
497
+ button: {
498
+ backgroundColor: theme.colors.primary,
499
+ _web: {
500
+ _hover: {
501
+ backgroundColor: theme.colors.primaryHover,
502
+ },
503
+ _active: {
504
+ backgroundColor: theme.colors.primaryActive,
505
+ transform: [{ scale: 0.98 }],
506
+ },
507
+ _focus: {
508
+ outlineWidth: 2,
509
+ outlineColor: theme.colors.focus,
510
+ },
511
+ _disabled: {
512
+ opacity: 0.5,
513
+ cursor: 'not-allowed',
514
+ },
515
+ _focusVisible: {
516
+ outlineStyle: 'dashed',
517
+ },
518
+ _focusWithin: {
519
+ borderColor: theme.colors.focus,
520
+ },
521
+ },
522
+ },
523
+ }))
524
+ ```
525
+
526
+ Supported pseudo-classes: `_hover`, `_active`, `_focus`, `_disabled`, `_focusVisible`, `_focusWithin`.
527
+
528
+ ### Custom CSS class names
529
+
530
+ ```tsx
531
+ const styles = StyleSheet.create({
532
+ container: {
533
+ _web: {
534
+ _classNames: ['my-custom-class', 'another-class'],
535
+ },
536
+ },
537
+ })
538
+ ```
539
+
540
+ ### getWebProps for custom web components
541
+
542
+ ```tsx
543
+ import { getWebProps } from 'react-native-unistyles/web-only'
544
+
545
+ const CustomWebComponent = () => {
546
+ const { className, style } = getWebProps(styles.container)
547
+ return <div className={className} style={style}>Content</div>
548
+ }
549
+ ```
550
+
551
+ ---
552
+
553
+ ## Reanimated Integration
554
+
555
+ ### useAnimatedTheme — access theme in worklets
556
+
557
+ ```tsx
558
+ import { useAnimatedTheme } from 'react-native-unistyles/reanimated'
559
+ import Animated, { useAnimatedStyle } from 'react-native-reanimated'
560
+
561
+ const MyComponent = () => {
562
+ const animatedTheme = useAnimatedTheme()
563
+
564
+ const animatedStyle = useAnimatedStyle(() => ({
565
+ backgroundColor: animatedTheme.value.colors.background,
566
+ }))
567
+
568
+ // IMPORTANT: use array syntax to combine Unistyles + Reanimated styles
569
+ return <Animated.View style={[styles.container, animatedStyle]} />
570
+ }
571
+ ```
572
+
573
+ ### useAnimatedVariantColor — animate color transitions
574
+
575
+ ```tsx
576
+ import { useAnimatedVariantColor } from 'react-native-unistyles/reanimated'
577
+
578
+ const styles = StyleSheet.create(theme => ({
579
+ button: {
580
+ variants: {
581
+ state: {
582
+ active: { backgroundColor: theme.colors.primary },
583
+ inactive: { backgroundColor: theme.colors.disabled },
584
+ },
585
+ },
586
+ },
587
+ }))
588
+
589
+ const AnimatedButton = ({ isActive }) => {
590
+ styles.useVariants({ state: isActive ? 'active' : 'inactive' })
591
+ const animatedColor = useAnimatedVariantColor(styles.button, 'backgroundColor')
592
+
593
+ return <Animated.View style={[styles.button, animatedColor]} />
594
+ }
595
+ ```
596
+
597
+ ### Combining Reanimated + Unistyles styles
598
+
599
+ Always use **array syntax**:
600
+
601
+ ```tsx
602
+ <Animated.View style={[styles.container, animatedStyle]} />
603
+ ```
604
+
605
+ Never spread:
606
+ ```tsx
607
+ // WRONG: <Animated.View style={{ ...styles.container, ...animatedStyle }} />
608
+ ```
609
+
610
+ ---
611
+
612
+ ## SSR with Next.js
613
+
614
+ ### App Router
615
+
616
+ ```tsx
617
+ // app/layout.tsx
618
+ import { useServerUnistyles } from 'react-native-unistyles'
619
+
620
+ export default function RootLayout({ children }) {
621
+ const styles = useServerUnistyles()
622
+
623
+ return (
624
+ <html>
625
+ <head>{styles}</head>
626
+ <body>{children}</body>
627
+ </html>
628
+ )
629
+ }
630
+
631
+ // app/page.tsx (client component)
632
+ 'use client'
633
+ import { hydrateServerUnistyles } from 'react-native-unistyles'
634
+
635
+ hydrateServerUnistyles()
636
+ ```
637
+
638
+ ### Pages Router
639
+
640
+ ```tsx
641
+ // pages/_document.tsx
642
+ import { getServerUnistyles, resetServerUnistyles } from 'react-native-unistyles'
643
+
644
+ export default function Document() {
645
+ const styles = getServerUnistyles()
646
+
647
+ return (
648
+ <Html>
649
+ <Head>{styles}</Head>
650
+ <body><Main /><NextScript /></body>
651
+ </Html>
652
+ )
653
+ }
654
+
655
+ // pages/_app.tsx
656
+ import { hydrateServerUnistyles } from 'react-native-unistyles'
657
+
658
+ hydrateServerUnistyles()
659
+ ```
660
+
661
+ ---
662
+
663
+ ## Runtime Values in Styles
664
+
665
+ The mini runtime (`rt`) provides these values for use in `StyleSheet.create((theme, rt) => ...)`:
666
+
667
+ ```tsx
668
+ const styles = StyleSheet.create((theme, rt) => ({
669
+ container: {
670
+ paddingTop: rt.insets.top,
671
+ paddingBottom: rt.insets.bottom,
672
+ paddingLeft: rt.insets.left,
673
+ paddingRight: rt.insets.right,
674
+ },
675
+ content: {
676
+ width: rt.screen.width - 32,
677
+ maxHeight: rt.screen.height * 0.8,
678
+ },
679
+ statusBarSpacer: {
680
+ height: rt.statusBar.height,
681
+ },
682
+ navBarSpacer: {
683
+ height: rt.navigationBar.height,
684
+ },
685
+ responsive: {
686
+ fontSize: rt.fontScale * 16,
687
+ padding: rt.pixelRatio > 2 ? 16 : 12,
688
+ },
689
+ rtlAware: {
690
+ textAlign: rt.rtl ? 'right' : 'left',
691
+ },
692
+ }))
693
+ ```
694
+
695
+ ### IME / Keyboard inset
696
+
697
+ `rt.insets.ime` provides the keyboard height, replacing `react-native-reanimated`'s `useAnimatedKeyboard`:
698
+
699
+ ```tsx
700
+ const styles = StyleSheet.create((theme, rt) => ({
701
+ input: {
702
+ marginBottom: rt.insets.ime, // automatically adjusts when keyboard opens/closes
703
+ },
704
+ }))
705
+ ```