@lssm/lib.presentation-runtime-react-native 3.0.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.
- package/dist/index.d.ts +111 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +127 -0
- package/dist/index.js.map +1 -0
- package/dist/nativewind-env.d.ts +1 -0
- package/dist/ui-kit/dist/ui/form.js +16 -0
- package/dist/ui-kit/dist/ui/form.js.map +1 -0
- package/package.json +43 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { DefaultValues, Resolver, UseFormReturn } from "react-hook-form";
|
|
3
|
+
|
|
4
|
+
//#region src/index.d.ts
|
|
5
|
+
interface UsePresentationControllerOpts<TFilters extends Record<string, unknown>, TVars, TItem> {
|
|
6
|
+
defaults: ListState<TFilters>;
|
|
7
|
+
form: {
|
|
8
|
+
defaultValues: DefaultValues<TFilters>;
|
|
9
|
+
resolver?: Resolver<TFilters>;
|
|
10
|
+
};
|
|
11
|
+
toVariables: (input: ListState<TFilters>) => TVars;
|
|
12
|
+
fetcher: ListFetcher<TVars, TItem>;
|
|
13
|
+
toChips?: (filters: TFilters, setFilter: (key: keyof TFilters, value: TFilters[keyof TFilters] | null) => void) => {
|
|
14
|
+
key: string;
|
|
15
|
+
label: React.ReactNode;
|
|
16
|
+
onRemove?: () => void;
|
|
17
|
+
}[];
|
|
18
|
+
useUrlState: (args: {
|
|
19
|
+
defaults: ListState<TFilters>;
|
|
20
|
+
replace?: boolean;
|
|
21
|
+
}) => {
|
|
22
|
+
state: ListState<TFilters>;
|
|
23
|
+
setState: (next: Partial<ListState<TFilters>>) => void;
|
|
24
|
+
setFilter: (key: keyof TFilters, value: TFilters[keyof TFilters] | null) => void;
|
|
25
|
+
clearFilters: () => void;
|
|
26
|
+
};
|
|
27
|
+
replace?: boolean;
|
|
28
|
+
}
|
|
29
|
+
declare function usePresentationController<TFilters extends Record<string, unknown>, TVars, TItem>({
|
|
30
|
+
defaults,
|
|
31
|
+
form: formOpts,
|
|
32
|
+
toVariables,
|
|
33
|
+
fetcher,
|
|
34
|
+
toChips,
|
|
35
|
+
useUrlState,
|
|
36
|
+
replace
|
|
37
|
+
}: UsePresentationControllerOpts<TFilters, TVars, TItem>): {
|
|
38
|
+
readonly form: UseFormReturn<TFilters>;
|
|
39
|
+
readonly url: {
|
|
40
|
+
state: ListState<TFilters>;
|
|
41
|
+
setState: (next: Partial<ListState<TFilters>>) => void;
|
|
42
|
+
setFilter: (key: keyof TFilters, value: TFilters[keyof TFilters] | null) => void;
|
|
43
|
+
clearFilters: () => void;
|
|
44
|
+
};
|
|
45
|
+
readonly variables: TVars;
|
|
46
|
+
readonly data: TItem[];
|
|
47
|
+
readonly loading: boolean;
|
|
48
|
+
readonly error: unknown;
|
|
49
|
+
readonly totalItems: number | undefined;
|
|
50
|
+
readonly totalPages: number | undefined;
|
|
51
|
+
readonly refetch: () => Promise<void>;
|
|
52
|
+
readonly chips: {
|
|
53
|
+
key: string;
|
|
54
|
+
label: React.ReactNode;
|
|
55
|
+
onRemove?: () => void;
|
|
56
|
+
}[];
|
|
57
|
+
readonly setSearch: (q: string) => void;
|
|
58
|
+
readonly submitFilters: any;
|
|
59
|
+
readonly clearAll: () => void;
|
|
60
|
+
};
|
|
61
|
+
interface UseListCoordinatorOpts<TFilters extends Record<string, unknown>, TVars> {
|
|
62
|
+
defaults: ListState<TFilters>;
|
|
63
|
+
form: {
|
|
64
|
+
defaultValues: DefaultValues<TFilters>;
|
|
65
|
+
resolver?: Resolver<TFilters>;
|
|
66
|
+
};
|
|
67
|
+
toVariables: (input: ListState<TFilters>) => TVars;
|
|
68
|
+
toChips?: (filters: TFilters, setFilter: (key: keyof TFilters, value: TFilters[keyof TFilters] | null) => void) => {
|
|
69
|
+
key: string;
|
|
70
|
+
label: React.ReactNode;
|
|
71
|
+
onRemove?: () => void;
|
|
72
|
+
}[];
|
|
73
|
+
useUrlState: (args: {
|
|
74
|
+
defaults: ListState<TFilters>;
|
|
75
|
+
replace?: boolean;
|
|
76
|
+
}) => {
|
|
77
|
+
state: ListState<TFilters>;
|
|
78
|
+
setState: (next: Partial<ListState<TFilters>>) => void;
|
|
79
|
+
setFilter: (key: keyof TFilters, value: TFilters[keyof TFilters] | null) => void;
|
|
80
|
+
clearFilters: () => void;
|
|
81
|
+
};
|
|
82
|
+
replace?: boolean;
|
|
83
|
+
}
|
|
84
|
+
declare function useListCoordinator<TFilters extends Record<string, unknown>, TVars>({
|
|
85
|
+
defaults,
|
|
86
|
+
form: formOpts,
|
|
87
|
+
toVariables,
|
|
88
|
+
toChips,
|
|
89
|
+
useUrlState,
|
|
90
|
+
replace
|
|
91
|
+
}: UseListCoordinatorOpts<TFilters, TVars>): {
|
|
92
|
+
readonly form: UseFormReturn<TFilters>;
|
|
93
|
+
readonly url: {
|
|
94
|
+
state: ListState<TFilters>;
|
|
95
|
+
setState: (next: Partial<ListState<TFilters>>) => void;
|
|
96
|
+
setFilter: (key: keyof TFilters, value: TFilters[keyof TFilters] | null) => void;
|
|
97
|
+
clearFilters: () => void;
|
|
98
|
+
};
|
|
99
|
+
readonly variables: TVars;
|
|
100
|
+
readonly chips: {
|
|
101
|
+
key: string;
|
|
102
|
+
label: React.ReactNode;
|
|
103
|
+
onRemove?: () => void;
|
|
104
|
+
}[];
|
|
105
|
+
readonly setSearch: (q: string) => void;
|
|
106
|
+
readonly submitFilters: any;
|
|
107
|
+
readonly clearAll: () => void;
|
|
108
|
+
};
|
|
109
|
+
//#endregion
|
|
110
|
+
export { UseListCoordinatorOpts, UsePresentationControllerOpts, useListCoordinator, usePresentationController };
|
|
111
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/index.ts"],"sourcesContent":[],"mappings":"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"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { useForm } from "./ui-kit/dist/ui/form.js";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
|
|
4
|
+
//#region src/index.ts
|
|
5
|
+
function usePresentationController({ defaults, form: formOpts, toVariables, fetcher, toChips, useUrlState, replace }) {
|
|
6
|
+
const url = useUrlState({
|
|
7
|
+
defaults,
|
|
8
|
+
replace
|
|
9
|
+
});
|
|
10
|
+
const form = useForm({
|
|
11
|
+
defaultValues: formOpts.defaultValues,
|
|
12
|
+
resolver: formOpts.resolver
|
|
13
|
+
});
|
|
14
|
+
React.useEffect(() => {
|
|
15
|
+
form.reset({
|
|
16
|
+
...form.getValues(),
|
|
17
|
+
...url.state.filters
|
|
18
|
+
});
|
|
19
|
+
}, [url.state.filters]);
|
|
20
|
+
const submitFilters = form.handleSubmit((values) => {
|
|
21
|
+
url.setState({
|
|
22
|
+
filters: values,
|
|
23
|
+
page: 1
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
const setSearch = React.useCallback((q) => url.setState({
|
|
27
|
+
q,
|
|
28
|
+
page: 1
|
|
29
|
+
}), [url]);
|
|
30
|
+
const variables = React.useMemo(() => toVariables(url.state), [url.state, toVariables]);
|
|
31
|
+
const [data, setData] = React.useState([]);
|
|
32
|
+
const [loading, setLoading] = React.useState(false);
|
|
33
|
+
const [error, setError] = React.useState(null);
|
|
34
|
+
const [totalItems, setTotalItems] = React.useState(void 0);
|
|
35
|
+
const [totalPages, setTotalPages] = React.useState(void 0);
|
|
36
|
+
const refetch = React.useCallback(async () => {
|
|
37
|
+
setLoading(true);
|
|
38
|
+
setError(null);
|
|
39
|
+
try {
|
|
40
|
+
const out = await fetcher(variables);
|
|
41
|
+
setData(out.items);
|
|
42
|
+
setTotalItems(out.totalItems);
|
|
43
|
+
setTotalPages(out.totalPages);
|
|
44
|
+
} catch (e) {
|
|
45
|
+
setError(e);
|
|
46
|
+
} finally {
|
|
47
|
+
setLoading(false);
|
|
48
|
+
}
|
|
49
|
+
}, [variables, fetcher]);
|
|
50
|
+
React.useEffect(() => {
|
|
51
|
+
refetch();
|
|
52
|
+
}, [refetch]);
|
|
53
|
+
return {
|
|
54
|
+
form,
|
|
55
|
+
url,
|
|
56
|
+
variables,
|
|
57
|
+
data,
|
|
58
|
+
loading,
|
|
59
|
+
error,
|
|
60
|
+
totalItems,
|
|
61
|
+
totalPages,
|
|
62
|
+
refetch,
|
|
63
|
+
chips: React.useMemo(() => toChips ? toChips(url.state.filters || {}, url.setFilter) : [], [url.state.filters, toChips]),
|
|
64
|
+
setSearch,
|
|
65
|
+
submitFilters,
|
|
66
|
+
clearAll: React.useCallback(() => {
|
|
67
|
+
form.reset(formOpts.defaultValues);
|
|
68
|
+
url.setState({
|
|
69
|
+
filters: {},
|
|
70
|
+
page: 1
|
|
71
|
+
});
|
|
72
|
+
}, [
|
|
73
|
+
form,
|
|
74
|
+
formOpts.defaultValues,
|
|
75
|
+
url
|
|
76
|
+
])
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
function useListCoordinator({ defaults, form: formOpts, toVariables, toChips, useUrlState, replace }) {
|
|
80
|
+
const url = useUrlState({
|
|
81
|
+
defaults,
|
|
82
|
+
replace
|
|
83
|
+
});
|
|
84
|
+
const form = useForm({
|
|
85
|
+
defaultValues: formOpts.defaultValues,
|
|
86
|
+
resolver: formOpts.resolver
|
|
87
|
+
});
|
|
88
|
+
React.useEffect(() => {
|
|
89
|
+
form.reset({
|
|
90
|
+
...form.getValues(),
|
|
91
|
+
...url.state.filters
|
|
92
|
+
});
|
|
93
|
+
}, [url.state.filters]);
|
|
94
|
+
const submitFilters = form.handleSubmit((values) => {
|
|
95
|
+
url.setState({
|
|
96
|
+
filters: values,
|
|
97
|
+
page: 1
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
const setSearch = React.useCallback((q) => url.setState({
|
|
101
|
+
q,
|
|
102
|
+
page: 1
|
|
103
|
+
}), [url]);
|
|
104
|
+
return {
|
|
105
|
+
form,
|
|
106
|
+
url,
|
|
107
|
+
variables: React.useMemo(() => toVariables(url.state), [url.state, toVariables]),
|
|
108
|
+
chips: React.useMemo(() => toChips ? toChips(url.state.filters || {}, url.setFilter) : [], [url.state.filters, toChips]),
|
|
109
|
+
setSearch,
|
|
110
|
+
submitFilters,
|
|
111
|
+
clearAll: React.useCallback(() => {
|
|
112
|
+
form.reset(formOpts.defaultValues);
|
|
113
|
+
url.setState({
|
|
114
|
+
filters: {},
|
|
115
|
+
page: 1
|
|
116
|
+
});
|
|
117
|
+
}, [
|
|
118
|
+
form,
|
|
119
|
+
formOpts.defaultValues,
|
|
120
|
+
url
|
|
121
|
+
])
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
//#endregion
|
|
126
|
+
export { useListCoordinator, usePresentationController };
|
|
127
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["import * as React from 'react';\nimport type { DefaultValues, Resolver, UseFormReturn } from 'react-hook-form';\nimport { useForm } from '@lssm/lib.ui-kit/ui/form';\nimport type {\n ListFetcher,\n ListState,\n} from '@lssm/lib.presentation-runtime-core';\n\nexport interface UsePresentationControllerOpts<\n TFilters extends Record<string, unknown>,\n TVars,\n TItem,\n> {\n defaults: ListState<TFilters>;\n form: {\n defaultValues: DefaultValues<TFilters>;\n resolver?: Resolver<TFilters>;\n };\n toVariables: (input: ListState<TFilters>) => TVars;\n fetcher: ListFetcher<TVars, TItem>;\n toChips?: (\n filters: TFilters,\n setFilter: (\n key: keyof TFilters,\n value: TFilters[keyof TFilters] | null\n ) => void\n ) => { key: string; label: React.ReactNode; onRemove?: () => void }[];\n useUrlState: (args: { defaults: ListState<TFilters>; replace?: boolean }) => {\n state: ListState<TFilters>;\n setState: (next: Partial<ListState<TFilters>>) => void;\n setFilter: (\n key: keyof TFilters,\n value: TFilters[keyof TFilters] | null\n ) => void;\n clearFilters: () => void;\n };\n replace?: boolean;\n}\n\nexport function usePresentationController<\n TFilters extends Record<string, unknown>,\n TVars,\n TItem,\n>({\n defaults,\n form: formOpts,\n toVariables,\n fetcher,\n toChips,\n useUrlState,\n replace,\n}: UsePresentationControllerOpts<TFilters, TVars, TItem>) {\n const url = useUrlState({ defaults, replace });\n const form = useForm<TFilters>({\n defaultValues: formOpts.defaultValues,\n resolver: formOpts.resolver as any,\n } as any);\n\n React.useEffect(() => {\n form.reset({ ...(form.getValues() as any), ...(url.state.filters as any) });\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [url.state.filters]);\n\n const submitFilters = form.handleSubmit((values) => {\n url.setState({ filters: values as TFilters, page: 1 });\n });\n\n const setSearch = React.useCallback(\n (q: string) => url.setState({ q, page: 1 }),\n [url]\n );\n const variables = React.useMemo(\n () => toVariables(url.state),\n [url.state, toVariables]\n );\n\n const [data, setData] = React.useState<TItem[]>([]);\n const [loading, setLoading] = React.useState(false);\n const [error, setError] = React.useState<unknown>(null);\n const [totalItems, setTotalItems] = React.useState<number | undefined>(\n undefined\n );\n const [totalPages, setTotalPages] = React.useState<number | undefined>(\n undefined\n );\n\n const refetch = React.useCallback(async () => {\n setLoading(true);\n setError(null);\n try {\n const out = await fetcher(variables);\n setData(out.items);\n setTotalItems(out.totalItems);\n setTotalPages(out.totalPages);\n } catch (e) {\n setError(e);\n } finally {\n setLoading(false);\n }\n }, [variables, fetcher]);\n\n React.useEffect(() => {\n void refetch();\n }, [refetch]);\n\n const chips = React.useMemo(\n () =>\n toChips\n ? toChips(\n (url.state.filters as TFilters) || ({} as any),\n url.setFilter as any\n )\n : [],\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [url.state.filters, toChips]\n );\n\n const clearAll = React.useCallback(() => {\n form.reset(formOpts.defaultValues as TFilters);\n url.setState({ filters: {} as TFilters, page: 1 });\n }, [form, formOpts.defaultValues, url]);\n\n return {\n form: form as UseFormReturn<TFilters>,\n url,\n variables,\n data,\n loading,\n error,\n totalItems,\n totalPages,\n refetch,\n chips,\n setSearch,\n submitFilters,\n clearAll,\n } as const;\n}\n\nexport interface UseListCoordinatorOpts<\n TFilters extends Record<string, unknown>,\n TVars,\n> {\n defaults: ListState<TFilters>;\n form: {\n defaultValues: DefaultValues<TFilters>;\n resolver?: Resolver<TFilters>;\n };\n toVariables: (input: ListState<TFilters>) => TVars;\n toChips?: (\n filters: TFilters,\n setFilter: (\n key: keyof TFilters,\n value: TFilters[keyof TFilters] | null\n ) => void\n ) => { key: string; label: React.ReactNode; onRemove?: () => void }[];\n useUrlState: (args: { defaults: ListState<TFilters>; replace?: boolean }) => {\n state: ListState<TFilters>;\n setState: (next: Partial<ListState<TFilters>>) => void;\n setFilter: (\n key: keyof TFilters,\n value: TFilters[keyof TFilters] | null\n ) => void;\n clearFilters: () => void;\n };\n replace?: boolean;\n}\n\nexport function useListCoordinator<\n TFilters extends Record<string, unknown>,\n TVars,\n>({\n defaults,\n form: formOpts,\n toVariables,\n toChips,\n useUrlState,\n replace,\n}: UseListCoordinatorOpts<TFilters, TVars>) {\n const url = useUrlState({ defaults, replace });\n const form = useForm<TFilters>({\n defaultValues: formOpts.defaultValues,\n resolver: formOpts.resolver as any,\n } as any);\n\n React.useEffect(() => {\n form.reset({ ...(form.getValues() as any), ...(url.state.filters as any) });\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [url.state.filters]);\n\n const submitFilters = form.handleSubmit((values) => {\n url.setState({ filters: values as TFilters, page: 1 });\n });\n\n const setSearch = React.useCallback(\n (q: string) => url.setState({ q, page: 1 }),\n [url]\n );\n const variables = React.useMemo(\n () => toVariables(url.state),\n [url.state, toVariables]\n );\n\n const chips = React.useMemo(\n () =>\n toChips\n ? toChips(\n (url.state.filters as TFilters) || ({} as any),\n url.setFilter as any\n )\n : [],\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [url.state.filters, toChips]\n );\n\n const clearAll = React.useCallback(() => {\n form.reset(formOpts.defaultValues as TFilters);\n url.setState({ filters: {} as TFilters, page: 1 });\n }, [form, formOpts.defaultValues, url]);\n\n return {\n form: form as UseFormReturn<TFilters>,\n url,\n variables,\n chips,\n setSearch,\n submitFilters,\n clearAll,\n } as const;\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
import * as React$1 from "react";
|
|
5
|
+
import "react/jsx-runtime";
|
|
6
|
+
import "../node_modules/@radix-ui/react-slot/dist/index.js";
|
|
7
|
+
import { useForm } from "../node_modules/react-hook-form/dist/index.esm.js";
|
|
8
|
+
import "../node_modules/@hookform/resolvers/zod/dist/zod.js";
|
|
9
|
+
|
|
10
|
+
//#region ../ui-kit/dist/ui/form.js
|
|
11
|
+
const FormFieldContext = React$1.createContext({});
|
|
12
|
+
const FormItemContext = React$1.createContext({});
|
|
13
|
+
|
|
14
|
+
//#endregion
|
|
15
|
+
export { useForm };
|
|
16
|
+
//# sourceMappingURL=form.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"form.js","names":[],"sources":["../../../../../ui-kit/dist/ui/form.js"],"sourcesContent":["'use client';\n\n\nimport { cn } from \"./utils.js\";\nimport { Label } from \"./label.js\";\nimport { Slot } from \"../node_modules/@radix-ui/react-slot/dist/index.js\";\nimport { Controller, FormProvider, useFieldArray, useForm, useFormContext, useFormState } from \"../node_modules/react-hook-form/dist/index.esm.js\";\nimport { t } from \"../node_modules/@hookform/resolvers/zod/dist/zod.js\";\nimport * as React$1 from \"react\";\nimport { jsx } from \"react/jsx-runtime\";\n\n//#region ui/form.tsx\nconst Form = FormProvider;\nconst FormFieldContext = React$1.createContext({});\nconst FormField = ({ ...props }) => {\n\treturn /* @__PURE__ */ jsx(FormFieldContext.Provider, {\n\t\tvalue: { name: props.name },\n\t\tchildren: /* @__PURE__ */ jsx(Controller, { ...props })\n\t});\n};\nconst useFormField = () => {\n\tconst fieldContext = React$1.useContext(FormFieldContext);\n\tconst itemContext = React$1.useContext(FormItemContext);\n\tconst { getFieldState } = useFormContext();\n\tconst formState = useFormState({ name: fieldContext.name });\n\tconst fieldState = getFieldState(fieldContext.name, formState);\n\tif (!fieldContext) throw new Error(\"useFormField should be used within <FormField>\");\n\tconst { id } = itemContext;\n\treturn {\n\t\tid,\n\t\tname: fieldContext.name,\n\t\tformItemId: `${id}-form-item`,\n\t\tformDescriptionId: `${id}-form-item-description`,\n\t\tformMessageId: `${id}-form-item-message`,\n\t\t...fieldState\n\t};\n};\nconst FormItemContext = React$1.createContext({});\nfunction FormItem({ className,...props }) {\n\tconst id = React$1.useId();\n\treturn /* @__PURE__ */ jsx(FormItemContext.Provider, {\n\t\tvalue: { id },\n\t\tchildren: /* @__PURE__ */ jsx(\"div\", {\n\t\t\t\"data-slot\": \"form-item\",\n\t\t\tclassName: cn(\"grid gap-2\", className),\n\t\t\t...props\n\t\t})\n\t});\n}\nfunction FormLabel({ className,...props }) {\n\tconst { error, formItemId } = useFormField();\n\treturn /* @__PURE__ */ jsx(Label, {\n\t\t\"data-slot\": \"form-label\",\n\t\t\"data-error\": !!error,\n\t\tclassName: cn(\"data-[error=true]:text-destructive\", className),\n\t\thtmlFor: formItemId,\n\t\t...props\n\t});\n}\nfunction FormControl({ ...props }) {\n\tconst { error, formItemId, formDescriptionId, formMessageId } = useFormField();\n\treturn /* @__PURE__ */ jsx(Slot, {\n\t\t\"data-slot\": \"form-control\",\n\t\tid: formItemId,\n\t\t\"aria-describedby\": !error ? `${formDescriptionId}` : `${formDescriptionId} ${formMessageId}`,\n\t\t\"aria-invalid\": !!error,\n\t\t...props\n\t});\n}\nfunction FormDescription({ className,...props }) {\n\tconst { formDescriptionId } = useFormField();\n\treturn /* @__PURE__ */ jsx(\"p\", {\n\t\t\"data-slot\": \"form-description\",\n\t\tid: formDescriptionId,\n\t\tclassName: cn(\"text-muted-foreground text-sm\", className),\n\t\t...props\n\t});\n}\nfunction FormMessage({ className,...props }) {\n\tconst { error, formMessageId } = useFormField();\n\tconst body = error ? String(error?.message ?? \"\") : props.children;\n\tif (!body) return null;\n\treturn /* @__PURE__ */ jsx(\"p\", {\n\t\t\"data-slot\": \"form-message\",\n\t\tid: formMessageId,\n\t\tclassName: cn(\"text-destructive text-sm\", className),\n\t\t...props,\n\t\tchildren: body\n\t});\n}\n\n//#endregion\nexport { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage, useFieldArray, useForm, useFormField, t as zodResolver };\n//# sourceMappingURL=form.js.map"],"mappings":";;;;;;;;;;AAaA,MAAM,mBAAmB,QAAQ,cAAc,EAAE,CAAC;AAwBlD,MAAM,kBAAkB,QAAQ,cAAc,EAAE,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@lssm/lib.presentation-runtime-react-native",
|
|
3
|
+
"version": "3.0.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"module": "./dist/index.js",
|
|
7
|
+
"types": "./dist/nativewind-env.d.ts",
|
|
8
|
+
"sideEffects": false,
|
|
9
|
+
"scripts": {
|
|
10
|
+
"build": "bun build:bundle && bun build:types",
|
|
11
|
+
"build:bundle": "tsdown",
|
|
12
|
+
"build:types": "tsc --noEmit -p tsconfig.json",
|
|
13
|
+
"dev": "bun run build:bundle --watch",
|
|
14
|
+
"lint": "bun run lint:fix",
|
|
15
|
+
"lint:fix": "eslint src --fix",
|
|
16
|
+
"lint:check": "eslint src"
|
|
17
|
+
},
|
|
18
|
+
"peerDependencies": {
|
|
19
|
+
"react": "^19.1.0",
|
|
20
|
+
"react-native": "*",
|
|
21
|
+
"react-hook-form": "7.66.0",
|
|
22
|
+
"zod": "^4.1.5",
|
|
23
|
+
"@lssm/lib.presentation-runtime-core": "^1.2.0"
|
|
24
|
+
},
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"@lssm/lib.presentation-runtime-core": "workspace:^1.2.0"
|
|
27
|
+
},
|
|
28
|
+
"exports": {
|
|
29
|
+
".": "./src/index.ts",
|
|
30
|
+
"./*": "./*"
|
|
31
|
+
},
|
|
32
|
+
"publishConfig": {
|
|
33
|
+
"exports": {
|
|
34
|
+
".": "./dist/index.js",
|
|
35
|
+
"./*": "./*"
|
|
36
|
+
},
|
|
37
|
+
"access": "public"
|
|
38
|
+
},
|
|
39
|
+
"files": [
|
|
40
|
+
"dist",
|
|
41
|
+
"README.md"
|
|
42
|
+
]
|
|
43
|
+
}
|