@typed/ui 1.0.0-beta.4 → 1.0.0-beta.5
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 +53 -9
- package/dist/Alert.d.ts +78 -0
- package/dist/Alert.d.ts.map +1 -0
- package/dist/Alert.js +37 -0
- package/dist/Button.d.ts +144 -0
- package/dist/Button.d.ts.map +1 -0
- package/dist/Button.js +38 -0
- package/dist/Carousel.d.ts +547 -0
- package/dist/Carousel.d.ts.map +1 -0
- package/dist/Carousel.js +387 -0
- package/dist/Checkbox.d.ts +203 -0
- package/dist/Checkbox.d.ts.map +1 -0
- package/dist/Checkbox.js +140 -0
- package/dist/Collection.d.ts +254 -0
- package/dist/Collection.d.ts.map +1 -0
- package/dist/Collection.js +218 -0
- package/dist/Combobox.d.ts +516 -0
- package/dist/Combobox.d.ts.map +1 -0
- package/dist/Combobox.js +371 -0
- package/dist/Component.d.ts +127 -0
- package/dist/Component.d.ts.map +1 -0
- package/dist/Component.js +60 -0
- package/dist/Composite.d.ts +823 -0
- package/dist/Composite.d.ts.map +1 -0
- package/dist/Composite.js +615 -0
- package/dist/Dialog.d.ts +544 -0
- package/dist/Dialog.d.ts.map +1 -0
- package/dist/Dialog.js +355 -0
- package/dist/Disclosure.d.ts +219 -0
- package/dist/Disclosure.d.ts.map +1 -0
- package/dist/Disclosure.js +128 -0
- package/dist/Dom/Events.d.ts +122 -0
- package/dist/Dom/Events.d.ts.map +1 -0
- package/dist/Dom/Events.js +192 -0
- package/dist/Dom/Props.d.ts +161 -0
- package/dist/Dom/Props.d.ts.map +1 -0
- package/dist/Dom/Props.js +110 -0
- package/dist/Dom/Refs.d.ts +58 -0
- package/dist/Dom/Refs.d.ts.map +1 -0
- package/dist/Dom/Refs.js +61 -0
- package/dist/Dom/Render.d.ts +59 -0
- package/dist/Dom/Render.d.ts.map +1 -0
- package/dist/Dom/Render.js +71 -0
- package/dist/Dom/Types.d.ts +570 -0
- package/dist/Dom/Types.d.ts.map +1 -0
- package/dist/Dom/Types.js +1 -0
- package/dist/Dom/index.d.ts +20 -0
- package/dist/Dom/index.d.ts.map +1 -0
- package/dist/Dom/index.js +8 -0
- package/dist/Dom.d.ts +14 -0
- package/dist/Dom.d.ts.map +1 -0
- package/dist/Dom.js +13 -0
- package/dist/Focusable.d.ts +85 -0
- package/dist/Focusable.d.ts.map +1 -0
- package/dist/Focusable.js +35 -0
- package/dist/Form.d.ts +1695 -0
- package/dist/Form.d.ts.map +1 -0
- package/dist/Form.js +987 -0
- package/dist/Grid.d.ts +569 -0
- package/dist/Grid.d.ts.map +1 -0
- package/dist/Grid.js +379 -0
- package/dist/Group.d.ts +147 -0
- package/dist/Group.d.ts.map +1 -0
- package/dist/Group.js +63 -0
- package/dist/Heading.d.ts +86 -0
- package/dist/Heading.d.ts.map +1 -0
- package/dist/Heading.js +48 -0
- package/dist/Hovercard.d.ts +297 -0
- package/dist/Hovercard.d.ts.map +1 -0
- package/dist/Hovercard.js +188 -0
- package/dist/HttpRouter.d.ts +129 -6
- package/dist/HttpRouter.d.ts.map +1 -1
- package/dist/HttpRouter.js +196 -53
- package/dist/Link.d.ts +67 -28
- package/dist/Link.d.ts.map +1 -1
- package/dist/Link.js +91 -37
- package/dist/Listbox.d.ts +437 -0
- package/dist/Listbox.d.ts.map +1 -0
- package/dist/Listbox.js +316 -0
- package/dist/Menu.d.ts +972 -0
- package/dist/Menu.d.ts.map +1 -0
- package/dist/Menu.js +731 -0
- package/dist/Menubar.d.ts +367 -0
- package/dist/Menubar.d.ts.map +1 -0
- package/dist/Menubar.js +265 -0
- package/dist/Meter.d.ts +217 -0
- package/dist/Meter.d.ts.map +1 -0
- package/dist/Meter.js +94 -0
- package/dist/NativeDetails.d.ts +41 -0
- package/dist/NativeDetails.d.ts.map +1 -0
- package/dist/NativeDetails.js +40 -0
- package/dist/NativeDialog.d.ts +64 -0
- package/dist/NativeDialog.d.ts.map +1 -0
- package/dist/NativeDialog.js +50 -0
- package/dist/NativePopover.d.ts +41 -0
- package/dist/NativePopover.d.ts.map +1 -0
- package/dist/NativePopover.js +46 -0
- package/dist/Popover.d.ts +241 -0
- package/dist/Popover.d.ts.map +1 -0
- package/dist/Popover.js +141 -0
- package/dist/RadioGroup.d.ts +432 -0
- package/dist/RadioGroup.d.ts.map +1 -0
- package/dist/RadioGroup.js +291 -0
- package/dist/Role.d.ts +64 -0
- package/dist/Role.d.ts.map +1 -0
- package/dist/Role.js +27 -0
- package/dist/Select.d.ts +529 -0
- package/dist/Select.d.ts.map +1 -0
- package/dist/Select.js +407 -0
- package/dist/Separator.d.ts +54 -0
- package/dist/Separator.d.ts.map +1 -0
- package/dist/Separator.js +26 -0
- package/dist/Slider.d.ts +188 -0
- package/dist/Slider.d.ts.map +1 -0
- package/dist/Slider.js +96 -0
- package/dist/SpinButton.d.ts +188 -0
- package/dist/SpinButton.d.ts.map +1 -0
- package/dist/SpinButton.js +96 -0
- package/dist/Storybook.d.ts +76 -0
- package/dist/Storybook.d.ts.map +1 -0
- package/dist/Storybook.js +102 -0
- package/dist/Switch.d.ts +187 -0
- package/dist/Switch.d.ts.map +1 -0
- package/dist/Switch.js +116 -0
- package/dist/Tab.d.ts +26 -0
- package/dist/Tab.d.ts.map +1 -0
- package/dist/Tab.js +25 -0
- package/dist/Tabs.d.ts +591 -0
- package/dist/Tabs.d.ts.map +1 -0
- package/dist/Tabs.js +346 -0
- package/dist/Toolbar.d.ts +366 -0
- package/dist/Toolbar.d.ts.map +1 -0
- package/dist/Toolbar.js +245 -0
- package/dist/Tooltip.d.ts +296 -0
- package/dist/Tooltip.d.ts.map +1 -0
- package/dist/Tooltip.js +172 -0
- package/dist/Tree.d.ts +591 -0
- package/dist/Tree.d.ts.map +1 -0
- package/dist/Tree.js +434 -0
- package/dist/TreeGrid.d.ts +645 -0
- package/dist/TreeGrid.d.ts.map +1 -0
- package/dist/TreeGrid.js +420 -0
- package/dist/VisuallyHidden.d.ts +54 -0
- package/dist/VisuallyHidden.d.ts.map +1 -0
- package/dist/VisuallyHidden.js +27 -0
- package/dist/WindowSplitter.d.ts +376 -0
- package/dist/WindowSplitter.d.ts.map +1 -0
- package/dist/WindowSplitter.js +222 -0
- package/dist/index.d.ts +49 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +49 -0
- package/package.json +45 -18
- package/src/HttpRouter.test.ts +0 -256
- package/src/HttpRouter.ts +0 -165
- package/src/Link.test.ts +0 -84
- package/src/Link.ts +0 -107
- package/src/index.ts +0 -2
package/dist/Form.d.ts
ADDED
|
@@ -0,0 +1,1695 @@
|
|
|
1
|
+
import * as Effect from "effect/Effect";
|
|
2
|
+
import * as Context from "effect/Context";
|
|
3
|
+
import * as Schema from "effect/Schema";
|
|
4
|
+
import { RefSubject } from "@typed/fx";
|
|
5
|
+
import type * as Scope from "effect/Scope";
|
|
6
|
+
import type { Fx } from "@typed/fx/Fx";
|
|
7
|
+
import { EventHandler, type Renderable, type RenderEvent, type RenderTemplate } from "@typed/template";
|
|
8
|
+
import * as Dom from "./Dom.js";
|
|
9
|
+
import type { HostResult } from "./Dom/Types.js";
|
|
10
|
+
/**
|
|
11
|
+
* Interaction metadata tracked for one form field.
|
|
12
|
+
*
|
|
13
|
+
* @remarks
|
|
14
|
+
* ## Why
|
|
15
|
+
* Dirty and touched state belong to renderer-independent form state so they can
|
|
16
|
+
* be tested without mounting UI and consumed by any host.
|
|
17
|
+
*
|
|
18
|
+
* ## Ownership and lifetime
|
|
19
|
+
* Stored inside `FormState`; updates are owned by that RefSubject's Scope and
|
|
20
|
+
* survive replacement of individual rendered controls.
|
|
21
|
+
*
|
|
22
|
+
* @since 1.0.0
|
|
23
|
+
* @category models
|
|
24
|
+
*/
|
|
25
|
+
export interface FieldMeta {
|
|
26
|
+
/** Stored mutation flag for the field; update operations decide when it becomes true. */
|
|
27
|
+
readonly dirty: boolean;
|
|
28
|
+
/** Whether user or programmatic field mutation has occurred. */
|
|
29
|
+
readonly touched: boolean;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Serializable renderer-independent state of a form.
|
|
33
|
+
*
|
|
34
|
+
* @remarks
|
|
35
|
+
* ## Why
|
|
36
|
+
* Values, defaults, validation messages, interaction metadata, and submission
|
|
37
|
+
* state can be inspected and tested without rendering a component.
|
|
38
|
+
*
|
|
39
|
+
* ## Ownership and lifetime
|
|
40
|
+
* A `FormState` RefSubject owns this value. Renderers subscribe to it; they do
|
|
41
|
+
* not contain or become the source of truth.
|
|
42
|
+
*
|
|
43
|
+
* @since 1.0.0
|
|
44
|
+
* @category models
|
|
45
|
+
*/
|
|
46
|
+
export interface State<Values extends object = object> {
|
|
47
|
+
/** Current decoded field values. */
|
|
48
|
+
readonly values: Values;
|
|
49
|
+
/** Exact baseline reference used by reset and retained independently from current values. */
|
|
50
|
+
readonly defaultValues: Values;
|
|
51
|
+
/** Current validation messages keyed by field name. */
|
|
52
|
+
readonly errors: Partial<Record<keyof Values & string, string>>;
|
|
53
|
+
/** Dirty/touched metadata keyed by field name. */
|
|
54
|
+
readonly meta: Partial<Record<keyof Values & string, FieldMeta>>;
|
|
55
|
+
/** Whether a valid-submit Effect is currently running. */
|
|
56
|
+
readonly submitting: boolean;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Input used to construct a hydrated form state.
|
|
60
|
+
*
|
|
61
|
+
* @remarks
|
|
62
|
+
* ## Why
|
|
63
|
+
* Defaults make the common case concise while allowing SSR callers to provide
|
|
64
|
+
* deterministic identity and server-known validation state.
|
|
65
|
+
*
|
|
66
|
+
* ## Ownership and lifetime
|
|
67
|
+
* `values` and an explicit `defaultValues` are retained by reference, including
|
|
68
|
+
* their nested objects. When `defaultValues` is omitted, both state fields
|
|
69
|
+
* initially reference the exact `values` object. Subsequent helpers replace the
|
|
70
|
+
* top-level `values` record but do not deep-clone nested values.
|
|
71
|
+
*
|
|
72
|
+
* @since 1.0.0
|
|
73
|
+
* @category models
|
|
74
|
+
*/
|
|
75
|
+
export interface InitialState<Values extends object> {
|
|
76
|
+
/** Stable relationship/hydration id; provide it for deterministic SSR. */
|
|
77
|
+
readonly id?: string;
|
|
78
|
+
/** Initial decoded values. */
|
|
79
|
+
readonly values: Values;
|
|
80
|
+
/** Exact reset-baseline reference; defaults to the same object as `values`. */
|
|
81
|
+
readonly defaultValues?: Values;
|
|
82
|
+
/** Optional initial validation messages. */
|
|
83
|
+
readonly errors?: Partial<Record<keyof Values & string, string>>;
|
|
84
|
+
/** Optional initial field metadata. */
|
|
85
|
+
readonly meta?: Partial<Record<keyof Values & string, FieldMeta>>;
|
|
86
|
+
/** Optional initial submission state. */
|
|
87
|
+
readonly submitting?: boolean;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Hydrated RefSubject carrying form state plus runtime schema metadata.
|
|
91
|
+
*
|
|
92
|
+
* @remarks
|
|
93
|
+
* ## Why
|
|
94
|
+
* State is serializable across SSR while codecs and field validators stay as
|
|
95
|
+
* runtime capabilities. This keeps validation type-safe without trying to
|
|
96
|
+
* serialize executable schemas.
|
|
97
|
+
*
|
|
98
|
+
* ## Ownership and lifetime
|
|
99
|
+
* The surrounding Effect Scope owns the hydrated RefSubject and its subscribers.
|
|
100
|
+
* On the server, serializable state is emitted for hydration; on the client it
|
|
101
|
+
* must be restored before mounted controls begin producing updates.
|
|
102
|
+
*
|
|
103
|
+
* @since 1.0.0
|
|
104
|
+
* @category models
|
|
105
|
+
*/
|
|
106
|
+
export type FormState<Values extends object> = RefSubject.HydratedRefSubject<State<Values>, Schema.SchemaError> & {
|
|
107
|
+
/** Runtime identity used to scope field/error relationships. Pass an id for deterministic SSR. */
|
|
108
|
+
readonly id: string;
|
|
109
|
+
/** Runtime-only validation codec; it is deliberately absent from hydration state. */
|
|
110
|
+
readonly codec: Schema.Codec<Values, unknown>;
|
|
111
|
+
/** Runtime field codecs used for field-level validation. */
|
|
112
|
+
readonly fields: Readonly<Record<keyof Values & string, Schema.Codec<any, any>>>;
|
|
113
|
+
};
|
|
114
|
+
/**
|
|
115
|
+
* Context service exposed to schema-bound descendant controls.
|
|
116
|
+
*
|
|
117
|
+
* @remarks
|
|
118
|
+
* ## Why
|
|
119
|
+
* A bound form can share its state through Effect context without a component tree.
|
|
120
|
+
*
|
|
121
|
+
* ## Ownership and lifetime
|
|
122
|
+
* The root form provides the service only for its rendered Fx lifetime; it does
|
|
123
|
+
* not own the underlying state beyond that state's Scope.
|
|
124
|
+
*
|
|
125
|
+
* @since 1.0.0
|
|
126
|
+
* @category services
|
|
127
|
+
*/
|
|
128
|
+
export interface FormService<Values extends object> {
|
|
129
|
+
/** Form state visible to bound descendants. */
|
|
130
|
+
readonly state: FormState<Values>;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Effect context service used by schema-bound form controls.
|
|
134
|
+
*
|
|
135
|
+
* @remarks
|
|
136
|
+
* ## Why
|
|
137
|
+
* Bound controls avoid threading `state` through every call while their
|
|
138
|
+
* service requirement remains visible in the Fx type.
|
|
139
|
+
*
|
|
140
|
+
* ## Ownership and lifetime
|
|
141
|
+
* `Form` provides the service for its child render lifetime; use outside that
|
|
142
|
+
* boundary fails with the ordinary Effect missing-service defect.
|
|
143
|
+
*
|
|
144
|
+
* @since 1.0.0
|
|
145
|
+
* @category services
|
|
146
|
+
*/
|
|
147
|
+
export declare const CurrentForm: Context.Service<FormService<any>, FormService<any>>;
|
|
148
|
+
declare const FieldMetaSchema: Schema.Struct<{
|
|
149
|
+
readonly dirty: Schema.Boolean;
|
|
150
|
+
readonly touched: Schema.Boolean;
|
|
151
|
+
}>;
|
|
152
|
+
/**
|
|
153
|
+
* Schema field map accepted by the schema-bound form factory.
|
|
154
|
+
*
|
|
155
|
+
* @remarks
|
|
156
|
+
* ## Why
|
|
157
|
+
* A Struct's individual codecs drive field-name inference and field-level decoding.
|
|
158
|
+
*
|
|
159
|
+
* ## Ownership and lifetime
|
|
160
|
+
* Codecs are runtime values retained by the created form API; they are not hydrated.
|
|
161
|
+
*
|
|
162
|
+
* @since 1.0.0
|
|
163
|
+
* @category models
|
|
164
|
+
*/
|
|
165
|
+
export type FormFields = Readonly<Record<string, Schema.Codec<any, any>>>;
|
|
166
|
+
type OptionalFields<Fields extends FormFields, Value extends Schema.Constraint> = {
|
|
167
|
+
readonly [Key in keyof Fields]: Schema.optionalKey<Value>;
|
|
168
|
+
};
|
|
169
|
+
type InitialStateFor<Fields extends FormFields> = {
|
|
170
|
+
readonly id?: string;
|
|
171
|
+
readonly values: Schema.Struct.Type<Fields>;
|
|
172
|
+
readonly defaultValues?: Schema.Struct.Type<Fields>;
|
|
173
|
+
readonly errors?: Schema.Struct.Type<OptionalFields<Fields, typeof Schema.String>>;
|
|
174
|
+
readonly meta?: Schema.Struct.Type<OptionalFields<Fields, typeof FieldMetaSchema>>;
|
|
175
|
+
readonly submitting?: boolean;
|
|
176
|
+
};
|
|
177
|
+
/**
|
|
178
|
+
* Builds the serializable schema for a form's hydrated state.
|
|
179
|
+
*
|
|
180
|
+
* @remarks
|
|
181
|
+
* ## Why
|
|
182
|
+
* The hydration payload needs validation independent from runtime-only field codecs.
|
|
183
|
+
*
|
|
184
|
+
* ## Ownership and lifetime
|
|
185
|
+
* Pure schema construction; the returned Schema acquires no Scope or subscription.
|
|
186
|
+
*
|
|
187
|
+
* @example
|
|
188
|
+
* ```ts
|
|
189
|
+
* import { StateSchema } from "@typed/ui/Form"
|
|
190
|
+
* import { Schema } from "effect"
|
|
191
|
+
*
|
|
192
|
+
* const codec = Schema.Struct({ email: Schema.String })
|
|
193
|
+
* const stateCodec = StateSchema(codec)
|
|
194
|
+
* ```
|
|
195
|
+
*
|
|
196
|
+
* @since 1.0.0
|
|
197
|
+
* @category schemas
|
|
198
|
+
*/
|
|
199
|
+
export declare function StateSchema<const Fields extends FormFields>(codec: Schema.Struct<Fields>): Schema.Struct<{
|
|
200
|
+
readonly values: Schema.Struct<Fields>;
|
|
201
|
+
readonly defaultValues: Schema.Struct<Fields>;
|
|
202
|
+
readonly errors: Schema.Struct<OptionalFields<Fields, Schema.String>>;
|
|
203
|
+
readonly meta: Schema.Struct<OptionalFields<Fields, Schema.Struct<{
|
|
204
|
+
readonly dirty: Schema.Boolean;
|
|
205
|
+
readonly touched: Schema.Boolean;
|
|
206
|
+
}>>>;
|
|
207
|
+
readonly submitting: Schema.Boolean;
|
|
208
|
+
}>;
|
|
209
|
+
/**
|
|
210
|
+
* Creates a Scope-owned hydrated form RefSubject from a Struct codec.
|
|
211
|
+
*
|
|
212
|
+
* @remarks
|
|
213
|
+
* ## Why
|
|
214
|
+
* One constructor establishes values, defaults, validation state, field codecs,
|
|
215
|
+
* and hydration identity consistently.
|
|
216
|
+
*
|
|
217
|
+
* ## Ownership and lifetime
|
|
218
|
+
* Requires `Scope.Scope`. Provide an explicit `id` during SSR; the counter-based
|
|
219
|
+
* fallback is process/order dependent. Only state data hydrates—`codec` and
|
|
220
|
+
* `fields` are reattached from the live Struct on each runtime.
|
|
221
|
+
*
|
|
222
|
+
* @example
|
|
223
|
+
* ```ts
|
|
224
|
+
* import { makeState } from "@typed/ui/Form"
|
|
225
|
+
* import { Effect, Schema } from "effect"
|
|
226
|
+
*
|
|
227
|
+
* const codec = Schema.Struct({ email: Schema.String })
|
|
228
|
+
* const program = Effect.gen(function* () {
|
|
229
|
+
* const state = yield* makeState(codec, { id: "signup", values: { email: "" } })
|
|
230
|
+
* return state
|
|
231
|
+
* })
|
|
232
|
+
* ```
|
|
233
|
+
*
|
|
234
|
+
* @since 1.0.0
|
|
235
|
+
* @category constructors
|
|
236
|
+
*/
|
|
237
|
+
export declare function makeState<const Fields extends FormFields>(codec: Schema.Struct<Fields>, initial: InitialStateFor<Fields>): Effect.Effect<RefSubject.HydratedRefSubject<{
|
|
238
|
+
readonly values: Schema.Struct.View<Fields, "Type", Schema.Struct.TypeOptionalKeys<Fields>, Schema.Struct.TypeMutableKeys<Fields>>;
|
|
239
|
+
readonly defaultValues: Schema.Struct.View<Fields, "Type", Schema.Struct.TypeOptionalKeys<Fields>, Schema.Struct.TypeMutableKeys<Fields>>;
|
|
240
|
+
readonly errors: Schema.Struct.View<OptionalFields<Fields, Schema.String>, "Type", Schema.Struct.TypeOptionalKeys<OptionalFields<Fields, Schema.String>>, Schema.Struct.TypeMutableKeys<OptionalFields<Fields, Schema.String>>>;
|
|
241
|
+
readonly meta: Schema.Struct.View<OptionalFields<Fields, Schema.Struct<{
|
|
242
|
+
readonly dirty: Schema.Boolean;
|
|
243
|
+
readonly touched: Schema.Boolean;
|
|
244
|
+
}>>, "Type", Schema.Struct.TypeOptionalKeys<OptionalFields<Fields, Schema.Struct<{
|
|
245
|
+
readonly dirty: Schema.Boolean;
|
|
246
|
+
readonly touched: Schema.Boolean;
|
|
247
|
+
}>>>, Schema.Struct.TypeMutableKeys<OptionalFields<Fields, Schema.Struct<{
|
|
248
|
+
readonly dirty: Schema.Boolean;
|
|
249
|
+
readonly touched: Schema.Boolean;
|
|
250
|
+
}>>>>;
|
|
251
|
+
readonly submitting: boolean;
|
|
252
|
+
}, Schema.SchemaError, never, Schema.Struct.DecodingServices<{
|
|
253
|
+
readonly values: Schema.Struct<Fields>;
|
|
254
|
+
readonly defaultValues: Schema.Struct<Fields>;
|
|
255
|
+
readonly errors: Schema.Struct<OptionalFields<Fields, Schema.String>>;
|
|
256
|
+
readonly meta: Schema.Struct<OptionalFields<Fields, Schema.Struct<{
|
|
257
|
+
readonly dirty: Schema.Boolean;
|
|
258
|
+
readonly touched: Schema.Boolean;
|
|
259
|
+
}>>>;
|
|
260
|
+
readonly submitting: Schema.Boolean;
|
|
261
|
+
}> | Schema.Struct.EncodingServices<{
|
|
262
|
+
readonly values: Schema.Struct<Fields>;
|
|
263
|
+
readonly defaultValues: Schema.Struct<Fields>;
|
|
264
|
+
readonly errors: Schema.Struct<OptionalFields<Fields, Schema.String>>;
|
|
265
|
+
readonly meta: Schema.Struct<OptionalFields<Fields, Schema.Struct<{
|
|
266
|
+
readonly dirty: Schema.Boolean;
|
|
267
|
+
readonly touched: Schema.Boolean;
|
|
268
|
+
}>>>;
|
|
269
|
+
readonly submitting: Schema.Boolean;
|
|
270
|
+
}>> & {
|
|
271
|
+
codec: Schema.Struct<Fields>;
|
|
272
|
+
fields: Fields;
|
|
273
|
+
id: string;
|
|
274
|
+
}, never, Scope.Scope>;
|
|
275
|
+
/**
|
|
276
|
+
* Field names whose decoded value is assignable to `Value`.
|
|
277
|
+
*
|
|
278
|
+
* @remarks
|
|
279
|
+
* ## Why
|
|
280
|
+
* Control options reject incompatible fields at compile time.
|
|
281
|
+
*
|
|
282
|
+
* ## Ownership and lifetime
|
|
283
|
+
* Type-only and resource-free.
|
|
284
|
+
*
|
|
285
|
+
* @since 1.0.0
|
|
286
|
+
* @category type-level
|
|
287
|
+
*/
|
|
288
|
+
export type FieldNameFor<Values extends object, Value> = {
|
|
289
|
+
[Key in keyof Values & string]: Values[Key] extends Value ? Key : never;
|
|
290
|
+
}[keyof Values & string];
|
|
291
|
+
/**
|
|
292
|
+
* Struct field names matching both decoded and encoded control value types.
|
|
293
|
+
*
|
|
294
|
+
* @remarks
|
|
295
|
+
* ## Why
|
|
296
|
+
* Schema-bound controls require an encoded form compatible with the native element.
|
|
297
|
+
*
|
|
298
|
+
* ## Ownership and lifetime
|
|
299
|
+
* Type-only and resource-free.
|
|
300
|
+
*
|
|
301
|
+
* @since 1.0.0
|
|
302
|
+
* @category type-level
|
|
303
|
+
*/
|
|
304
|
+
export type SchemaFieldNameFor<Fields extends FormFields, Value, Encoded> = {
|
|
305
|
+
[Key in keyof Fields & string]: Fields[Key]["Type"] extends Value ? Fields[Key]["Encoded"] extends Encoded ? Key : never : never;
|
|
306
|
+
}[keyof Fields & string];
|
|
307
|
+
/**
|
|
308
|
+
* Options shared by state-explicit native input components.
|
|
309
|
+
*
|
|
310
|
+
* @remarks
|
|
311
|
+
* ## Why
|
|
312
|
+
* Controls bind a typed field directly to renderer-independent state while
|
|
313
|
+
* leaving every ordinary input prop and native event available.
|
|
314
|
+
*
|
|
315
|
+
* ## Ownership and lifetime
|
|
316
|
+
* The rendered control subscribes within its Scope. `state` remains independently
|
|
317
|
+
* owned and may outlive that control; custom codecs are retained for that host.
|
|
318
|
+
*
|
|
319
|
+
* @since 1.0.0
|
|
320
|
+
* @category component-options
|
|
321
|
+
*/
|
|
322
|
+
export interface InputOptions<Values extends object, Value> extends Dom.HostOptions<HTMLInputElement> {
|
|
323
|
+
/** Renderer-independent form state to read and update. */
|
|
324
|
+
readonly state: FormState<Values>;
|
|
325
|
+
/** Type-compatible field name. */
|
|
326
|
+
readonly name: FieldNameFor<Values, Value>;
|
|
327
|
+
/** Optional string codec overriding the input type's default codec. */
|
|
328
|
+
readonly codec?: Schema.Codec<Value, string>;
|
|
329
|
+
}
|
|
330
|
+
/**
|
|
331
|
+
* String-valued native input options.
|
|
332
|
+
* @remarks
|
|
333
|
+
* ## Why
|
|
334
|
+
* Names are restricted to fields a text-like control can represent without an incompatible cast.
|
|
335
|
+
* ## Ownership and lifetime
|
|
336
|
+
* The control Scope owns DOM work; the referenced state and optional codec are borrowed.
|
|
337
|
+
* @since 1.0.0
|
|
338
|
+
* @category component-options
|
|
339
|
+
*/
|
|
340
|
+
export type TextInputOptions<Values extends object> = InputOptions<Values, string>;
|
|
341
|
+
/**
|
|
342
|
+
* Finite-number native input options.
|
|
343
|
+
* @remarks
|
|
344
|
+
* ## Why
|
|
345
|
+
* Names are restricted to numeric fields compatible with number/range decoding.
|
|
346
|
+
* ## Ownership and lifetime
|
|
347
|
+
* The control Scope owns DOM work; the referenced state and optional codec are borrowed.
|
|
348
|
+
* @since 1.0.0
|
|
349
|
+
* @category component-options
|
|
350
|
+
*/
|
|
351
|
+
export type NumberInputOptions<Values extends object> = InputOptions<Values, number>;
|
|
352
|
+
/**
|
|
353
|
+
* Date-valued native input options.
|
|
354
|
+
* @remarks
|
|
355
|
+
* ## Why
|
|
356
|
+
* Names are restricted to Date fields compatible with native date-string decoding.
|
|
357
|
+
* ## Ownership and lifetime
|
|
358
|
+
* The control Scope owns DOM work; the referenced state and optional codec are borrowed.
|
|
359
|
+
* @since 1.0.0
|
|
360
|
+
* @category component-options
|
|
361
|
+
*/
|
|
362
|
+
export type DateInputOptions<Values extends object> = InputOptions<Values, Date>;
|
|
363
|
+
declare function inputProps<Values extends object, Value>(options: InputOptions<Values, Value>, type: string, codec: Schema.Codec<Value, string>): () => {
|
|
364
|
+
readonly type: string;
|
|
365
|
+
readonly name: FieldNameFor<Values, Value>;
|
|
366
|
+
readonly "aria-describedby": RefSubject.Computed<string | undefined, Schema.SchemaError, never>;
|
|
367
|
+
readonly "aria-invalid": RefSubject.Computed<true | undefined, Schema.SchemaError, never>;
|
|
368
|
+
readonly ".value": RefSubject.Computed<string, Schema.SchemaError, never>;
|
|
369
|
+
readonly oninput: EventHandler.EventHandler<Event, Schema.SchemaError, never>;
|
|
370
|
+
};
|
|
371
|
+
type InputProps<Values extends object, Value> = ReturnType<ReturnType<typeof inputProps<Values, Value>>>;
|
|
372
|
+
type RenderableComponentOptions<Options> = Pick<Options, Extract<keyof Options, "props" | "ref" | "content" | Dom.EventHandlerProperty>>;
|
|
373
|
+
/**
|
|
374
|
+
* Options for a schema-bound native input.
|
|
375
|
+
*
|
|
376
|
+
* @remarks
|
|
377
|
+
* ## Why
|
|
378
|
+
* The factory's Struct infers compatible field names, so callers need not pass state or a codec.
|
|
379
|
+
*
|
|
380
|
+
* ## Ownership and lifetime
|
|
381
|
+
* State is borrowed from `CurrentForm`; the control's Scope owns its DOM subscription.
|
|
382
|
+
*
|
|
383
|
+
* @since 1.0.0
|
|
384
|
+
* @category component-options
|
|
385
|
+
*/
|
|
386
|
+
export interface SchemaBoundInputOptions<Fields extends FormFields, Value> extends Dom.HostOptions<HTMLInputElement> {
|
|
387
|
+
/** Struct field whose decoded type matches `Value` and whose encoded type is string. */
|
|
388
|
+
readonly name: SchemaFieldNameFor<Fields, Value, string>;
|
|
389
|
+
}
|
|
390
|
+
/**
|
|
391
|
+
* Options for a schema-bound masked text input.
|
|
392
|
+
*
|
|
393
|
+
* @remarks
|
|
394
|
+
* ## Why
|
|
395
|
+
* Any field with a string encoding can use the Struct field codec as its mask codec.
|
|
396
|
+
*
|
|
397
|
+
* ## Ownership and lifetime
|
|
398
|
+
* State is borrowed from `CurrentForm`; the control Scope owns DOM work.
|
|
399
|
+
*
|
|
400
|
+
* @since 1.0.0
|
|
401
|
+
* @category component-options
|
|
402
|
+
*/
|
|
403
|
+
export interface SchemaBoundMaskedInputOptions<Fields extends FormFields> extends Dom.HostOptions<HTMLInputElement> {
|
|
404
|
+
/** Struct field whose codec accepts the input's string representation. */
|
|
405
|
+
readonly name: SchemaFieldNameFor<Fields, unknown, string>;
|
|
406
|
+
}
|
|
407
|
+
/**
|
|
408
|
+
* Options for a schema-bound boolean checkbox.
|
|
409
|
+
*
|
|
410
|
+
* @remarks
|
|
411
|
+
* ## Why
|
|
412
|
+
* Field-name inference limits the native checked binding to boolean fields.
|
|
413
|
+
*
|
|
414
|
+
* ## Ownership and lifetime
|
|
415
|
+
* State is borrowed from `CurrentForm`; the control Scope owns DOM work.
|
|
416
|
+
*
|
|
417
|
+
* @since 1.0.0
|
|
418
|
+
* @category component-options
|
|
419
|
+
*/
|
|
420
|
+
export interface SchemaBoundCheckboxOptions<Values extends object> extends Dom.HostOptions<HTMLInputElement> {
|
|
421
|
+
/** Boolean field controlled by the checkbox. */
|
|
422
|
+
readonly name: BooleanFieldName<Values>;
|
|
423
|
+
}
|
|
424
|
+
/**
|
|
425
|
+
* Options for a schema-bound native select.
|
|
426
|
+
*
|
|
427
|
+
* @remarks
|
|
428
|
+
* ## Why
|
|
429
|
+
* Native option markup remains caller-authored while selection binds to a string field.
|
|
430
|
+
*
|
|
431
|
+
* ## Ownership and lifetime
|
|
432
|
+
* State is borrowed from `CurrentForm`; rendered content is owned by the control Scope.
|
|
433
|
+
*
|
|
434
|
+
* @since 1.0.0
|
|
435
|
+
* @category component-options
|
|
436
|
+
*/
|
|
437
|
+
export interface SchemaBoundSelectOptions<Values extends object> extends Dom.HostOptions<HTMLSelectElement> {
|
|
438
|
+
/** String field controlled by the select. */
|
|
439
|
+
readonly name: FieldNameFor<Values, string>;
|
|
440
|
+
/** Native option/optgroup renderable content. */
|
|
441
|
+
readonly content: Renderable.Any;
|
|
442
|
+
}
|
|
443
|
+
/**
|
|
444
|
+
* Options for a schema-bound field-error region.
|
|
445
|
+
*
|
|
446
|
+
* @remarks
|
|
447
|
+
* ## Why
|
|
448
|
+
* Error text and ARIA relationships derive from the same form identity and field name.
|
|
449
|
+
*
|
|
450
|
+
* ## Ownership and lifetime
|
|
451
|
+
* State is borrowed from `CurrentForm`; the error host Scope owns its subscription.
|
|
452
|
+
*
|
|
453
|
+
* @since 1.0.0
|
|
454
|
+
* @category component-options
|
|
455
|
+
*/
|
|
456
|
+
export interface SchemaBoundErrorOptions<Values extends object> extends Dom.HostOptions<HTMLDivElement> {
|
|
457
|
+
/** Field whose current validation message is rendered. */
|
|
458
|
+
readonly name: keyof Values & string;
|
|
459
|
+
}
|
|
460
|
+
/**
|
|
461
|
+
* Options for a schema-bound reset button.
|
|
462
|
+
*
|
|
463
|
+
* @remarks
|
|
464
|
+
* ## Why
|
|
465
|
+
* The button can use native semantics without receiving state explicitly.
|
|
466
|
+
*
|
|
467
|
+
* ## Ownership and lifetime
|
|
468
|
+
* State is borrowed from `CurrentForm`; button content is Scope-owned renderable work.
|
|
469
|
+
*
|
|
470
|
+
* @since 1.0.0
|
|
471
|
+
* @category component-options
|
|
472
|
+
*/
|
|
473
|
+
export interface SchemaBoundResetOptions extends Dom.HostOptions<HTMLButtonElement> {
|
|
474
|
+
/** Reset button label/content. */
|
|
475
|
+
readonly content: Renderable.Any;
|
|
476
|
+
}
|
|
477
|
+
/**
|
|
478
|
+
* Options for a schema-bound array append button.
|
|
479
|
+
*
|
|
480
|
+
* @remarks
|
|
481
|
+
* ## Why
|
|
482
|
+
* Array field and element types are inferred from the form schema.
|
|
483
|
+
*
|
|
484
|
+
* ## Ownership and lifetime
|
|
485
|
+
* State is borrowed from `CurrentForm`; the click Effect and content share the host Scope.
|
|
486
|
+
*
|
|
487
|
+
* @since 1.0.0
|
|
488
|
+
* @category component-options
|
|
489
|
+
*/
|
|
490
|
+
export interface SchemaBoundPushOptions<Values extends object, Name extends ArrayFieldName<Values>> extends Dom.HostOptions<HTMLButtonElement> {
|
|
491
|
+
/** Array-valued field to append to. */
|
|
492
|
+
readonly name: Name;
|
|
493
|
+
/** Type-compatible item appended on activation. */
|
|
494
|
+
readonly value: ArrayFieldValue<Values, Name>;
|
|
495
|
+
/** Button label/content. */
|
|
496
|
+
readonly content: Renderable.Any;
|
|
497
|
+
}
|
|
498
|
+
/**
|
|
499
|
+
* Options for a schema-bound array removal button.
|
|
500
|
+
*
|
|
501
|
+
* @remarks
|
|
502
|
+
* ## Why
|
|
503
|
+
* The field is constrained to arrays and the index remains an explicit local operation.
|
|
504
|
+
*
|
|
505
|
+
* ## Ownership and lifetime
|
|
506
|
+
* State is borrowed from `CurrentForm`; the click Effect and content share the host Scope.
|
|
507
|
+
*
|
|
508
|
+
* @since 1.0.0
|
|
509
|
+
* @category component-options
|
|
510
|
+
*/
|
|
511
|
+
export interface SchemaBoundRemoveOptions<Values extends object, Name extends ArrayFieldName<Values>> extends Dom.HostOptions<HTMLButtonElement> {
|
|
512
|
+
/** Array-valued field to remove from. */
|
|
513
|
+
readonly name: Name;
|
|
514
|
+
/** Zero-based item index removed on activation. */
|
|
515
|
+
readonly index: number;
|
|
516
|
+
/** Button label/content. */
|
|
517
|
+
readonly content: Renderable.Any;
|
|
518
|
+
}
|
|
519
|
+
/**
|
|
520
|
+
* Public component contract shared by state-explicit native input factories.
|
|
521
|
+
*
|
|
522
|
+
* @remarks
|
|
523
|
+
* ## Why
|
|
524
|
+
*
|
|
525
|
+
* Text-like, numeric, range, and date controls differ in their default codec while preserving one
|
|
526
|
+
* field-inference, host-override, error, and service contract. Naming that contract keeps emitted
|
|
527
|
+
* declarations readable without hiding any generic channel behind a private compiler alias.
|
|
528
|
+
*
|
|
529
|
+
* ## Ownership and lifetime
|
|
530
|
+
*
|
|
531
|
+
* Calling an input component starts no work. The returned Fx requires the Scope and RenderTemplate
|
|
532
|
+
* that own DOM rendering; the supplied FormState remains independently owned and may outlive it.
|
|
533
|
+
*
|
|
534
|
+
* @example
|
|
535
|
+
* ```ts
|
|
536
|
+
* import { InputComponent, makeState, TextInput } from "@typed/ui/Form"
|
|
537
|
+
* import { html } from "@typed/template"
|
|
538
|
+
* import { Effect, Schema } from "effect"
|
|
539
|
+
*
|
|
540
|
+
* const Text: InputComponent<string> = TextInput
|
|
541
|
+
* const rendered = Effect.gen(function* () {
|
|
542
|
+
* const state = yield* makeState(Schema.Struct({ name: Schema.String }), {
|
|
543
|
+
* values: { name: "" }
|
|
544
|
+
* })
|
|
545
|
+
* return Text({ state, name: "name" }, (props) => html`<input ...${props} />`)
|
|
546
|
+
* })
|
|
547
|
+
* ```
|
|
548
|
+
*
|
|
549
|
+
* @since 1.0.0
|
|
550
|
+
* @category models
|
|
551
|
+
*/
|
|
552
|
+
export type InputComponent<Value> = <const Values extends object, const Options extends InputOptions<Values, Value>, const Host extends HostResult = never>(options: Options & Pick<InputOptions<Values, Value>, "state" | "name">, host?: Dom.HostOverride<Dom.RenderHostProps<Options, InputProps<Values, Value>>, "", Host>) => Fx<RenderEvent, Schema.SchemaError | Renderable.Error<RenderableComponentOptions<Options> | Host>, Renderable.Services<RenderableComponentOptions<Options> | Host> | Scope.Scope | RenderTemplate>;
|
|
553
|
+
/**
|
|
554
|
+
* Binds a native `input[type=text]` to a string field.
|
|
555
|
+
*
|
|
556
|
+
* @remarks
|
|
557
|
+
* ## Why
|
|
558
|
+
* The control uses the browser's real input event and a Schema codec while
|
|
559
|
+
* keeping state independently testable.
|
|
560
|
+
*
|
|
561
|
+
* ## Ownership and lifetime
|
|
562
|
+
* The control Scope owns DOM listeners/subscriptions; the supplied `FormState`
|
|
563
|
+
* may outlive the rendered input. A custom host must apply all merged props.
|
|
564
|
+
*
|
|
565
|
+
* @example
|
|
566
|
+
* ```ts
|
|
567
|
+
* import { TextInput, makeState } from "@typed/ui/Form"
|
|
568
|
+
* import { Effect, Schema } from "effect"
|
|
569
|
+
*
|
|
570
|
+
* const codec = Schema.Struct({ name: Schema.String })
|
|
571
|
+
* const input = Effect.gen(function* () {
|
|
572
|
+
* const state = yield* makeState(codec, { values: { name: "" } })
|
|
573
|
+
* return TextInput({ state, name: "name" })
|
|
574
|
+
* })
|
|
575
|
+
* ```
|
|
576
|
+
*
|
|
577
|
+
* @since 1.0.0
|
|
578
|
+
* @category components
|
|
579
|
+
*/
|
|
580
|
+
export declare const TextInput: InputComponent<string>;
|
|
581
|
+
/**
|
|
582
|
+
* Binds a native search input to a string field.
|
|
583
|
+
* @remarks
|
|
584
|
+
* ## Why
|
|
585
|
+
* Preserves the platform's search-input semantics while sharing Typed validation.
|
|
586
|
+
* ## Ownership and lifetime
|
|
587
|
+
* DOM work is control-Scope-owned; form state remains independently owned.
|
|
588
|
+
* @since 1.0.0
|
|
589
|
+
* @category components
|
|
590
|
+
*/
|
|
591
|
+
export declare const SearchInput: InputComponent<string>;
|
|
592
|
+
/**
|
|
593
|
+
* Binds a native email input to a string field.
|
|
594
|
+
* @remarks
|
|
595
|
+
* ## Why
|
|
596
|
+
* Keeps browser email affordances and constraints available alongside Schema validation.
|
|
597
|
+
* ## Ownership and lifetime
|
|
598
|
+
* DOM work is control-Scope-owned; form state remains independently owned.
|
|
599
|
+
* @since 1.0.0
|
|
600
|
+
* @category components
|
|
601
|
+
*/
|
|
602
|
+
export declare const EmailInput: InputComponent<string>;
|
|
603
|
+
/**
|
|
604
|
+
* Binds a native URL input to a string field.
|
|
605
|
+
* @remarks
|
|
606
|
+
* ## Why
|
|
607
|
+
* Keeps browser URL affordances while the schema remains the decoded state contract.
|
|
608
|
+
* ## Ownership and lifetime
|
|
609
|
+
* DOM work is control-Scope-owned; form state remains independently owned.
|
|
610
|
+
* @since 1.0.0
|
|
611
|
+
* @category components
|
|
612
|
+
*/
|
|
613
|
+
export declare const UrlInput: InputComponent<string>;
|
|
614
|
+
/**
|
|
615
|
+
* Binds a native telephone input to a string field.
|
|
616
|
+
* @remarks
|
|
617
|
+
* ## Why
|
|
618
|
+
* Preserves platform telephone keyboards and autocomplete behavior.
|
|
619
|
+
* ## Ownership and lifetime
|
|
620
|
+
* DOM work is control-Scope-owned; form state remains independently owned.
|
|
621
|
+
* @since 1.0.0
|
|
622
|
+
* @category components
|
|
623
|
+
*/
|
|
624
|
+
export declare const TelInput: InputComponent<string>;
|
|
625
|
+
/**
|
|
626
|
+
* Binds a native password input to a string field.
|
|
627
|
+
* @remarks
|
|
628
|
+
* ## Why
|
|
629
|
+
* Uses browser password handling instead of recreating sensitive-input behavior.
|
|
630
|
+
* ## Ownership and lifetime
|
|
631
|
+
* DOM work is control-Scope-owned; form state remains independently owned.
|
|
632
|
+
* @since 1.0.0
|
|
633
|
+
* @category components
|
|
634
|
+
*/
|
|
635
|
+
export declare const PasswordInput: InputComponent<string>;
|
|
636
|
+
/**
|
|
637
|
+
* Binds a native hidden input to a string field.
|
|
638
|
+
* @remarks
|
|
639
|
+
* ## Why
|
|
640
|
+
* Allows standards-based form serialization for non-visible values.
|
|
641
|
+
* ## Ownership and lifetime
|
|
642
|
+
* DOM work is control-Scope-owned; form state remains independently owned.
|
|
643
|
+
* @since 1.0.0
|
|
644
|
+
* @category components
|
|
645
|
+
*/
|
|
646
|
+
export declare const HiddenInput: InputComponent<string>;
|
|
647
|
+
/**
|
|
648
|
+
* Binds a native color input to a string field.
|
|
649
|
+
* @remarks
|
|
650
|
+
* ## Why
|
|
651
|
+
* Retains the browser's color picker while state receives its string value.
|
|
652
|
+
* ## Ownership and lifetime
|
|
653
|
+
* DOM work is control-Scope-owned; form state remains independently owned.
|
|
654
|
+
* @since 1.0.0
|
|
655
|
+
* @category components
|
|
656
|
+
*/
|
|
657
|
+
export declare const ColorInput: InputComponent<string>;
|
|
658
|
+
/**
|
|
659
|
+
* Binds a native time input to a string field.
|
|
660
|
+
* @remarks
|
|
661
|
+
* ## Why
|
|
662
|
+
* Preserves browser locale and time-entry behavior without inventing a picker.
|
|
663
|
+
* ## Ownership and lifetime
|
|
664
|
+
* DOM work is control-Scope-owned; form state remains independently owned.
|
|
665
|
+
* @since 1.0.0
|
|
666
|
+
* @category components
|
|
667
|
+
*/
|
|
668
|
+
export declare const TimeInput: InputComponent<string>;
|
|
669
|
+
/**
|
|
670
|
+
* Binds a native local date-time input to a string field.
|
|
671
|
+
* @remarks
|
|
672
|
+
* ## Why
|
|
673
|
+
* Keeps the platform's local date-time UI and its standard encoded value.
|
|
674
|
+
* ## Ownership and lifetime
|
|
675
|
+
* DOM work is control-Scope-owned; form state remains independently owned.
|
|
676
|
+
* @since 1.0.0
|
|
677
|
+
* @category components
|
|
678
|
+
*/
|
|
679
|
+
export declare const DateTimeLocalInput: InputComponent<string>;
|
|
680
|
+
/**
|
|
681
|
+
* Binds a native month input to a string field.
|
|
682
|
+
* @remarks
|
|
683
|
+
* ## Why
|
|
684
|
+
* Preserves the browser month picker and standardized string encoding.
|
|
685
|
+
* ## Ownership and lifetime
|
|
686
|
+
* DOM work is control-Scope-owned; form state remains independently owned.
|
|
687
|
+
* @since 1.0.0
|
|
688
|
+
* @category components
|
|
689
|
+
*/
|
|
690
|
+
export declare const MonthInput: InputComponent<string>;
|
|
691
|
+
/**
|
|
692
|
+
* Binds a native week input to a string field.
|
|
693
|
+
* @remarks
|
|
694
|
+
* ## Why
|
|
695
|
+
* Preserves platform week-entry behavior and standardized string encoding.
|
|
696
|
+
* ## Ownership and lifetime
|
|
697
|
+
* DOM work is control-Scope-owned; form state remains independently owned.
|
|
698
|
+
* @since 1.0.0
|
|
699
|
+
* @category components
|
|
700
|
+
*/
|
|
701
|
+
export declare const WeekInput: InputComponent<string>;
|
|
702
|
+
/**
|
|
703
|
+
* Binds a native number input to a finite number field.
|
|
704
|
+
* @remarks
|
|
705
|
+
* ## Why
|
|
706
|
+
* `FiniteFromString` makes the browser's string value an explicit typed decode.
|
|
707
|
+
* ## Ownership and lifetime
|
|
708
|
+
* DOM work is control-Scope-owned; form state remains independently owned.
|
|
709
|
+
* @since 1.0.0
|
|
710
|
+
* @category components
|
|
711
|
+
*/
|
|
712
|
+
export declare const NumberInput: InputComponent<number>;
|
|
713
|
+
/**
|
|
714
|
+
* Binds a native range input to a finite number field.
|
|
715
|
+
* @remarks
|
|
716
|
+
* ## Why
|
|
717
|
+
* Retains native slider interaction while exposing a decoded numeric value.
|
|
718
|
+
* ## Ownership and lifetime
|
|
719
|
+
* DOM work is control-Scope-owned; form state remains independently owned.
|
|
720
|
+
* @since 1.0.0
|
|
721
|
+
* @category components
|
|
722
|
+
*/
|
|
723
|
+
export declare const RangeInput: InputComponent<number>;
|
|
724
|
+
/**
|
|
725
|
+
* Binds a native date input to a `Date` field.
|
|
726
|
+
* @remarks
|
|
727
|
+
* ## Why
|
|
728
|
+
* `DateFromString` makes the native encoded value's conversion explicit and fallible.
|
|
729
|
+
* ## Ownership and lifetime
|
|
730
|
+
* DOM work is control-Scope-owned; form state remains independently owned.
|
|
731
|
+
* @since 1.0.0
|
|
732
|
+
* @category components
|
|
733
|
+
*/
|
|
734
|
+
export declare const DateInput: InputComponent<Date>;
|
|
735
|
+
/**
|
|
736
|
+
* Native value emitted by `FormData`.
|
|
737
|
+
* @remarks
|
|
738
|
+
* ## Why
|
|
739
|
+
* Browser serialization produces strings and Files; the union states that boundary exactly.
|
|
740
|
+
* ## Ownership and lifetime
|
|
741
|
+
* Files remain browser-owned objects referenced by the converted record.
|
|
742
|
+
* @since 1.0.0
|
|
743
|
+
* @category models
|
|
744
|
+
*/
|
|
745
|
+
export type FormDataValue = string | File;
|
|
746
|
+
/**
|
|
747
|
+
* Object representation of native FormData, preserving repeated names as arrays.
|
|
748
|
+
* @remarks
|
|
749
|
+
* ## Why
|
|
750
|
+
* A plain record is directly consumable by Effect Schema without losing repeats.
|
|
751
|
+
* ## Ownership and lifetime
|
|
752
|
+
* Conversion allocates arrays/record entries but retains original File objects.
|
|
753
|
+
* @since 1.0.0
|
|
754
|
+
* @category models
|
|
755
|
+
*/
|
|
756
|
+
export type FormDataRecord = Readonly<Record<string, FormDataValue | ReadonlyArray<FormDataValue>>>;
|
|
757
|
+
/**
|
|
758
|
+
* Converts native FormData to a record and preserves repeated fields as arrays.
|
|
759
|
+
* @remarks
|
|
760
|
+
* ## Why
|
|
761
|
+
* `Object.fromEntries` silently loses repeated names, which breaks checkbox,
|
|
762
|
+
* multiselect, and multi-file submissions.
|
|
763
|
+
* ## Ownership and lifetime
|
|
764
|
+
* The function is synchronous and resource-free; File values are not cloned.
|
|
765
|
+
* @example
|
|
766
|
+
* ```ts
|
|
767
|
+
* import { formDataToRecord } from "@typed/ui/Form"
|
|
768
|
+
*
|
|
769
|
+
* const data = new FormData()
|
|
770
|
+
* data.append("tag", "one")
|
|
771
|
+
* data.append("tag", "two")
|
|
772
|
+
* const record = formDataToRecord(data)
|
|
773
|
+
* ```
|
|
774
|
+
* @since 1.0.0
|
|
775
|
+
* @category conversions
|
|
776
|
+
*/
|
|
777
|
+
export declare function formDataToRecord(data: FormData): FormDataRecord;
|
|
778
|
+
/**
|
|
779
|
+
* Decodes native FormData through an Effect Schema codec.
|
|
780
|
+
* @remarks
|
|
781
|
+
* ## Why
|
|
782
|
+
* Browser serialization, repeated values, Files, and typed validation meet at
|
|
783
|
+
* one explicit fallible boundary.
|
|
784
|
+
* ## Ownership and lifetime
|
|
785
|
+
* The returned Effect is lazy and owns no browser resource; it references File
|
|
786
|
+
* objects present in the supplied FormData.
|
|
787
|
+
* @example
|
|
788
|
+
* ```ts
|
|
789
|
+
* import { decodeFormData } from "@typed/ui/Form"
|
|
790
|
+
* import { Schema } from "effect"
|
|
791
|
+
*
|
|
792
|
+
* const decode = decodeFormData(Schema.Struct({ name: Schema.String }), new FormData())
|
|
793
|
+
* ```
|
|
794
|
+
* @since 1.0.0
|
|
795
|
+
* @category conversions
|
|
796
|
+
*/
|
|
797
|
+
export declare function decodeFormData<Values extends object, Codec extends Schema.Codec<Values, unknown>>(codec: Codec, data: FormData): Effect.Effect<Codec["Type"], Schema.SchemaError, Codec["DecodingServices"]>;
|
|
798
|
+
/**
|
|
799
|
+
* Validates current form values and synchronizes decoded values or field errors.
|
|
800
|
+
* @remarks
|
|
801
|
+
* ## Why
|
|
802
|
+
* Submission needs one whole-form schema check in addition to incremental field decoding.
|
|
803
|
+
* ## Ownership and lifetime
|
|
804
|
+
* The returned Effect updates the supplied state when run. On success it clears
|
|
805
|
+
* errors; on failure it records messages and re-fails with `SchemaError`.
|
|
806
|
+
* @since 1.0.0
|
|
807
|
+
* @category validation
|
|
808
|
+
*/
|
|
809
|
+
export declare function validate<Values extends object>(state: FormState<Values>): Effect.Effect<Values, Schema.SchemaError, never>;
|
|
810
|
+
/**
|
|
811
|
+
* Named decoded segment in a bidirectional text mask.
|
|
812
|
+
* @remarks
|
|
813
|
+
* ## Why
|
|
814
|
+
* Slots make structured display strings type-safe and Schema-driven rather than cursor heuristics.
|
|
815
|
+
* ## Ownership and lifetime
|
|
816
|
+
* A slot retains its codec and optional validation constraints; it acquires no Scope.
|
|
817
|
+
* @since 1.0.0
|
|
818
|
+
* @category models
|
|
819
|
+
*/
|
|
820
|
+
export interface MaskSlot<Name extends string = string, Value = unknown> {
|
|
821
|
+
/** Discriminant used to distinguish slots from literal mask parts. */
|
|
822
|
+
readonly _tag: "MaskSlot";
|
|
823
|
+
/** Property name written into the decoded mask object. */
|
|
824
|
+
readonly name: Name;
|
|
825
|
+
/** Bidirectional conversion between this slot's string segment and decoded value. */
|
|
826
|
+
readonly codec: Schema.Codec<Value, string>;
|
|
827
|
+
/** Exact encoded character count, when fixed-width. */
|
|
828
|
+
readonly length?: number;
|
|
829
|
+
/** Per-character acceptance test applied before Schema decoding. */
|
|
830
|
+
readonly charset?: RegExp | ((character: string) => boolean);
|
|
831
|
+
}
|
|
832
|
+
/**
|
|
833
|
+
* Literal or decoded segment of a mask.
|
|
834
|
+
* @remarks
|
|
835
|
+
* ## Why
|
|
836
|
+
* The tuple order completely specifies parsing and formatting.
|
|
837
|
+
* ## Ownership and lifetime
|
|
838
|
+
* Immutable description data with no runtime ownership.
|
|
839
|
+
* @since 1.0.0
|
|
840
|
+
* @category models
|
|
841
|
+
*/
|
|
842
|
+
export type MaskPart = string | MaskSlot;
|
|
843
|
+
/**
|
|
844
|
+
* Decoded object inferred from the named slots in a mask tuple.
|
|
845
|
+
* @remarks
|
|
846
|
+
* ## Why
|
|
847
|
+
* Slot names and codecs become a precise form-field value type.
|
|
848
|
+
* ## Ownership and lifetime
|
|
849
|
+
* Type-only and resource-free.
|
|
850
|
+
* @since 1.0.0
|
|
851
|
+
* @category type-level
|
|
852
|
+
*/
|
|
853
|
+
export type MaskValue<Parts extends ReadonlyArray<MaskPart>> = {
|
|
854
|
+
readonly [Part in Parts[number] as Part extends MaskSlot<infer Name> ? Name : never]: Part extends MaskSlot<string, infer Value> ? Value : never;
|
|
855
|
+
};
|
|
856
|
+
/**
|
|
857
|
+
* Creates a named, Schema-decoded mask slot.
|
|
858
|
+
* @remarks
|
|
859
|
+
* ## Why
|
|
860
|
+
* Length and character constraints are expressed beside the codec that owns conversion.
|
|
861
|
+
* ## Ownership and lifetime
|
|
862
|
+
* Pure constructor; the returned descriptor retains the codec but acquires no Scope.
|
|
863
|
+
* @example
|
|
864
|
+
* ```ts
|
|
865
|
+
* import { slot } from "@typed/ui/Form"
|
|
866
|
+
* import { Schema } from "effect"
|
|
867
|
+
*
|
|
868
|
+
* const areaCode = slot("area", Schema.String, { length: 3, charset: /[0-9]/ })
|
|
869
|
+
* ```
|
|
870
|
+
* @since 1.0.0
|
|
871
|
+
* @category constructors
|
|
872
|
+
*/
|
|
873
|
+
export declare function slot<Name extends string, Value>(name: Name, codec: Schema.Codec<Value, string>, options?: Omit<MaskSlot<Name, Value>, "_tag" | "name" | "codec">): MaskSlot<Name, Value>;
|
|
874
|
+
/**
|
|
875
|
+
* Builds a bidirectional Schema codec from literal text and named slots.
|
|
876
|
+
* @remarks
|
|
877
|
+
* ## Why
|
|
878
|
+
* Display formatting and decoding share one ordered specification and produce
|
|
879
|
+
* ordinary Schema issues on invalid length, characters, literals, or slot values.
|
|
880
|
+
* ## Ownership and lifetime
|
|
881
|
+
* Pure codec construction. Decode/encode Effects are lazy and Scope-free.
|
|
882
|
+
* @example
|
|
883
|
+
* ```ts
|
|
884
|
+
* import { mask, slot } from "@typed/ui/Form"
|
|
885
|
+
* import { Schema } from "effect"
|
|
886
|
+
*
|
|
887
|
+
* const phone = mask("(", slot("area", Schema.String, { length: 3 }), ") ",
|
|
888
|
+
* slot("number", Schema.String, { length: 7 }))
|
|
889
|
+
* ```
|
|
890
|
+
* @since 1.0.0
|
|
891
|
+
* @category schemas
|
|
892
|
+
*/
|
|
893
|
+
export declare function mask<const Parts extends ReadonlyArray<MaskPart>>(...parts: Parts): Schema.Codec<MaskValue<Parts>, string>;
|
|
894
|
+
/**
|
|
895
|
+
* Options for an input decoded through a structured mask codec.
|
|
896
|
+
* @remarks
|
|
897
|
+
* ## Why
|
|
898
|
+
* A normal text input can expose a structured typed value without hiding native events or props.
|
|
899
|
+
* ## Ownership and lifetime
|
|
900
|
+
* The control Scope owns DOM work; form state and the mask codec remain independently owned.
|
|
901
|
+
* @since 1.0.0
|
|
902
|
+
* @category component-options
|
|
903
|
+
*/
|
|
904
|
+
export interface MaskedInputOptions<Values extends object, Parts extends ReadonlyArray<MaskPart>> extends InputOptions<Values, MaskValue<Parts>> {
|
|
905
|
+
/** Bidirectional mask codec used for display and input decoding. */
|
|
906
|
+
readonly mask: Schema.Codec<MaskValue<Parts>, string>;
|
|
907
|
+
}
|
|
908
|
+
/**
|
|
909
|
+
* Binds a native text input to a structured mask value.
|
|
910
|
+
* @remarks
|
|
911
|
+
* ## Why
|
|
912
|
+
* The supplied Schema codec controls both display encoding and input decoding;
|
|
913
|
+
* failed edits update field errors rather than corrupting decoded state.
|
|
914
|
+
* ## Ownership and lifetime
|
|
915
|
+
* DOM listeners and reactive value binding live in the control Scope. The
|
|
916
|
+
* supplied state can be tested and retained without mounting this control.
|
|
917
|
+
* @since 1.0.0
|
|
918
|
+
* @category components
|
|
919
|
+
*/
|
|
920
|
+
export declare function MaskedInput<const Values extends object, const Parts extends ReadonlyArray<MaskPart>, const Options extends MaskedInputOptions<Values, Parts>, const Host extends HostResult = never>(options: Options & Pick<MaskedInputOptions<Values, Parts>, "state" | "name" | "mask">, host?: Dom.HostOverride<Dom.RenderHostProps<Omit<Options, "mask">, InputProps<Values, MaskValue<Parts>>>, "", Host>): Fx<RenderEvent, Schema.SchemaError | Renderable.Error<RenderableComponentOptions<Omit<Options, "mask">> | Host>, Renderable.Services<RenderableComponentOptions<Omit<Options, "mask">> | Host> | Scope.Scope | RenderTemplate>;
|
|
921
|
+
/**
|
|
922
|
+
* Options for a state-explicit native checkbox.
|
|
923
|
+
* @remarks
|
|
924
|
+
* ## Why
|
|
925
|
+
* Boolean field inference and live `checked` binding preserve native checkbox behavior.
|
|
926
|
+
* ## Ownership and lifetime
|
|
927
|
+
* The control Scope owns the listener/binding; form state may outlive the element.
|
|
928
|
+
* @since 1.0.0
|
|
929
|
+
* @category component-options
|
|
930
|
+
*/
|
|
931
|
+
export interface CheckboxOptions<Values extends object> extends Dom.HostOptions<HTMLInputElement> {
|
|
932
|
+
/** Renderer-independent state read and updated by the checkbox. */
|
|
933
|
+
readonly state: FormState<Values>;
|
|
934
|
+
/** Boolean field controlled by the checkbox. */
|
|
935
|
+
readonly name: BooleanFieldName<Values>;
|
|
936
|
+
}
|
|
937
|
+
declare function checkboxProps<Values extends object>(options: CheckboxOptions<Values>): () => {
|
|
938
|
+
readonly type: "checkbox";
|
|
939
|
+
readonly name: BooleanFieldName<Values>;
|
|
940
|
+
readonly "aria-describedby": RefSubject.Computed<string | undefined, Schema.SchemaError, never>;
|
|
941
|
+
readonly "aria-invalid": RefSubject.Computed<true | undefined, Schema.SchemaError, never>;
|
|
942
|
+
readonly "?checked": RefSubject.Computed<boolean, Schema.SchemaError, never>;
|
|
943
|
+
readonly ".checked": RefSubject.Computed<boolean, Schema.SchemaError, never>;
|
|
944
|
+
readonly onchange: EventHandler.EventHandler<Event, Schema.SchemaError, never>;
|
|
945
|
+
};
|
|
946
|
+
type CheckboxProps<Values extends object> = ReturnType<ReturnType<typeof checkboxProps<Values>>>;
|
|
947
|
+
/**
|
|
948
|
+
* Binds a native checkbox to a boolean form field.
|
|
949
|
+
* @remarks
|
|
950
|
+
* ## Why
|
|
951
|
+
* Both the checked attribute and live property follow state, while the browser's
|
|
952
|
+
* real change event is decoded through the field codec.
|
|
953
|
+
* ## Ownership and lifetime
|
|
954
|
+
* The rendered Scope owns the input, listener, and subscriptions. A custom host
|
|
955
|
+
* must apply merged name, ARIA, checked, and change props.
|
|
956
|
+
* @since 1.0.0
|
|
957
|
+
* @category components
|
|
958
|
+
*/
|
|
959
|
+
export declare function Checkbox<const Values extends object, const Options extends CheckboxOptions<Values>, const Host extends HostResult = never>(options: Options & Pick<CheckboxOptions<Values>, "state" | "name">, host?: Dom.HostOverride<Dom.RenderHostProps<Options, CheckboxProps<Values>>, "", Host>): import("./Dom/Types.js").HostComponent<Host | Options>;
|
|
960
|
+
/**
|
|
961
|
+
* Options for a state-explicit native select.
|
|
962
|
+
* @remarks
|
|
963
|
+
* ## Why
|
|
964
|
+
* Callers author ordinary option markup while the selected value binds to typed state.
|
|
965
|
+
* ## Ownership and lifetime
|
|
966
|
+
* The control Scope owns content, listener, and binding; form state may outlive it.
|
|
967
|
+
* @since 1.0.0
|
|
968
|
+
* @category component-options
|
|
969
|
+
*/
|
|
970
|
+
export interface SelectOptions<Values extends object> extends Dom.HostOptions<HTMLSelectElement> {
|
|
971
|
+
/** Renderer-independent state read and updated by the select. */
|
|
972
|
+
readonly state: FormState<Values>;
|
|
973
|
+
/** String field controlled by the select. */
|
|
974
|
+
readonly name: FieldNameFor<Values, string>;
|
|
975
|
+
/** Native option/optgroup renderable content. */
|
|
976
|
+
readonly content: Renderable.Any;
|
|
977
|
+
}
|
|
978
|
+
declare function selectProps<Values extends object>(options: SelectOptions<Values>): () => {
|
|
979
|
+
readonly name: FieldNameFor<Values, string>;
|
|
980
|
+
readonly "aria-describedby": RefSubject.Computed<string | undefined, Schema.SchemaError, never>;
|
|
981
|
+
readonly "aria-invalid": RefSubject.Computed<true | undefined, Schema.SchemaError, never>;
|
|
982
|
+
readonly ".value": RefSubject.Computed<string, Schema.SchemaError, never>;
|
|
983
|
+
readonly onchange: EventHandler.EventHandler<Event, Schema.SchemaError, never>;
|
|
984
|
+
};
|
|
985
|
+
type SelectProps<Values extends object> = ReturnType<ReturnType<typeof selectProps<Values>>>;
|
|
986
|
+
/**
|
|
987
|
+
* Binds a native select element to a string form field.
|
|
988
|
+
* @remarks
|
|
989
|
+
* ## Why
|
|
990
|
+
* Native keyboard, accessibility, option, and form semantics remain browser-owned.
|
|
991
|
+
* ## Ownership and lifetime
|
|
992
|
+
* The rendered Scope owns the select/content subscriptions. A custom host must
|
|
993
|
+
* preserve supplied name, ARIA, value, and change props.
|
|
994
|
+
* @since 1.0.0
|
|
995
|
+
* @category components
|
|
996
|
+
*/
|
|
997
|
+
export declare function Select<const Values extends object, const Options extends SelectOptions<Values>, const Host extends HostResult = never>(options: Options & Pick<SelectOptions<Values>, "state" | "name" | "content">, host?: Dom.HostOverride<Dom.RenderHostProps<Options, SelectProps<Values>>, Options["content"], Host>): import("./Dom/Types.js").HostComponent<Host | Options>;
|
|
998
|
+
/**
|
|
999
|
+
* Options for a native form label.
|
|
1000
|
+
* @remarks
|
|
1001
|
+
* ## Why
|
|
1002
|
+
* Explicit `for` linkage keeps accessible naming in browser-standard markup.
|
|
1003
|
+
* ## Ownership and lifetime
|
|
1004
|
+
* The label Scope owns rendered content only; it does not own the referenced control.
|
|
1005
|
+
* @since 1.0.0
|
|
1006
|
+
* @category component-options
|
|
1007
|
+
*/
|
|
1008
|
+
export interface LabelOptions extends Dom.HostOptions<HTMLLabelElement> {
|
|
1009
|
+
/** ID of the native control labeled by this element. */
|
|
1010
|
+
readonly for: string;
|
|
1011
|
+
/** Human-readable label content. */
|
|
1012
|
+
readonly content: Renderable.Any;
|
|
1013
|
+
}
|
|
1014
|
+
declare function labelProps<const Options extends LabelOptions>(options: Options): () => {
|
|
1015
|
+
readonly for: string;
|
|
1016
|
+
};
|
|
1017
|
+
type LabelProps<Options extends LabelOptions> = ReturnType<ReturnType<typeof labelProps<Options>>>;
|
|
1018
|
+
/**
|
|
1019
|
+
* Renders a native label with an explicit control relationship.
|
|
1020
|
+
* @remarks
|
|
1021
|
+
* ## Why
|
|
1022
|
+
* The browser supplies click-to-focus and accessible-name behavior with no synthetic layer.
|
|
1023
|
+
* ## Ownership and lifetime
|
|
1024
|
+
* The Scope owns label output/content; the referenced element remains separately owned.
|
|
1025
|
+
* @since 1.0.0
|
|
1026
|
+
* @category components
|
|
1027
|
+
*/
|
|
1028
|
+
export declare function Label<const Options extends LabelOptions, const Host extends HostResult = never>(options: Options, host?: Dom.HostOverride<Dom.RenderHostProps<Options, LabelProps<Options>>, Options["content"], Host>): Fx<RenderEvent, Renderable.Error<Options | Host>, Renderable.Services<Options | Host> | Scope.Scope | RenderTemplate>;
|
|
1029
|
+
/**
|
|
1030
|
+
* Options for descriptive form content.
|
|
1031
|
+
* @remarks
|
|
1032
|
+
* ## Why
|
|
1033
|
+
* Provides a host-overrideable descriptive region without inventing text semantics.
|
|
1034
|
+
* ## Ownership and lifetime
|
|
1035
|
+
* The host Scope owns the rendered content.
|
|
1036
|
+
* @since 1.0.0
|
|
1037
|
+
* @category component-options
|
|
1038
|
+
*/
|
|
1039
|
+
export interface DescriptionOptions extends Dom.HostOptions<HTMLDivElement> {
|
|
1040
|
+
/** Descriptive renderable content. */
|
|
1041
|
+
readonly content: Renderable.Any;
|
|
1042
|
+
}
|
|
1043
|
+
declare function descriptionProps(): () => {};
|
|
1044
|
+
type DescriptionProps = ReturnType<ReturnType<typeof descriptionProps>>;
|
|
1045
|
+
/**
|
|
1046
|
+
* Renders form description content in a neutral native div by default.
|
|
1047
|
+
* @remarks
|
|
1048
|
+
* ## Why
|
|
1049
|
+
* Consumers can connect the resulting element with ordinary ARIA props where needed.
|
|
1050
|
+
* ## Ownership and lifetime
|
|
1051
|
+
* The Scope owns the description host/content and no external control.
|
|
1052
|
+
* @since 1.0.0
|
|
1053
|
+
* @category components
|
|
1054
|
+
*/
|
|
1055
|
+
export declare function Description<const Options extends DescriptionOptions, const Host extends HostResult = never>(options: Options, host?: Dom.HostOverride<Dom.RenderHostProps<Options, DescriptionProps>, Options["content"], Host>): import("./Dom/Types.js").HostComponent<Host | Options>;
|
|
1056
|
+
/**
|
|
1057
|
+
* Options for a field validation alert.
|
|
1058
|
+
* @remarks
|
|
1059
|
+
* ## Why
|
|
1060
|
+
* Error identity derives from form and field IDs so controls can reference it reliably.
|
|
1061
|
+
* ## Ownership and lifetime
|
|
1062
|
+
* The error host subscribes within its Scope; form state remains independently owned.
|
|
1063
|
+
* @since 1.0.0
|
|
1064
|
+
* @category component-options
|
|
1065
|
+
*/
|
|
1066
|
+
export interface ErrorOptions<Values extends object> extends Dom.HostOptions<HTMLDivElement> {
|
|
1067
|
+
/** Renderer-independent state supplying validation errors. */
|
|
1068
|
+
readonly state: FormState<Values>;
|
|
1069
|
+
/** Field whose current message is rendered. */
|
|
1070
|
+
readonly name: keyof Values & string;
|
|
1071
|
+
}
|
|
1072
|
+
declare function errorProps<Values extends object>(options: ErrorOptions<Values>): () => {
|
|
1073
|
+
readonly id: string;
|
|
1074
|
+
readonly role: "alert";
|
|
1075
|
+
};
|
|
1076
|
+
type ErrorProps<Values extends object> = ReturnType<ReturnType<typeof errorProps<Values>>>;
|
|
1077
|
+
/**
|
|
1078
|
+
* Renders the current field error as a native ARIA alert region.
|
|
1079
|
+
* @remarks
|
|
1080
|
+
* ## Why
|
|
1081
|
+
* The same derived ID is placed on the error and in the control's
|
|
1082
|
+
* `aria-describedby`, keeping validation messaging coherent.
|
|
1083
|
+
* ## Ownership and lifetime
|
|
1084
|
+
* The Scope owns the alert and state subscription; removing it does not remove form state.
|
|
1085
|
+
* @since 1.0.0
|
|
1086
|
+
* @category components
|
|
1087
|
+
*/
|
|
1088
|
+
export declare function Error<const Values extends object, const Options extends ErrorOptions<Values>, const Host extends HostResult = never>(options: Options & Pick<ErrorOptions<Values>, "state" | "name">, host?: Dom.HostOverride<Dom.RenderHostProps<Options, ErrorProps<Values>>, Renderable.Any, Host>): import("./Dom/Types.js").HostComponent<Host | Options>;
|
|
1089
|
+
/**
|
|
1090
|
+
* Options for a native submit button.
|
|
1091
|
+
* @remarks
|
|
1092
|
+
* ## Why
|
|
1093
|
+
* Uses ordinary form submission semantics while exposing all button props/events.
|
|
1094
|
+
* ## Ownership and lifetime
|
|
1095
|
+
* The button Scope owns rendered content and listeners.
|
|
1096
|
+
* @since 1.0.0
|
|
1097
|
+
* @category component-options
|
|
1098
|
+
*/
|
|
1099
|
+
export interface SubmitOptions extends Dom.HostOptions<HTMLButtonElement> {
|
|
1100
|
+
/** Submit button label/content. */
|
|
1101
|
+
readonly content: Renderable.Any;
|
|
1102
|
+
}
|
|
1103
|
+
declare function submitProps(): () => {
|
|
1104
|
+
readonly type: "submit";
|
|
1105
|
+
};
|
|
1106
|
+
type SubmitProps = ReturnType<ReturnType<typeof submitProps>>;
|
|
1107
|
+
/**
|
|
1108
|
+
* Renders a native `type=submit` button.
|
|
1109
|
+
* @remarks
|
|
1110
|
+
* ## Why
|
|
1111
|
+
* Keyboard activation, form association, and accessibility stay browser-standard.
|
|
1112
|
+
* ## Ownership and lifetime
|
|
1113
|
+
* The Scope owns the button/content; the surrounding Form owns submission sequencing.
|
|
1114
|
+
* @since 1.0.0
|
|
1115
|
+
* @category components
|
|
1116
|
+
*/
|
|
1117
|
+
export declare function Submit<const Options extends SubmitOptions, const Host extends HostResult = never>(options: Options, host?: Dom.HostOverride<Dom.RenderHostProps<Options, SubmitProps>, Options["content"], Host>): import("./Dom/Types.js").HostComponent<Host | Options>;
|
|
1118
|
+
/**
|
|
1119
|
+
* Options for a state-explicit reset button.
|
|
1120
|
+
* @remarks
|
|
1121
|
+
* ## Why
|
|
1122
|
+
* Native reset activation can restore renderer-independent Typed state deterministically.
|
|
1123
|
+
* ## Ownership and lifetime
|
|
1124
|
+
* The click Effect runs in the button Scope; state may outlive the button.
|
|
1125
|
+
* @since 1.0.0
|
|
1126
|
+
* @category component-options
|
|
1127
|
+
*/
|
|
1128
|
+
export interface ResetOptions<Values extends object> extends Dom.HostOptions<HTMLButtonElement> {
|
|
1129
|
+
/** Renderer-independent state restored on activation. */
|
|
1130
|
+
readonly state: FormState<Values>;
|
|
1131
|
+
/** Reset button label/content. */
|
|
1132
|
+
readonly content: Renderable.Any;
|
|
1133
|
+
}
|
|
1134
|
+
declare function resetProps<Values extends object>(options: ResetOptions<Values>): () => {
|
|
1135
|
+
readonly type: "reset";
|
|
1136
|
+
readonly onclick: EventHandler.EventHandler<Event, Schema.SchemaError, never>;
|
|
1137
|
+
};
|
|
1138
|
+
type ResetProps<Values extends object> = ReturnType<ReturnType<typeof resetProps<Values>>>;
|
|
1139
|
+
/**
|
|
1140
|
+
* Renders a native reset button that restores Typed form defaults.
|
|
1141
|
+
* @remarks
|
|
1142
|
+
* ## Why
|
|
1143
|
+
* It prevents the browser's independent control mutation and resets the single
|
|
1144
|
+
* RefSubject source of truth, clearing errors, metadata, and submitting state.
|
|
1145
|
+
* ## Ownership and lifetime
|
|
1146
|
+
* The Scope owns the click handler/content. The supplied form state remains independently owned.
|
|
1147
|
+
* @since 1.0.0
|
|
1148
|
+
* @category components
|
|
1149
|
+
*/
|
|
1150
|
+
export declare function Reset<const Values extends object, const Options extends ResetOptions<Values>, const Host extends HostResult = never>(options: Options & Pick<ResetOptions<Values>, "state" | "content">, host?: Dom.HostOverride<Dom.RenderHostProps<Options, ResetProps<Values>>, Options["content"], Host>): import("./Dom/Types.js").HostComponent<Host | Options>;
|
|
1151
|
+
/**
|
|
1152
|
+
* Options for an accessible group of form controls.
|
|
1153
|
+
* @remarks
|
|
1154
|
+
* ## Why
|
|
1155
|
+
* Provides a native host with `role=group` and optional accessible label.
|
|
1156
|
+
* ## Ownership and lifetime
|
|
1157
|
+
* The group Scope owns child renderables but not their independent form state.
|
|
1158
|
+
* @since 1.0.0
|
|
1159
|
+
* @category component-options
|
|
1160
|
+
*/
|
|
1161
|
+
export interface GroupOptions extends Dom.HostOptions<HTMLDivElement> {
|
|
1162
|
+
/** Controls or other renderable members of the group. */
|
|
1163
|
+
readonly content: Renderable.Any;
|
|
1164
|
+
/** Optional accessible name applied through `aria-label`. */
|
|
1165
|
+
readonly label?: string;
|
|
1166
|
+
}
|
|
1167
|
+
declare function groupProps<const Options extends GroupOptions>(options: Options): () => {
|
|
1168
|
+
readonly role: "group";
|
|
1169
|
+
readonly "aria-label": string | undefined;
|
|
1170
|
+
};
|
|
1171
|
+
type GroupProps<Options extends GroupOptions> = ReturnType<ReturnType<typeof groupProps<Options>>>;
|
|
1172
|
+
/**
|
|
1173
|
+
* Renders an ARIA group with an optional accessible name.
|
|
1174
|
+
* @remarks
|
|
1175
|
+
* ## Why
|
|
1176
|
+
* Related controls can expose their relationship without a framework-specific wrapper.
|
|
1177
|
+
* ## Ownership and lifetime
|
|
1178
|
+
* The Scope owns host/content; child controls retain their own DOM/state contracts.
|
|
1179
|
+
* @since 1.0.0
|
|
1180
|
+
* @category components
|
|
1181
|
+
*/
|
|
1182
|
+
export declare function Group<const Options extends GroupOptions, const Host extends HostResult = never>(options: Options, host?: Dom.HostOverride<Dom.RenderHostProps<Options, GroupProps<Options>>, Options["content"], Host>): import("./Dom/Types.js").HostComponent<Host | Options>;
|
|
1183
|
+
/**
|
|
1184
|
+
* Options for an array-field append button.
|
|
1185
|
+
* @remarks
|
|
1186
|
+
* ## Why
|
|
1187
|
+
* The field name and appended item are derived from the form value type.
|
|
1188
|
+
* ## Ownership and lifetime
|
|
1189
|
+
* The click Effect runs in the button Scope; form state remains independently owned.
|
|
1190
|
+
* @since 1.0.0
|
|
1191
|
+
* @category component-options
|
|
1192
|
+
*/
|
|
1193
|
+
export interface PushOptions<Values extends object, Name extends ArrayFieldName<Values>> extends Dom.HostOptions<HTMLButtonElement> {
|
|
1194
|
+
/** Renderer-independent state updated on activation. */
|
|
1195
|
+
readonly state: FormState<Values>;
|
|
1196
|
+
/** Array-valued field to append to. */
|
|
1197
|
+
readonly name: Name;
|
|
1198
|
+
/** Type-compatible item appended to the field. */
|
|
1199
|
+
readonly value: ArrayFieldValue<Values, Name>;
|
|
1200
|
+
/** Button label/content. */
|
|
1201
|
+
readonly content: Renderable.Any;
|
|
1202
|
+
}
|
|
1203
|
+
declare function pushProps<Values extends object, Name extends ArrayFieldName<Values>>(options: PushOptions<Values, Name>): () => {
|
|
1204
|
+
readonly type: "button";
|
|
1205
|
+
readonly onclick: Effect.Effect<State<Values>, Schema.SchemaError, never>;
|
|
1206
|
+
};
|
|
1207
|
+
type PushProps<Values extends object, Name extends ArrayFieldName<Values>> = ReturnType<ReturnType<typeof pushProps<Values, Name>>>;
|
|
1208
|
+
/**
|
|
1209
|
+
* Renders a button that appends one item to an array field.
|
|
1210
|
+
* @remarks
|
|
1211
|
+
* ## Why
|
|
1212
|
+
* Array mutation is immutable, typed, and marks the field dirty/touched.
|
|
1213
|
+
* ## Ownership and lifetime
|
|
1214
|
+
* The Scope owns the button handler/content; state may outlive the button.
|
|
1215
|
+
* @since 1.0.0
|
|
1216
|
+
* @category components
|
|
1217
|
+
*/
|
|
1218
|
+
export declare function Push<const Values extends object, const Name extends ArrayFieldName<Values>, const Options extends PushOptions<Values, Name>, const Host extends HostResult = never>(options: Options, host?: Dom.HostOverride<Dom.RenderHostProps<Options, PushProps<Values, Name>>, Options["content"], Host>): import("./Dom/Types.js").HostComponent<Host | Options>;
|
|
1219
|
+
/**
|
|
1220
|
+
* Options for an array-field removal button.
|
|
1221
|
+
* @remarks
|
|
1222
|
+
* ## Why
|
|
1223
|
+
* The array field is type-checked and the local index is explicit.
|
|
1224
|
+
* ## Ownership and lifetime
|
|
1225
|
+
* The click Effect runs in the button Scope; form state remains independently owned.
|
|
1226
|
+
* @since 1.0.0
|
|
1227
|
+
* @category component-options
|
|
1228
|
+
*/
|
|
1229
|
+
export interface RemoveOptions<Values extends object, Name extends ArrayFieldName<Values>> extends Dom.HostOptions<HTMLButtonElement> {
|
|
1230
|
+
/** Renderer-independent state updated on activation. */
|
|
1231
|
+
readonly state: FormState<Values>;
|
|
1232
|
+
/** Array-valued field to remove from. */
|
|
1233
|
+
readonly name: Name;
|
|
1234
|
+
/** Zero-based item index removed from the field. */
|
|
1235
|
+
readonly index: number;
|
|
1236
|
+
/** Button label/content. */
|
|
1237
|
+
readonly content: Renderable.Any;
|
|
1238
|
+
}
|
|
1239
|
+
declare function removeProps<Values extends object, Name extends ArrayFieldName<Values>>(options: RemoveOptions<Values, Name>): () => {
|
|
1240
|
+
readonly type: "button";
|
|
1241
|
+
readonly onclick: Effect.Effect<State<Values>, Schema.SchemaError, never>;
|
|
1242
|
+
};
|
|
1243
|
+
type RemoveProps<Values extends object, Name extends ArrayFieldName<Values>> = ReturnType<ReturnType<typeof removeProps<Values, Name>>>;
|
|
1244
|
+
/**
|
|
1245
|
+
* Renders a button that removes one array item by index.
|
|
1246
|
+
* @remarks
|
|
1247
|
+
* ## Why
|
|
1248
|
+
* Array mutation is immutable, typed, and marks the field dirty/touched.
|
|
1249
|
+
* ## Ownership and lifetime
|
|
1250
|
+
* The Scope owns the button handler/content; state may outlive the button.
|
|
1251
|
+
* @since 1.0.0
|
|
1252
|
+
* @category components
|
|
1253
|
+
*/
|
|
1254
|
+
export declare function Remove<const Values extends object, const Name extends ArrayFieldName<Values>, const Options extends RemoveOptions<Values, Name>, const Host extends HostResult = never>(options: Options, host?: Dom.HostOverride<Dom.RenderHostProps<Options, RemoveProps<Values, Name>>, Options["content"], Host>): import("./Dom/Types.js").HostComponent<Host | Options>;
|
|
1255
|
+
/**
|
|
1256
|
+
* Sets one decoded field value and updates dirty/touched metadata.
|
|
1257
|
+
* @remarks
|
|
1258
|
+
* ## Why
|
|
1259
|
+
* Programmatic updates use the same renderer-independent state transition as controls.
|
|
1260
|
+
* ## Ownership and lifetime
|
|
1261
|
+
* The returned Effect mutates only the supplied RefSubject when run.
|
|
1262
|
+
* @since 1.0.0
|
|
1263
|
+
* @category state
|
|
1264
|
+
*/
|
|
1265
|
+
export declare function setValue<Values extends object, Key extends keyof Values & string, E, R>(state: RefSubject.RefSubject<State<Values>, E, R>, key: Key, value: Values[Key]): Effect.Effect<State<Values>, E, R>;
|
|
1266
|
+
/**
|
|
1267
|
+
* Restores default values and clears errors, interaction metadata, and submission state.
|
|
1268
|
+
* @remarks
|
|
1269
|
+
* ## Why
|
|
1270
|
+
* Resetting the RefSubject, rather than only DOM controls, keeps every renderer
|
|
1271
|
+
* and test observer consistent with the source of truth.
|
|
1272
|
+
* ## Ownership and lifetime
|
|
1273
|
+
* The returned Effect performs one update when run and requires the same services as `state`.
|
|
1274
|
+
* @since 1.0.0
|
|
1275
|
+
* @category state
|
|
1276
|
+
*/
|
|
1277
|
+
export declare function reset<Values extends object, E, R>(state: RefSubject.RefSubject<State<Values>, E, R>): Effect.Effect<State<Values>, E, R>;
|
|
1278
|
+
/**
|
|
1279
|
+
* Names of boolean-valued fields.
|
|
1280
|
+
* @remarks
|
|
1281
|
+
* ## Why
|
|
1282
|
+
* Constrains checkbox bindings to values the control can represent exactly.
|
|
1283
|
+
* ## Ownership and lifetime
|
|
1284
|
+
* Type-only and resource-free.
|
|
1285
|
+
* @since 1.0.0
|
|
1286
|
+
* @category type-level
|
|
1287
|
+
*/
|
|
1288
|
+
export type BooleanFieldName<Values extends object> = FieldNameFor<Values, boolean>;
|
|
1289
|
+
/**
|
|
1290
|
+
* Names of readonly-array-valued fields.
|
|
1291
|
+
* @remarks
|
|
1292
|
+
* ## Why
|
|
1293
|
+
* Constrains append/removal helpers to collection fields.
|
|
1294
|
+
* ## Ownership and lifetime
|
|
1295
|
+
* Type-only and resource-free.
|
|
1296
|
+
* @since 1.0.0
|
|
1297
|
+
* @category type-level
|
|
1298
|
+
*/
|
|
1299
|
+
export type ArrayFieldName<Values extends object> = {
|
|
1300
|
+
[Key in keyof Values & string]: Values[Key] extends ReadonlyArray<unknown> ? Key : never;
|
|
1301
|
+
}[keyof Values & string];
|
|
1302
|
+
/**
|
|
1303
|
+
* Element type of a selected array field.
|
|
1304
|
+
* @remarks
|
|
1305
|
+
* ## Why
|
|
1306
|
+
* Append values are checked against the exact chosen field.
|
|
1307
|
+
* ## Ownership and lifetime
|
|
1308
|
+
* Type-only and resource-free.
|
|
1309
|
+
* @since 1.0.0
|
|
1310
|
+
* @category type-level
|
|
1311
|
+
*/
|
|
1312
|
+
export type ArrayFieldValue<Values extends object, Name extends ArrayFieldName<Values>> = Values[Name] extends ReadonlyArray<infer Value> ? Value : never;
|
|
1313
|
+
/**
|
|
1314
|
+
* Appends one item to an array field and marks it dirty and touched.
|
|
1315
|
+
* @remarks
|
|
1316
|
+
* ## Why
|
|
1317
|
+
* The immutable state transition is usable in tests, commands, or any renderer.
|
|
1318
|
+
* ## Ownership and lifetime
|
|
1319
|
+
* The returned Effect performs one RefSubject update when run.
|
|
1320
|
+
* @since 1.0.0
|
|
1321
|
+
* @category state
|
|
1322
|
+
*/
|
|
1323
|
+
export declare function pushValue<Values extends object, Name extends ArrayFieldName<Values>, E, R>(state: RefSubject.RefSubject<State<Values>, E, R>, name: Name, value: ArrayFieldValue<Values, Name>): Effect.Effect<State<Values>, E, R>;
|
|
1324
|
+
/**
|
|
1325
|
+
* Removes one item by index from an array field and marks it dirty and touched.
|
|
1326
|
+
* @remarks
|
|
1327
|
+
* ## Why
|
|
1328
|
+
* The transition is explicit and renderer-independent; an out-of-range index leaves values unchanged.
|
|
1329
|
+
* ## Ownership and lifetime
|
|
1330
|
+
* The returned Effect performs one RefSubject update when run.
|
|
1331
|
+
* @since 1.0.0
|
|
1332
|
+
* @category state
|
|
1333
|
+
*/
|
|
1334
|
+
export declare function removeValue<Values extends object, Name extends ArrayFieldName<Values>, E, R>(state: RefSubject.RefSubject<State<Values>, E, R>, name: Name, index: number): Effect.Effect<State<Values>, E, R>;
|
|
1335
|
+
/**
|
|
1336
|
+
* Handler invoked only after whole-form Schema validation succeeds.
|
|
1337
|
+
* @remarks
|
|
1338
|
+
* ## Why
|
|
1339
|
+
* Callers receive decoded values and the real native SubmitEvent, and may return an Effect.
|
|
1340
|
+
* ## Ownership and lifetime
|
|
1341
|
+
* A returned Effect runs inside the form submit handler and completes before `submitting` resets.
|
|
1342
|
+
* @since 1.0.0
|
|
1343
|
+
* @category events
|
|
1344
|
+
*/
|
|
1345
|
+
export type ValidSubmitHandler<Values extends object, E = never, R = never> = (values: Values, event: SubmitEvent) => void | Effect.Effect<unknown, E, R>;
|
|
1346
|
+
/**
|
|
1347
|
+
* Options for the state-explicit form root.
|
|
1348
|
+
* @remarks
|
|
1349
|
+
* ## Why
|
|
1350
|
+
* The form supplies native submit/reset behavior and Effect context while its
|
|
1351
|
+
* data remains in a standalone hydrated RefSubject.
|
|
1352
|
+
* ## Ownership and lifetime
|
|
1353
|
+
* The root Scope owns DOM handlers/content and provides `CurrentForm` to descendants.
|
|
1354
|
+
* It borrows `state`; submission Effects are finalized before `submitting` is cleared.
|
|
1355
|
+
* @since 1.0.0
|
|
1356
|
+
* @category component-options
|
|
1357
|
+
*/
|
|
1358
|
+
export interface FormOptions<Values extends object, E = never, R = never> extends Dom.HostOptions<HTMLFormElement> {
|
|
1359
|
+
/** Hydrated renderer-independent state owned outside the form renderer. */
|
|
1360
|
+
readonly state: FormState<Values>;
|
|
1361
|
+
/** Controls and other renderable form content. */
|
|
1362
|
+
readonly content: Renderable.Any;
|
|
1363
|
+
/** Callback invoked with decoded values only after successful validation. */
|
|
1364
|
+
readonly onValidSubmit?: ValidSubmitHandler<Values, E, R>;
|
|
1365
|
+
}
|
|
1366
|
+
declare function formProps<const Values extends object, E, R, const Options extends FormOptions<Values, E, R>>(options: Options): () => {
|
|
1367
|
+
readonly ref: FormState<Values>;
|
|
1368
|
+
readonly onsubmit: EventHandler.EventHandler<SubmitEvent, E | Schema.SchemaError, R>;
|
|
1369
|
+
readonly onreset: EventHandler.EventHandler<Event, Schema.SchemaError, never>;
|
|
1370
|
+
};
|
|
1371
|
+
type FormProps<Values extends object, E, R, Options extends FormOptions<Values, E, R>> = ReturnType<ReturnType<typeof formProps<Values, E, R, Options>>>;
|
|
1372
|
+
/**
|
|
1373
|
+
* Renders a native form and provides its state to schema-bound descendants.
|
|
1374
|
+
* @remarks
|
|
1375
|
+
* ## Why
|
|
1376
|
+
* Native submission is intercepted once, whole-form Schema validation runs,
|
|
1377
|
+
* then `onValidSubmit` receives decoded values. Reset updates the RefSubject so
|
|
1378
|
+
* all renderers stay coherent.
|
|
1379
|
+
* ## Ownership and lifetime
|
|
1380
|
+
* The root Scope owns its listeners/content and `CurrentForm` service. A valid
|
|
1381
|
+
* submit Effect runs in that lifetime; `submitting` is cleared in finalization
|
|
1382
|
+
* even on failure or interruption. Hydration does not itself attach client UI.
|
|
1383
|
+
* @example
|
|
1384
|
+
* ```ts
|
|
1385
|
+
* import { Form, Submit, TextInput, makeState } from "@typed/ui/Form"
|
|
1386
|
+
* import { Effect, Schema } from "effect"
|
|
1387
|
+
* import { html } from "@typed/template"
|
|
1388
|
+
*
|
|
1389
|
+
* const codec = Schema.Struct({ email: Schema.String })
|
|
1390
|
+
* const view = Effect.gen(function* () {
|
|
1391
|
+
* const state = yield* makeState(codec, { id: "signup", values: { email: "" } })
|
|
1392
|
+
* return Form({
|
|
1393
|
+
* state,
|
|
1394
|
+
* content: html`${TextInput({ state, name: "email" })}${Submit({ content: "Join" })}`,
|
|
1395
|
+
* onValidSubmit: (values) => Effect.log(`Submitting ${values.email}`)
|
|
1396
|
+
* })
|
|
1397
|
+
* })
|
|
1398
|
+
* ```
|
|
1399
|
+
* @since 1.0.0
|
|
1400
|
+
* @category components
|
|
1401
|
+
*/
|
|
1402
|
+
export declare function Form<const Values extends object, E, R, const Options extends FormOptions<Values, E, R>, const Host extends HostResult = never>(options: Options & Pick<FormOptions<Values, E, R>, "state" | "content">, host?: Dom.HostOverride<Dom.RenderHostProps<Options, FormProps<Values, E, R, Options>>, Options["content"], Host>): SchemaBoundRootResult<Options, Host>;
|
|
1403
|
+
/**
|
|
1404
|
+
* Options accepted by a schema-bound form root.
|
|
1405
|
+
* @remarks
|
|
1406
|
+
* ## Why
|
|
1407
|
+
* The factory names the state `form` and supplies its schema/context automatically.
|
|
1408
|
+
* ## Ownership and lifetime
|
|
1409
|
+
* The root Scope borrows `form` and owns content, listeners, and submit Effects.
|
|
1410
|
+
* @since 1.0.0
|
|
1411
|
+
* @category component-options
|
|
1412
|
+
*/
|
|
1413
|
+
export interface BoundFormOptions<Values extends object, E = never, R = never> extends Dom.HostOptions<HTMLFormElement> {
|
|
1414
|
+
/** State previously created by the bound API's `state` constructor. */
|
|
1415
|
+
readonly form: FormState<Values>;
|
|
1416
|
+
/** Schema-bound controls and other renderable form content. */
|
|
1417
|
+
readonly content: Renderable.Any;
|
|
1418
|
+
/** Callback invoked with decoded values only after successful validation. */
|
|
1419
|
+
readonly onValidSubmit?: ValidSubmitHandler<Values, E, R>;
|
|
1420
|
+
}
|
|
1421
|
+
type CurrentFormIdentifier = Context.Service.Identifier<typeof CurrentForm>;
|
|
1422
|
+
/**
|
|
1423
|
+
* Fx result of a schema-bound descendant control.
|
|
1424
|
+
* @remarks
|
|
1425
|
+
* ## Why
|
|
1426
|
+
* Its type makes `CurrentForm`, render services, Schema errors, Scope, and custom-host requirements explicit.
|
|
1427
|
+
* ## Ownership and lifetime
|
|
1428
|
+
* The parent form supplies `CurrentForm`; the running Scope owns DOM work.
|
|
1429
|
+
* @since 1.0.0
|
|
1430
|
+
* @category models
|
|
1431
|
+
*/
|
|
1432
|
+
export type SchemaBoundComponentResult<Options, Host> = Fx<RenderEvent, Schema.SchemaError | Renderable.Error<RenderableComponentOptions<Options> | Host>, Renderable.Services<RenderableComponentOptions<Options> | Host> | CurrentFormIdentifier | Scope.Scope | RenderTemplate>;
|
|
1433
|
+
/**
|
|
1434
|
+
* Fx result of a schema-bound root after it provides `CurrentForm` internally.
|
|
1435
|
+
* @remarks
|
|
1436
|
+
* ## Why
|
|
1437
|
+
* Consumers see only external render/host requirements, not the service supplied by the root itself.
|
|
1438
|
+
* ## Ownership and lifetime
|
|
1439
|
+
* The running Scope owns the service provision, listeners, and rendered range.
|
|
1440
|
+
* @since 1.0.0
|
|
1441
|
+
* @category models
|
|
1442
|
+
*/
|
|
1443
|
+
export type SchemaBoundRootResult<Options, Host> = Fx<RenderEvent, Schema.SchemaError | Renderable.Error<RenderableComponentOptions<Options> | Host>, Exclude<Renderable.Services<RenderableComponentOptions<Options> | Host>, CurrentFormIdentifier> | Scope.Scope | RenderTemplate>;
|
|
1444
|
+
/**
|
|
1445
|
+
* Callable schema-bound input constructor for fields with one decoded value type.
|
|
1446
|
+
* @remarks
|
|
1447
|
+
* ## Why
|
|
1448
|
+
* Struct field names, errors, and services remain inferred without passing state repeatedly.
|
|
1449
|
+
* ## Ownership and lifetime
|
|
1450
|
+
* Each call borrows `CurrentForm` and returns Scope-owned render work.
|
|
1451
|
+
* @since 1.0.0
|
|
1452
|
+
* @category models
|
|
1453
|
+
*/
|
|
1454
|
+
export interface SchemaBoundInput<Fields extends FormFields, Value> {
|
|
1455
|
+
/** Creates a bound native input and optionally delegates its merged props to a custom host. @since 1.0.0 @category constructors */
|
|
1456
|
+
<const Options extends object, const Host extends HostResult = never>(options: SchemaBoundInputOptions<Fields, Value> & Options, host?: Dom.HostOverride<Dom.HostProps<HTMLInputElement>, "", Host>): SchemaBoundComponentResult<Omit<Options, "name">, Host>;
|
|
1457
|
+
}
|
|
1458
|
+
/**
|
|
1459
|
+
* Callable schema-bound input using its selected field's string codec as a mask.
|
|
1460
|
+
* @remarks
|
|
1461
|
+
* ## Why
|
|
1462
|
+
* Structured string encodings stay declared once in the Struct schema.
|
|
1463
|
+
* ## Ownership and lifetime
|
|
1464
|
+
* Each call borrows `CurrentForm` and returns Scope-owned render work.
|
|
1465
|
+
* @since 1.0.0
|
|
1466
|
+
* @category models
|
|
1467
|
+
*/
|
|
1468
|
+
export interface SchemaBoundMaskedInput<Fields extends FormFields> {
|
|
1469
|
+
/** Creates a bound text input using the selected field's bidirectional string codec. @since 1.0.0 @category constructors */
|
|
1470
|
+
<const Options extends object, const Host extends HostResult = never>(options: SchemaBoundMaskedInputOptions<Fields> & Options, host?: Dom.HostOverride<Dom.HostProps<HTMLInputElement>, "", Host>): SchemaBoundComponentResult<Options, Host>;
|
|
1471
|
+
}
|
|
1472
|
+
/**
|
|
1473
|
+
* Callable schema-bound checkbox constructor.
|
|
1474
|
+
* @remarks
|
|
1475
|
+
* ## Why
|
|
1476
|
+
* Only boolean field names are accepted and state comes from `CurrentForm`.
|
|
1477
|
+
* ## Ownership and lifetime
|
|
1478
|
+
* Each call returns Scope-owned DOM work and borrows the current form state.
|
|
1479
|
+
* @since 1.0.0
|
|
1480
|
+
* @category models
|
|
1481
|
+
*/
|
|
1482
|
+
export interface SchemaBoundCheckbox<Values extends object> {
|
|
1483
|
+
/** Creates a bound native checkbox for a boolean field. @since 1.0.0 @category constructors */
|
|
1484
|
+
<const Options extends object, const Host extends HostResult = never>(options: SchemaBoundCheckboxOptions<Values> & Options, host?: Dom.HostOverride<Dom.RenderHostProps<Options, CheckboxProps<Values>>, "", Host>): SchemaBoundComponentResult<Options, Host>;
|
|
1485
|
+
}
|
|
1486
|
+
/**
|
|
1487
|
+
* Callable schema-bound native select constructor.
|
|
1488
|
+
* @remarks
|
|
1489
|
+
* ## Why
|
|
1490
|
+
* String field names are inferred while option content remains caller-authored.
|
|
1491
|
+
* ## Ownership and lifetime
|
|
1492
|
+
* Each call returns Scope-owned DOM/content work and borrows current form state.
|
|
1493
|
+
* @since 1.0.0
|
|
1494
|
+
* @category models
|
|
1495
|
+
*/
|
|
1496
|
+
export interface SchemaBoundSelect<Values extends object> {
|
|
1497
|
+
/** Creates a bound native select and preserves caller-authored option content. @since 1.0.0 @category constructors */
|
|
1498
|
+
<const Options extends object, const Host extends HostResult = never>(options: SchemaBoundSelectOptions<Values> & Options, host?: Dom.HostOverride<Dom.RenderHostProps<Options, SelectProps<Values>>, (SchemaBoundSelectOptions<Values> & Options)["content"], Host>): SchemaBoundComponentResult<Options, Host>;
|
|
1499
|
+
}
|
|
1500
|
+
/**
|
|
1501
|
+
* Callable schema-bound field-error constructor.
|
|
1502
|
+
* @remarks
|
|
1503
|
+
* ## Why
|
|
1504
|
+
* Field error text and relationship IDs derive from the current form automatically.
|
|
1505
|
+
* ## Ownership and lifetime
|
|
1506
|
+
* Each call returns a Scope-owned subscription and borrows current form state.
|
|
1507
|
+
* @since 1.0.0
|
|
1508
|
+
* @category models
|
|
1509
|
+
*/
|
|
1510
|
+
export interface SchemaBoundError<Values extends object> {
|
|
1511
|
+
/** Creates a bound alert region for one field's current error. @since 1.0.0 @category constructors */
|
|
1512
|
+
<const Options extends object, const Host extends HostResult = never>(options: SchemaBoundErrorOptions<Values> & Options, host?: Dom.HostOverride<Dom.RenderHostProps<Options, ErrorProps<Values>>, Renderable.Any, Host>): SchemaBoundComponentResult<Options, Host>;
|
|
1513
|
+
}
|
|
1514
|
+
/**
|
|
1515
|
+
* Callable schema-bound reset-button constructor.
|
|
1516
|
+
* @remarks
|
|
1517
|
+
* ## Why
|
|
1518
|
+
* Reset behavior can access the current form without a state argument.
|
|
1519
|
+
* ## Ownership and lifetime
|
|
1520
|
+
* Each call returns Scope-owned DOM work and borrows current form state.
|
|
1521
|
+
* @since 1.0.0
|
|
1522
|
+
* @category models
|
|
1523
|
+
*/
|
|
1524
|
+
export interface SchemaBoundReset {
|
|
1525
|
+
/** Creates a reset button targeting the form provided by `CurrentForm`. @since 1.0.0 @category constructors */
|
|
1526
|
+
<const Options extends object, const Host extends HostResult = never>(options: SchemaBoundResetOptions & Options, host?: Dom.HostOverride<Dom.RenderHostProps<Options, ResetProps<object>>, (SchemaBoundResetOptions & Options)["content"], Host>): SchemaBoundComponentResult<Options, Host>;
|
|
1527
|
+
}
|
|
1528
|
+
/**
|
|
1529
|
+
* Callable schema-bound array append-button constructor.
|
|
1530
|
+
* @remarks
|
|
1531
|
+
* ## Why
|
|
1532
|
+
* Field and item types are derived from the form value.
|
|
1533
|
+
* ## Ownership and lifetime
|
|
1534
|
+
* Each call returns Scope-owned DOM work and borrows current form state.
|
|
1535
|
+
* @since 1.0.0
|
|
1536
|
+
* @category models
|
|
1537
|
+
*/
|
|
1538
|
+
export interface SchemaBoundPush<Values extends object> {
|
|
1539
|
+
/** Creates an append button for a type-compatible array field and item. @since 1.0.0 @category constructors */
|
|
1540
|
+
<const Name extends ArrayFieldName<Values>, const Options extends object, const Host extends HostResult = never>(options: SchemaBoundPushOptions<Values, Name> & Options, host?: Dom.HostOverride<Dom.RenderHostProps<Options, PushProps<Values, Name>>, (SchemaBoundPushOptions<Values, Name> & Options)["content"], Host>): SchemaBoundComponentResult<Options, Host>;
|
|
1541
|
+
}
|
|
1542
|
+
/**
|
|
1543
|
+
* Callable schema-bound array removal-button constructor.
|
|
1544
|
+
* @remarks
|
|
1545
|
+
* ## Why
|
|
1546
|
+
* Array fields remain type-checked without passing state explicitly.
|
|
1547
|
+
* ## Ownership and lifetime
|
|
1548
|
+
* Each call returns Scope-owned DOM work and borrows current form state.
|
|
1549
|
+
* @since 1.0.0
|
|
1550
|
+
* @category models
|
|
1551
|
+
*/
|
|
1552
|
+
export interface SchemaBoundRemove<Values extends object> {
|
|
1553
|
+
/** Creates a remove button for an array field and explicit item index. @since 1.0.0 @category constructors */
|
|
1554
|
+
<const Name extends ArrayFieldName<Values>, const Options extends object, const Host extends HostResult = never>(options: SchemaBoundRemoveOptions<Values, Name> & Options, host?: Dom.HostOverride<Dom.RenderHostProps<Options, RemoveProps<Values, Name>>, (SchemaBoundRemoveOptions<Values, Name> & Options)["content"], Host>): SchemaBoundComponentResult<Options, Host>;
|
|
1555
|
+
}
|
|
1556
|
+
/**
|
|
1557
|
+
* Callable root constructor supplied by a schema-bound form API.
|
|
1558
|
+
* @remarks
|
|
1559
|
+
* ## Why
|
|
1560
|
+
* It connects one factory-created state to native form behavior and descendant context.
|
|
1561
|
+
* ## Ownership and lifetime
|
|
1562
|
+
* The returned Fx provides `CurrentForm` for its own Scope and borrows the state.
|
|
1563
|
+
* @since 1.0.0
|
|
1564
|
+
* @category models
|
|
1565
|
+
*/
|
|
1566
|
+
export interface SchemaBoundRoot<Values extends object> {
|
|
1567
|
+
/** Creates the native form root that provides its `form` state to bound descendants. @since 1.0.0 @category constructors */
|
|
1568
|
+
<E, R, const Options extends BoundFormOptions<Values, E, R>, const Host extends HostResult = never>(options: Options, host?: Dom.HostOverride<Dom.HostProps<HTMLFormElement>, Options["content"], Host>): SchemaBoundRootResult<Options, Host>;
|
|
1569
|
+
}
|
|
1570
|
+
/**
|
|
1571
|
+
* Optional state metadata for `SchemaBoundForm.state`.
|
|
1572
|
+
* @remarks
|
|
1573
|
+
* ## Why
|
|
1574
|
+
* Callers may seed SSR identity, defaults, errors, and interaction/submission state.
|
|
1575
|
+
* ## Ownership and lifetime
|
|
1576
|
+
* Values/defaults and nested references are retained exactly; provide `id` for
|
|
1577
|
+
* deterministic SSR identity.
|
|
1578
|
+
* @since 1.0.0
|
|
1579
|
+
* @category models
|
|
1580
|
+
*/
|
|
1581
|
+
export interface SchemaBoundStateOptions<Values extends object> {
|
|
1582
|
+
/** Stable hydration and accessibility relationship ID; required for deterministic SSR ordering. */
|
|
1583
|
+
readonly id?: string;
|
|
1584
|
+
/** Exact reset-baseline reference, defaulting to the same object passed as initial values. */
|
|
1585
|
+
readonly defaultValues?: Values;
|
|
1586
|
+
/** Initial field validation messages. */
|
|
1587
|
+
readonly errors?: Partial<Record<keyof Values & string, string>>;
|
|
1588
|
+
/** Initial dirty/touched metadata. */
|
|
1589
|
+
readonly meta?: Partial<Record<keyof Values & string, FieldMeta>>;
|
|
1590
|
+
/** Initial in-flight submission flag. */
|
|
1591
|
+
readonly submitting?: boolean;
|
|
1592
|
+
}
|
|
1593
|
+
/**
|
|
1594
|
+
* Schema-specialized form API returned by `make`.
|
|
1595
|
+
* @remarks
|
|
1596
|
+
* ## Why
|
|
1597
|
+
* The Struct codec is declared once, then every state, field name, component,
|
|
1598
|
+
* error, and custom-host signature stays aligned with it.
|
|
1599
|
+
* ## Ownership and lifetime
|
|
1600
|
+
* The API retains the codec but acquires no Scope. Each `state` call creates a
|
|
1601
|
+
* Scope-owned hydrated RefSubject; each component call creates lazy Fx output.
|
|
1602
|
+
* @since 1.0.0
|
|
1603
|
+
* @category models
|
|
1604
|
+
*/
|
|
1605
|
+
export interface SchemaBoundForm<Fields extends FormFields> {
|
|
1606
|
+
/** Struct codec shared by state construction and every bound field. */
|
|
1607
|
+
readonly codec: Schema.Struct<Fields>;
|
|
1608
|
+
/** Creates a Scope-owned hydrated state from decoded initial values. */
|
|
1609
|
+
readonly state: (values: Schema.Struct.Type<Fields>, options?: SchemaBoundStateOptions<Schema.Struct.Type<Fields>>) => Effect.Effect<FormState<Schema.Struct.Type<Fields>>, Schema.SchemaError, Scope.Scope>;
|
|
1610
|
+
/** Native form root that provides the current state to bound descendants. */
|
|
1611
|
+
readonly Root: SchemaBoundRoot<Schema.Struct.Type<Fields>>;
|
|
1612
|
+
/** Bound native text input for string-encoded string fields. */
|
|
1613
|
+
readonly TextInput: SchemaBoundInput<Fields, string>;
|
|
1614
|
+
/** Bound native search input for string-encoded string fields. */
|
|
1615
|
+
readonly SearchInput: SchemaBoundInput<Fields, string>;
|
|
1616
|
+
/** Bound native email input for string-encoded string fields. */
|
|
1617
|
+
readonly EmailInput: SchemaBoundInput<Fields, string>;
|
|
1618
|
+
/** Bound native URL input for string-encoded string fields. */
|
|
1619
|
+
readonly UrlInput: SchemaBoundInput<Fields, string>;
|
|
1620
|
+
/** Bound native telephone input for string-encoded string fields. */
|
|
1621
|
+
readonly TelInput: SchemaBoundInput<Fields, string>;
|
|
1622
|
+
/** Bound native password input for string-encoded string fields. */
|
|
1623
|
+
readonly PasswordInput: SchemaBoundInput<Fields, string>;
|
|
1624
|
+
/** Bound native hidden input for string-encoded string fields. */
|
|
1625
|
+
readonly HiddenInput: SchemaBoundInput<Fields, string>;
|
|
1626
|
+
/** Bound native color input for string-encoded string fields. */
|
|
1627
|
+
readonly ColorInput: SchemaBoundInput<Fields, string>;
|
|
1628
|
+
/** Bound native time input for string-encoded string fields. */
|
|
1629
|
+
readonly TimeInput: SchemaBoundInput<Fields, string>;
|
|
1630
|
+
/** Bound native local date-time input for string-encoded string fields. */
|
|
1631
|
+
readonly DateTimeLocalInput: SchemaBoundInput<Fields, string>;
|
|
1632
|
+
/** Bound native month input for string-encoded string fields. */
|
|
1633
|
+
readonly MonthInput: SchemaBoundInput<Fields, string>;
|
|
1634
|
+
/** Bound native week input for string-encoded string fields. */
|
|
1635
|
+
readonly WeekInput: SchemaBoundInput<Fields, string>;
|
|
1636
|
+
/** Bound native number input for finite-number fields encoded as strings. */
|
|
1637
|
+
readonly NumberInput: SchemaBoundInput<Fields, number>;
|
|
1638
|
+
/** Bound native range input for finite-number fields encoded as strings. */
|
|
1639
|
+
readonly RangeInput: SchemaBoundInput<Fields, number>;
|
|
1640
|
+
/** Bound native date input for Date fields encoded as strings. */
|
|
1641
|
+
readonly DateInput: SchemaBoundInput<Fields, Date>;
|
|
1642
|
+
/** Bound text input using the selected field's own string codec. */
|
|
1643
|
+
readonly MaskedInput: SchemaBoundMaskedInput<Fields>;
|
|
1644
|
+
/** Bound native checkbox limited to boolean fields. */
|
|
1645
|
+
readonly Checkbox: SchemaBoundCheckbox<Schema.Struct.Type<Fields>>;
|
|
1646
|
+
/** Bound native select limited to string fields. */
|
|
1647
|
+
readonly Select: SchemaBoundSelect<Schema.Struct.Type<Fields>>;
|
|
1648
|
+
/** Bound ARIA alert for a field's current validation message. */
|
|
1649
|
+
readonly Error: SchemaBoundError<Schema.Struct.Type<Fields>>;
|
|
1650
|
+
/** Bound reset button that restores the current form's defaults. */
|
|
1651
|
+
readonly Reset: SchemaBoundReset;
|
|
1652
|
+
/** Bound button that appends to an array field. */
|
|
1653
|
+
readonly Push: SchemaBoundPush<Schema.Struct.Type<Fields>>;
|
|
1654
|
+
/** Bound button that removes an item from an array field. */
|
|
1655
|
+
readonly Remove: SchemaBoundRemove<Schema.Struct.Type<Fields>>;
|
|
1656
|
+
/** Native label component; callers provide the target control ID. */
|
|
1657
|
+
readonly Label: typeof Label;
|
|
1658
|
+
/** Neutral description host for caller-linked explanatory content. */
|
|
1659
|
+
readonly Description: typeof Description;
|
|
1660
|
+
/** Native submit button. */
|
|
1661
|
+
readonly Submit: typeof Submit;
|
|
1662
|
+
/** Accessible group host for related controls. */
|
|
1663
|
+
readonly Group: typeof Group;
|
|
1664
|
+
}
|
|
1665
|
+
/**
|
|
1666
|
+
* Creates a schema-bound form component family from one Struct codec.
|
|
1667
|
+
* @remarks
|
|
1668
|
+
* ## Why
|
|
1669
|
+
* Defining the schema once removes repeated state/codec arguments and makes
|
|
1670
|
+
* incompatible field/component combinations compile-time errors.
|
|
1671
|
+
* ## Ownership and lifetime
|
|
1672
|
+
* Factory creation is pure and retains the codec. `state` requires Scope and
|
|
1673
|
+
* returns a hydrated RefSubject. `Root` provides that state through Effect
|
|
1674
|
+
* context only for its render lifetime; controls borrow it.
|
|
1675
|
+
* @example
|
|
1676
|
+
* ```ts
|
|
1677
|
+
* import { make } from "@typed/ui/Form"
|
|
1678
|
+
* import { Effect, Schema } from "effect"
|
|
1679
|
+
* import { html } from "@typed/template"
|
|
1680
|
+
*
|
|
1681
|
+
* const Signup = make(Schema.Struct({ email: Schema.String, accepted: Schema.Boolean }))
|
|
1682
|
+
* const view = Effect.gen(function* () {
|
|
1683
|
+
* const form = yield* Signup.state({ email: "", accepted: false }, { id: "signup" })
|
|
1684
|
+
* return Signup.Root({
|
|
1685
|
+
* form,
|
|
1686
|
+
* content: html`${Signup.EmailInput({ name: "email" })}${Signup.Checkbox({ name: "accepted" })}`
|
|
1687
|
+
* })
|
|
1688
|
+
* })
|
|
1689
|
+
* ```
|
|
1690
|
+
* @since 1.0.0
|
|
1691
|
+
* @category constructors
|
|
1692
|
+
*/
|
|
1693
|
+
export declare function make<const Fields extends FormFields>(codec: Schema.Struct<Fields>): SchemaBoundForm<Fields>;
|
|
1694
|
+
export {};
|
|
1695
|
+
//# sourceMappingURL=Form.d.ts.map
|