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.
Files changed (49) hide show
  1. package/README.md +15 -10
  2. package/dist/client/cjs/index.js +2 -1
  3. package/dist/client/esm/index.js +2 -1
  4. package/dist/config/cjs/index.js +1 -1
  5. package/dist/config/esm/index.js +1 -1
  6. package/dist/schema/cjs/index.js +1 -1
  7. package/dist/schema/esm/index.js +1 -1
  8. package/dist/server/cjs/index.js +1 -1
  9. package/dist/server/esm/index.js +1 -1
  10. package/dist/types/luna-core/util/extract.d.ts +21 -0
  11. package/dist/types/luna-core/util/prepare.d.ts +1 -1
  12. package/dist/types/luna-react/src/client/component/field/field-preview.d.ts +4 -2
  13. package/dist/types/luna-react/src/{component → client/component}/field/field-set-advanced.d.ts +1 -1
  14. package/dist/types/luna-react/src/client/component/field/field-set.d.ts +11 -0
  15. package/dist/types/luna-react/src/client/component/field/field.d.ts +20 -11
  16. package/dist/types/luna-react/src/client/component/field-description.d.ts +2 -0
  17. package/dist/types/luna-react/src/{component → client/component}/formatted-description.d.ts +2 -2
  18. package/dist/types/luna-react/src/client/component/input-strategies.d.ts +1 -1
  19. package/dist/types/luna-react/src/client/hook/use-entry-atom.d.ts +18 -0
  20. package/dist/types/luna-react/src/client/hook/use-input-core.d.ts +2 -2
  21. package/dist/types/luna-react/src/client/hook/use-latest.d.ts +22 -0
  22. package/dist/types/luna-react/src/client/hook/use-live-item-value.d.ts +17 -3
  23. package/dist/types/luna-react/src/client/hook/use-value.d.ts +1 -1
  24. package/dist/types/luna-react/src/client/lib/error-store.d.ts +3 -4
  25. package/dist/types/luna-react/src/client/lib/host-value-store.d.ts +13 -15
  26. package/dist/types/luna-react/src/client/lib/list-store.d.ts +0 -2
  27. package/dist/types/luna-react/src/client/lib/resolve-value.d.ts +0 -5
  28. package/dist/types/luna-react/src/client/lib/source-store.d.ts +7 -4
  29. package/dist/types/luna-react/src/client/lib/state-store.d.ts +0 -4
  30. package/dist/types/luna-react/src/client/lib/store-helper.d.ts +5 -15
  31. package/dist/types/luna-react/src/client/lib/value-store.d.ts +0 -4
  32. package/dist/types/luna-react/src/component/column.d.ts +2 -0
  33. package/dist/types/luna-react/src/component/description.d.ts +9 -0
  34. package/dist/types/luna-react/src/component/field/{field-set.d.ts → field-set-static.d.ts} +1 -1
  35. package/dist/types/luna-react/src/component/field/field.d.ts +1 -1
  36. package/dist/types/luna-react/src/component/field-description.d.ts +3 -2
  37. package/dist/types/luna-react/src/component/form.d.ts +9 -0
  38. package/dist/types/luna-react/src/component/input-group.d.ts +2 -0
  39. package/dist/types/luna-react/src/component/input-label.d.ts +2 -0
  40. package/dist/types/luna-react/src/component/slot/slot-base.d.ts +2 -0
  41. package/dist/types/luna-react/src/lib/visibility.d.ts +3 -0
  42. package/dist/types/luna-react/src/server/component/field.d.ts +2 -0
  43. package/dist/types/luna-react/src/server/component/list-slot.d.ts +2 -0
  44. package/dist/types/luna-react/src/server/component/slot.d.ts +15 -0
  45. package/docs/forms/submit.md +8 -7
  46. package/docs/setup.md +39 -19
  47. package/docs/validation/overview.md +1 -1
  48. package/package.json +5 -5
  49. 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
- * Not released the way the per-name families in `store-helper` are, and it does
16
- * not need to be for the same reason it is keyed this way: a position is reused
17
- * where a stable id only ever climbs, so the keys here are bounded by the
18
- * widest the form has ever been rather than by every row it has ever held.
19
- * Measured going 1 -> 20 -> 14 -> 20 rows: the released families fall back to
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
- /** What the host says about one field, with the sentinel already read. */
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 reportSourceAtom: import("jotai-family").AtomFamily<string, import("jotai").WritableAtom<DataSource | undefined, [target: string, value: DataSource | undefined], void>>;
3
- export declare const clearInputSourceAtom: import("jotai").WritableAtom<null, [contributorNames: string[]], void> & {
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 releaseInputSourceAtom: import("jotai").WritableAtom<null, [names: string[]], void> & {
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 createNestedRecordAtomFamily<TInner, TRecord extends Record<string, Record<string, TInner>> = Record<string, Record<string, TInner>>>(baseAtom: PrimitiveAtom<TRecord>, options?: NestedAtomFamilyOptions<TInner>): import("jotai-family").AtomFamily<string, import("jotai").WritableAtom<TInner | undefined, [target: string, value: TInner | undefined], void>>;
8
- export declare function createNestedReleaseAtom(family: {
9
- remove: (name: string) => void;
10
- }): import("jotai").WritableAtom<null, [names: string[]], void> & {
11
- init: null;
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,5 +1,5 @@
1
1
  import { type Section, type Style } from '../../../../luna-core/index';
2
- export declare function FieldSet(props: Readonly<{
2
+ export declare function StaticFieldSet(props: Readonly<{
3
3
  advanced?: {
4
4
  step?: boolean;
5
5
  };
@@ -3,7 +3,7 @@ import type { Children } from '../../type';
3
3
  export type FieldProps = Readonly<{
4
4
  children: Children;
5
5
  disabled?: boolean;
6
- errors?: Record<string, string[]>;
6
+ errors?: string[];
7
7
  field: Field;
8
8
  lang?: string;
9
9
  style?: Style;
@@ -1,8 +1,9 @@
1
1
  import type { Config } from '../type';
2
2
  import type { Field } from '../../../luna-core/index';
3
- export declare function FieldDescription(props: Readonly<{
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
- }>): import("react").JSX.Element;
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,2 @@
1
+ import type { FieldProps } from '../../component/field/field';
2
+ export declare function Field(props: FieldProps): import("react").JSX.Element;
@@ -0,0 +1,2 @@
1
+ import type { ListProps } from '../../component/field/field-list';
2
+ export declare function ListSlot(props: ListProps): import("react").JSX.Element;
@@ -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;
@@ -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, ... } })` skips the parse
117
- entirely. The action is called with the raw `FormData` and the schema, and
118
- nothing is checked, reported or cleared on the way — for a form whose action
119
- does its own parsing. With no action at all, submitting does nothing.
120
-
121
- Remember that this object [replaces the defaults rather than merging](../setup.md#validation),
122
- so pass the keys you still want.
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 | 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`, `jotai-family` | `^2.0.0` / `^1.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.5.0` | merging the classes the components render |
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`, `column`, `list-item-card` — so a design
52
- system can restyle the structure without patching the library. The components
53
- you register yourself are yours to style; these slots cover the scaffolding
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
- **This object replaces the defaults, it does not merge into them.** Passing
103
- `{ change: false }` also turns off `blur`, `submit` and `showError`, so the form
104
- stops validating on blur and loses its error summary with no indication why.
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.86",
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.5.0",
28
+ "tailwind-merge": "^3.7.0",
30
29
  "zod": "^4.0.0"
31
30
  },
32
31
  "devDependencies": {
33
- "@luna-form/core": "0.0.86",
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;