cpk-ui 0.5.4 → 0.7.0

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 (136) hide show
  1. package/README.md +80 -147
  2. package/components/modals/AlertDialog/AlertDialog.d.ts.map +1 -1
  3. package/components/modals/AlertDialog/AlertDialog.js +14 -7
  4. package/components/modals/Snackbar/Snackbar.d.ts.map +1 -1
  5. package/components/modals/Snackbar/Snackbar.js +20 -17
  6. package/components/uis/Accordion/AccordionItem.d.ts.map +1 -1
  7. package/components/uis/Accordion/AccordionItem.js +41 -17
  8. package/components/uis/Button/Button.d.ts +2 -1
  9. package/components/uis/Button/Button.d.ts.map +1 -1
  10. package/components/uis/Button/Button.js +11 -11
  11. package/components/uis/Card/Card.d.ts +2 -1
  12. package/components/uis/Card/Card.d.ts.map +1 -1
  13. package/components/uis/Card/Card.js +12 -3
  14. package/components/uis/Checkbox/Checkbox.d.ts +2 -1
  15. package/components/uis/Checkbox/Checkbox.d.ts.map +1 -1
  16. package/components/uis/Checkbox/Checkbox.js +2 -2
  17. package/components/uis/CustomPressable/CustomPressable.d.ts.map +1 -1
  18. package/components/uis/CustomPressable/CustomPressable.js +6 -6
  19. package/components/uis/EditText/EditText.d.ts +1 -0
  20. package/components/uis/EditText/EditText.d.ts.map +1 -1
  21. package/components/uis/EditText/EditText.js +18 -13
  22. package/components/uis/Fab/Fab.d.ts +2 -2
  23. package/components/uis/Fab/Fab.d.ts.map +1 -1
  24. package/components/uis/Fab/Fab.js +22 -4
  25. package/components/uis/Icon/Icon.d.ts.map +1 -1
  26. package/components/uis/Icon/Icon.js +6 -3
  27. package/components/uis/IconButton/IconButton.d.ts +2 -1
  28. package/components/uis/IconButton/IconButton.d.ts.map +1 -1
  29. package/components/uis/IconButton/IconButton.js +44 -42
  30. package/components/uis/LoadingIndicator/LoadingIndicator.d.ts +2 -1
  31. package/components/uis/LoadingIndicator/LoadingIndicator.d.ts.map +1 -1
  32. package/components/uis/LoadingIndicator/LoadingIndicator.js +4 -4
  33. package/components/uis/RadioGroup/RadioButton.d.ts +2 -1
  34. package/components/uis/RadioGroup/RadioButton.d.ts.map +1 -1
  35. package/components/uis/RadioGroup/RadioButton.js +2 -2
  36. package/components/uis/RadioGroup/RadioGroup.d.ts.map +1 -1
  37. package/components/uis/RadioGroup/RadioGroup.js +16 -3
  38. package/components/uis/Rating/Rating.d.ts.map +1 -1
  39. package/components/uis/Rating/Rating.js +23 -19
  40. package/components/uis/SegmentedControl/SegmentedControl.d.ts.map +1 -1
  41. package/components/uis/SegmentedControl/SegmentedControl.js +1 -1
  42. package/components/uis/StatusbarBrightness/StatusBarBrightness.d.ts +2 -2
  43. package/components/uis/StatusbarBrightness/StatusBarBrightness.d.ts.map +1 -1
  44. package/components/uis/StatusbarBrightness/StatusBarBrightness.js +1 -1
  45. package/components/uis/SwitchToggle/SwitchToggle.d.ts +2 -1
  46. package/components/uis/SwitchToggle/SwitchToggle.d.ts.map +1 -1
  47. package/components/uis/SwitchToggle/SwitchToggle.js +2 -2
  48. package/hooks/useHoverState.d.ts +8 -0
  49. package/hooks/useHoverState.d.ts.map +1 -0
  50. package/hooks/useHoverState.js +16 -0
  51. package/package.json +18 -6
  52. package/providers/ThemeProvider.d.ts.map +1 -1
  53. package/providers/ThemeProvider.js +0 -1
  54. package/providers/index.d.ts.map +1 -1
  55. package/providers/index.js +3 -2
  56. package/components/uis/Icon/selection.json +0 -1
  57. package/src/components/common/ErrorBoundary/ErrorBoundary.tsx +0 -75
  58. package/src/components/modals/AlertDialog/AlertDialog.stories.tsx +0 -216
  59. package/src/components/modals/AlertDialog/AlertDialog.test.tsx +0 -251
  60. package/src/components/modals/AlertDialog/AlertDialog.tsx +0 -356
  61. package/src/components/modals/Snackbar/Snackbar.stories.tsx +0 -182
  62. package/src/components/modals/Snackbar/Snackbar.test.tsx +0 -319
  63. package/src/components/modals/Snackbar/Snackbar.tsx +0 -260
  64. package/src/components/modals/Snackbar/const.ts +0 -4
  65. package/src/components/uis/Accordion/Accordion.stories.tsx +0 -167
  66. package/src/components/uis/Accordion/Accordion.test.tsx +0 -272
  67. package/src/components/uis/Accordion/Accordion.tsx +0 -109
  68. package/src/components/uis/Accordion/AccordionItem.tsx +0 -306
  69. package/src/components/uis/Button/Button.stories.tsx +0 -218
  70. package/src/components/uis/Button/Button.test.tsx +0 -620
  71. package/src/components/uis/Button/Button.tsx +0 -436
  72. package/src/components/uis/Card/Card.test.tsx +0 -146
  73. package/src/components/uis/Card/Card.tsx +0 -102
  74. package/src/components/uis/Checkbox/Checkbox.stories.tsx +0 -216
  75. package/src/components/uis/Checkbox/Checkbox.test.tsx +0 -173
  76. package/src/components/uis/Checkbox/Checkbox.tsx +0 -220
  77. package/src/components/uis/CustomPressable/CustomPressable.tsx +0 -48
  78. package/src/components/uis/EditText/EditText.stories.tsx +0 -124
  79. package/src/components/uis/EditText/EditText.test.tsx +0 -477
  80. package/src/components/uis/EditText/EditText.tsx +0 -590
  81. package/src/components/uis/Fab/Fab.stories.tsx +0 -133
  82. package/src/components/uis/Fab/Fab.test.tsx +0 -110
  83. package/src/components/uis/Fab/Fab.tsx +0 -168
  84. package/src/components/uis/Hr/Hr.test.tsx +0 -26
  85. package/src/components/uis/Hr/Hr.tsx +0 -19
  86. package/src/components/uis/Icon/Icon.stories.tsx +0 -98
  87. package/src/components/uis/Icon/Icon.test.tsx +0 -49
  88. package/src/components/uis/Icon/Icon.tsx +0 -3819
  89. package/src/components/uis/IconButton/IconButton.test.tsx +0 -165
  90. package/src/components/uis/IconButton/IconButton.tsx +0 -275
  91. package/src/components/uis/LoadingIndicator/LoadingIndicator.tsx +0 -126
  92. package/src/components/uis/LoadingIndicator/LodingIndicator.stories.tsx +0 -81
  93. package/src/components/uis/PinchZoom/PinchZoom.stories.tsx +0 -266
  94. package/src/components/uis/PinchZoom/PinchZoom.test.tsx +0 -113
  95. package/src/components/uis/PinchZoom/PinchZoom.tsx +0 -424
  96. package/src/components/uis/RadioGroup/RadioButton.tsx +0 -188
  97. package/src/components/uis/RadioGroup/RadioGroup.stories.tsx +0 -188
  98. package/src/components/uis/RadioGroup/RadioGroup.test.tsx +0 -287
  99. package/src/components/uis/RadioGroup/RadioGroup.tsx +0 -109
  100. package/src/components/uis/Rating/Rating.test.tsx +0 -98
  101. package/src/components/uis/Rating/Rating.tsx +0 -200
  102. package/src/components/uis/SegmentedControl/SegmentedControl.stories.tsx +0 -546
  103. package/src/components/uis/SegmentedControl/SegmentedControl.test.tsx +0 -274
  104. package/src/components/uis/SegmentedControl/SegmentedControl.tsx +0 -229
  105. package/src/components/uis/StatusbarBrightness/StatusBarBrightness.test.tsx +0 -41
  106. package/src/components/uis/StatusbarBrightness/StatusBarBrightness.tsx +0 -26
  107. package/src/components/uis/Styled/StyledComponents.tsx +0 -217
  108. package/src/components/uis/SwitchToggle/SwitchToggle.stories.tsx +0 -75
  109. package/src/components/uis/SwitchToggle/SwitchToggle.test.tsx +0 -105
  110. package/src/components/uis/SwitchToggle/SwitchToggle.tsx +0 -305
  111. package/src/components/uis/Typography/Typography.stories.tsx +0 -149
  112. package/src/components/uis/Typography/Typography.test.tsx +0 -58
  113. package/src/components/uis/Typography/Typography.tsx +0 -386
  114. package/src/hooks/index.ts +0 -2
  115. package/src/hooks/useAnimations.ts +0 -71
  116. package/src/hooks/useDebouncedColorScheme.tsx +0 -30
  117. package/src/hooks/useOptimizedStyles.ts +0 -22
  118. package/src/hooks/usePerformance.ts +0 -93
  119. package/src/index.tsx +0 -38
  120. package/src/providers/ThemeProvider.tsx +0 -177
  121. package/src/providers/index.tsx +0 -130
  122. package/src/test/testUtils.tsx +0 -101
  123. package/src/types/common.ts +0 -77
  124. package/src/types/index.ts +0 -1
  125. package/src/types/kstyled.d.ts +0 -6
  126. package/src/utils/accessibility.ts +0 -110
  127. package/src/utils/colors.ts +0 -151
  128. package/src/utils/createCtx.tsx +0 -26
  129. package/src/utils/guards.ts +0 -93
  130. package/src/utils/index.ts +0 -2
  131. package/src/utils/performanceTest.ts +0 -174
  132. package/src/utils/platform.ts +0 -69
  133. package/src/utils/theme.ts +0 -38
  134. package/test/testUtils.d.ts +0 -113
  135. package/test/testUtils.d.ts.map +0 -1
  136. package/test/testUtils.js +0 -65
