react-luna-form 0.0.86 → 0.0.87
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 +15 -10
- package/dist/client/cjs/index.js +2 -1
- package/dist/client/esm/index.js +2 -1
- package/dist/config/cjs/index.js +1 -1
- package/dist/config/esm/index.js +1 -1
- package/dist/schema/cjs/index.js +1 -1
- package/dist/schema/esm/index.js +1 -1
- package/dist/server/cjs/index.js +1 -1
- package/dist/server/esm/index.js +1 -1
- package/dist/types/luna-core/util/extract.d.ts +21 -0
- package/dist/types/luna-core/util/prepare.d.ts +1 -1
- package/dist/types/luna-react/src/client/component/field/field-preview.d.ts +4 -2
- package/dist/types/luna-react/src/{component → client/component}/field/field-set-advanced.d.ts +1 -1
- package/dist/types/luna-react/src/client/component/field/field-set.d.ts +11 -0
- package/dist/types/luna-react/src/client/component/field/field.d.ts +20 -11
- package/dist/types/luna-react/src/client/component/field-description.d.ts +2 -0
- package/dist/types/luna-react/src/{component → client/component}/formatted-description.d.ts +2 -2
- package/dist/types/luna-react/src/client/component/input-strategies.d.ts +1 -1
- package/dist/types/luna-react/src/client/hook/use-entry-atom.d.ts +18 -0
- package/dist/types/luna-react/src/client/hook/use-input-core.d.ts +2 -2
- package/dist/types/luna-react/src/client/hook/use-latest.d.ts +22 -0
- package/dist/types/luna-react/src/client/hook/use-live-item-value.d.ts +17 -3
- package/dist/types/luna-react/src/client/hook/use-value.d.ts +1 -1
- package/dist/types/luna-react/src/client/lib/error-store.d.ts +3 -4
- package/dist/types/luna-react/src/client/lib/host-value-store.d.ts +13 -15
- package/dist/types/luna-react/src/client/lib/list-store.d.ts +0 -2
- package/dist/types/luna-react/src/client/lib/resolve-value.d.ts +0 -5
- package/dist/types/luna-react/src/client/lib/source-store.d.ts +7 -4
- package/dist/types/luna-react/src/client/lib/state-store.d.ts +0 -4
- package/dist/types/luna-react/src/client/lib/store-helper.d.ts +5 -15
- package/dist/types/luna-react/src/client/lib/value-store.d.ts +0 -4
- package/dist/types/luna-react/src/component/column.d.ts +2 -0
- package/dist/types/luna-react/src/component/description.d.ts +9 -0
- package/dist/types/luna-react/src/component/field/{field-set.d.ts → field-set-static.d.ts} +1 -1
- package/dist/types/luna-react/src/component/field/field.d.ts +1 -1
- package/dist/types/luna-react/src/component/field-description.d.ts +3 -2
- package/dist/types/luna-react/src/component/form.d.ts +9 -0
- package/dist/types/luna-react/src/component/input-group.d.ts +2 -0
- package/dist/types/luna-react/src/component/input-label.d.ts +2 -0
- package/dist/types/luna-react/src/component/slot/slot-base.d.ts +2 -0
- package/dist/types/luna-react/src/lib/visibility.d.ts +3 -0
- package/dist/types/luna-react/src/server/component/field.d.ts +2 -0
- package/dist/types/luna-react/src/server/component/list-slot.d.ts +2 -0
- package/dist/types/luna-react/src/server/component/slot.d.ts +15 -0
- package/docs/forms/submit.md +8 -7
- package/docs/setup.md +39 -19
- package/docs/validation/overview.md +1 -1
- package/package.json +5 -5
- package/dist/types/luna-react/src/client/component/field/field-with-state.d.ts +0 -13
|
@@ -2,6 +2,13 @@ import type { Nullable } from '../../../../luna-core/index';
|
|
|
2
2
|
export declare const hostValueAtom: import("jotai").PrimitiveAtom<Nullable<Record<string, unknown>>> & {
|
|
3
3
|
init: Nullable<Record<string, unknown>>;
|
|
4
4
|
};
|
|
5
|
+
/** What the host says about one field, with the sentinel already read. */
|
|
6
|
+
export type HostEntry = {
|
|
7
|
+
/** The host names this field. A field it does not name reads `undefined`. */
|
|
8
|
+
found: boolean;
|
|
9
|
+
value: unknown;
|
|
10
|
+
};
|
|
11
|
+
export declare function readHostEntry(entry: unknown): HostEntry;
|
|
5
12
|
/**
|
|
6
13
|
* One field's entry in that record.
|
|
7
14
|
*
|
|
@@ -12,19 +19,10 @@ export declare const hostValueAtom: import("jotai").PrimitiveAtom<Nullable<Recor
|
|
|
12
19
|
* read; doing it at the call site is what keeps this correct where a memo
|
|
13
20
|
* comparator could not be. See `ListPathContext`.
|
|
14
21
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
* 23 and this one stays at 29, its high-water mark. Worth knowing before
|
|
21
|
-
* someone reads the absence of a release as an oversight.
|
|
22
|
+
* Made by whoever subscribes rather than cached by name, so it goes with the
|
|
23
|
+
* component that asked: a family kept one per name for the life of the page,
|
|
24
|
+
* and this one was never released at all -- 110 keys after ten definitions of
|
|
25
|
+
* ten fields. See `useEntryAtom` for the same move on the records a field
|
|
26
|
+
* writes into.
|
|
22
27
|
*/
|
|
23
|
-
|
|
24
|
-
export type HostEntry = {
|
|
25
|
-
/** The host names this field. A field it does not name reads `undefined`. */
|
|
26
|
-
found: boolean;
|
|
27
|
-
value: unknown;
|
|
28
|
-
};
|
|
29
|
-
export declare function readHostEntry(entry: unknown): HostEntry;
|
|
30
|
-
export declare const hostEntryAtom: import("jotai-family").AtomFamily<string, import("jotai").Atom<unknown>>;
|
|
28
|
+
export declare function hostEntryAtom(name: string): import("jotai").Atom<unknown>;
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
export declare const pendingListRowsAtom: import("jotai").PrimitiveAtom<Record<string, Record<string, unknown>[]>> & {
|
|
2
2
|
init: Record<string, Record<string, unknown>[]>;
|
|
3
3
|
};
|
|
4
|
-
export declare const reportPendingListRowsAtom: import("jotai-family").AtomFamily<string, import("jotai").WritableAtom<Record<string, unknown>[] | undefined, [newValue: Record<string, unknown>[] | undefined], void>>;
|
|
5
4
|
/**
|
|
6
5
|
* What a list on screen is holding: the stable ids of its live rows, in the
|
|
7
6
|
* order they are shown, and the name of every leaf a row owns.
|
|
@@ -37,4 +36,3 @@ export type MountedList = {
|
|
|
37
36
|
export declare const mountedListsAtom: import("jotai").PrimitiveAtom<Record<string, MountedList>> & {
|
|
38
37
|
init: Record<string, MountedList>;
|
|
39
38
|
};
|
|
40
|
-
export declare const reportMountedListAtom: import("jotai-family").AtomFamily<string, import("jotai").WritableAtom<MountedList | undefined, [newValue: MountedList | undefined], void>>;
|
|
@@ -1,6 +1 @@
|
|
|
1
|
-
export type Entry = {
|
|
2
|
-
found: boolean;
|
|
3
|
-
value: unknown;
|
|
4
|
-
};
|
|
5
|
-
export declare function resolveEntry(name: string, currentValue: Record<string, unknown> | unknown[]): Entry;
|
|
6
1
|
export declare function resolveValue(name: string, currentValue: Record<string, unknown> | unknown[]): unknown;
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { type DataSource } from '../../../../luna-core/index';
|
|
2
|
-
export declare const
|
|
3
|
-
|
|
4
|
-
init: null;
|
|
2
|
+
export declare const sourceAtom: import("jotai").PrimitiveAtom<Record<string, Record<string, DataSource>>> & {
|
|
3
|
+
init: Record<string, Record<string, DataSource>>;
|
|
5
4
|
};
|
|
6
|
-
export declare const
|
|
5
|
+
export declare const SOURCE_OPTIONS: {
|
|
6
|
+
readonly merge: (values: DataSource[]) => DataSource | undefined;
|
|
7
|
+
readonly validateTarget: (target: string) => boolean;
|
|
8
|
+
};
|
|
9
|
+
export declare const clearInputSourceAtom: import("jotai").WritableAtom<null, [contributorNames: string[]], void> & {
|
|
7
10
|
init: null;
|
|
8
11
|
};
|
|
@@ -2,7 +2,3 @@ import type { FieldState } from '../../../../luna-core/index';
|
|
|
2
2
|
export declare const fieldStateAtom: import("jotai").PrimitiveAtom<Record<string, FieldState>> & {
|
|
3
3
|
init: Record<string, FieldState>;
|
|
4
4
|
};
|
|
5
|
-
export declare const releaseFieldStateAtom: import("jotai").WritableAtom<null, [names: string[]], void> & {
|
|
6
|
-
init: null;
|
|
7
|
-
};
|
|
8
|
-
export declare const reportFieldStateAtom: import("jotai-family").AtomFamily<string, import("jotai").WritableAtom<FieldState | undefined, [newValue: FieldState | undefined], void>>;
|
|
@@ -1,15 +1,10 @@
|
|
|
1
1
|
import { type PrimitiveAtom } from 'jotai';
|
|
2
|
-
type NestedAtomFamilyOptions<TInner> = {
|
|
3
|
-
merge?: (values: TInner[]) => TInner | undefined;
|
|
4
|
-
validateTarget?: (target: string) => boolean;
|
|
5
|
-
};
|
|
6
2
|
export declare function omitKey<T extends Record<string, unknown>>(obj: T, key: string): T;
|
|
7
|
-
export declare function
|
|
8
|
-
export declare function
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
};
|
|
3
|
+
export declare function createEntryAtom<T>(base: PrimitiveAtom<Record<string, T>>, name: string): import("jotai").WritableAtom<NonNullable<T> | undefined, [next: T | undefined], void>;
|
|
4
|
+
export declare function createContributionAtom<T>(base: PrimitiveAtom<Record<string, Record<string, T>>>, name: string, options: Readonly<{
|
|
5
|
+
merge: (values: T[]) => T | undefined;
|
|
6
|
+
validateTarget: (target: string) => boolean;
|
|
7
|
+
}>): import("jotai").WritableAtom<T | undefined, [target: string, value: T | undefined], void>;
|
|
13
8
|
export declare function createNestedClearAtom<TInner>(baseAtom: PrimitiveAtom<Record<string, Record<string, TInner>>>): import("jotai").WritableAtom<null, [contributorNames: string[]], void> & {
|
|
14
9
|
init: null;
|
|
15
10
|
};
|
|
@@ -26,9 +21,4 @@ export declare function createAtomStore<T>(initialValue?: Record<string, T>): {
|
|
|
26
21
|
bulkReport: import("jotai").WritableAtom<null, [newValue: Record<string, T>], void> & {
|
|
27
22
|
init: null;
|
|
28
23
|
};
|
|
29
|
-
release: import("jotai").WritableAtom<null, [names: string[]], void> & {
|
|
30
|
-
init: null;
|
|
31
|
-
};
|
|
32
|
-
report: import("jotai-family").AtomFamily<string, import("jotai").WritableAtom<NonNullable<T> | undefined, [newValue: T | undefined], void>>;
|
|
33
24
|
};
|
|
34
|
-
export {};
|
|
@@ -7,10 +7,6 @@ export declare const clearAllValueAtom: import("jotai").WritableAtom<null, [], v
|
|
|
7
7
|
export declare const clearInputValueAtom: import("jotai").WritableAtom<null, [names: string[]], void> & {
|
|
8
8
|
init: null;
|
|
9
9
|
};
|
|
10
|
-
export declare const releaseInputValueAtom: import("jotai").WritableAtom<null, [names: string[]], void> & {
|
|
11
|
-
init: null;
|
|
12
|
-
};
|
|
13
|
-
export declare const reportValueAtom: import("jotai-family").AtomFamily<string, import("jotai").WritableAtom<{} | undefined, [newValue: unknown], void>>;
|
|
14
10
|
export declare const appliedAutoFillAtom: import("jotai").PrimitiveAtom<Record<string, unknown>> & {
|
|
15
11
|
init: Record<string, unknown>;
|
|
16
12
|
};
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type DescriptionTextProps } from './description';
|
|
1
2
|
import { type Column } from '../../../luna-core/index';
|
|
2
3
|
import type { Config } from '../type';
|
|
3
4
|
export declare function Column(props: Readonly<{
|
|
@@ -5,5 +6,6 @@ export declare function Column(props: Readonly<{
|
|
|
5
6
|
column?: Column;
|
|
6
7
|
config?: Config;
|
|
7
8
|
context?: Record<string, unknown>;
|
|
9
|
+
description?: React.ComponentType<DescriptionTextProps>;
|
|
8
10
|
translations?: Record<string, string>;
|
|
9
11
|
}>): import("react").JSX.Element;
|
|
@@ -1,4 +1,13 @@
|
|
|
1
|
+
import { type Description as DescriptionType } from '../../../luna-core/index';
|
|
2
|
+
import type { Config } from '../type';
|
|
1
3
|
export declare function Description(props: Readonly<{
|
|
2
4
|
children: string | React.ReactNode;
|
|
3
5
|
title?: string;
|
|
4
6
|
}>): import("react").JSX.Element;
|
|
7
|
+
export type DescriptionTextProps = Readonly<{
|
|
8
|
+
config?: Config;
|
|
9
|
+
context?: Record<string, unknown>;
|
|
10
|
+
text?: DescriptionType;
|
|
11
|
+
translations?: Record<string, string>;
|
|
12
|
+
}>;
|
|
13
|
+
export declare function DescriptionText(props: DescriptionTextProps): import("react").JSX.Element | null;
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import type { Config } from '../type';
|
|
2
2
|
import type { Field } from '../../../luna-core/index';
|
|
3
|
-
export
|
|
3
|
+
export type DescriptionProps = Readonly<{
|
|
4
4
|
config?: Config;
|
|
5
5
|
context?: Record<string, unknown>;
|
|
6
6
|
field: Field;
|
|
7
7
|
translations?: Record<string, string>;
|
|
8
|
-
}
|
|
8
|
+
}>;
|
|
9
|
+
export declare function StaticDescription(props: DescriptionProps): import("react").JSX.Element;
|
|
@@ -1,6 +1,13 @@
|
|
|
1
|
+
import { StaticFieldSet } from './field/field-set-static';
|
|
1
2
|
import { type Definition, type Sections } from '../../../luna-core/index';
|
|
2
3
|
import type { Config, Control, Slot } from '../type';
|
|
4
|
+
import type { Fields } from '../../../luna-core/index';
|
|
3
5
|
import type { FormEvent } from 'react';
|
|
6
|
+
export type GuardProps = Readonly<{
|
|
7
|
+
children: React.ReactNode;
|
|
8
|
+
fields: Fields;
|
|
9
|
+
}>;
|
|
10
|
+
export declare function StaticGuard(props: GuardProps): import("react").ReactNode;
|
|
4
11
|
export declare function Form(props: Readonly<{
|
|
5
12
|
advanced?: {
|
|
6
13
|
step?: boolean;
|
|
@@ -10,6 +17,8 @@ export declare function Form(props: Readonly<{
|
|
|
10
17
|
config: Config;
|
|
11
18
|
control?: Control;
|
|
12
19
|
definition?: Definition;
|
|
20
|
+
fieldSet?: React.ComponentType<React.ComponentProps<typeof StaticFieldSet>>;
|
|
21
|
+
guard?: React.ComponentType<GuardProps>;
|
|
13
22
|
isPending?: boolean;
|
|
14
23
|
noValidate?: boolean;
|
|
15
24
|
onSubmit?: (event: FormEvent<HTMLFormElement>) => void;
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
import { type DescriptionProps } from './field-description';
|
|
1
2
|
import type { Config } from '../type';
|
|
2
3
|
import type { Field } from '../../../luna-core/index';
|
|
3
4
|
export declare function InputGroup(props: Readonly<{
|
|
4
5
|
children: React.ReactNode;
|
|
5
6
|
config?: Config;
|
|
6
7
|
context?: Record<string, unknown>;
|
|
8
|
+
description?: React.ComponentType<DescriptionProps>;
|
|
7
9
|
field: Field;
|
|
8
10
|
horizontal?: boolean;
|
|
9
11
|
translations?: Record<string, string>;
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
import { type DescriptionProps } from './field-description';
|
|
1
2
|
import { type Field } from '../../../luna-core/index';
|
|
2
3
|
import type { Config } from '../type';
|
|
3
4
|
export declare function InputLabel(props: Readonly<{
|
|
4
5
|
config?: Config;
|
|
5
6
|
context?: Record<string, unknown>;
|
|
7
|
+
description?: React.ComponentType<DescriptionProps>;
|
|
6
8
|
field: Field;
|
|
7
9
|
horizontal?: boolean;
|
|
8
10
|
translations?: Record<string, string>;
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { type Fields, type Nullable, type Style } from '../../../../luna-core/index';
|
|
2
|
+
import type { DescriptionTextProps } from '../description';
|
|
2
3
|
import type { Children, Config } from '../../type';
|
|
3
4
|
import type { FieldProps } from '../field/field';
|
|
4
5
|
import type { ListProps } from '../field/field-list';
|
|
5
6
|
export type SlotComponents = {
|
|
7
|
+
description?: React.ComponentType<DescriptionTextProps>;
|
|
6
8
|
field: React.ComponentType<FieldProps>;
|
|
7
9
|
list: React.ComponentType<ListProps>;
|
|
8
10
|
};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { Field, FieldState, Fields, List } from '../../../luna-core/index';
|
|
2
|
+
export declare function isEntryHidden(entry: Fields[number], states: Record<string, FieldState>): boolean;
|
|
3
|
+
export declare function isGuardHidden(states: Record<string, FieldState>, fields: Fields, container?: Field | List): boolean;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export declare const Slot: (props: Readonly<{
|
|
2
|
+
children: import("../../type").Children;
|
|
3
|
+
config: import("../../type").Config;
|
|
4
|
+
context?: Record<string, unknown>;
|
|
5
|
+
disabled?: boolean;
|
|
6
|
+
fields?: import('../../../../luna-core/index').Fields;
|
|
7
|
+
lang?: string;
|
|
8
|
+
onValueChange?: (input: {
|
|
9
|
+
name: string;
|
|
10
|
+
value: unknown;
|
|
11
|
+
}) => void;
|
|
12
|
+
style?: import('../../../../luna-core/index').Style;
|
|
13
|
+
translations?: Record<string, string>;
|
|
14
|
+
value?: import('../../../../luna-core/index').Nullable<Record<string, unknown>>;
|
|
15
|
+
}>) => import("react").JSX.Element;
|
package/docs/forms/submit.md
CHANGED
|
@@ -113,13 +113,14 @@ it, or put it back, while the errors are showing.
|
|
|
113
113
|
|
|
114
114
|
## Turning submit validation off
|
|
115
115
|
|
|
116
|
-
`defineConfig({ validation: { submit: false
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
116
|
+
`defineConfig({ validation: { submit: false } })` skips the parse entirely. The
|
|
117
|
+
action is called with the raw `FormData` and the schema, and nothing is checked,
|
|
118
|
+
reported or cleared on the way — for a form whose action does its own parsing.
|
|
119
|
+
With no action at all, submitting does nothing.
|
|
120
|
+
|
|
121
|
+
The other three keys are untouched by that: this object
|
|
122
|
+
[merges into the defaults](../setup.md#validation), so a form that stops
|
|
123
|
+
validating on submit goes on validating as the user types.
|
|
123
124
|
|
|
124
125
|
## The error summary
|
|
125
126
|
|
package/docs/setup.md
CHANGED
|
@@ -13,15 +13,15 @@ pnpm add react-luna-form
|
|
|
13
13
|
The package carries no dependencies of its own: everything it needs is a peer
|
|
14
14
|
dependency, so your application resolves one copy of React, Zod and the rest.
|
|
15
15
|
|
|
16
|
-
| Peer
|
|
17
|
-
|
|
|
18
|
-
| `react`, `react-dom`
|
|
19
|
-
| `zod`
|
|
20
|
-
| `jotai
|
|
21
|
-
| `swr`
|
|
22
|
-
| `date-fns`
|
|
23
|
-
| `fast-equals`
|
|
24
|
-
| `tailwind-merge`
|
|
16
|
+
| Peer | Version | Used for |
|
|
17
|
+
| -------------------- | --------- | ------------------------------------------- |
|
|
18
|
+
| `react`, `react-dom` | `^19.0.0` | rendering, and `useActionState` on submit |
|
|
19
|
+
| `zod` | `^4.0.0` | the schema derived from `sections` |
|
|
20
|
+
| `jotai` | `^2.0.0` | the value, error and source stores |
|
|
21
|
+
| `swr` | `^2.0.0` | fetching a field's remote `source` |
|
|
22
|
+
| `date-fns` | `^4.0.0` | date and time formatting, `duration` filter |
|
|
23
|
+
| `fast-equals` | `^6.0.0` | change detection in the stores |
|
|
24
|
+
| `tailwind-merge` | `^3.7.0` | merging the classes the components render |
|
|
25
25
|
|
|
26
26
|
None of them is optional, and none is bundled. A package manager that installs
|
|
27
27
|
peers automatically (npm 7+, or pnpm with `auto-install-peers=true`) brings
|
|
@@ -48,20 +48,26 @@ CSS.
|
|
|
48
48
|
|
|
49
49
|
Every element also carries a `data-slot` attribute — `field`, `field-label`,
|
|
50
50
|
`field-control`, `field-set`, `field-set-content`, `field-content`,
|
|
51
|
-
`field-group`, `field-separator`, `
|
|
52
|
-
system can restyle the structure without
|
|
53
|
-
you register yourself are yours to style;
|
|
54
|
-
around them.
|
|
51
|
+
`field-group`, `field-separator`, `collapsible-content`, `column`,
|
|
52
|
+
`list-item-card` — so a design system can restyle the structure without
|
|
53
|
+
patching the library. The components you register yourself are yours to style;
|
|
54
|
+
these slots cover the scaffolding around them.
|
|
55
55
|
|
|
56
56
|
## Entry points
|
|
57
57
|
|
|
58
58
|
| Import | Contains |
|
|
59
59
|
| ------------------------ | ----------------------------------------------------------------------------------------- |
|
|
60
60
|
| `react-luna-form` | `Form` (client), `withDeclaredFields`, and the `Sections`, `Source` and `ZodSchema` types |
|
|
61
|
-
| `react-luna-form/server` | `Form` (server) and `Fallback`
|
|
61
|
+
| `react-luna-form/server` | `Form` (server) and `Fallback`, usable under the `react-server` condition |
|
|
62
62
|
| `react-luna-form/config` | `defineConfig` and the `define*` registration helpers |
|
|
63
63
|
| `react-luna-form/schema` | `buildFormSchema` and `collectIssues` |
|
|
64
64
|
|
|
65
|
+
The client bundle is published carrying a `'use client'` directive, so an App
|
|
66
|
+
Router project imports `Form` straight from a Server Component and needs no
|
|
67
|
+
wrapper module of its own to say it. The server bundle carries none and
|
|
68
|
+
resolves under the `react-server` condition, which is what lets a Server
|
|
69
|
+
Component render the form itself.
|
|
70
|
+
|
|
65
71
|
## Configuring
|
|
66
72
|
|
|
67
73
|
`defineConfig` is called once, usually in a `luna.config.ts` at the root of the
|
|
@@ -99,10 +105,9 @@ When to validate and whether to summarise errors. All four default to `true`.
|
|
|
99
105
|
validation: { blur: true, change: true, showError: true, submit: true }
|
|
100
106
|
```
|
|
101
107
|
|
|
102
|
-
|
|
103
|
-
`{ change: false }`
|
|
104
|
-
|
|
105
|
-
Pass every key you still want.
|
|
108
|
+
This object merges into the defaults, so pass only what you want to change.
|
|
109
|
+
`{ change: false }` stops the form validating as the user types and leaves the
|
|
110
|
+
other three alone.
|
|
106
111
|
|
|
107
112
|
### `fetcher.remotePatterns`
|
|
108
113
|
|
|
@@ -127,7 +132,8 @@ fetcher: {
|
|
|
127
132
|
A blocked URL is not an error. The library logs
|
|
128
133
|
`URL blocked by remotePatterns: <url>` and the field renders with no options at
|
|
129
134
|
all, which on screen looks like an empty select rather than a rejected request.
|
|
130
|
-
Check the console when a remote source comes back empty
|
|
135
|
+
Check the console when a remote source comes back empty — see
|
|
136
|
+
[Warnings](#warnings) for when that line is written.
|
|
131
137
|
|
|
132
138
|
### `style`, `alert`, `env`
|
|
133
139
|
|
|
@@ -137,6 +143,20 @@ Check the console when a remote source comes back empty.
|
|
|
137
143
|
- `env` is a flat record of values available to interpolation, in labels and in
|
|
138
144
|
descriptions. Its `locale` key is also what those two read to format values.
|
|
139
145
|
|
|
146
|
+
## Warnings
|
|
147
|
+
|
|
148
|
+
Some of what can go wrong is nobody's to fix but the author of the form, and
|
|
149
|
+
the library says so on the console rather than on screen: a `pattern` that does
|
|
150
|
+
not compile, a field name that reaches a prototype and is left out of the
|
|
151
|
+
submit, the error an `action` threw, a remote `source` that failed or was
|
|
152
|
+
blocked. Every one of those lines is prefixed `[Luna Form]`.
|
|
153
|
+
|
|
154
|
+
They are written outside production and silent inside it, and which one you are
|
|
155
|
+
in is your build's answer to give: the published bundle leaves
|
|
156
|
+
`process.env.NODE_ENV` for your bundler to resolve instead of deciding while it
|
|
157
|
+
is being packaged. A development build of your application shows them and a
|
|
158
|
+
production build does not. Where nothing defines it at all, they are shown.
|
|
159
|
+
|
|
140
160
|
## Rendering
|
|
141
161
|
|
|
142
162
|
### `Form` from `react-luna-form`
|
|
@@ -111,7 +111,7 @@ Validates a string value against a regular expression.
|
|
|
111
111
|
|
|
112
112
|
`pattern` never fires on an empty value — pair it with `required`/`requiredWhen` when the field is mandatory.
|
|
113
113
|
|
|
114
|
-
A `regex` or `flags` that does not compile is a mistake in the definition, not in the value. The rule then holds back every value it checks with its `message`, as it does a value that does not match, and the form keeps working. The same goes for a `pattern` among [`rules`](#rules).
|
|
114
|
+
A `regex` or `flags` that does not compile is a mistake in the definition, not in the value. The rule then holds back every value it checks with its `message`, as it does a value that does not match, and the form keeps working. The same goes for a `pattern` among [`rules`](#rules). Since the `message` is written for whoever fills the form in, the expression that failed to compile is named on the console instead — see [Warnings](../setup.md#warnings).
|
|
115
115
|
|
|
116
116
|
A `regex` that compiles runs as written, on what the user types: in the browser when the form is submitted, and on the server when it validates with `buildFormSchema`. Nothing inspects it first, so it is part of the code the form ships with. Accept one only from someone you would let write that code.
|
|
117
117
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-luna-form",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.87",
|
|
4
4
|
"description": "A React library for building forms based on JSON",
|
|
5
5
|
"main": "./dist/client/cjs/index.js",
|
|
6
6
|
"module": "./dist/client/esm/index.js",
|
|
@@ -22,20 +22,20 @@
|
|
|
22
22
|
"date-fns": "^4.0.0",
|
|
23
23
|
"fast-equals": "^6.0.0",
|
|
24
24
|
"jotai": "^2.0.0",
|
|
25
|
-
"jotai-family": "^1.0.0",
|
|
26
25
|
"react": "^19.0.0",
|
|
27
26
|
"react-dom": "^19.0.0",
|
|
28
27
|
"swr": "^2.0.0",
|
|
29
|
-
"tailwind-merge": "^3.
|
|
28
|
+
"tailwind-merge": "^3.7.0",
|
|
30
29
|
"zod": "^4.0.0"
|
|
31
30
|
},
|
|
32
31
|
"devDependencies": {
|
|
33
|
-
"@luna-form/core": "0.0.
|
|
32
|
+
"@luna-form/core": "0.0.87",
|
|
34
33
|
"@types/react": "19.3.0",
|
|
35
34
|
"@types/react-dom": "19.3.0",
|
|
36
35
|
"eslint-plugin-react": "7.37.5",
|
|
37
36
|
"eslint-plugin-react-hooks": "7.1.1",
|
|
38
|
-
"eslint-plugin-react-refresh": "0.5.7"
|
|
37
|
+
"eslint-plugin-react-refresh": "0.5.7",
|
|
38
|
+
"jotai-family": "1.1.0"
|
|
39
39
|
},
|
|
40
40
|
"license": "Apache-2.0",
|
|
41
41
|
"repository": {
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
export declare function withError<P extends {
|
|
2
|
-
errors?: Record<string, string[]>;
|
|
3
|
-
field: {
|
|
4
|
-
name: string;
|
|
5
|
-
};
|
|
6
|
-
}>(Component: React.ComponentType<P>): (props: Readonly<P>) => import("react").JSX.Element | null;
|
|
7
|
-
export declare function withState<P extends {
|
|
8
|
-
disabled?: boolean;
|
|
9
|
-
field: {
|
|
10
|
-
name: string;
|
|
11
|
-
hidden?: boolean;
|
|
12
|
-
};
|
|
13
|
-
}>(Component: React.ComponentType<P>): (props: Readonly<P>) => import("react").JSX.Element | null;
|