@cdx-ui/components 0.0.1-beta.79 → 0.0.1-beta.80

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 (214) hide show
  1. package/lib/commonjs/animation/hooks/index.js +17 -0
  2. package/lib/commonjs/animation/hooks/index.js.map +1 -0
  3. package/lib/commonjs/animation/hooks/useCombinedAnimationDisabledState.js +50 -0
  4. package/lib/commonjs/animation/hooks/useCombinedAnimationDisabledState.js.map +1 -0
  5. package/lib/commonjs/animation/index.js +39 -0
  6. package/lib/commonjs/animation/index.js.map +1 -0
  7. package/lib/commonjs/animation/types.js +6 -0
  8. package/lib/commonjs/animation/types.js.map +1 -0
  9. package/lib/commonjs/animation/utils.js +223 -0
  10. package/lib/commonjs/animation/utils.js.map +1 -0
  11. package/lib/commonjs/components/CLAUDE.md +1 -1
  12. package/lib/commonjs/components/Card/index.js +45 -17
  13. package/lib/commonjs/components/Card/index.js.map +1 -1
  14. package/lib/commonjs/components/Toast/animation.js +329 -0
  15. package/lib/commonjs/components/Toast/animation.js.map +1 -0
  16. package/lib/commonjs/components/Toast/hooks.js +66 -0
  17. package/lib/commonjs/components/Toast/hooks.js.map +1 -0
  18. package/lib/commonjs/components/Toast/index.js +493 -0
  19. package/lib/commonjs/components/Toast/index.js.map +1 -0
  20. package/lib/commonjs/components/Toast/styles.js +141 -0
  21. package/lib/commonjs/components/Toast/styles.js.map +1 -0
  22. package/lib/commonjs/components/Toast/types.js +6 -0
  23. package/lib/commonjs/components/Toast/types.js.map +1 -0
  24. package/lib/commonjs/components/index.js +12 -0
  25. package/lib/commonjs/components/index.js.map +1 -1
  26. package/lib/commonjs/index.js +15 -0
  27. package/lib/commonjs/index.js.map +1 -1
  28. package/lib/commonjs/providers/animation-settings/index.js +31 -0
  29. package/lib/commonjs/providers/animation-settings/index.js.map +1 -0
  30. package/lib/commonjs/providers/animation-settings/provider.js +59 -0
  31. package/lib/commonjs/providers/animation-settings/provider.js.map +1 -0
  32. package/lib/commonjs/providers/animation-settings/types.js +6 -0
  33. package/lib/commonjs/providers/animation-settings/types.js.map +1 -0
  34. package/lib/commonjs/providers/forge-design/index.js +29 -0
  35. package/lib/commonjs/providers/forge-design/index.js.map +1 -0
  36. package/lib/commonjs/providers/forge-design/provider.js +71 -0
  37. package/lib/commonjs/providers/forge-design/provider.js.map +1 -0
  38. package/lib/commonjs/providers/forge-design/types.js +6 -0
  39. package/lib/commonjs/providers/forge-design/types.js.map +1 -0
  40. package/lib/commonjs/providers/text-component/index.js +28 -0
  41. package/lib/commonjs/providers/text-component/index.js.map +1 -0
  42. package/lib/commonjs/providers/text-component/provider.js +11 -0
  43. package/lib/commonjs/providers/text-component/provider.js.map +1 -0
  44. package/lib/commonjs/providers/text-component/types.js +6 -0
  45. package/lib/commonjs/providers/text-component/types.js.map +1 -0
  46. package/lib/commonjs/providers/toast/index.js +33 -0
  47. package/lib/commonjs/providers/toast/index.js.map +1 -0
  48. package/lib/commonjs/providers/toast/insets-container.js +160 -0
  49. package/lib/commonjs/providers/toast/insets-container.js.map +1 -0
  50. package/lib/commonjs/providers/toast/lifecycle.context.js +36 -0
  51. package/lib/commonjs/providers/toast/lifecycle.context.js.map +1 -0
  52. package/lib/commonjs/providers/toast/provider.js +508 -0
  53. package/lib/commonjs/providers/toast/provider.js.map +1 -0
  54. package/lib/commonjs/providers/toast/reducer.js +46 -0
  55. package/lib/commonjs/providers/toast/reducer.js.map +1 -0
  56. package/lib/commonjs/providers/toast/toast-config.context.js +29 -0
  57. package/lib/commonjs/providers/toast/toast-config.context.js.map +1 -0
  58. package/lib/commonjs/providers/toast/toast-item-renderer.js +43 -0
  59. package/lib/commonjs/providers/toast/toast-item-renderer.js.map +1 -0
  60. package/lib/commonjs/providers/toast/types.js +6 -0
  61. package/lib/commonjs/providers/toast/types.js.map +1 -0
  62. package/lib/module/animation/hooks/index.js +4 -0
  63. package/lib/module/animation/hooks/index.js.map +1 -0
  64. package/lib/module/animation/hooks/useCombinedAnimationDisabledState.js +47 -0
  65. package/lib/module/animation/hooks/useCombinedAnimationDisabledState.js.map +1 -0
  66. package/lib/module/animation/index.js +6 -0
  67. package/lib/module/animation/index.js.map +1 -0
  68. package/lib/module/animation/types.js +4 -0
  69. package/lib/module/animation/types.js.map +1 -0
  70. package/lib/module/animation/utils.js +212 -0
  71. package/lib/module/animation/utils.js.map +1 -0
  72. package/lib/module/components/CLAUDE.md +1 -1
  73. package/lib/module/components/Card/index.js +47 -19
  74. package/lib/module/components/Card/index.js.map +1 -1
  75. package/lib/module/components/Toast/animation.js +324 -0
  76. package/lib/module/components/Toast/animation.js.map +1 -0
  77. package/lib/module/components/Toast/hooks.js +61 -0
  78. package/lib/module/components/Toast/hooks.js.map +1 -0
  79. package/lib/module/components/Toast/index.js +487 -0
  80. package/lib/module/components/Toast/index.js.map +1 -0
  81. package/lib/module/components/Toast/styles.js +138 -0
  82. package/lib/module/components/Toast/styles.js.map +1 -0
  83. package/lib/module/components/Toast/types.js +4 -0
  84. package/lib/module/components/Toast/types.js.map +1 -0
  85. package/lib/module/components/index.js +1 -0
  86. package/lib/module/components/index.js.map +1 -1
  87. package/lib/module/index.js +1 -0
  88. package/lib/module/index.js.map +1 -1
  89. package/lib/module/providers/animation-settings/index.js +4 -0
  90. package/lib/module/providers/animation-settings/index.js.map +1 -0
  91. package/lib/module/providers/animation-settings/provider.js +52 -0
  92. package/lib/module/providers/animation-settings/provider.js.map +1 -0
  93. package/lib/module/providers/animation-settings/types.js +4 -0
  94. package/lib/module/providers/animation-settings/types.js.map +1 -0
  95. package/lib/module/providers/forge-design/index.js +5 -0
  96. package/lib/module/providers/forge-design/index.js.map +1 -0
  97. package/lib/module/providers/forge-design/provider.js +66 -0
  98. package/lib/module/providers/forge-design/provider.js.map +1 -0
  99. package/lib/module/providers/forge-design/types.js +4 -0
  100. package/lib/module/providers/forge-design/types.js.map +1 -0
  101. package/lib/module/providers/text-component/index.js +5 -0
  102. package/lib/module/providers/text-component/index.js.map +1 -0
  103. package/lib/module/providers/text-component/provider.js +6 -0
  104. package/lib/module/providers/text-component/provider.js.map +1 -0
  105. package/lib/module/providers/text-component/types.js +4 -0
  106. package/lib/module/providers/text-component/types.js.map +1 -0
  107. package/lib/module/providers/toast/index.js +6 -0
  108. package/lib/module/providers/toast/index.js.map +1 -0
  109. package/lib/module/providers/toast/insets-container.js +156 -0
  110. package/lib/module/providers/toast/insets-container.js.map +1 -0
  111. package/lib/module/providers/toast/lifecycle.context.js +32 -0
  112. package/lib/module/providers/toast/lifecycle.context.js.map +1 -0
  113. package/lib/module/providers/toast/provider.js +503 -0
  114. package/lib/module/providers/toast/provider.js.map +1 -0
  115. package/lib/module/providers/toast/reducer.js +42 -0
  116. package/lib/module/providers/toast/reducer.js.map +1 -0
  117. package/lib/module/providers/toast/toast-config.context.js +25 -0
  118. package/lib/module/providers/toast/toast-config.context.js.map +1 -0
  119. package/lib/module/providers/toast/toast-item-renderer.js +39 -0
  120. package/lib/module/providers/toast/toast-item-renderer.js.map +1 -0
  121. package/lib/module/providers/toast/types.js +4 -0
  122. package/lib/module/providers/toast/types.js.map +1 -0
  123. package/lib/typescript/animation/hooks/index.d.ts +2 -0
  124. package/lib/typescript/animation/hooks/index.d.ts.map +1 -0
  125. package/lib/typescript/animation/hooks/useCombinedAnimationDisabledState.d.ts +22 -0
  126. package/lib/typescript/animation/hooks/useCombinedAnimationDisabledState.d.ts.map +1 -0
  127. package/lib/typescript/animation/index.d.ts +4 -0
  128. package/lib/typescript/animation/index.d.ts.map +1 -0
  129. package/lib/typescript/animation/types.d.ts +105 -0
  130. package/lib/typescript/animation/types.d.ts.map +1 -0
  131. package/lib/typescript/animation/utils.d.ts +120 -0
  132. package/lib/typescript/animation/utils.d.ts.map +1 -0
  133. package/lib/typescript/components/Card/index.d.ts +4 -0
  134. package/lib/typescript/components/Card/index.d.ts.map +1 -1
  135. package/lib/typescript/components/Toast/animation.d.ts +21 -0
  136. package/lib/typescript/components/Toast/animation.d.ts.map +1 -0
  137. package/lib/typescript/components/Toast/hooks.d.ts +17 -0
  138. package/lib/typescript/components/Toast/hooks.d.ts.map +1 -0
  139. package/lib/typescript/components/Toast/index.d.ts +28 -0
  140. package/lib/typescript/components/Toast/index.d.ts.map +1 -0
  141. package/lib/typescript/components/Toast/styles.d.ts +73 -0
  142. package/lib/typescript/components/Toast/styles.d.ts.map +1 -0
  143. package/lib/typescript/components/Toast/types.d.ts +303 -0
  144. package/lib/typescript/components/Toast/types.d.ts.map +1 -0
  145. package/lib/typescript/components/index.d.ts +1 -0
  146. package/lib/typescript/components/index.d.ts.map +1 -1
  147. package/lib/typescript/index.d.ts +2 -0
  148. package/lib/typescript/index.d.ts.map +1 -1
  149. package/lib/typescript/providers/animation-settings/index.d.ts +3 -0
  150. package/lib/typescript/providers/animation-settings/index.d.ts.map +1 -0
  151. package/lib/typescript/providers/animation-settings/provider.d.ts +28 -0
  152. package/lib/typescript/providers/animation-settings/provider.d.ts.map +1 -0
  153. package/lib/typescript/providers/animation-settings/types.d.ts +35 -0
  154. package/lib/typescript/providers/animation-settings/types.d.ts.map +1 -0
  155. package/lib/typescript/providers/forge-design/index.d.ts +3 -0
  156. package/lib/typescript/providers/forge-design/index.d.ts.map +1 -0
  157. package/lib/typescript/providers/forge-design/provider.d.ts +24 -0
  158. package/lib/typescript/providers/forge-design/provider.d.ts.map +1 -0
  159. package/lib/typescript/providers/forge-design/types.d.ts +82 -0
  160. package/lib/typescript/providers/forge-design/types.d.ts.map +1 -0
  161. package/lib/typescript/providers/text-component/index.d.ts +3 -0
  162. package/lib/typescript/providers/text-component/index.d.ts.map +1 -0
  163. package/lib/typescript/providers/text-component/provider.d.ts +7 -0
  164. package/lib/typescript/providers/text-component/provider.d.ts.map +1 -0
  165. package/lib/typescript/providers/text-component/types.d.ts +51 -0
  166. package/lib/typescript/providers/text-component/types.d.ts.map +1 -0
  167. package/lib/typescript/providers/toast/index.d.ts +5 -0
  168. package/lib/typescript/providers/toast/index.d.ts.map +1 -0
  169. package/lib/typescript/providers/toast/insets-container.d.ts +72 -0
  170. package/lib/typescript/providers/toast/insets-container.d.ts.map +1 -0
  171. package/lib/typescript/providers/toast/lifecycle.context.d.ts +32 -0
  172. package/lib/typescript/providers/toast/lifecycle.context.d.ts.map +1 -0
  173. package/lib/typescript/providers/toast/provider.d.ts +32 -0
  174. package/lib/typescript/providers/toast/provider.d.ts.map +1 -0
  175. package/lib/typescript/providers/toast/reducer.d.ts +14 -0
  176. package/lib/typescript/providers/toast/reducer.d.ts.map +1 -0
  177. package/lib/typescript/providers/toast/toast-config.context.d.ts +20 -0
  178. package/lib/typescript/providers/toast/toast-config.context.d.ts.map +1 -0
  179. package/lib/typescript/providers/toast/toast-item-renderer.d.ts +7 -0
  180. package/lib/typescript/providers/toast/toast-item-renderer.d.ts.map +1 -0
  181. package/lib/typescript/providers/toast/types.d.ts +422 -0
  182. package/lib/typescript/providers/toast/types.d.ts.map +1 -0
  183. package/package.json +4 -4
  184. package/src/animation/hooks/index.ts +1 -0
  185. package/src/animation/hooks/useCombinedAnimationDisabledState.ts +46 -0
  186. package/src/animation/index.ts +3 -0
  187. package/src/animation/types.ts +128 -0
  188. package/src/animation/utils.ts +249 -0
  189. package/src/components/CLAUDE.md +1 -1
  190. package/src/components/Card/index.tsx +58 -28
  191. package/src/components/Toast/animation.ts +387 -0
  192. package/src/components/Toast/hooks.ts +92 -0
  193. package/src/components/Toast/index.tsx +520 -0
  194. package/src/components/Toast/styles.ts +186 -0
  195. package/src/components/Toast/types.ts +332 -0
  196. package/src/components/index.ts +1 -0
  197. package/src/index.ts +2 -0
  198. package/src/providers/animation-settings/index.ts +11 -0
  199. package/src/providers/animation-settings/provider.tsx +54 -0
  200. package/src/providers/animation-settings/types.ts +37 -0
  201. package/src/providers/forge-design/index.ts +2 -0
  202. package/src/providers/forge-design/provider.tsx +61 -0
  203. package/src/providers/forge-design/types.ts +84 -0
  204. package/src/providers/text-component/index.ts +2 -0
  205. package/src/providers/text-component/provider.tsx +7 -0
  206. package/src/providers/text-component/types.ts +52 -0
  207. package/src/providers/toast/index.ts +4 -0
  208. package/src/providers/toast/insets-container.tsx +230 -0
  209. package/src/providers/toast/lifecycle.context.tsx +37 -0
  210. package/src/providers/toast/provider.tsx +567 -0
  211. package/src/providers/toast/reducer.ts +40 -0
  212. package/src/providers/toast/toast-config.context.ts +25 -0
  213. package/src/providers/toast/toast-item-renderer.tsx +40 -0
  214. package/src/providers/toast/types.ts +431 -0