@@ -1,424 +0,0 @@
1
- import type {PropsWithChildren, Ref} from 'react';
2
- import React, {
3
- forwardRef,
4
- useEffect,
5
- useImperativeHandle,
6
- useRef,
7
- useState,
8
- } from 'react';
9
- import type {
10
- NativeMethods,
11
- NativeTouchEvent,
12
- PanResponderInstance,
13
- ViewStyle,
14
- } from 'react-native';
15
- import {Animated, PanResponder} from 'react-native';
16
-
17
- export type PinchZoomProps = PropsWithChildren<{
18
- /**
19
- * Custom view style.
20
- * @warning Passing `transform` in style will disable pinch-zoom functionality.
21
- * Use a wrapper View for custom transforms instead.
22
- */
23
- style?: ViewStyle;
24
- children?: any;
25
- /** Callback fired when zoom scale changes */
26
- onScaleChanged?(value: number): void;
27
- /** Callback fired when content position changes */
28
- onTranslateChanged?(valueXY: {x: number; y: number}): void;
29
- /** Callback fired after gesture animation completes (decay or snap-back) */
30
- onRelease?(): void;
31
- /**
32
- * Allow unrestricted overflow on specific axes.
33
- * When true, allows overflow. When false/undefined, clamps to bounds.
34
- */
35
- allowEmpty?: {x?: boolean; y?: boolean};
36
- /**
37
- * Auto-snap to bounds after release.
38
- * @default true
39
- */
40
- fixOverflowAfterRelease?: boolean;
41
- /** Test ID for component testing */
42
- testID?: string;
43
- }>;
44
-
45
- export interface PinchZoomRef {
46
- animatedValue: {scale: Animated.Value; translate: Animated.ValueXY};
47
- setValues(_: {scale?: number; translate?: {x: number; y: number}}): void;
48
- }
49
-
50
- type TouchePosition = Pick<
51
- NativeTouchEvent,
52
- 'locationX' | 'locationY' | 'pageX' | 'pageY'
53
- >;
54
-
55
- function getDistanceFromTouches(touches: NativeTouchEvent[]): number {
56
- const [touch1, touch2] = touches;
57
-
58
- return Math.sqrt(
59
- (touch1.pageX - touch2.pageX) ** 2 + (touch1.pageY - touch2.pageY) ** 2,
60
- );
61
- }
62
-
63
- function getRelativeTouchesCenterPosition(
64
- touches: NativeTouchEvent[],
65
- layout: {width: number; height: number; pageX: number; pageY: number},
66
- transformCache: {scale: number; translateX: number; translateY: number},
67
- ): TouchePosition {
68
- const pageX =
69
- (touches[0].pageX + touches[1].pageX) / 2 - layout.width / 2 - layout.pageX;
70
-
71
- const pageY =
72
- (touches[0].pageY + touches[1].pageY) / 2 -
73
- layout.height / 2 -
74
- layout.pageY;
75
-
76
- return {
77
- locationX: (pageX - transformCache.translateX) / transformCache.scale,
78
- locationY: (pageY - transformCache.translateY) / transformCache.scale,
79
- pageX,
80
- pageY,
81
- };
82
- }
83
-
84
- function PinchZoom(
85
- {
86
- style,
87
- children,
88
- onScaleChanged,
89
- onRelease,
90
- onTranslateChanged,
91
- allowEmpty,
92
- fixOverflowAfterRelease = true,
93
- testID = 'pinch-zoom-container',
94
- }: PinchZoomProps,
95
- ref: Ref<PinchZoomRef>,
96
- ): JSX.Element {
97
- const containerView = useRef<NativeMethods | null>(null);
98
- const scale = useRef(new Animated.Value(1)).current;
99
- const translate = useRef(new Animated.ValueXY({x: 0, y: 0})).current;
100
-
101
- const transformCache = useRef({
102
- scale: 1,
103
- translateX: 0,
104
- translateY: 0,
105
- }).current;
106
-
107
- const lastTransform = useRef({scale: 1, translateX: 0, translateY: 0});
108
- const initialDistance = useRef<number | undefined>(undefined);
109
- const initialTouchesCenter = useRef<TouchePosition | undefined>(undefined);
110
-
111
- type Layout = {
112
- width: number;
113
- height: number;
114
- pageX: number;
115
- pageY: number;
116
- };
117
-
118
- const layout = useRef<Layout | undefined>(undefined);
119
-
120
- const decayingTranslateAnimation = useRef<
121
- Animated.CompositeAnimation | undefined
122
- >(undefined);
123
- const isResponderActive = useRef(false);
124
- const movingVelocity = useRef<{x: number; y: number} | undefined>(undefined);
125
-
126
- containerView.current?.measure((x, y, width, height, pageX, pageY) => {
127
- layout.current = {width, height, pageX, pageY};
128
- });
129
-
130
- useEffect(() => {
131
- scale.addListener(({value}) => {
132
- transformCache.scale = value;
133
- onScaleChanged?.(value);
134
- });
135
-
136
- const id = translate.addListener(({x, y}) => {
137
- if (
138
- decayingTranslateAnimation.current &&
139
- layout.current &&
140
- !isResponderActive.current
141
- ) {
142
- const overflowX =
143
- !allowEmpty?.x &&
144
- Math.abs(x) > ((transformCache.scale - 1) * layout.current.width) / 2;
145
-
146
- const overflowY =
147
- !allowEmpty?.y &&
148
- Math.abs(y) >
149
- ((transformCache.scale - 1) * layout.current.height) / 2;
150
-
151
- if (overflowX || overflowY) {
152
- decayingTranslateAnimation.current?.stop();
153
- decayingTranslateAnimation.current = undefined;
154
-
155
- translate.setValue({
156
- x: overflowX
157
- ? (Math.sign(x) *
158
- (transformCache.scale - 1) *
159
- layout.current.width) /
160
- 2
161
- : x,
162
- y: overflowY
163
- ? (Math.sign(y) *
164
- (transformCache.scale - 1) *
165
- layout.current.height) /
166
- 2
167
- : y,
168
- });
169
- }
170
- }
171
-
172
- transformCache.translateX = x;
173
- transformCache.translateY = y;
174
- onTranslateChanged?.({x, y});
175
- });
176
-
177
- return () => {
178
- scale.removeAllListeners();
179
- translate.removeListener(id);
180
- };
181
- }, [
182
- onScaleChanged,
183
- onTranslateChanged,
184
- scale,
185
- transformCache,
186
- translate,
187
- allowEmpty?.x,
188
- allowEmpty?.y,
189
- ]);
190
-
191
- const [panResponder, setPanResponder] = useState<PanResponderInstance>();
192
-
193
- useEffect(() => {
194
- setPanResponder(
195
- PanResponder.create({
196
- onMoveShouldSetPanResponder: () => true,
197
- onPanResponderGrant: ({nativeEvent}) => {
198
- isResponderActive.current = true;
199
- movingVelocity.current = undefined;
200
-
201
- if (decayingTranslateAnimation.current) {
202
- decayingTranslateAnimation.current.stop();
203
- }
204
-
205
- const {touches} = nativeEvent;
206
-
207
- lastTransform.current = {...transformCache};
208
-
209
- initialDistance.current = undefined;
210
-
211
- if (layout.current != null) {
212
- if (touches.length === 2) {
213
- initialDistance.current = getDistanceFromTouches(touches);
214
-
215
- initialTouchesCenter.current = getRelativeTouchesCenterPosition(
216
- touches,
217
- layout.current,
218
- transformCache,
219
- );
220
- } else {
221
- initialDistance.current = undefined;
222
- }
223
- }
224
- },
225
- onPanResponderMove: ({nativeEvent}, gestureState) => {
226
- const {touches} = nativeEvent;
227
-
228
- if (layout.current == null) {
229
- return;
230
- }
231
-
232
- if (movingVelocity.current) {
233
- movingVelocity.current = {
234
- x: (movingVelocity.current.x + gestureState.vx) / 2,
235
- y: (movingVelocity.current.y + gestureState.vy) / 2,
236
- };
237
- } else {
238
- movingVelocity.current = {x: gestureState.vx, y: gestureState.vy};
239
- }
240
-
241
- if (touches.length === 2) {
242
- if (
243
- initialDistance.current &&
244
- initialTouchesCenter.current &&
245
- layout.current
246
- ) {
247
- const newScale = Math.max(
248
- 1,
249
- (getDistanceFromTouches(touches) / initialDistance.current) *
250
- lastTransform.current.scale,
251
- );
252
-
253
- const {pageX, pageY} = getRelativeTouchesCenterPosition(
254
- touches,
255
- layout.current,
256
- transformCache,
257
- );
258
-
259
- scale.setValue(newScale);
260
-
261
- const newTranslateX =
262
- pageX - initialTouchesCenter.current.locationX * newScale;
263
-
264
- const newTranslateY =
265
- pageY - initialTouchesCenter.current.locationY * newScale;
266
-
267
- translate.setValue({
268
- x: allowEmpty?.x
269
- ? newTranslateX
270
- : Math.min(
271
- Math.abs(newTranslateX),
272
- ((newScale - 1) * layout.current.width) / 2,
273
- ) * Math.sign(newTranslateX),
274
- y: allowEmpty?.y
275
- ? newTranslateY
276
- : Math.min(
277
- Math.abs(newTranslateY),
278
- ((newScale - 1) * layout.current.height) / 2,
279
- ) * Math.sign(newTranslateY),
280
- });
281
- } else {
282
- initialDistance.current = getDistanceFromTouches(touches);
283
-
284
- initialTouchesCenter.current = getRelativeTouchesCenterPosition(
285
- touches,
286
- layout.current,
287
- transformCache,
288
- );
289
- }
290
- } else if (touches.length === 1) {
291
- if (initialDistance.current) {
292
- return;
293
- }
294
-
295
- const newTranslateX =
296
- lastTransform.current.translateX + gestureState.dx;
297
-
298
- const newTranslateY =
299
- lastTransform.current.translateY + gestureState.dy;
300
-
301
- translate.setValue({
302
- x: newTranslateX,
303
- y: newTranslateY,
304
- });
305
- }
306
- },
307
- onPanResponderRelease: () => {
308
- isResponderActive.current = false;
309
-
310
- if (layout.current == null) {
311
- return;
312
- }
313
-
314
- const overflowX =
315
- !allowEmpty?.x &&
316
- Math.abs(transformCache.translateX) >
317
- ((transformCache.scale - 1) * layout.current.width) / 2;
318
-
319
- const overflowY =
320
- !allowEmpty?.y &&
321
- Math.abs(transformCache.translateY) >
322
- ((transformCache.scale - 1) * layout.current.height) / 2;
323
-
324
- if (overflowX || overflowY) {
325
- if (!fixOverflowAfterRelease) {
326
- onRelease?.();
327
-
328
- return;
329
- }
330
-
331
- decayingTranslateAnimation.current?.stop();
332
- decayingTranslateAnimation.current = undefined;
333
-
334
- const toValue = {
335
- x: overflowX
336
- ? (Math.sign(transformCache.translateX) *
337
- (transformCache.scale - 1) *
338
- layout.current.width) /
339
- 2
340
- : transformCache.translateX,
341
- y: overflowY
342
- ? (Math.sign(transformCache.translateY) *
343
- (transformCache.scale - 1) *
344
- layout.current.height) /
345
- 2
346
- : transformCache.translateY,
347
- };
348
-
349
- Animated.timing(translate, {
350
- toValue,
351
- duration: 100,
352
- useNativeDriver: true,
353
- }).start(() => {
354
- onRelease?.();
355
- });
356
- } else {
357
- decayingTranslateAnimation.current = Animated.decay(translate, {
358
- velocity: movingVelocity.current ?? {x: 0, y: 0},
359
- useNativeDriver: true,
360
- });
361
-
362
- decayingTranslateAnimation.current.start(() => {
363
- decayingTranslateAnimation.current = undefined;
364
- onRelease?.();
365
- });
366
- }
367
- },
368
- }),
369
- );
370
- }, [
371
- allowEmpty?.x,
372
- allowEmpty?.y,
373
- fixOverflowAfterRelease,
374
- onRelease,
375
- scale,
376
- transformCache,
377
- translate,
378
- ]);
379
-
380
- useImperativeHandle(ref, () => ({
381
- animatedValue: {scale, translate},
382
- setValues: (values) => {
383
- values.scale != null && scale.setValue(values.scale);
384
- values.translate != null && translate.setValue(values.translate);
385
- },
386
- }));
387
-
388
- // Warn if style.transform is provided, as it will disable pinch-zoom
389
- if (__DEV__ && style?.transform) {
390
- console.warn(
391
- 'PinchZoom: passing transform in style prop will disable pinch-zoom functionality. ' +
392
- 'Use a wrapper View for custom transforms instead.',
393
- );
394
- }
395
-
396
- return (
397
- <Animated.View
398
- // @ts-ignore - ref type issue with NativeMethods
399
- ref={(pinchViewRef: NativeMethods | null) => {
400
- containerView.current = pinchViewRef;
401
- }}
402
- style={[
403
- style,
404
- style?.transform
405
- ? {}
406
- : {
407
- transform: [
408
- {translateX: translate.x},
409
- {translateY: translate.y},
410
- {scale},
411
- ],
412
- },
413
- ]}
414
- testID={testID}
415
- {...(panResponder?.panHandlers || {})}
416
- >
417
- {children}
418
- </Animated.View>
419
- );
420
- }
421
-
422
- const PinchZoomRoot = forwardRef<PinchZoomRef, PinchZoomProps>(PinchZoom);
423
-
424
- export {PinchZoomRoot as PinchZoom};
@@ -1,188 +0,0 @@
1
- import React, {useCallback, useEffect, useMemo, useRef, useState, type ReactElement} from 'react';
2
- import type {
3
- LayoutRectangle,
4
- StyleProp,
5
- TextStyle,
6
- ViewStyle,
7
- } from 'react-native';
8
- import {Animated, Platform, TouchableOpacity, View} from 'react-native';
9
- import {styled, css} from 'kstyled';
10
-
11
- import {
12
- ColoredText,
13
- RadioButtonWrapper,
14
- RadioWrapper,
15
- } from '../Styled/StyledComponents';
16
-
17
- import type {RadioButtonType} from './RadioGroup';
18
-
19
- export type RadioButtonSizeType = 'small' | 'medium' | 'large' | number;
20
-
21
- export type RadioButtonStyles = {
22
- container?: StyleProp<ViewStyle>;
23
- label?: StyleProp<TextStyle>;
24
- circleWrapper?: StyleProp<ViewStyle>;
25
- circle?: StyleProp<ViewStyle>;
26
- };
27
-
28
- export type RadioButtonProps = {
29
- testID?: string;
30
- onPress?: () => void;
31
- label?: string;
32
- labelPosition?: 'left' | 'right';
33
- style?: StyleProp<ViewStyle>;
34
- styles?: RadioButtonStyles;
35
- type?: RadioButtonType;
36
- size?: RadioButtonSizeType;
37
- disabled?: boolean;
38
- selected?: boolean;
39
- endElement?: ReactElement;
40
- startElement?: ReactElement;
41
- };
42
-
43
- const Container = styled.TouchableOpacity`
44
- flex-direction: row;
45
- align-items: center;
46
- `;
47
-
48
- const StyledRadioCircle = Animated.createAnimatedComponent(RadioWrapper);
49
-
50
- export default function RadioButton({
51
- testID,
52
- style,
53
- styles,
54
- endElement,
55
- startElement,
56
- type = 'primary',
57
- size = 'medium',
58
- disabled = false,
59
- selected,
60
- onPress,
61
- label,
62
- labelPosition = 'right',
63
- }: RadioButtonProps): ReactElement {
64
- const [innerLayout, setInnerLayout] = useState<LayoutRectangle>();
65
- const fadeAnim = useRef(new Animated.Value(selected ? 1 : 0)).current;
66
- const scaleAnim = useRef(new Animated.Value(selected ? 1 : 0)).current;
67
-
68
- // Memoize layout handler
69
- const handleLayout = useCallback((e: any) => {
70
- setInnerLayout(e.nativeEvent.layout);
71
- }, []);
72
-
73
- // Memoize animation config
74
- const animationConfig = useMemo(
75
- () => ({
76
- useNativeDriver: Platform.select({
77
- web: false,
78
- default: true,
79
- }),
80
- }),
81
- []
82
- );
83
-
84
- useEffect(() => {
85
- Animated.parallel([
86
- Animated.spring(fadeAnim, {
87
- toValue: !selected ? 0 : 1,
88
- ...animationConfig,
89
- }),
90
- Animated.spring(scaleAnim, {
91
- toValue: !selected ? 0 : 1,
92
- ...animationConfig,
93
- }),
94
- ]).start();
95
- }, [fadeAnim, scaleAnim, selected, animationConfig]);
96
-
97
- // Memoize container styles
98
- const containerStyles = useMemo(
99
- () => [
100
- css`
101
- padding-top: 6;
102
- padding-bottom: 6;
103
- padding-left: ${startElement || (label && labelPosition === 'left')
104
- ? 8
105
- : 0};
106
- padding-right: ${endElement || (label && labelPosition === 'right')
107
- ? 8
108
- : 0};
109
-
110
- flex-direction: row;
111
- align-items: center;
112
- `,
113
- styles?.container,
114
- ],
115
- [startElement, endElement, label, labelPosition, styles?.container]
116
- );
117
-
118
- // Memoize animated styles with margin and borderRadius
119
- const animatedStyles = useMemo(
120
- () => [
121
- styles?.circle,
122
- {
123
- margin: innerLayout ? 2 : 0,
124
- borderRadius: innerLayout ? innerLayout.width / 2 : 0,
125
- opacity: fadeAnim,
126
- transform: [{scale: scaleAnim}],
127
- },
128
- ],
129
- [innerLayout, styles?.circle, fadeAnim, scaleAnim]
130
- );
131
-
132
- return (
133
- <Container
134
- activeOpacity={0.9}
135
- disabled={disabled}
136
- onPress={onPress}
137
- style={style}
138
- testID={testID}
139
- >
140
- <View style={containerStyles}>
141
- {startElement}
142
- {label && labelPosition === 'left' ? (
143
- <ColoredText
144
- $disabled={!!disabled}
145
- $selected={!!selected}
146
- $size={size}
147
- style={styles?.label}
148
- $type={type}
149
- >
150
- {label}
151
- </ColoredText>
152
- ) : null}
153
- <RadioButtonWrapper
154
- $disabled={disabled}
155
- $selected={!!selected}
156
- $size={size}
157
- style={styles?.circleWrapper}
158
- $type={type}
159
- >
160
- <StyledRadioCircle
161
- $disabled={!!disabled}
162
- onLayout={handleLayout}
163
- $selected={!!selected}
164
- style={animatedStyles}
165
- testID={`circle-${testID}`}
166
- $type={type}
167
- />
168
- </RadioButtonWrapper>
169
- {label && labelPosition === 'right' ? (
170
- <ColoredText
171
- $disabled={!!disabled}
172
- $selected={!!selected}
173
- $size={size}
174
- style={styles?.label}
175
- $type={type}
176
- >
177
- {label}
178
- </ColoredText>
179
- ) : null}
180
- {endElement}
181
- </View>
182
- </Container>
183
- );
184
- }
185
-
186
- // Export memoized component for better performance
187
- const MemoizedRadioButton = React.memo(RadioButton);
188
- export {MemoizedRadioButton as RadioButton};