native-pytech 1.0.1 → 1.0.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/README.md CHANGED
@@ -8,23 +8,59 @@ Librería de componentes y utilidades para apps **React Native** / **Expo** (Pyt
8
8
  npm install native-pytech
9
9
  ```
10
10
 
11
+ Para mantener actualizado:
12
+
13
+ ```bash
14
+ npx expo install native-pytech@latest
15
+ ```
16
+
11
17
  Instalá también las **peer dependencies** que use tu app (Expo, React Native, etc.). Revisá la sección `peerDependencies` en el `package.json` del paquete o de este repo.
12
18
 
13
19
  ## Uso
14
20
 
15
- Entrada principal (reexporta los módulos públicos):
16
-
17
21
  ```ts
18
- import { ... } from 'native-pytech'
22
+ import { ... } from 'native-pytech/{submodulo}'
19
23
  ```
20
24
 
21
- Submódulos (ejemplos):
25
+ Ejemplos:
22
26
 
23
27
  ```ts
24
- import { ... } from 'native-pytech/login'
25
- import { ... } from 'native-pytech/supabase'
28
+ import Login, { ... } from 'native-pytech/login'
29
+ import Table, { ... } from 'native-pytech/table'
26
30
  ```
27
31
 
32
+ # Rutas disponibles
33
+
34
+ - `/assets`
35
+ - `/components`
36
+ - `/RemoveCircle`
37
+ - `/ReorderThreeOutline`
38
+ - `/images`
39
+ - `/ionicons`
40
+ - `/components`
41
+ - `/Gradient`
42
+ - `/CloseButton`
43
+ - `/Link`
44
+ - `/Text`
45
+ - `/Theme`
46
+ - `/constants`
47
+ - `/colors`
48
+ - `/consts`
49
+ - `/handleFontObserver`
50
+ - `/hooks`
51
+ - `/utils`
52
+ - `/editPage`
53
+ - `/footer`
54
+ - `/login`
55
+ - `/page`
56
+ - `/providers`
57
+ - `/app`
58
+ - `/segmentedControl`
59
+ - `/sql`
60
+ - `/supabase`
61
+ - `/swiftui`
62
+ - `/table`
63
+
28
64
  ## Licencia
29
65
 
30
66
  MIT — ver `LICENSE`.
@@ -0,0 +1 @@
1
+ export { default } from '../libs/editPage';
@@ -0,0 +1 @@
1
+ export { default } from '../libs/editPage';
@@ -0,0 +1,7 @@
1
+ import Page from './src/components/Page';
2
+ import Item from './src/components/Item';
3
+ type EditPageComponent = typeof Page & {
4
+ Item: typeof Item;
5
+ };
6
+ declare const EditPage: EditPageComponent;
7
+ export default EditPage;
@@ -0,0 +1,5 @@
1
+ import Page from './src/components/Page';
2
+ import Item from './src/components/Item';
3
+ const EditPage = Page;
4
+ EditPage.Item = Item;
5
+ export default EditPage;
@@ -0,0 +1,4 @@
1
+ import React from 'react';
2
+ import type Props from './types';
3
+ declare const _default: React.MemoExoticComponent<({ label, minLengthSpacer, ...textFieldProps }: Props) => React.JSX.Element>;
4
+ export default _default;
@@ -0,0 +1,12 @@
1
+ import { HStack, Spacer, Text } from '@expo/ui/swift-ui';
2
+ import React, { memo } from 'react';
3
+ import TextField from '../TextField';
4
+ export default memo(({ label, minLengthSpacer, ...textFieldProps }) => {
5
+ if (!label)
6
+ return <TextField {...textFieldProps}/>;
7
+ return (<HStack>
8
+ <Text>{label}</Text>
9
+ <Spacer minLength={minLengthSpacer}/>
10
+ <TextField {...textFieldProps}/>
11
+ </HStack>);
12
+ });
@@ -0,0 +1,15 @@
1
+ import { type SpacerProps } from "@expo/ui/swift-ui";
2
+ import type TextFieldProps from '../TextField/types';
3
+ type Props = TextFieldProps & {
4
+ /**
5
+ Text to display on the left of the text field.
6
+ If not provided, the item will be only a text field.
7
+ */
8
+ label?: string;
9
+ /**
10
+ Minimum length of the spacer between the title and the text field.
11
+ If the title is not provided, will not be displayed.
12
+ */
13
+ minLengthSpacer?: SpacerProps['minLength'];
14
+ };
15
+ export default Props;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,5 @@
1
+ import React from 'react';
2
+ import Props from './types';
3
+ declare function Component<T>({ data, renderItem, onSave, }: Props<T>): React.JSX.Element;
4
+ declare const _default: typeof Component;
5
+ export default _default;
@@ -0,0 +1,84 @@
1
+ import { Host, List, Section } from '@expo/ui/swift-ui';
2
+ import { useObservable, useValue } from '@legendapp/state/react';
3
+ import { Stack, useRouter } from 'expo-router';
4
+ import React, { memo, useCallback, useMemo, useRef } from 'react';
5
+ import { useEffectWithoutFirstRender } from '../../../../../libs/constants/hooks';
6
+ import { Provider } from '../../context/page';
7
+ import { Provider as ItemProvider } from '../../context/item';
8
+ function Component({ data = [], renderItem, onSave, }) {
9
+ // ------------------- Variables -------------------
10
+ const router = useRouter();
11
+ const saveEnabledRef = useRef(false);
12
+ const values = (data ?? []).reduce((acc, item, index) => {
13
+ acc[index] = {
14
+ value: undefined,
15
+ hasChanged: false,
16
+ isValid: true,
17
+ };
18
+ return acc;
19
+ }, {});
20
+ const store = useObservable({
21
+ values: values,
22
+ saveEnabled: (() => {
23
+ const values = store.values.get();
24
+ const listValues = Object.values(values);
25
+ const hasChanged = listValues.some(value => value.hasChanged);
26
+ const allValid = listValues.every(value => value.isValid);
27
+ return hasChanged && allValid;
28
+ }),
29
+ });
30
+ const saveEnabled = useValue(() => store.saveEnabled.get());
31
+ useEffectWithoutFirstRender(() => {
32
+ saveEnabledRef.current = saveEnabled;
33
+ }, [saveEnabled]);
34
+ const textFieldsRefs = useRef({});
35
+ // ------------------- Functions -------------------
36
+ const onPressSave = useCallback(async () => {
37
+ // Obtengo los valores del store
38
+ const values = store.values.peek();
39
+ const valuesToSave = Object.values(values).map(value => value.value ?? null);
40
+ // Llamo a la función onSave
41
+ const result = await onSave?.(valuesToSave);
42
+ if (result === false)
43
+ return;
44
+ router.back();
45
+ }, [onSave, store.values]);
46
+ // ------------------- Provider -------------------
47
+ const value = useMemo(() => ({
48
+ store,
49
+ saveEnabledRef,
50
+ onPressSave,
51
+ isUniqueItem: (data?.length ?? 0) === 1,
52
+ textFieldsRefs
53
+ }), []);
54
+ return (<>
55
+ <Stack.Toolbar placement="left">
56
+ <Stack.Toolbar.Button onPress={() => router.back()}>
57
+ <Stack.Toolbar.Icon sf="xmark"/>
58
+ </Stack.Toolbar.Button>
59
+ </Stack.Toolbar>
60
+
61
+ <Stack.Toolbar placement="right">
62
+ <Stack.Toolbar.Button disabled={!saveEnabled} variant="done" onPress={onPressSave}>
63
+ <Stack.Toolbar.Icon sf="checkmark"/>
64
+ </Stack.Toolbar.Button>
65
+ </Stack.Toolbar>
66
+
67
+ <Host style={{ flex: 1 }}>
68
+ <List>
69
+ <Section>
70
+ <Provider value={value}>
71
+ {data.map((item, index) => {
72
+ const nextIndex = index + 1;
73
+ const value = { index, nextIndex: nextIndex < data.length ? nextIndex : undefined };
74
+ return (<ItemProvider key={index} value={value}>
75
+ {renderItem?.(item)}
76
+ </ItemProvider>);
77
+ })}
78
+ </Provider>
79
+ </Section>
80
+ </List>
81
+ </Host>
82
+ </>);
83
+ }
84
+ export default memo(Component);
@@ -0,0 +1,26 @@
1
+ type Props<T> = {
2
+ /**
3
+ The data items to be rendered inside the list.
4
+ @default []
5
+ */
6
+ data?: T[];
7
+ /**
8
+ The function to render the item.
9
+ */
10
+ renderItem?: (item: T) => React.ReactNode;
11
+ /**
12
+ Function to be called when the user saves the changes.
13
+ If the function returns true, the user will be redirected to the previous screen.
14
+ */
15
+ onSave?: (values: (string | null)[]) => boolean | Promise<boolean>;
16
+ };
17
+ export type Values = Record<number, {
18
+ value: string | null | undefined;
19
+ hasChanged: boolean;
20
+ isValid: boolean;
21
+ }>;
22
+ export type Store = {
23
+ values: Values;
24
+ saveEnabled: boolean;
25
+ };
26
+ export default Props;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,4 @@
1
+ import React from "react";
2
+ import type Props from './types';
3
+ declare const _default: React.MemoExoticComponent<({ defaultValue, placeholder, keyboardType, autocapitalization, secureTextEntry, isValid, }: Props) => React.JSX.Element>;
4
+ export default _default;
@@ -0,0 +1,55 @@
1
+ import React, { useMemo, memo, useRef, useCallback, useEffect } from "react";
2
+ import { SecureField, TextField } from "@expo/ui/swift-ui";
3
+ import { keyboardType as keyboardTypeModifier, submitLabel, textInputAutocapitalization, onSubmit } from '@expo/ui/swift-ui/modifiers';
4
+ import { usePage } from '../../context/page';
5
+ import { useItem } from '../../context/item';
6
+ export default memo(({ defaultValue, placeholder, keyboardType, autocapitalization = true, secureTextEntry, isValid, }) => {
7
+ // ------------------- Variables -------------------
8
+ const { store, isUniqueItem, saveEnabledRef, onPressSave, textFieldsRefs } = usePage();
9
+ const { index, nextIndex } = useItem();
10
+ const ref = useRef(null);
11
+ textFieldsRefs.current[index] = ref;
12
+ useEffect(() => {
13
+ store.values[index].value.set(defaultValue);
14
+ }, [defaultValue]);
15
+ // -------------------- Functions --------------------
16
+ const onValueChange = useCallback((value) => {
17
+ const _value = value.trim() === '' ? null : value.trim();
18
+ store.values[index].set({
19
+ value: _value,
20
+ hasChanged: _value !== defaultValue,
21
+ isValid: isValid?.(_value) ?? true,
22
+ });
23
+ }, []);
24
+ const _onSubmit = useCallback(() => {
25
+ // Guarda los cambios
26
+ if (isUniqueItem) {
27
+ const saveEnabled = saveEnabledRef.current;
28
+ if (!saveEnabled)
29
+ return;
30
+ onPressSave();
31
+ return;
32
+ }
33
+ // Va al siguiente campo
34
+ if (!nextIndex)
35
+ return;
36
+ textFieldsRefs.current[nextIndex].current?.focus();
37
+ }, []);
38
+ // -------------------- Props --------------------
39
+ const modifiers = useMemo(() => [
40
+ ...(isUniqueItem ? [submitLabel('done')] : []),
41
+ ...(keyboardType ? [keyboardTypeModifier(keyboardType)] : []),
42
+ ...(!autocapitalization ? [textInputAutocapitalization('never')] : []),
43
+ onSubmit(_onSubmit),
44
+ ], [keyboardType, autocapitalization, isUniqueItem]);
45
+ const props = useMemo(() => ({
46
+ autoFocus: isUniqueItem,
47
+ modifiers,
48
+ placeholder,
49
+ defaultValue,
50
+ onValueChange,
51
+ }), [modifiers, placeholder, defaultValue]);
52
+ if (secureTextEntry)
53
+ return <SecureField {...props} ref={ref}/>;
54
+ return <TextField {...props} ref={ref}/>;
55
+ });
@@ -0,0 +1,29 @@
1
+ import { keyboardType } from "@expo/ui/swift-ui/modifiers";
2
+ type Props = {
3
+ /**
4
+ Default value of the text field.
5
+ */
6
+ defaultValue?: string;
7
+ /**
8
+ Placeholder of the text field.
9
+ */
10
+ placeholder?: string;
11
+ /**
12
+ Keyboard type. Uses the keyboardType modifier.
13
+ */
14
+ keyboardType?: Parameters<typeof keyboardType>[0];
15
+ /**
16
+ If true, the text field will be autocapitalized. Uses the textInputAutocapitalization modifier.
17
+ @default true
18
+ */
19
+ autocapitalization?: boolean;
20
+ /**
21
+ If true, the text field will be secure (password).
22
+ */
23
+ secureTextEntry?: boolean;
24
+ /**
25
+ Function to validate the value.
26
+ */
27
+ isValid?: (value: string | null) => boolean;
28
+ };
29
+ export default Props;
@@ -0,0 +1,7 @@
1
+ export declare const Provider: import("react").Provider<{
2
+ index: number;
3
+ nextIndex?: number;
4
+ }>, useItem: () => {
5
+ index: number;
6
+ nextIndex?: number;
7
+ };
@@ -0,0 +1,2 @@
1
+ import { createCtx } from '../../../../libs/constants/utils';
2
+ export const [Provider, useItem] = createCtx();
@@ -0,0 +1,18 @@
1
+ import type { Observable } from '@legendapp/state';
2
+ import { TextFieldRef } from '@expo/ui/swift-ui';
3
+ import type { RefObject } from 'react';
4
+ import type { Store } from '../components/Page/types';
5
+ export type TextFieldsRefsType = Record<number, RefObject<TextFieldRef | null>>;
6
+ export declare const Provider: import("react").Provider<{
7
+ store: Observable<Store>;
8
+ saveEnabledRef: RefObject<boolean>;
9
+ onPressSave: () => Promise<void>;
10
+ isUniqueItem: boolean;
11
+ textFieldsRefs: RefObject<TextFieldsRefsType>;
12
+ }>, usePage: () => {
13
+ store: Observable<Store>;
14
+ saveEnabledRef: RefObject<boolean>;
15
+ onPressSave: () => Promise<void>;
16
+ isUniqueItem: boolean;
17
+ textFieldsRefs: RefObject<TextFieldsRefsType>;
18
+ };
@@ -0,0 +1,2 @@
1
+ import { createCtx } from '../../../../libs/constants/utils';
2
+ export const [Provider, usePage] = createCtx();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "native-pytech",
3
- "version": "1.0.1",
3
+ "version": "1.0.4",
4
4
  "description": "Libreria de React Native Pytech",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -9,7 +9,8 @@
9
9
  "scripts": {
10
10
  "build": "node scripts/build.js",
11
11
  "typecheck": "tsc --noEmit",
12
- "prepublishOnly": "npm run build"
12
+ "prepublishOnly": "npm run build",
13
+ "release": "npm version patch && npm publish"
13
14
  },
14
15
  "files": [
15
16
  "dist",