react-luna-form 0.0.85 → 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/type.d.ts +30 -16
- package/dist/types/luna-core/util/build.d.ts +3 -1
- package/dist/types/luna-core/util/extract.d.ts +22 -0
- package/dist/types/luna-core/util/is-input.d.ts +13 -0
- package/dist/types/luna-core/util/prepare.d.ts +1 -1
- package/dist/types/luna-core/util/schema.d.ts +5 -5
- 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 +37 -9
- 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/context/failed-submit-context.d.ts +3 -0
- package/dist/types/luna-react/src/client/context/reveal-context.d.ts +1 -0
- package/dist/types/luna-react/src/client/hook/use-disclosure.d.ts +1 -0
- package/dist/types/luna-react/src/client/hook/use-entry-atom.d.ts +18 -0
- package/dist/types/luna-react/src/client/hook/use-form-action.d.ts +2 -1
- package/dist/types/luna-react/src/client/hook/use-host-entry.d.ts +17 -0
- package/dist/types/luna-react/src/client/hook/use-input-core.d.ts +6 -8
- package/dist/types/luna-react/src/client/hook/use-input.d.ts +1 -1
- 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-schema.d.ts +4 -2
- package/dist/types/luna-react/src/client/hook/use-value.d.ts +3 -3
- package/dist/types/luna-react/src/client/lib/compose-list-value.d.ts +29 -2
- package/dist/types/luna-react/src/client/lib/error-store.d.ts +3 -1
- package/dist/types/luna-react/src/client/lib/host-value-store.d.ts +28 -0
- package/dist/types/luna-react/src/client/lib/list-store.d.ts +6 -4
- 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 -1
- package/dist/types/luna-react/src/client/lib/state-store.d.ts +0 -1
- package/dist/types/luna-react/src/client/lib/store-helper.d.ts +5 -7
- package/dist/types/luna-react/src/client/lib/value-store.d.ts +0 -1
- package/dist/types/luna-react/src/component/collapsible.d.ts +2 -1
- 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 +11 -0
- package/dist/types/luna-react/src/component/input/input-base.d.ts +1 -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/dist/types/luna-react/src/type.d.ts +1 -0
- package/docs/events/change.md +21 -7
- package/docs/fields/custom-inputs.md +4 -0
- package/docs/fields/input.md +9 -3
- package/docs/fields/list.md +2 -0
- package/docs/fields/specialized-selectors.md +4 -0
- package/docs/forms/submit.md +14 -8
- package/docs/setup.md +39 -19
- package/docs/structure/sections.md +3 -1
- package/docs/validation/overview.md +10 -1
- package/package.json +7 -7
- package/dist/types/luna-react/src/client/component/field/field-with-state.d.ts +0 -13
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { PrimitiveAtom } from 'jotai';
|
|
2
|
+
/**
|
|
3
|
+
* One entry of a record the whole form shares, as an atom of the component that
|
|
4
|
+
* reads it.
|
|
5
|
+
*
|
|
6
|
+
* A family did this before: one atom per name, kept in a module-level cache for
|
|
7
|
+
* the life of the page. That cache never let go on its own, so it had to be
|
|
8
|
+
* emptied by hand -- release atoms, a call in `useStore`, and a comment on the
|
|
9
|
+
* loop to avoid -- and two of the three families grew anyway, a key per row ever
|
|
10
|
+
* added and a key per name ever shown. Made here, the atom goes when the
|
|
11
|
+
* component does, and there is nothing left to release.
|
|
12
|
+
*/
|
|
13
|
+
export declare function useEntryAtom<T>(base: PrimitiveAtom<Record<string, T>>, name: string): import("jotai").WritableAtom<NonNullable<T> | undefined, [next: T | undefined], void>;
|
|
14
|
+
/** The same for a record of contributions. See `createContributionAtom`. */
|
|
15
|
+
export declare function useContributionAtom<T>(base: PrimitiveAtom<Record<string, Record<string, T>>>, name: string, options: Readonly<{
|
|
16
|
+
merge: (values: T[]) => T | undefined;
|
|
17
|
+
validateTarget: (target: string) => boolean;
|
|
18
|
+
}>): import("jotai").WritableAtom<T | undefined, [target: string, value: T | undefined], void>;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type FormEvent } from 'react';
|
|
1
2
|
import { type Field, type FormStateError, type Nullable, type Schemas, type ZodSchema } from '../../../../luna-core/index';
|
|
2
3
|
export type FormState<T> = {
|
|
3
4
|
data: Nullable<T>;
|
|
@@ -10,4 +11,4 @@ export type FormActionOptions<T> = {
|
|
|
10
11
|
translations?: Record<string, string>;
|
|
11
12
|
validation?: boolean;
|
|
12
13
|
};
|
|
13
|
-
export declare function useFormState<T, F = Record<string, unknown>>(getSchema: () => readonly [Schemas, Field[]], action?: (formData: F, schema?: ZodSchema) => Promise<FormState<T>>, options?: FormActionOptions<T>): readonly [(payload: FormData) => void, FormState<T>, boolean];
|
|
14
|
+
export declare function useFormState<T, F = Record<string, unknown>>(getSchema: () => readonly [Schemas, Field[]], action?: (formData: F, schema?: ZodSchema) => Promise<FormState<T>>, options?: FormActionOptions<T>): readonly [(payload: FormData) => void, FormState<T>, boolean, (event: FormEvent<HTMLFormElement>) => void];
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type HostEntry } from '../lib/host-value-store';
|
|
2
|
+
/**
|
|
3
|
+
* What the host says about one field. Re-renders this field when its own entry
|
|
4
|
+
* changes, and only then.
|
|
5
|
+
*/
|
|
6
|
+
export declare function useHostEntry(name: string): HostEntry;
|
|
7
|
+
/**
|
|
8
|
+
* The same answer, read at the moment it is asked rather than at the moment the
|
|
9
|
+
* component rendered.
|
|
10
|
+
*
|
|
11
|
+
* For a reader that decides once and marks itself done. The store is written
|
|
12
|
+
* from the form's effect, and a parent's effects run after its children's, so a
|
|
13
|
+
* child asking during its own effect is always one commit behind. Asking from
|
|
14
|
+
* the microtask that follows the commit is not: every effect in that commit has
|
|
15
|
+
* run by then, the form's write included.
|
|
16
|
+
*/
|
|
17
|
+
export declare function useHostEntryReader(name: string): () => HostEntry;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type AriaAttributes, type CommonProps, type DataAttributes, type DataSource, type Field, type
|
|
1
|
+
import { type AriaAttributes, type CommonProps, type DataAttributes, type DataSource, type Field, type Schema, type Value } from '../../../../luna-core/index';
|
|
2
2
|
import type { Config, InputChange } from '../../type';
|
|
3
3
|
export type InputCoreProps = Readonly<{
|
|
4
4
|
ariaAttributes?: AriaAttributes;
|
|
@@ -7,23 +7,22 @@ export type InputCoreProps = Readonly<{
|
|
|
7
7
|
context?: Record<string, unknown>;
|
|
8
8
|
dataAttributes?: DataAttributes;
|
|
9
9
|
field: Field;
|
|
10
|
-
|
|
10
|
+
getField: (name: string) => Field | undefined;
|
|
11
11
|
horizontal?: boolean;
|
|
12
|
-
|
|
12
|
+
onRegister: (name: string, schema: Schema, field: Field) => void;
|
|
13
13
|
onUnmount: (name: string, options?: {
|
|
14
14
|
keepValue?: boolean;
|
|
15
15
|
}) => void;
|
|
16
16
|
onValueChange?: (input: InputChange) => void;
|
|
17
|
+
readOnly?: boolean;
|
|
17
18
|
translations?: Record<string, string>;
|
|
18
|
-
value?: Nullable<Record<string, unknown>>;
|
|
19
19
|
}>;
|
|
20
20
|
export declare function useInputCore(props: InputCoreProps, deps: Readonly<{
|
|
21
21
|
setSource: (target: string, source?: DataSource) => void;
|
|
22
22
|
setValue: (value: unknown) => void;
|
|
23
|
-
shouldSkipOnChange: () => boolean;
|
|
24
23
|
value: unknown;
|
|
25
24
|
}>): {
|
|
26
|
-
readonly applyChangeEventsRef: import("react").RefObject<(
|
|
25
|
+
readonly applyChangeEventsRef: import("react").RefObject<(selected: unknown) => void>;
|
|
27
26
|
readonly commonProps: {
|
|
28
27
|
placeholder: string;
|
|
29
28
|
disabled?: boolean;
|
|
@@ -34,9 +33,8 @@ export declare function useInputCore(props: InputCoreProps, deps: Readonly<{
|
|
|
34
33
|
readonly entity: string | undefined;
|
|
35
34
|
readonly hasClickable: boolean;
|
|
36
35
|
readonly onBlur: (event: React.FocusEvent<HTMLInputElement>) => void;
|
|
37
|
-
readonly onValueChangeRef: import("react").RefObject<(
|
|
36
|
+
readonly onValueChangeRef: import("react").RefObject<(value: Value) => void>;
|
|
38
37
|
readonly setTimeoutRef: (callback: () => void, delay: number) => void;
|
|
39
|
-
readonly shouldSkipOnChange: () => boolean;
|
|
40
38
|
readonly validated: (value: Value) => void;
|
|
41
39
|
readonly valueRef: import("react").RefObject<unknown>;
|
|
42
40
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import type { Field, Schema } from '../../../../luna-core/index';
|
|
2
|
-
export declare function useInput(field: Field,
|
|
2
|
+
export declare function useInput(field: Field, onRegister: (name: string, schema: Schema, field: Field) => void, onUnmount: (name: string, options?: {
|
|
3
3
|
keepValue?: boolean;
|
|
4
4
|
}) => void, translations?: Record<string, string>): import("zod").ZodType<unknown, unknown, import("zod/v4/core").$ZodTypeInternals<unknown, unknown>>;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The latest value a commit left, for the code that runs after it: an event
|
|
3
|
+
* handler, an effect, a callback whose identity has to stay steady across
|
|
4
|
+
* renders.
|
|
5
|
+
*
|
|
6
|
+
* Written from a layout effect and not from the render body, which is the whole
|
|
7
|
+
* point. A render is not a promise that anything reached the screen -- React
|
|
8
|
+
* throws one away when a transition is interrupted or a boundary retries -- and
|
|
9
|
+
* a ref assigned while rendering keeps whatever that discarded render held,
|
|
10
|
+
* which is props nobody ever saw. A commit is the moment a value becomes real,
|
|
11
|
+
* so that is when this writes it. It is also what the React Compiler asks of a
|
|
12
|
+
* component before it will optimize it.
|
|
13
|
+
*
|
|
14
|
+
* Layout and not `useEffect`: every effect of a commit runs after every layout
|
|
15
|
+
* effect of that same commit, so an effect reading this ref reads the value of
|
|
16
|
+
* the render it belongs to, whatever order the hooks were declared in.
|
|
17
|
+
*
|
|
18
|
+
* Reading it while rendering is still wrong, and still reported by
|
|
19
|
+
* `react-hooks/refs`: there the value is one commit old. What a render needs is
|
|
20
|
+
* the value itself.
|
|
21
|
+
*/
|
|
22
|
+
export declare function useLatest<T>(value: T): import("react").RefObject<T>;
|
|
@@ -1,6 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
2
|
+
* What a row holds right now: the form's own state over the initial value tree,
|
|
3
|
+
* for a `when` that has to follow what the user types.
|
|
4
|
+
*
|
|
5
|
+
* Subscribed to the row's keys and not to the record. Every field in the form
|
|
6
|
+
* writes into that one record, so a row that read it woke up on every keystroke
|
|
7
|
+
* anywhere and walked every key in the form to find its own. The selection is
|
|
8
|
+
* compared shallowly, so a keystroke outside the row recomputes the pick, finds
|
|
9
|
+
* the same keys, and renders nothing.
|
|
10
|
+
*
|
|
11
|
+
* Only a condition needs this, and only a condition asks for it: the components
|
|
12
|
+
* that own one render the child that calls this hook, so a row with no
|
|
13
|
+
* condition to answer never subscribes at all.
|
|
14
|
+
*
|
|
15
|
+
* The atom is made with the component that reads it and goes with it: jotai
|
|
16
|
+
* caches a selection under the selector function, `pickRow` makes a new one per
|
|
17
|
+
* row, and both are held weakly, so nothing is kept by name for the life of the
|
|
18
|
+
* page.
|
|
5
19
|
*/
|
|
6
20
|
export declare function useLiveItemValue(name: string, initialValue?: Record<string, unknown> | unknown[] | null): unknown;
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import type { Field, Schema
|
|
2
|
-
export declare function useSchema(): readonly [() => readonly [
|
|
1
|
+
import type { Field, Schema } from '../../../../luna-core/index';
|
|
2
|
+
export declare function useSchema(): readonly [() => readonly [{
|
|
3
|
+
[k: string]: Schema;
|
|
4
|
+
}, Field[]], (name: string) => Field | undefined, (name: string, schema: Schema, field: Field) => void, (name: string, options?: {
|
|
3
5
|
keepValue?: boolean;
|
|
4
6
|
}) => void];
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { type Field
|
|
2
|
-
export declare function useValue(field: Field
|
|
3
|
-
readonly setValue: (
|
|
1
|
+
import { type Field } from '../../../../luna-core/index';
|
|
2
|
+
export declare function useValue(field: Field): {
|
|
3
|
+
readonly setValue: (next: unknown) => void;
|
|
4
4
|
readonly shouldSkipOnChange: () => boolean;
|
|
5
5
|
readonly value: {} | undefined;
|
|
6
6
|
};
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
import { type Nullable } from '../../../../luna-core/index';
|
|
1
2
|
import type { MountedList } from './list-store';
|
|
2
|
-
|
|
3
|
+
/** A list's rows as a consumer is given them, in order. */
|
|
4
|
+
export type ListRows = Array<Record<string, unknown>>;
|
|
3
5
|
export declare function itemKey(listName: string, stableId: number, leafName: string): string;
|
|
4
6
|
/**
|
|
5
7
|
* The three places a leaf can be found, declared in the order they are tried.
|
|
@@ -38,4 +40,29 @@ export type ValueSources = {
|
|
|
38
40
|
* @param listName - The list's name, already carrying its ancestors' stable
|
|
39
41
|
* ids (`rules.0.rule`), which is what makes the keys unambiguous.
|
|
40
42
|
*/
|
|
41
|
-
export declare function composeListValue(listName: string, { items, leafNames }: MountedList, sources: ValueSources):
|
|
43
|
+
export declare function composeListValue(listName: string, { items, leafNames }: MountedList, sources: ValueSources): ListRows;
|
|
44
|
+
/**
|
|
45
|
+
* Every positional name a change to a list's rows can have left out of date,
|
|
46
|
+
* each with what it holds now.
|
|
47
|
+
*
|
|
48
|
+
* A consumer that keeps each report in one record -- the way the docs suggest
|
|
49
|
+
* keeping values -- holds a row's leaves there twice: inside the list's array,
|
|
50
|
+
* and under their own positional names, `items.0.value`, from the reports the
|
|
51
|
+
* leaves made as they were typed in. Removing a row moves every row after it
|
|
52
|
+
* up one position; assigning rows rewrites what every position holds. The
|
|
53
|
+
* array is reported again either way, but the names would go on holding what
|
|
54
|
+
* the rows used to hold, and `resolveEntry` tries a flat name before the path
|
|
55
|
+
* into the array: the next row to read one of them gets a row that is gone.
|
|
56
|
+
*
|
|
57
|
+
* So every name from `from` to the end of the longer of the two lists comes
|
|
58
|
+
* back, with what its position holds now, or `undefined` where no row is left
|
|
59
|
+
* -- whether or not that differs from before, because what the consumer holds
|
|
60
|
+
* is not necessarily what the list last said.
|
|
61
|
+
*
|
|
62
|
+
* @param base - The list's positional name, as the consumer addresses it.
|
|
63
|
+
* @param from - The first position the change can have touched.
|
|
64
|
+
*/
|
|
65
|
+
export declare function positionalEntries(base: string, from: number, previous: ListRows, next: ListRows): Array<{
|
|
66
|
+
name: string;
|
|
67
|
+
value: unknown;
|
|
68
|
+
}>;
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
export declare const inputErrorAtom: import("jotai").PrimitiveAtom<Record<string, string[]>> & {
|
|
2
|
+
init: Record<string, string[]>;
|
|
3
|
+
};
|
|
1
4
|
export declare const clearInputErrorAtom: import("jotai").WritableAtom<null, [names: string[]], void> & {
|
|
2
5
|
init: null;
|
|
3
6
|
};
|
|
4
7
|
export declare const reportErrorAtom: import("jotai").WritableAtom<null, [newValue: Record<string, string[]>], void> & {
|
|
5
8
|
init: null;
|
|
6
9
|
};
|
|
7
|
-
export declare const reportInputErrorAtom: import("jotai-family").AtomFamily<string, import("jotai").WritableAtom<string[] | undefined, [newValue: string[] | undefined], void>>;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { Nullable } from '../../../../luna-core/index';
|
|
2
|
+
export declare const hostValueAtom: import("jotai").PrimitiveAtom<Nullable<Record<string, unknown>>> & {
|
|
3
|
+
init: Nullable<Record<string, unknown>>;
|
|
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;
|
|
12
|
+
/**
|
|
13
|
+
* One field's entry in that record.
|
|
14
|
+
*
|
|
15
|
+
* Keyed by the name the record actually uses -- the POSITIONAL one. A leaf
|
|
16
|
+
* inside a list is named after its row's stable id, and the two diverge the
|
|
17
|
+
* moment a non-tail row is removed, so the caller translates before it
|
|
18
|
+
* subscribes. That translation lives in a React context, which an atom cannot
|
|
19
|
+
* read; doing it at the call site is what keeps this correct where a memo
|
|
20
|
+
* comparator could not be. See `ListPathContext`.
|
|
21
|
+
*
|
|
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.
|
|
27
|
+
*/
|
|
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.
|
|
@@ -16,7 +15,7 @@ export type MountedList = {
|
|
|
16
15
|
* The list's own `hidden`, as its definition declares it.
|
|
17
16
|
*
|
|
18
17
|
* Here rather than looked up, because there is nowhere to look it up: the
|
|
19
|
-
* schema registry `
|
|
18
|
+
* schema registry `getField` answers from is filled by `onRegister` on the
|
|
20
19
|
* input path, and a container never goes through it. That gap is what let a
|
|
21
20
|
* list keep its values through a hide -- the branch that clears a target
|
|
22
21
|
* reverting to its static hidden asked only that registry, found nothing,
|
|
@@ -27,10 +26,13 @@ export type MountedList = {
|
|
|
27
26
|
* rather than a gap: the only target worth clearing is one that was showing.
|
|
28
27
|
*/
|
|
29
28
|
hidden?: boolean;
|
|
30
|
-
/**
|
|
29
|
+
/**
|
|
30
|
+
* The list's own `advanced.keepValue`, published for the same reason as
|
|
31
|
+
* `hidden` and flattened on the way in: this registry answers about a list
|
|
32
|
+
* that is on screen, not about the JSON that declared it.
|
|
33
|
+
*/
|
|
31
34
|
keepValue?: boolean;
|
|
32
35
|
};
|
|
33
36
|
export declare const mountedListsAtom: import("jotai").PrimitiveAtom<Record<string, MountedList>> & {
|
|
34
37
|
init: Record<string, MountedList>;
|
|
35
38
|
};
|
|
36
|
-
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,5 +1,11 @@
|
|
|
1
1
|
import { type DataSource } from '../../../../luna-core/index';
|
|
2
|
-
export declare const
|
|
2
|
+
export declare const sourceAtom: import("jotai").PrimitiveAtom<Record<string, Record<string, DataSource>>> & {
|
|
3
|
+
init: Record<string, Record<string, DataSource>>;
|
|
4
|
+
};
|
|
5
|
+
export declare const SOURCE_OPTIONS: {
|
|
6
|
+
readonly merge: (values: DataSource[]) => DataSource | undefined;
|
|
7
|
+
readonly validateTarget: (target: string) => boolean;
|
|
8
|
+
};
|
|
3
9
|
export declare const clearInputSourceAtom: import("jotai").WritableAtom<null, [contributorNames: string[]], void> & {
|
|
4
10
|
init: null;
|
|
5
11
|
};
|
|
@@ -2,4 +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 reportFieldStateAtom: import("jotai-family").AtomFamily<string, import("jotai").WritableAtom<FieldState | undefined, [newValue: FieldState | undefined], void>>;
|
|
@@ -1,10 +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
|
|
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>;
|
|
8
8
|
export declare function createNestedClearAtom<TInner>(baseAtom: PrimitiveAtom<Record<string, Record<string, TInner>>>): import("jotai").WritableAtom<null, [contributorNames: string[]], void> & {
|
|
9
9
|
init: null;
|
|
10
10
|
};
|
|
@@ -21,6 +21,4 @@ export declare function createAtomStore<T>(initialValue?: Record<string, T>): {
|
|
|
21
21
|
bulkReport: import("jotai").WritableAtom<null, [newValue: Record<string, T>], void> & {
|
|
22
22
|
init: null;
|
|
23
23
|
};
|
|
24
|
-
report: import("jotai-family").AtomFamily<string, import("jotai").WritableAtom<NonNullable<T> | undefined, [newValue: T | undefined], void>>;
|
|
25
24
|
};
|
|
26
|
-
export {};
|
|
@@ -7,7 +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 reportValueAtom: import("jotai-family").AtomFamily<string, import("jotai").WritableAtom<{} | undefined, [newValue: unknown], void>>;
|
|
11
10
|
export declare const appliedAutoFillAtom: import("jotai").PrimitiveAtom<Record<string, unknown>> & {
|
|
12
11
|
init: Record<string, unknown>;
|
|
13
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,5 +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';
|
|
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;
|
|
3
11
|
export declare function Form(props: Readonly<{
|
|
4
12
|
advanced?: {
|
|
5
13
|
step?: boolean;
|
|
@@ -9,8 +17,11 @@ export declare function Form(props: Readonly<{
|
|
|
9
17
|
config: Config;
|
|
10
18
|
control?: Control;
|
|
11
19
|
definition?: Definition;
|
|
20
|
+
fieldSet?: React.ComponentType<React.ComponentProps<typeof StaticFieldSet>>;
|
|
21
|
+
guard?: React.ComponentType<GuardProps>;
|
|
12
22
|
isPending?: boolean;
|
|
13
23
|
noValidate?: boolean;
|
|
24
|
+
onSubmit?: (event: FormEvent<HTMLFormElement>) => void;
|
|
14
25
|
readOnly?: boolean;
|
|
15
26
|
sections: Sections;
|
|
16
27
|
translations?: Record<string, string>;
|
|
@@ -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/events/change.md
CHANGED
|
@@ -159,7 +159,7 @@ A row's key can name a field that is itself a `list`, in which case its value is
|
|
|
159
159
|
Every rule above holds one level down as well: an inner list assigns rather than adds, honours its own `advanced.length`, and keeps the identity of the rows that survive. Two more only come up here:
|
|
160
160
|
|
|
161
161
|
- **A row that names an inner list without giving it rows empties it.** `"checks": []`, a `checks` key holding something that is not rows, and no `checks` key at all all mean the same thing — none — rather than leaving behind what the row in that position had.
|
|
162
|
-
- **The consumer is told
|
|
162
|
+
- **The consumer is told the whole tree at once**, under the outer list's name, with the inner rows already in it, and then every positional name the assignment rewrote (`groups.0.label`, `groups.1.checks.0.v`) with what that position holds now, or nothing where no row is left. A consumer that keeps each report in one record would otherwise go on holding the values of the rows that went away under those names. The inner lists then report their own paths (`groups.0.checks`) as they take their rows, the same way they do when a row is added or removed by hand.
|
|
163
163
|
|
|
164
164
|
This is what the relative syntax cannot do. `"groups/checks"` reaches the inner list of the row the sender is sitting in, and `"groups.0.checks"` reaches the first one; neither can say "every group", so a control that appends a group has to assign the outer list and carry the inner rows along with it.
|
|
165
165
|
|
|
@@ -237,11 +237,19 @@ It does not matter how the form phrases the hiding. A rule whose state is
|
|
|
237
237
|
so the field falls back to its own `hidden`, are the same act and clear the
|
|
238
238
|
same values -- containers included.
|
|
239
239
|
|
|
240
|
+
What the cleared target decided goes with it. A target with `state` rules of its
|
|
241
|
+
own asserted them on the strength of its value, and that value is gone, so its
|
|
242
|
+
rules are undone as if it held nothing: a field it revealed is hidden again --
|
|
243
|
+
and cleared, if it too falls back to `hidden` -- and so on down the chain.
|
|
244
|
+
Showing the first target again brings it back empty, and nothing it had revealed
|
|
245
|
+
comes back with it. A target that keeps its value through the hide keeps what
|
|
246
|
+
its rules decided as well; see below.
|
|
247
|
+
|
|
240
248
|
#### Keeping a value through a hide
|
|
241
249
|
|
|
242
|
-
A field that declares `keepValue: true` is put away rather than
|
|
243
|
-
it leaves what it held, showing it again gives it back, and the
|
|
244
|
-
told nothing because nothing was taken.
|
|
250
|
+
A field that declares `advanced.keepValue: true` is put away rather than
|
|
251
|
+
dropped: hiding it leaves what it held, showing it again gives it back, and the
|
|
252
|
+
consumer is told nothing because nothing was taken.
|
|
245
253
|
|
|
246
254
|
```json
|
|
247
255
|
{
|
|
@@ -249,15 +257,21 @@ told nothing because nothing was taken.
|
|
|
249
257
|
"name": "raw",
|
|
250
258
|
"type": "textarea",
|
|
251
259
|
"hidden": true,
|
|
252
|
-
"keepValue": true
|
|
260
|
+
"advanced": { "keepValue": true }
|
|
253
261
|
}
|
|
254
262
|
```
|
|
255
263
|
|
|
264
|
+
It sits in `advanced` beside [`transient`](#transient-controls), which is the
|
|
265
|
+
other key that decides what ends up stored, rather than beside `hidden`: the
|
|
266
|
+
two read as a pair, but `hidden` is what the form does to the field and this is
|
|
267
|
+
what the field is.
|
|
268
|
+
|
|
256
269
|
It is declared on the FIELD and not on the rule, for the same reason the clear
|
|
257
270
|
does not care how the hiding was phrased: a field either survives being put
|
|
258
271
|
away or it does not, and which of several rules happened to hide it this time
|
|
259
|
-
says nothing about that. A
|
|
260
|
-
|
|
272
|
+
says nothing about that. A
|
|
273
|
+
[`list`](../fields/list.md#advanced-configuration-advanced-object) may declare
|
|
274
|
+
it too, and then it covers every value its rows hold.
|
|
261
275
|
|
|
262
276
|
Reach for it where two fields are two views of the same thing and the form
|
|
263
277
|
swaps between them -- there, hiding one is a change of scenery, not a change of
|
|
@@ -60,6 +60,10 @@ its own handlers must call the ones it received, or the form never learns the
|
|
|
60
60
|
value changed: validation will not run, and neither will any `change` event the
|
|
61
61
|
field declares.
|
|
62
62
|
|
|
63
|
+
A `readonly` field arrives `disabled` and without a `name`. Its value is still
|
|
64
|
+
submitted, but by the form, in hidden inputs of its own: nothing your component
|
|
65
|
+
renders for it is sent, so it is sent once, whatever your component renders.
|
|
66
|
+
|
|
63
67
|
## Forwarding `id` is what gives the field its name
|
|
64
68
|
|
|
65
69
|
The label is rendered by this library, outside your component, as
|