@@ -0,0 +1,46 @@
1
+ import {
2
+ useGlobalAnimationSettings,
3
+ useAnimationSettings,
4
+ } from '../../providers/animation-settings';
5
+ import type { AnimationRoot } from '../types';
6
+ import { getCombinedAnimationDisabledState, getRootAnimationState } from '../utils';
7
+
8
+ /**
9
+ * Hook to combine global, parent, and own animation disabled states
10
+ *
11
+ * @description
12
+ * This hook combines three sources of animation disabled state:
13
+ * 1. Global state from GlobalAnimationSettingsProvider
14
+ * 2. Parent state from AnimationSettingsContext (component tree cascading)
15
+ * 3. Own state from the component's animation prop
16
+ *
17
+ * Priority: Global > Parent > Own (global wins if enabled)
18
+ *
19
+ * @param animation - Root animation configuration for the component
20
+ * @returns Combined isAllAnimationsDisabled value
21
+ *
22
+ * @example
23
+ * ```tsx
24
+ * const isAllAnimationsDisabled = useCombinedAnimationDisabledState(animation);
25
+ * ```
26
+ */
27
+ export function useCombinedAnimationDisabledState<TConfig extends Record<string, any>>(
28
+ animation: AnimationRoot<TConfig> | undefined,
29
+ ): boolean {
30
+ // Get global animation disabled state
31
+ const { globalIsAllAnimationsDisabled } = useGlobalAnimationSettings();
32
+
33
+ // Read parent animation disabled state from global context
34
+ const parentAnimationSettingsContext = useAnimationSettings();
35
+ const parentIsAllAnimationsDisabled = parentAnimationSettingsContext?.isAllAnimationsDisabled;
36
+
37
+ // Get own animation disabled state
38
+ const { isAllAnimationsDisabled: ownIsAllAnimationsDisabled } = getRootAnimationState(animation);
39
+
40
+ // Combine global, parent, and own disable-all states (global > parent > own)
41
+ return getCombinedAnimationDisabledState({
42
+ globalIsAllAnimationsDisabled,
43
+ parentIsAllAnimationsDisabled,
44
+ ownIsAllAnimationsDisabled,
45
+ });
46
+ }
@@ -0,0 +1,3 @@
1
+ export * from './types';
2
+ export * from './hooks';
3
+ export * from './utils';
@@ -0,0 +1,128 @@
1
+ import type {
2
+ BaseAnimationBuilder,
3
+ EntryOrExitLayoutType,
4
+ LayoutAnimationFunction,
5
+ WithSpringConfig,
6
+ WithTimingConfig,
7
+ } from 'react-native-reanimated';
8
+
9
+ /**
10
+ * Universal animation prop type
11
+ * - `true` or `undefined`: Use default animations
12
+ * - `false` or `"disabled"`: Disable all animations
13
+ * - `object`: Custom animation configuration
14
+ * - Can include `state?: 'disabled' | boolean | undefined` to disable animations while customizing properties
15
+ */
16
+ export type Animation<TConfig extends Record<string, any> = Record<string, any>> =
17
+ | boolean
18
+ | 'disabled'
19
+ | (TConfig & { state?: 'disabled' | boolean });
20
+
21
+ export type AnimationDisabled = 'disabled' | false;
22
+
23
+ /**
24
+ * Root-level animation prop type with cascading control
25
+ * - `true` or `undefined`: Use default animations
26
+ * - `false` or `"disabled"`: Disable only root animations (children can still animate)
27
+ * - `"disable-all"`: Disable all animations including children (cascades down)
28
+ * - `object`: Custom animation configuration
29
+ * - Can include `state?: 'disabled' | 'disable-all' | boolean` to disable animations while customizing properties
30
+ */
31
+ export type AnimationRoot<TConfig extends Record<string, any> = Record<string, any>> =
32
+ | boolean
33
+ | 'disabled'
34
+ | 'disable-all'
35
+ | (TConfig & { state?: 'disabled' | 'disable-all' | boolean });
36
+
37
+ export type AnimationRootDisableAll = Extract<AnimationRoot, 'disable-all'>;
38
+
39
+ /**
40
+ * Animation value that can be a custom config
41
+ * Used for granular animation control within a component
42
+ */
43
+ export type AnimationValue<TConfig extends Record<string, any> = Record<string, any>> = TConfig;
44
+
45
+ export type LayoutTransition =
46
+ | BaseAnimationBuilder
47
+ | LayoutAnimationFunction
48
+ | typeof BaseAnimationBuilder
49
+ | undefined;
50
+
51
+ /**
52
+ * Spring animation configuration
53
+ */
54
+ export interface SpringAnimationConfig {
55
+ type: 'spring';
56
+ config?: WithSpringConfig;
57
+ }
58
+
59
+ /**
60
+ * Timing animation configuration
61
+ */
62
+ export interface TimingAnimationConfig {
63
+ type: 'timing';
64
+ config?: WithTimingConfig;
65
+ }
66
+
67
+ /**
68
+ * Animation configuration for popup overlay components (Dialog, Select, BottomSheet, Popover, etc.)
69
+ * Supports both progress-based opacity animation and entering/exiting animations
70
+ */
71
+ export type PopupOverlayAnimation = Animation<{
72
+ /**
73
+ * Opacity animation configuration (progress-based)
74
+ * Takes effect for bottom-sheet/dialog presentation
75
+ * @default [0, 1, 0] - opacity values for [idle, open, close] states
76
+ */
77
+ opacity?: AnimationValue<{
78
+ /**
79
+ * Opacity values [idle, open, close]
80
+ * @default [0, 1, 0]
81
+ */
82
+ value?: [number, number, number];
83
+ }>;
84
+ /**
85
+ * Takes effect for popover presentation
86
+ * @default FadeIn with duration 200ms
87
+ */
88
+ entering?: EntryOrExitLayoutType;
89
+ /**
90
+ * Takes effect for popover presentation
91
+ * @default FadeOut with duration 150ms
92
+ */
93
+ exiting?: EntryOrExitLayoutType;
94
+ }>;
95
+
96
+ /**
97
+ * Animation configuration for popup dialog content components (Dialog, Select dialog presentation)
98
+ * Supports opacity and scale animations
99
+ */
100
+ export type PopupDialogContentAnimation = Animation<{
101
+ /**
102
+ * Custom Keyframe animation for entering transition
103
+ * @default Keyframe with scale, and opacity (200ms)
104
+ */
105
+ entering?: EntryOrExitLayoutType;
106
+ /**
107
+ * Custom Keyframe animation for exiting transition
108
+ * @default Keyframe mirroring entering animation (150ms)
109
+ */
110
+ exiting?: EntryOrExitLayoutType;
111
+ }>;
112
+
113
+ /**
114
+ * Animation configuration for popup popover content components (Popover, Select popover presentation)
115
+ * Supports custom Keyframe animations for entering and exiting transitions
116
+ */
117
+ export type PopupPopoverContentAnimation = Animation<{
118
+ /**
119
+ * Custom Keyframe animation for entering transition
120
+ * @default Keyframe with translateY/translateX, scale, and opacity (200ms)
121
+ */
122
+ entering?: EntryOrExitLayoutType;
123
+ /**
124
+ * Custom Keyframe animation for exiting transition
125
+ * @default Keyframe mirroring entering animation (150ms)
126
+ */
127
+ exiting?: EntryOrExitLayoutType;
128
+ }>;
@@ -0,0 +1,249 @@
1
+ import type { Animation, AnimationRoot, AnimationValue } from './types';
2
+
3
+ /**
4
+ * Check if the entire animation is disabled
5
+ * @param animation - Animation configuration
6
+ * @returns true if animation is disabled
7
+ */
8
+ export function isAnimationDisabled<TConfig extends Record<string, any>>(
9
+ animation: Animation<TConfig> | AnimationRoot<TConfig> | undefined,
10
+ ): boolean {
11
+ // Check top-level disabled values
12
+ if (animation === false || animation === 'disabled') {
13
+ return true;
14
+ }
15
+
16
+ // Check state property in config objects
17
+ if (typeof animation === 'object' && animation !== null && 'state' in animation) {
18
+ const state = animation.state;
19
+ return state === false || state === 'disabled';
20
+ }
21
+
22
+ return false;
23
+ }
24
+
25
+ /**
26
+ * Check if root animation should cascade disable to all children
27
+ * @param animation - Root animation configuration
28
+ * @returns true if all animations should be disabled (including children)
29
+ */
30
+ export function shouldDisableAll<TConfig extends Record<string, any>>(
31
+ animation: AnimationRoot<TConfig> | undefined,
32
+ ): boolean {
33
+ // Check top-level disable-all value
34
+ if (animation === 'disable-all') {
35
+ return true;
36
+ }
37
+
38
+ // Check state property in config objects
39
+ if (typeof animation === 'object' && animation !== null && 'state' in animation) {
40
+ const state = animation.state;
41
+ return state === 'disable-all';
42
+ }
43
+
44
+ return false;
45
+ }
46
+
47
+ /**
48
+ * Get animation state including config and disabled status
49
+ * @param animation - Animation configuration
50
+ * @returns Object with animationConfig and isAnimationDisabled
51
+ */
52
+ export function getAnimationState<TConfig extends Record<string, any>>(
53
+ animation: Animation<TConfig> | undefined,
54
+ ): {
55
+ animationConfig: TConfig | undefined;
56
+ isAnimationDisabled: boolean;
57
+ } {
58
+ const isDisabled = isAnimationDisabled(animation);
59
+ // Always extract config when it's an object, regardless of disabled state
60
+ // This allows users to customize colors/properties even when animations are disabled
61
+ const config =
62
+ typeof animation === 'object' && animation !== null ? (animation as TConfig) : undefined;
63
+
64
+ return {
65
+ animationConfig: config,
66
+ isAnimationDisabled: isDisabled,
67
+ };
68
+ }
69
+
70
+ /**
71
+ * Get root animation state including config, disabled status, and cascade flag
72
+ * @param animation - Root animation configuration
73
+ * @returns Object with animationConfig, isAnimationDisabled, and isAllAnimationsDisabled
74
+ */
75
+ export function getRootAnimationState<TConfig extends Record<string, any>>(
76
+ animation: AnimationRoot<TConfig> | undefined,
77
+ ): {
78
+ animationConfig: TConfig | undefined;
79
+ isAnimationDisabled: boolean;
80
+ isAllAnimationsDisabled: boolean;
81
+ } {
82
+ const shouldCascade = shouldDisableAll(animation);
83
+ const isDisabled = isAnimationDisabled(animation) || shouldCascade;
84
+ // Always extract config when it's an object, regardless of disabled state
85
+ // This allows users to customize colors/properties even when animations are disabled
86
+ const config =
87
+ typeof animation === 'object' && animation !== null ? (animation as TConfig) : undefined;
88
+
89
+ return {
90
+ animationConfig: config,
91
+ isAnimationDisabled: isDisabled,
92
+ isAllAnimationsDisabled: shouldCascade,
93
+ };
94
+ }
95
+
96
+ /**
97
+ * Get animation value property or return default
98
+ * Extracts a property from the animation value config object
99
+ *
100
+ * @param options - Object containing animationValue, property, and defaultValue
101
+ * @param options.animationValue - The animation value configuration
102
+ * @param options.property - Property name to extract
103
+ * @param options.defaultValue - Default value if property is not found
104
+ * @returns The property value or default (never undefined)
105
+ *
106
+ * @example
107
+ * const scaleValue = getAnimationValueProperty({
108
+ * animationValue: animation?.scale,
109
+ * property: 'value',
110
+ * defaultValue: 0.95
111
+ * });
112
+ */
113
+ export function getAnimationValueProperty<
114
+ TConfig extends Record<string, any>,
115
+ K extends keyof TConfig,
116
+ D extends NonNullable<TConfig[K]>,
117
+ >(options: {
118
+ animationValue: AnimationValue<TConfig> | undefined;
119
+ property: K;
120
+ defaultValue: D;
121
+ }): D {
122
+ // If animation value is undefined, return default
123
+ if (options.animationValue === undefined) {
124
+ return options.defaultValue;
125
+ }
126
+
127
+ // Return the property value if it exists, otherwise return default
128
+ return options.animationValue[options.property] ?? options.defaultValue;
129
+ }
130
+
131
+ /**
132
+ * Get animation value merged config or return default
133
+ * Merges the animation value config with defaults, useful when you need multiple properties
134
+ *
135
+ * @param options - Object containing animationValue, property, and defaultValue
136
+ * @param options.animationValue - The animation value configuration
137
+ * @param options.property - Property name to extract from the config
138
+ * @param options.defaultValue - Default configuration object
139
+ * @returns The merged config object or default
140
+ *
141
+ * @example
142
+ * const scaleConfig = getAnimationValueMergedConfig({
143
+ * animationValue: animation?.scale,
144
+ * property: 'timingConfig',
145
+ * defaultValue: { duration: 150 }
146
+ * });
147
+ */
148
+ export function getAnimationValueMergedConfig<
149
+ TConfig extends Record<string, any>,
150
+ K extends keyof TConfig,
151
+ >(options: {
152
+ animationValue: AnimationValue<TConfig> | undefined;
153
+ property: K;
154
+ defaultValue: TConfig[K];
155
+ }): TConfig[K] {
156
+ // If animation value is undefined, return default
157
+ if (options.animationValue === undefined) {
158
+ return options.defaultValue;
159
+ }
160
+
161
+ const value = options.animationValue[options.property];
162
+
163
+ // If the specific property value is undefined or not an object, return default
164
+ if (value === undefined || typeof value !== 'object') {
165
+ return options.defaultValue;
166
+ }
167
+
168
+ // Merge with defaults to ensure all properties exist
169
+ return { ...options.defaultValue, ...value };
170
+ }
171
+
172
+ /**
173
+ * Determine if animations should be disabled based on disabled flags
174
+ * Priority: isAllAnimationsDisabled > isAnimationDisabled
175
+ *
176
+ * @param options - Object containing isAnimationDisabled and isAllAnimationsDisabled
177
+ * @param options.isAnimationDisabled - Whether animation is explicitly disabled
178
+ * @param options.isAllAnimationsDisabled - Whether all animations should be disabled (cascading from root/global)
179
+ * @returns true if animations should be disabled, false otherwise
180
+ *
181
+ * @example
182
+ * const isDisabled = getIsAnimationDisabledValue({
183
+ * isAnimationDisabled: false,
184
+ * isAllAnimationsDisabled: true
185
+ * });
186
+ * // Returns: true (all animations disabled takes priority)
187
+ */
188
+ export function getIsAnimationDisabledValue(options: {
189
+ isAnimationDisabled: boolean;
190
+ isAllAnimationsDisabled: boolean | undefined;
191
+ }): boolean {
192
+ const { isAnimationDisabled: isDisabled, isAllAnimationsDisabled } = options;
193
+
194
+ // First priority: if all animations are disabled, return true
195
+ if (isAllAnimationsDisabled === true) {
196
+ return true;
197
+ }
198
+
199
+ // Second priority: if this animation is disabled, return true
200
+ if (isDisabled) {
201
+ return true;
202
+ }
203
+
204
+ // Default: animations are enabled
205
+ return false;
206
+ }
207
+
208
+ /**
209
+ * Combine global, parent, and own animation disabled states
210
+ * Priority: Global > Parent > Own (global wins if enabled)
211
+ *
212
+ * @param options - Object containing globalIsAllAnimationsDisabled, parentIsAllAnimationsDisabled, and ownIsAllAnimationsDisabled
213
+ * @param options.globalIsAllAnimationsDisabled - Whether global provider has disable-all (from GlobalAnimationSettingsProvider)
214
+ * @param options.parentIsAllAnimationsDisabled - Whether parent context has disable-all (from AnimationSettingsContext)
215
+ * @param options.ownIsAllAnimationsDisabled - Whether own animation prop has disable-all
216
+ * @returns Combined isAllAnimationsDisabled value (global || parent || own)
217
+ *
218
+ * @example
219
+ * const combined = getCombinedAnimationDisabledState({
220
+ * globalIsAllAnimationsDisabled: true,
221
+ * parentIsAllAnimationsDisabled: false,
222
+ * ownIsAllAnimationsDisabled: false
223
+ * });
224
+ * // Returns: true (global wins)
225
+ */
226
+ export function getCombinedAnimationDisabledState(options: {
227
+ globalIsAllAnimationsDisabled?: boolean;
228
+ parentIsAllAnimationsDisabled: boolean | undefined;
229
+ ownIsAllAnimationsDisabled: boolean;
230
+ }): boolean {
231
+ const {
232
+ globalIsAllAnimationsDisabled,
233
+ parentIsAllAnimationsDisabled,
234
+ ownIsAllAnimationsDisabled,
235
+ } = options;
236
+
237
+ // Global always wins if it has disable-all
238
+ if (globalIsAllAnimationsDisabled === true) {
239
+ return true;
240
+ }
241
+
242
+ // Parent wins if it has disable-all
243
+ if (parentIsAllAnimationsDisabled === true) {
244
+ return true;
245
+ }
246
+
247
+ // Otherwise use own value
248
+ return ownIsAllAnimationsDisabled;
249
+ }
@@ -120,7 +120,7 @@ Where: **styled layer.** Pure styling hint with no behavior or a11y semantics
120
120
  Each component follows this structure (see `Button/index.tsx`):
