react-native-varia 0.2.3 → 0.2.4
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.
- package/bin/cli.js +24 -34
- package/lib/components/Accordion.tsx +113 -0
- package/lib/components/Button.tsx +10 -1
- package/lib/components/CircleProgress.tsx +30 -21
- package/lib/components/Divider.tsx +18 -15
- package/lib/components/Drawer.tsx +5 -48
- package/lib/components/Field.tsx +24 -39
- package/lib/components/GradientBackground.tsx +25 -7
- package/lib/components/GradientText.tsx +38 -11
- package/lib/components/IconWrapper.tsx +20 -14
- package/lib/components/Input.tsx +106 -25
- package/lib/components/NumberInput.tsx +54 -11
- package/lib/components/OldSlider.tsx +327 -0
- package/lib/components/RadioGroup.tsx +55 -17
- package/lib/components/ReText.tsx +1 -1
- package/lib/components/Select.tsx +58 -22
- package/lib/components/Slider.tsx +176 -115
- package/lib/components/Slideshow.tsx +65 -63
- package/lib/components/SlidingDrawer.tsx +20 -21
- package/lib/components/Spinner.tsx +6 -2
- package/lib/components/Toast.tsx +89 -0
- package/lib/components/context/Field.tsx +27 -0
- package/lib/theme/Button.recipe.tsx +11 -1
- package/lib/theme/CircleProgress.recipe.tsx +3 -3
- package/lib/theme/Field.recipe.tsx +17 -2
- package/lib/theme/Input.recipe.tsx +12 -3
- package/lib/theme/NumberInput.recipe.tsx +8 -3
- package/lib/theme/RadioGroup.recipe.tsx +7 -1
- package/lib/theme/Select.recipe.tsx +7 -7
- package/lib/theme/Slider.recipe.tsx +366 -22
- package/lib/theme/Slideshow.recipe.tsx +1 -1
- package/lib/theme/SlidingDrawer.recipe.tsx +58 -4
- package/lib/theme/Toast.recipe.tsx +71 -0
- package/package.json +1 -1
- package/lib/theme/Button.recipe-old.tsx +0 -67
package/bin/cli.js
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
1
|
+
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
const { program } = require("commander");
|
|
4
4
|
const inquirer = require("inquirer");
|
|
5
5
|
const path = require("path");
|
|
6
6
|
const fs = require("fs-extra");
|
|
7
7
|
|
|
8
|
-
// 🔹 Dependencias entre componentes
|
|
9
8
|
const COMPONENT_DEPENDENCIES = {
|
|
10
9
|
Button: ["Spinner", "IconWrapper"],
|
|
11
10
|
Field: ["Text"],
|
|
@@ -19,9 +18,18 @@ const ICON_DEPENDENCIES = {
|
|
|
19
18
|
NumberInput: ["Plus", "Minus"],
|
|
20
19
|
};
|
|
21
20
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
21
|
+
const CONTEXT_DEPENDENCIES = {
|
|
22
|
+
Field: true
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
function copyContextComponentIfNeeded(component, destComponents, overwrite = true) {
|
|
26
|
+
if (!CONTEXT_DEPENDENCIES[component]) return;
|
|
27
|
+
|
|
28
|
+
const contextSrc = path.join(COMPONENTS_DIR, "context", `${component}.tsx`);
|
|
29
|
+
const contextDest = path.join(process.cwd(), destComponents, "context", `${component}.tsx`);
|
|
30
|
+
copyFile(contextSrc, contextDest, `Context de "${component}"`, overwrite);
|
|
31
|
+
}
|
|
32
|
+
|
|
25
33
|
function resolveDependencies(component, seen = new Set()) {
|
|
26
34
|
if (seen.has(component)) return [];
|
|
27
35
|
seen.add(component);
|
|
@@ -36,21 +44,14 @@ function resolveDependencies(component, seen = new Set()) {
|
|
|
36
44
|
return [...new Set(allDeps)];
|
|
37
45
|
}
|
|
38
46
|
|
|
39
|
-
// Carpetas base
|
|
40
47
|
const COMPONENTS_DIR = path.join(__dirname, "../lib/components");
|
|
41
48
|
const THEME_DIR = path.join(__dirname, "../lib/theme");
|
|
42
49
|
|
|
43
|
-
/**
|
|
44
|
-
* Obtiene la lista de todos los componentes disponibles en la librería.
|
|
45
|
-
*/
|
|
46
50
|
function getAvailableComponents() {
|
|
47
51
|
if (!fs.existsSync(COMPONENTS_DIR)) return [];
|
|
48
52
|
return fs.readdirSync(COMPONENTS_DIR).map((name) => path.parse(name).name);
|
|
49
53
|
}
|
|
50
54
|
|
|
51
|
-
/**
|
|
52
|
-
* Copia un archivo desde origen a destino.
|
|
53
|
-
*/
|
|
54
55
|
function copyFile(srcPath, destPath, label, overwrite = true) {
|
|
55
56
|
if (!fs.existsSync(srcPath)) {
|
|
56
57
|
console.warn(`⚠️ ${label} no encontrado: ${srcPath}`);
|
|
@@ -73,9 +74,6 @@ function copyFile(srcPath, destPath, label, overwrite = true) {
|
|
|
73
74
|
}
|
|
74
75
|
}
|
|
75
76
|
|
|
76
|
-
/**
|
|
77
|
-
* Copia un componente y su recipe.
|
|
78
|
-
*/
|
|
79
77
|
function copyComponentAndRecipe(component, destComponents, destTheme, overwrite = true) {
|
|
80
78
|
const componentSrc = path.join(COMPONENTS_DIR, `${component}.tsx`);
|
|
81
79
|
const componentDest = path.join(process.cwd(), destComponents, `${component}.tsx`);
|
|
@@ -86,9 +84,6 @@ function copyComponentAndRecipe(component, destComponents, destTheme, overwrite
|
|
|
86
84
|
copyFile(recipeSrc, recipeDest, `Recipe de "${component}"`, overwrite);
|
|
87
85
|
}
|
|
88
86
|
|
|
89
|
-
/**
|
|
90
|
-
* Pregunta si se desea sobrescribir componentes existentes.
|
|
91
|
-
*/
|
|
92
87
|
async function confirmOverwrite(existingComponents) {
|
|
93
88
|
const { overwrite } = await inquirer.prompt([
|
|
94
89
|
{
|
|
@@ -119,12 +114,10 @@ program
|
|
|
119
114
|
const patternsDest = path.join(process.cwd(), "src/patterns");
|
|
120
115
|
|
|
121
116
|
try {
|
|
122
|
-
// Copiar varia
|
|
123
117
|
fs.ensureDirSync(path.dirname(variaDest));
|
|
124
118
|
fs.copySync(variaSrc, variaDest, { overwrite: true });
|
|
125
119
|
console.log(`✅ Carpeta "varia" copiada a ${variaDest}`);
|
|
126
120
|
|
|
127
|
-
// Copiar patterns
|
|
128
121
|
fs.ensureDirSync(path.dirname(patternsDest));
|
|
129
122
|
fs.copySync(patternsSrc, patternsDest, { overwrite: true });
|
|
130
123
|
console.log(`✅ Carpeta "patterns" copiada a ${patternsDest}`);
|
|
@@ -233,9 +226,8 @@ program
|
|
|
233
226
|
(c) => c.charAt(0).toUpperCase() + c.slice(1)
|
|
234
227
|
);
|
|
235
228
|
|
|
236
|
-
// 🔹 Obtener dependencias totales
|
|
237
229
|
const allComponents = new Set();
|
|
238
|
-
const componentToDeps = {};
|
|
230
|
+
const componentToDeps = {};
|
|
239
231
|
for (const c of componentsCapitalized) {
|
|
240
232
|
const deps = resolveDependencies(c);
|
|
241
233
|
componentToDeps[c] = deps;
|
|
@@ -245,7 +237,6 @@ program
|
|
|
245
237
|
|
|
246
238
|
const allComponentsArray = Array.from(allComponents);
|
|
247
239
|
|
|
248
|
-
// 🔹 Validar existencia
|
|
249
240
|
const notFound = allComponentsArray.filter((c) => !available.includes(c));
|
|
250
241
|
if (notFound.length > 0) {
|
|
251
242
|
console.error(`❌ Los siguientes componentes no existen: ${notFound.join(", ")}`);
|
|
@@ -254,12 +245,18 @@ program
|
|
|
254
245
|
process.exit(1);
|
|
255
246
|
}
|
|
256
247
|
|
|
257
|
-
|
|
248
|
+
function copyContextComponentIfNeeded(component, destComponents, overwrite = true) {
|
|
249
|
+
if (!CONTEXT_DEPENDENCIES[component]) return;
|
|
250
|
+
|
|
251
|
+
const contextSrc = path.join(COMPONENTS_DIR, "context", `${component}.tsx`);
|
|
252
|
+
const contextDest = path.join(process.cwd(), destComponents, "context", `${component}.tsx`);
|
|
253
|
+
copyFile(contextSrc, contextDest, `Context de "${component}"`, overwrite);
|
|
254
|
+
}
|
|
255
|
+
|
|
258
256
|
for (const mainComponent of componentsCapitalized) {
|
|
259
257
|
const componentPath = path.join(process.cwd(), options.dest, `${mainComponent}.tsx`);
|
|
260
258
|
let overwriteMain = true;
|
|
261
259
|
|
|
262
|
-
// Preguntar solo si el componente principal existe
|
|
263
260
|
if (fs.existsSync(componentPath)) {
|
|
264
261
|
const { overwrite } = await inquirer.prompt([
|
|
265
262
|
{
|
|
@@ -276,10 +273,10 @@ program
|
|
|
276
273
|
}
|
|
277
274
|
}
|
|
278
275
|
|
|
279
|
-
// 🔹 Copiar componente principal
|
|
280
276
|
copyComponentAndRecipe(mainComponent, options.dest, options.theme, overwriteMain);
|
|
281
277
|
|
|
282
|
-
|
|
278
|
+
copyContextComponentIfNeeded(mainComponent, options.dest, overwriteMain);
|
|
279
|
+
|
|
283
280
|
const deps = componentToDeps[mainComponent] || [];
|
|
284
281
|
for (const dep of deps) {
|
|
285
282
|
const depPath = path.join(process.cwd(), options.dest, `${dep}.tsx`);
|
|
@@ -291,7 +288,6 @@ program
|
|
|
291
288
|
copyComponentAndRecipe(dep, options.dest, options.theme, true);
|
|
292
289
|
}
|
|
293
290
|
|
|
294
|
-
// 🔹 Copiar íconos dependientes
|
|
295
291
|
const iconDeps = ICON_DEPENDENCIES[mainComponent] || [];
|
|
296
292
|
if (iconDeps.length > 0) {
|
|
297
293
|
console.log(`🎨 Añadiendo íconos requeridos por "${mainComponent}": ${iconDeps.join(", ")}`);
|
|
@@ -305,7 +301,6 @@ program
|
|
|
305
301
|
copyIconTemplate(iconName, options.icons);
|
|
306
302
|
}
|
|
307
303
|
|
|
308
|
-
// Asegurar que IconWrapper esté disponible
|
|
309
304
|
ensureIconWrapper(options.dest, options.theme);
|
|
310
305
|
}
|
|
311
306
|
}
|
|
@@ -336,9 +331,6 @@ function copyIconTemplate(iconName, dest) {
|
|
|
336
331
|
}
|
|
337
332
|
}
|
|
338
333
|
|
|
339
|
-
/**
|
|
340
|
-
* Copia IconWrapper si no existe en la app
|
|
341
|
-
*/
|
|
342
334
|
function ensureIconWrapper(destComponents, destTheme) {
|
|
343
335
|
const wrapperComponentDest = path.join(process.cwd(), destComponents, "IconWrapper.tsx");
|
|
344
336
|
const wrapperRecipeDest = path.join(process.cwd(), destTheme, "IconWrapper.recipe.tsx");
|
|
@@ -363,7 +355,6 @@ function ensureIconWrapper(destComponents, destTheme) {
|
|
|
363
355
|
}
|
|
364
356
|
}
|
|
365
357
|
|
|
366
|
-
// Comando CLI: add-icon
|
|
367
358
|
program
|
|
368
359
|
.command("add-icon [iconName]")
|
|
369
360
|
.description("Copia un icono basado en la plantilla Icon.tsx")
|
|
@@ -381,7 +372,6 @@ program
|
|
|
381
372
|
const finalName = rawName.charAt(0).toUpperCase() + rawName.slice(1);
|
|
382
373
|
const destPath = path.join(process.cwd(), options.dest, `${finalName}.tsx`);
|
|
383
374
|
|
|
384
|
-
// 🔹 Si ya existe, preguntar antes de sobrescribir
|
|
385
375
|
if (fs.existsSync(destPath)) {
|
|
386
376
|
const { overwrite } = await inquirer.prompt([
|
|
387
377
|
{
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import React, {ReactNode, useState} from 'react'
|
|
2
|
+
import {View, Pressable} from 'react-native'
|
|
3
|
+
import Animated from 'react-native-reanimated'
|
|
4
|
+
import {LinearTransition} from 'react-native-reanimated'
|
|
5
|
+
import {StyleSheet} from 'react-native-unistyles'
|
|
6
|
+
import Text from './Text'
|
|
7
|
+
|
|
8
|
+
type AccordionItemProps = {
|
|
9
|
+
title: string
|
|
10
|
+
itemKey: string
|
|
11
|
+
children: ReactNode
|
|
12
|
+
isOpen?: boolean
|
|
13
|
+
onToggle?: () => void
|
|
14
|
+
scrollViewRef?: any
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
type AccordionGroupRootProps = {
|
|
18
|
+
children: ReactNode
|
|
19
|
+
defaultOpenKeys?: string[]
|
|
20
|
+
allowMultiple?: boolean
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export const AccordionGroup = {
|
|
24
|
+
Root: AccordionGroupRoot,
|
|
25
|
+
Item: AccordionGroupItem,
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function AccordionGroupRoot({
|
|
29
|
+
children,
|
|
30
|
+
defaultOpenKeys = [],
|
|
31
|
+
allowMultiple = false,
|
|
32
|
+
}: AccordionGroupRootProps) {
|
|
33
|
+
const [openKeys, setOpenKeys] = useState<Set<string>>(
|
|
34
|
+
() => new Set(defaultOpenKeys),
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
const toggleItem = (key: string) => {
|
|
38
|
+
setOpenKeys(prev => {
|
|
39
|
+
const newSet = new Set(prev)
|
|
40
|
+
if (newSet.has(key)) {
|
|
41
|
+
newSet.delete(key)
|
|
42
|
+
} else {
|
|
43
|
+
if (allowMultiple) {
|
|
44
|
+
newSet.add(key)
|
|
45
|
+
} else {
|
|
46
|
+
return new Set([key])
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return newSet
|
|
50
|
+
})
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const items = React.Children.map(children, child => {
|
|
54
|
+
if (!React.isValidElement(child)) return child
|
|
55
|
+
const cp = child.props as AccordionItemProps
|
|
56
|
+
const key = cp.itemKey
|
|
57
|
+
const isOpen = openKeys.has(key)
|
|
58
|
+
return React.cloneElement(child, {
|
|
59
|
+
isOpen,
|
|
60
|
+
onToggle: () => toggleItem(key),
|
|
61
|
+
})
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
return <View style={styles.groupContainer}>{items}</View>
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function AccordionGroupItem({
|
|
68
|
+
title,
|
|
69
|
+
children,
|
|
70
|
+
isOpen = false,
|
|
71
|
+
onToggle,
|
|
72
|
+
}: AccordionItemProps) {
|
|
73
|
+
return (
|
|
74
|
+
<Animated.View
|
|
75
|
+
// Aquí aplicas la transición de layout
|
|
76
|
+
layout={LinearTransition.duration(150)}
|
|
77
|
+
style={styles.itemContainer}>
|
|
78
|
+
<Pressable onPress={onToggle} style={styles.header}>
|
|
79
|
+
<Text style={styles.headerText}>{title}</Text>
|
|
80
|
+
</Pressable>
|
|
81
|
+
|
|
82
|
+
{isOpen && (
|
|
83
|
+
<View style={styles.contentContainer}>
|
|
84
|
+
<View style={styles.innerContent}>{children}</View>
|
|
85
|
+
</View>
|
|
86
|
+
)}
|
|
87
|
+
</Animated.View>
|
|
88
|
+
)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const styles = StyleSheet.create({
|
|
92
|
+
groupContainer: {},
|
|
93
|
+
itemContainer: {
|
|
94
|
+
borderWidth: 1,
|
|
95
|
+
borderColor: '#ddd',
|
|
96
|
+
borderRadius: 6,
|
|
97
|
+
marginVertical: 8,
|
|
98
|
+
overflow: 'hidden', // importante para que no se vea contenido fuera
|
|
99
|
+
},
|
|
100
|
+
header: {
|
|
101
|
+
padding: 12,
|
|
102
|
+
backgroundColor: '#f0f0f0',
|
|
103
|
+
},
|
|
104
|
+
headerText: {
|
|
105
|
+
fontSize: 16,
|
|
106
|
+
},
|
|
107
|
+
contentContainer: {
|
|
108
|
+
// no necesitamos animar altura manual, lo hace el layout
|
|
109
|
+
},
|
|
110
|
+
innerContent: {
|
|
111
|
+
padding: 12,
|
|
112
|
+
},
|
|
113
|
+
})
|
|
@@ -10,6 +10,12 @@ type TextAdjustment = 'singleLine' | 'multiline' | 'adjustToFit'
|
|
|
10
10
|
|
|
11
11
|
type ButtonVariants = UnistylesVariants<typeof ButtonStyles>
|
|
12
12
|
|
|
13
|
+
interface TextAdjustmentProps {
|
|
14
|
+
adjustsFontSizeToFit?: boolean
|
|
15
|
+
numberOfLines?: number
|
|
16
|
+
ellipsizeMode?: 'tail' | 'head' | 'middle' | 'clip'
|
|
17
|
+
}
|
|
18
|
+
|
|
13
19
|
type ButtonProps = ButtonVariants & {
|
|
14
20
|
colorPalette?: PalettesWithNestedKeys
|
|
15
21
|
text?: string
|
|
@@ -27,6 +33,7 @@ type ButtonProps = ButtonVariants & {
|
|
|
27
33
|
size?: number
|
|
28
34
|
}
|
|
29
35
|
mixins?: StyleProp<ViewStyle> | StyleProp<ViewStyle>[]
|
|
36
|
+
style?: StyleProp<ViewStyle>
|
|
30
37
|
}
|
|
31
38
|
|
|
32
39
|
const Button = ({
|
|
@@ -42,6 +49,7 @@ const Button = ({
|
|
|
42
49
|
textAdjustment = 'singleLine',
|
|
43
50
|
icon,
|
|
44
51
|
mixins,
|
|
52
|
+
style,
|
|
45
53
|
}: ButtonProps) => {
|
|
46
54
|
ButtonStyles.useVariants({
|
|
47
55
|
size,
|
|
@@ -50,7 +58,7 @@ const Button = ({
|
|
|
50
58
|
})
|
|
51
59
|
|
|
52
60
|
const getTextProps = useMemo(
|
|
53
|
-
() => ():
|
|
61
|
+
() => (): TextAdjustmentProps => {
|
|
54
62
|
switch (textAdjustment) {
|
|
55
63
|
case 'adjustToFit':
|
|
56
64
|
return {adjustsFontSizeToFit: true, numberOfLines: 1}
|
|
@@ -87,6 +95,7 @@ const Button = ({
|
|
|
87
95
|
styles.container(flex, maxWidth),
|
|
88
96
|
ButtonStyles.container(colorPalette),
|
|
89
97
|
mixins && mixins,
|
|
98
|
+
style,
|
|
90
99
|
]}
|
|
91
100
|
onPress={onPress}
|
|
92
101
|
disabled={disabled || loading}>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import {useEffect} from 'react'
|
|
2
|
-
import {View,
|
|
2
|
+
import {TextStyle, View, ViewStyle} from 'react-native'
|
|
3
3
|
import Animated, {
|
|
4
4
|
Easing,
|
|
5
5
|
interpolate,
|
|
@@ -10,9 +10,15 @@ import Animated, {
|
|
|
10
10
|
} from 'react-native-reanimated'
|
|
11
11
|
import Svg, {Circle, G} from 'react-native-svg'
|
|
12
12
|
import {circleProgressTokens} from '../theme/CircleProgress.recipe'
|
|
13
|
-
import {withUnistyles} from 'react-native-unistyles'
|
|
13
|
+
import {withUnistyles, StyleSheet} from 'react-native-unistyles'
|
|
14
14
|
import {resolveColor} from '../style/varia/utils'
|
|
15
|
-
import {
|
|
15
|
+
import {
|
|
16
|
+
NestedColorsType,
|
|
17
|
+
PalettesWithNestedKeys,
|
|
18
|
+
progressDirection,
|
|
19
|
+
rotationDirection,
|
|
20
|
+
ThemeType,
|
|
21
|
+
} from '../style/varia/types'
|
|
16
22
|
import {SharedValue} from 'react-native-reanimated'
|
|
17
23
|
|
|
18
24
|
const AnimatedCircle = Animated.createAnimatedComponent(Circle)
|
|
@@ -22,17 +28,19 @@ interface CircleProgressProps {
|
|
|
22
28
|
variant?: keyof typeof circleProgressTokens.variants.variant
|
|
23
29
|
size?: keyof typeof circleProgressTokens.variants.size
|
|
24
30
|
trackStrokeWidth?: number
|
|
25
|
-
progress: SharedValue<number>
|
|
26
|
-
|
|
31
|
+
progress: SharedValue<number>
|
|
27
32
|
progressStrokeWidth?: number
|
|
28
33
|
duration: number
|
|
29
34
|
trackColor?: string
|
|
30
35
|
progressColor?: string
|
|
31
|
-
progressDirection?:
|
|
32
|
-
rotationDirection?:
|
|
36
|
+
progressDirection?: progressDirection
|
|
37
|
+
rotationDirection?: rotationDirection
|
|
33
38
|
children?: React.ReactNode
|
|
34
|
-
fontSize?:
|
|
35
|
-
colors:
|
|
39
|
+
fontSize?: TextStyle['fontSize']
|
|
40
|
+
colors: NestedColorsType
|
|
41
|
+
flex?: ViewStyle['flex']
|
|
42
|
+
width?: ViewStyle['width']
|
|
43
|
+
height?: ViewStyle['height']
|
|
36
44
|
}
|
|
37
45
|
|
|
38
46
|
const BaseCircleProgress = ({
|
|
@@ -49,6 +57,9 @@ const BaseCircleProgress = ({
|
|
|
49
57
|
rotationDirection = 'clockwise',
|
|
50
58
|
children,
|
|
51
59
|
colors,
|
|
60
|
+
flex = 1,
|
|
61
|
+
width = '100%',
|
|
62
|
+
height,
|
|
52
63
|
}: CircleProgressProps) => {
|
|
53
64
|
const resolvedSize = circleProgressTokens.variants.size[size]
|
|
54
65
|
|
|
@@ -106,7 +117,7 @@ const BaseCircleProgress = ({
|
|
|
106
117
|
})
|
|
107
118
|
|
|
108
119
|
return (
|
|
109
|
-
<View style={styles.container}>
|
|
120
|
+
<View style={styles.container(flex, width, height)}>
|
|
110
121
|
<Svg
|
|
111
122
|
width="100%"
|
|
112
123
|
height="100%"
|
|
@@ -143,16 +154,17 @@ const BaseCircleProgress = ({
|
|
|
143
154
|
}
|
|
144
155
|
|
|
145
156
|
const styles = StyleSheet.create({
|
|
146
|
-
container:
|
|
157
|
+
container: (
|
|
158
|
+
flex: ViewStyle['flex'],
|
|
159
|
+
width: ViewStyle['width'],
|
|
160
|
+
height: ViewStyle['height'],
|
|
161
|
+
) => ({
|
|
147
162
|
aspectRatio: 1,
|
|
148
|
-
flex
|
|
149
|
-
|
|
163
|
+
flex,
|
|
164
|
+
maxWidth: width,
|
|
165
|
+
maxHeight: height,
|
|
166
|
+
}),
|
|
150
167
|
childContainer: {
|
|
151
|
-
position: 'absolute',
|
|
152
|
-
top: 0,
|
|
153
|
-
left: 0,
|
|
154
|
-
right: 0,
|
|
155
|
-
bottom: 0,
|
|
156
168
|
justifyContent: 'center',
|
|
157
169
|
alignItems: 'center',
|
|
158
170
|
},
|
|
@@ -163,6 +175,3 @@ const CircleProgress = withUnistyles(BaseCircleProgress, theme => ({
|
|
|
163
175
|
}))
|
|
164
176
|
|
|
165
177
|
export default CircleProgress
|
|
166
|
-
|
|
167
|
-
const clamp = (num: number, min: number, max: number) =>
|
|
168
|
-
Math.min(Math.max(num, min), max)
|
|
@@ -1,24 +1,27 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
1
|
+
import {View} from 'react-native'
|
|
2
|
+
import {StyleSheet} from 'react-native-unistyles'
|
|
3
|
+
import {PalettesWithNestedKeys, ThemeColors} from '../style/varia/types'
|
|
4
|
+
import {resolveColor} from '../style/varia/utils'
|
|
4
5
|
|
|
5
6
|
const Divider = ({
|
|
6
7
|
color,
|
|
7
8
|
size = 1,
|
|
8
9
|
axis = 'y',
|
|
9
10
|
margin = 0,
|
|
11
|
+
colorPalette = 'accent',
|
|
10
12
|
}: {
|
|
11
|
-
color?:
|
|
12
|
-
size?: number
|
|
13
|
-
axis?: 'x' | 'y'
|
|
14
|
-
margin?: number
|
|
13
|
+
color?: ThemeColors
|
|
14
|
+
size?: number
|
|
15
|
+
axis?: 'x' | 'y'
|
|
16
|
+
margin?: number
|
|
17
|
+
colorPalette?: PalettesWithNestedKeys
|
|
15
18
|
}) => {
|
|
16
19
|
return (
|
|
17
20
|
<View style={styles.container(size, axis, margin)}>
|
|
18
|
-
<View style={[styles.divider(color, size, axis)]} />
|
|
21
|
+
<View style={[styles.divider(color, colorPalette, size, axis)]} />
|
|
19
22
|
</View>
|
|
20
|
-
)
|
|
21
|
-
}
|
|
23
|
+
)
|
|
24
|
+
}
|
|
22
25
|
|
|
23
26
|
const styles = StyleSheet.create(theme => ({
|
|
24
27
|
container: (size, axis, margin) => ({
|
|
@@ -31,13 +34,13 @@ const styles = StyleSheet.create(theme => ({
|
|
|
31
34
|
marginHorizontal: axis === 'x' ? margin : 0,
|
|
32
35
|
marginVertical: axis === 'y' ? margin : 0,
|
|
33
36
|
}),
|
|
34
|
-
divider: (color, size, axis) => ({
|
|
37
|
+
divider: (color, colorPalette, size, axis) => ({
|
|
35
38
|
width: axis === 'x' ? size : '100%',
|
|
36
39
|
height: axis === 'y' ? size : '100%',
|
|
37
40
|
backgroundColor: color
|
|
38
|
-
? color
|
|
39
|
-
: theme.colors.
|
|
41
|
+
? resolveColor(color, theme.colors, colorPalette)
|
|
42
|
+
: theme.colors.fg.default,
|
|
40
43
|
}),
|
|
41
|
-
}))
|
|
44
|
+
}))
|
|
42
45
|
|
|
43
|
-
export default Divider
|
|
46
|
+
export default Divider
|
|
@@ -202,7 +202,6 @@ type InternalDrawerSliderProps = {
|
|
|
202
202
|
externalTranslate?: SharedValue<number>
|
|
203
203
|
}
|
|
204
204
|
|
|
205
|
-
// Tipo público — el que exportas (sin direction)
|
|
206
205
|
export type DrawerSliderProps = Omit<
|
|
207
206
|
InternalDrawerSliderProps,
|
|
208
207
|
'direction' | 'axis'
|
|
@@ -238,7 +237,6 @@ const DrawerSliderInternal = ({
|
|
|
238
237
|
const animationVariant = SlidingDrawerTokens.variants.animation[animation]
|
|
239
238
|
const VELOCITY_THRESHOLD = 2000
|
|
240
239
|
|
|
241
|
-
// --- shared values base ---
|
|
242
240
|
const viewRef = useAnimatedRef<Animated.View>()
|
|
243
241
|
const translate = useSharedValue(screenHeight)
|
|
244
242
|
const context = useSharedValue({position: screenHeight, snapPoint: 0})
|
|
@@ -254,37 +252,7 @@ const DrawerSliderInternal = ({
|
|
|
254
252
|
)
|
|
255
253
|
}
|
|
256
254
|
|
|
257
|
-
// --- medir el contenido dinámicamente ---
|
|
258
|
-
// const onLayout = () => {
|
|
259
|
-
// scheduleOnUI(() => {
|
|
260
|
-
// 'worklet'
|
|
261
|
-
// const measured = measure(viewRef)
|
|
262
|
-
// if (measured) {
|
|
263
|
-
// const {height} = measured
|
|
264
|
-
// contentHeight.value = height
|
|
265
|
-
|
|
266
|
-
// // resuelve snapPoints declarativos
|
|
267
|
-
// const resolved = snapPoints.map(p => {
|
|
268
|
-
// if (p === 'hidden') return screenHeight * direction
|
|
269
|
-
// if (p === 'content') return (screenHeight - height) * direction
|
|
270
|
-
// // if (typeof p === 'string' && p.endsWith('%')) {
|
|
271
|
-
// // const percentage = parseFloat(p) / 100
|
|
272
|
-
// // return screenHeight * (1 - percentage) * direction
|
|
273
|
-
// // }
|
|
274
|
-
// return p * direction
|
|
275
|
-
// })
|
|
276
|
-
|
|
277
|
-
// resolvedSnapPoints.value = resolved
|
|
278
|
-
|
|
279
|
-
// // inicializa la posición (oculto)
|
|
280
|
-
// translate.value = resolved[0]
|
|
281
|
-
// context.value = {position: resolved[0], snapPoint: 0}
|
|
282
|
-
// }
|
|
283
|
-
// })
|
|
284
|
-
// }
|
|
285
|
-
|
|
286
255
|
const onLayout = () => {
|
|
287
|
-
// captura valores aquí (en JS)
|
|
288
256
|
const _screenHeight = screenHeight
|
|
289
257
|
const _screenWidth = screenWidth
|
|
290
258
|
const _axis = axis
|
|
@@ -316,10 +284,13 @@ const DrawerSliderInternal = ({
|
|
|
316
284
|
'worklet'
|
|
317
285
|
return resolvedSnapPoints.value.length > 0
|
|
318
286
|
? resolvedSnapPoints.value
|
|
319
|
-
: snapPoints.map(p =>
|
|
287
|
+
: snapPoints.map(p => {
|
|
288
|
+
// if (p === 'hidden') return screenHeight * direction
|
|
289
|
+
// if (p === 'content') return (screenHeight - contentHeight.value) * direction
|
|
290
|
+
return (p as number) * direction
|
|
291
|
+
})
|
|
320
292
|
}
|
|
321
293
|
|
|
322
|
-
// --- lógica de snapping ---
|
|
323
294
|
const updateCurrentSnapPoint = (snapPoint: number) => {
|
|
324
295
|
'worklet'
|
|
325
296
|
context.value = {position: context.value.position, snapPoint}
|
|
@@ -374,7 +345,6 @@ const DrawerSliderInternal = ({
|
|
|
374
345
|
isCollapsed,
|
|
375
346
|
}))
|
|
376
347
|
|
|
377
|
-
// --- sincronizar overlay con movimiento ---
|
|
378
348
|
useAnimatedReaction(
|
|
379
349
|
() => translate.value,
|
|
380
350
|
value => {
|
|
@@ -392,7 +362,6 @@ const DrawerSliderInternal = ({
|
|
|
392
362
|
},
|
|
393
363
|
)
|
|
394
364
|
|
|
395
|
-
// --- Gestures ---
|
|
396
365
|
const slideGesture = Gesture.Pan()
|
|
397
366
|
.enabled(allowGestures)
|
|
398
367
|
.onBegin(() => {
|
|
@@ -408,16 +377,13 @@ const DrawerSliderInternal = ({
|
|
|
408
377
|
|
|
409
378
|
if (proposed < minPoint) {
|
|
410
379
|
if (lockAtEdges) {
|
|
411
|
-
// Bloquea overscroll superior (cuando ya estás en el extremo)
|
|
412
380
|
clamped = minPoint
|
|
413
381
|
} else {
|
|
414
|
-
// Aplica resistencia
|
|
415
382
|
const overdrag = minPoint - proposed
|
|
416
383
|
clamped = minPoint - overdrag / (1 + overdrag / 60)
|
|
417
384
|
}
|
|
418
385
|
} else if (proposed > maxPoint) {
|
|
419
386
|
if (lockAtEdges) {
|
|
420
|
-
// Bloquea overscroll inferior
|
|
421
387
|
clamped = maxPoint
|
|
422
388
|
} else {
|
|
423
389
|
const overdrag = proposed - maxPoint
|
|
@@ -477,7 +443,6 @@ const DrawerSliderInternal = ({
|
|
|
477
443
|
}
|
|
478
444
|
})
|
|
479
445
|
|
|
480
|
-
// --- estilos animados ---
|
|
481
446
|
const blockAnimatedStyle = useAnimatedStyle(() => {
|
|
482
447
|
return {
|
|
483
448
|
transform: [
|
|
@@ -504,10 +469,6 @@ const DrawerSliderInternal = ({
|
|
|
504
469
|
)
|
|
505
470
|
}
|
|
506
471
|
|
|
507
|
-
/* -----------------------------
|
|
508
|
-
* Export grouped
|
|
509
|
-
* ----------------------------*/
|
|
510
|
-
|
|
511
472
|
export const Drawer = {
|
|
512
473
|
Root: DrawerRoot,
|
|
513
474
|
Positioner: DrawerPositioner,
|
|
@@ -515,10 +476,6 @@ export const Drawer = {
|
|
|
515
476
|
Slider: DrawerSlider,
|
|
516
477
|
}
|
|
517
478
|
|
|
518
|
-
/* -----------------------------
|
|
519
|
-
* Styles
|
|
520
|
-
* ----------------------------*/
|
|
521
|
-
|
|
522
479
|
const styles = StyleSheet.create((theme, rt) => ({
|
|
523
480
|
positioner: {
|
|
524
481
|
flex: 1,
|