121
121
 
122
122
  1. **Imports** — RN base components, primitive `Root` and `Slot` from `@cdx-ui/primitives`, `cn` + style context from `@cdx-ui/utils`, variant functions from `./styles`
123
- 2. **Scope constant** — `const SCOPE = 'COMPONENT_NAME'` for `withStyleContext` / `useStyleContext` (or a `ParentContext.Provider` wrapper for static variant context)
123
+ 2. **Scope constant** — `const SCOPE = 'COMPONENT_NAME'` for `useStyleContext` with a `ParentContext.Provider` wrapper for static variant context
124
124
  3. **Root component** — renders the primitive Root (or a host element directly when no primitive exists), spreads `dataAttributes({ slot: '<component>' })`
125
125
  4. **Sub-slots** — each accepts `asChild`, renders a host element via `const Comp = asChild ? Slot : DefaultElement`, spreads `dataAttributes({ slot: '<component>-<slot>' })`. Sub-slots **do not** call `useButtonContext()` (or its equivalent) unless their own styling reacts to interaction state.
126
126
  5. **Position-aware sub-slots** — icon/spinner-style slots accept `position?: 'leading' | 'trailing'` and emit `data-icon` via `dataAttributes({ icon: '...' })`.
@@ -1,6 +1,7 @@
1
- import { forwardRef, type ReactNode } from 'react';
1
+ import { forwardRef, useMemo, type ReactNode } from 'react';
2
2
  import { View, type ViewProps } from 'react-native';
3
- import { cn, useStyleContext, withStyleContext } from '@cdx-ui/utils';
3
+ import { Slot, dataAttributes, mergeDataAttributes } from '@cdx-ui/primitives';
4
+ import { cn, ParentContext, useParentContext, useStyleContext } from '@cdx-ui/utils';
4
5
  import {
5
6
  cardContentVariants,
6
7
  cardFooterVariants,
@@ -17,29 +18,34 @@ import {
17
18
 
18
19
  const SCOPE = 'CARD';
19
20
 
20
- const Root = withStyleContext(View, SCOPE);
21
-
22
21
  const useCardStyleContext = () => useStyleContext(SCOPE) as CardVariantProps;
23
22
 
24
23
  export interface CardProps extends ViewProps, CardVariantProps {
24
+ asChild?: boolean;
25
25
  className?: string;
26
26
  children?: ReactNode;
27
27
  }
28
28
 
29
29
  const CardRoot = forwardRef<View, CardProps>(
30
- ({ className, children, style, fullBleed, ...props }, ref) => {
30
+ ({ asChild, className, children, style, fullBleed, ...props }, ref) => {
31
+ const parent = useParentContext();
32
+ const ctx = useMemo(() => ({ ...parent, [SCOPE]: { fullBleed } }), [parent, fullBleed]);
33
+
31
34
  const computedClassName = cn(cardRootVariants(), className);
35
+ const Comp = asChild ? Slot : View;
32
36
 
33
37
  return (
34
- <Root
35
- ref={ref}
36
- className={computedClassName}
37
- style={style}
38
- context={{ fullBleed }}
39
- {...props}
40
- >
41
- {children}
42
- </Root>
38
+ <ParentContext.Provider value={ctx}>
39
+ <Comp
40
+ ref={ref}
41
+ className={computedClassName}
42
+ style={style}
43
+ {...props}
44
+ {...mergeDataAttributes(props, dataAttributes({ slot: 'card' }))}
45
+ >
46
+ {children}
47
+ </Comp>
48
+ </ParentContext.Provider>
43
49
  );
44
50
  },
45
51
  );
@@ -51,18 +57,26 @@ CardRoot.displayName = 'Card';
51
57
  // =============================================================================
52
58
 
53
59
  export interface CardHeaderProps extends ViewProps {
60
+ asChild?: boolean;
54
61
  className?: string;
55
62
  children?: ReactNode;
56
63
  }
57
64
 
58
65
  const CardHeader = forwardRef<View, CardHeaderProps>(
59
- ({ className, children, style, ...props }, ref) => {
66
+ ({ asChild, className, children, style, ...props }, ref) => {
60
67
  const computedClassName = cn(cardHeaderVariants(), className);
68
+ const Comp = asChild ? Slot : View;
61
69
 
62
70
  return (
63
- <View ref={ref} className={computedClassName} style={style} {...props}>
71
+ <Comp
72
+ ref={ref}
73
+ className={computedClassName}
74
+ style={style}
75
+ {...props}
76
+ {...mergeDataAttributes(props, dataAttributes({ slot: 'card-header' }))}
77
+ >
64
78
  {children}
65
- </View>
79
+ </Comp>
66
80
  );
67
81
  },
68
82
  );
@@ -74,22 +88,30 @@ CardHeader.displayName = 'Card.Header';
74
88
  // =============================================================================
75
89
 
76
90
  export interface CardContentProps extends ViewProps, CardContentVariantProps {
91
+ asChild?: boolean;
77
92
  className?: string;
78
93
  children?: ReactNode;
79
94
  }
80
95
 
81
96
  const CardContent = forwardRef<View, CardContentProps>(
82
- ({ className, children, style, fullBleed, ...props }, ref) => {
97
+ ({ asChild, className, children, style, fullBleed, ...props }, ref) => {
83
98
  const { fullBleed: fullBleedFromContext } = useCardStyleContext();
84
99
  const computedClassName = cn(
85
100
  cardContentVariants({ fullBleed: fullBleed ?? fullBleedFromContext }),
86
101
  className,
87
102
  );
103
+ const Comp = asChild ? Slot : View;
88
104
 
89
105
  return (
90
- <View ref={ref} className={computedClassName} style={style} {...props}>
106
+ <Comp
107
+ ref={ref}
108
+ className={computedClassName}
109
+ style={style}
110
+ {...props}
111
+ {...mergeDataAttributes(props, dataAttributes({ slot: 'card-content' }))}
112
+ >
91
113
  {children}
92
- </View>
114
+ </Comp>
93
115
  );
94
116
  },
95
117
  );
@@ -101,22 +123,30 @@ CardContent.displayName = 'Card.Content';
101
123
  // =============================================================================
102
124
 
103
125
  export interface CardFooterProps extends ViewProps, CardFooterVariantProps {
126
+ asChild?: boolean;
104
127
  className?: string;
105
128
  children?: ReactNode;
106
129
  }
107
130
 
108
131
  const CardFooter = forwardRef<View, CardFooterProps>(
109
- ({ className, children, style, fullBleed, ...props }, ref) => {
132
+ ({ asChild, className, children, style, fullBleed, ...props }, ref) => {
110
133
  const { fullBleed: fullBleedFromContext } = useCardStyleContext();
111
134
  const computedClassName = cn(
112
135
  cardFooterVariants({ fullBleed: fullBleed ?? fullBleedFromContext }),
113
136
  className,
114
137
  );
138
+ const Comp = asChild ? Slot : View;
115
139
 
116
140
  return (
117
- <View ref={ref} className={computedClassName} style={style} {...props}>
141
+ <Comp
142
+ ref={ref}
143
+ className={computedClassName}
144
+ style={style}
145
+ {...props}
146
+ {...mergeDataAttributes(props, dataAttributes({ slot: 'card-footer' }))}
147
+ >
118
148
  {children}
119
- </View>
149
+ </Comp>
120
150
  );
121
151
  },
122
152
  );
@@ -133,8 +163,8 @@ type CardCompoundComponent = typeof CardRoot & {
133
163
  Footer: typeof CardFooter;
134
164
  };
135
165
 
136
- export const Card = CardRoot as CardCompoundComponent;
137
-
138
- Card.Header = CardHeader;
139
- Card.Content = CardContent;
140
- Card.Footer = CardFooter;
166
+ export const Card = Object.assign(CardRoot, {
167
+ Header: CardHeader,
168
+ Content: CardContent,
169
+ Footer: CardFooter,
170
+ }) as CardCompoundComponent;