@typed/ui 1.0.0-beta.0 → 1.0.0-beta.10
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/LICENSE +21 -0
- package/README.md +78 -26
- package/dist/Alert.d.ts +72 -0
- package/dist/Alert.d.ts.map +1 -0
- package/dist/Alert.js +40 -0
- package/dist/Button.d.ts +100 -0
- package/dist/Button.d.ts.map +1 -0
- package/dist/Button.js +42 -0
- package/dist/Carousel.d.ts +346 -0
- package/dist/Carousel.d.ts.map +1 -0
- package/dist/Carousel.js +264 -0
- package/dist/Checkbox.d.ts +168 -0
- package/dist/Checkbox.d.ts.map +1 -0
- package/dist/Checkbox.js +146 -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 +367 -0
- package/dist/Combobox.d.ts.map +1 -0
- package/dist/Combobox.js +300 -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 +357 -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 +1727 -0
- package/dist/Form.d.ts.map +1 -0
- package/dist/Form.js +1142 -0
- package/dist/Grid.d.ts +388 -0
- package/dist/Grid.d.ts.map +1 -0
- package/dist/Grid.js +284 -0
- package/dist/Group.d.ts +128 -0
- package/dist/Group.d.ts.map +1 -0
- package/dist/Group.js +71 -0
- package/dist/Heading.d.ts +87 -0
- package/dist/Heading.d.ts.map +1 -0
- package/dist/Heading.js +58 -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 +199 -56
- package/dist/Link.d.ts +63 -28
- package/dist/Link.d.ts.map +1 -1
- package/dist/Link.js +84 -37
- package/dist/Listbox.d.ts +305 -0
- package/dist/Listbox.d.ts.map +1 -0
- package/dist/Listbox.js +245 -0
- package/dist/Menu.d.ts +663 -0
- package/dist/Menu.d.ts.map +1 -0
- package/dist/Menu.js +569 -0
- package/dist/Menubar.d.ts +249 -0
- package/dist/Menubar.d.ts.map +1 -0
- package/dist/Menubar.js +207 -0
- package/dist/Meter.d.ts +157 -0
- package/dist/Meter.d.ts.map +1 -0
- package/dist/Meter.js +87 -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 +66 -0
- package/dist/NativeDialog.d.ts.map +1 -0
- package/dist/NativeDialog.js +88 -0
- package/dist/NativePopover.d.ts +43 -0
- package/dist/NativePopover.d.ts.map +1 -0
- package/dist/NativePopover.js +84 -0
- package/dist/Popover.d.ts +240 -0
- package/dist/Popover.d.ts.map +1 -0
- package/dist/Popover.js +140 -0
- package/dist/RadioGroup.d.ts +330 -0
- package/dist/RadioGroup.d.ts.map +1 -0
- package/dist/RadioGroup.js +241 -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 +418 -0
- package/dist/Select.d.ts.map +1 -0
- package/dist/Select.js +357 -0
- package/dist/Separator.d.ts +58 -0
- package/dist/Separator.d.ts.map +1 -0
- package/dist/Separator.js +32 -0
- package/dist/Slider.d.ts +141 -0
- package/dist/Slider.d.ts.map +1 -0
- package/dist/Slider.js +101 -0
- package/dist/SpinButton.d.ts +141 -0
- package/dist/SpinButton.d.ts.map +1 -0
- package/dist/SpinButton.js +101 -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 +148 -0
- package/dist/Switch.d.ts.map +1 -0
- package/dist/Switch.js +110 -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 +411 -0
- package/dist/Tabs.d.ts.map +1 -0
- package/dist/Tabs.js +262 -0
- package/dist/Toolbar.d.ts +248 -0
- package/dist/Toolbar.d.ts.map +1 -0
- package/dist/Toolbar.js +187 -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 +405 -0
- package/dist/Tree.d.ts.map +1 -0
- package/dist/Tree.js +333 -0
- package/dist/TreeGrid.d.ts +426 -0
- package/dist/TreeGrid.d.ts.map +1 -0
- package/dist/TreeGrid.js +308 -0
- package/dist/VisuallyHidden.d.ts +68 -0
- package/dist/VisuallyHidden.d.ts.map +1 -0
- package/dist/VisuallyHidden.js +44 -0
- package/dist/WindowSplitter.d.ts +336 -0
- package/dist/WindowSplitter.d.ts.map +1 -0
- package/dist/WindowSplitter.js +305 -0
- package/dist/index.d.ts +48 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +48 -0
- package/package.json +47 -14
- package/src/HttpRouter.test.ts +0 -294
- package/src/HttpRouter.ts +0 -168
- package/src/Link.test.ts +0 -85
- package/src/Link.ts +0 -107
- package/src/index.ts +0 -2
- package/tsconfig.json +0 -6
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Native radio selection with optional registered keyboard movement.
|
|
3
|
+
* Choice values, element IDs, and shared native names have distinct responsibilities.
|
|
4
|
+
*
|
|
5
|
+
* Read the [RadioGroup guide](/explore/ui-radio-group) for a complete example.
|
|
6
|
+
*
|
|
7
|
+
* [APG interaction reference](https://www.w3.org/WAI/ARIA/apg/patterns/radio/).
|
|
8
|
+
* @since 1.0.0
|
|
9
|
+
* @category Overview
|
|
10
|
+
* @packageDocumentation
|
|
11
|
+
*/
|
|
12
|
+
import * as Effect from "effect/Effect";
|
|
13
|
+
import type * as Scope from "effect/Scope";
|
|
14
|
+
import * as Schema from "effect/Schema";
|
|
15
|
+
import type { Fx } from "@typed/fx/Fx";
|
|
16
|
+
import { RefSubject } from "@typed/fx";
|
|
17
|
+
import { EventHandler, type Renderable, type RenderEvent, type RenderTemplate } from "@typed/template";
|
|
18
|
+
import * as Collection from "./Collection.js";
|
|
19
|
+
import * as Composite from "./Composite.js";
|
|
20
|
+
import * as Dom from "./Dom.js";
|
|
21
|
+
import type { HostResult } from "./Dom/Types.js";
|
|
22
|
+
/**
|
|
23
|
+
* Selected choice plus the active element used for keyboard movement.
|
|
24
|
+
*
|
|
25
|
+
* @remarks
|
|
26
|
+
* value need not equal activeId. Orientation is vertical, virtualFocus is false, and the native
|
|
27
|
+
* inputs retain their own browser grouping by name.
|
|
28
|
+
* @since 1.0.0
|
|
29
|
+
* @category State models
|
|
30
|
+
*/
|
|
31
|
+
export interface State extends Omit<Composite.State, "orientation"> {
|
|
32
|
+
/**
|
|
33
|
+
* Axis used to interpret Arrow-key movement.
|
|
34
|
+
* @since 1.0.0
|
|
35
|
+
* @category Keyboard navigation
|
|
36
|
+
*/
|
|
37
|
+
readonly orientation: "vertical";
|
|
38
|
+
/**
|
|
39
|
+
* Current semantic value selected or edited by the widget.
|
|
40
|
+
* @since 1.0.0
|
|
41
|
+
* @category Value state
|
|
42
|
+
*/
|
|
43
|
+
readonly value: string;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Required selected value with optional initial active ID and wrap policy.
|
|
47
|
+
*
|
|
48
|
+
* @remarks
|
|
49
|
+
* activeId defaults to null; loop defaults to true. Supply an element ID only when the initial
|
|
50
|
+
* active choice is known.
|
|
51
|
+
* @since 1.0.0
|
|
52
|
+
* @category State models
|
|
53
|
+
*/
|
|
54
|
+
export interface InitialState {
|
|
55
|
+
/**
|
|
56
|
+
* Current semantic value selected or edited by the widget.
|
|
57
|
+
* @since 1.0.0
|
|
58
|
+
* @category Value state
|
|
59
|
+
*/
|
|
60
|
+
readonly value: string;
|
|
61
|
+
/**
|
|
62
|
+
* Id currently active for keyboard navigation; null means no active item.
|
|
63
|
+
* @since 1.0.0
|
|
64
|
+
* @category Keyboard focus
|
|
65
|
+
*/
|
|
66
|
+
readonly activeId?: string | null;
|
|
67
|
+
/**
|
|
68
|
+
* Whether movement wraps between the first and last enabled items.
|
|
69
|
+
* @since 1.0.0
|
|
70
|
+
* @category Keyboard navigation
|
|
71
|
+
*/
|
|
72
|
+
readonly loop?: boolean;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Effect Schema used by makeState to encode, decode, and hydrate RadioGroup state.
|
|
76
|
+
*
|
|
77
|
+
* @remarks
|
|
78
|
+
* A public schema makes hydration and serialized state use the same runtime validation as direct
|
|
79
|
+
* construction.
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* ```ts
|
|
83
|
+
* import * as Schema from "effect/Schema";
|
|
84
|
+
* import * as RadioGroup from "@typed/ui/RadioGroup";
|
|
85
|
+
*
|
|
86
|
+
* const decodeState = Schema.decodeUnknownEffect(RadioGroup.StateSchema);
|
|
87
|
+
* ```
|
|
88
|
+
* @since 1.0.0
|
|
89
|
+
* @category Hydration schemas
|
|
90
|
+
*/
|
|
91
|
+
export declare const StateSchema: Schema.Struct<{
|
|
92
|
+
readonly value: Schema.String;
|
|
93
|
+
readonly activeId: Schema.NullOr<Schema.String>;
|
|
94
|
+
readonly orientation: Schema.Literals<readonly ["vertical"]>;
|
|
95
|
+
readonly loop: Schema.Boolean;
|
|
96
|
+
readonly rtl: Schema.Boolean;
|
|
97
|
+
readonly virtualFocus: Schema.Boolean;
|
|
98
|
+
}>;
|
|
99
|
+
/**
|
|
100
|
+
* Creates hydrated radio selection with a required value, null active ID, and looping enabled by
|
|
101
|
+
* default.
|
|
102
|
+
*
|
|
103
|
+
* @remarks
|
|
104
|
+
* The selected value and element ID are separate. The first keyboard movement can resolve the
|
|
105
|
+
* selected value against the mounted collection. Creation requires Scope; renderers borrow the
|
|
106
|
+
* returned subject.
|
|
107
|
+
*
|
|
108
|
+
* @example
|
|
109
|
+
* ```ts
|
|
110
|
+
* import * as Effect from "effect/Effect";
|
|
111
|
+
* import * as RadioGroup from "@typed/ui/RadioGroup";
|
|
112
|
+
*
|
|
113
|
+
* const program = Effect.scoped(
|
|
114
|
+
* Effect.gen(function* () {
|
|
115
|
+
* const state = yield* RadioGroup.makeState({ value: "email" });
|
|
116
|
+
* const collection = yield* RadioGroup.makeCollection();
|
|
117
|
+
* return { state: yield* state, collection: yield* collection };
|
|
118
|
+
* }),
|
|
119
|
+
* );
|
|
120
|
+
* ```
|
|
121
|
+
* @since 1.0.0
|
|
122
|
+
* @category State construction
|
|
123
|
+
*/
|
|
124
|
+
export declare function makeState(initial: InitialState): Effect.Effect<RefSubject.HydratedRefSubject<{
|
|
125
|
+
readonly value: string;
|
|
126
|
+
readonly activeId: string | null;
|
|
127
|
+
readonly orientation: "vertical";
|
|
128
|
+
readonly loop: boolean;
|
|
129
|
+
readonly rtl: boolean;
|
|
130
|
+
readonly virtualFocus: boolean;
|
|
131
|
+
}, Schema.SchemaError, never, never>, never, Scope.Scope>;
|
|
132
|
+
/**
|
|
133
|
+
* Creates a scoped Collection for RadioGroup items.
|
|
134
|
+
*
|
|
135
|
+
* @remarks
|
|
136
|
+
* State and collection ownership can be composed and tested independently from any renderer.
|
|
137
|
+
*
|
|
138
|
+
* The returned Effect allocates the RefSubject in the caller's Scope. Each later registration is
|
|
139
|
+
* owned by the Scope that runs register, independently of this construction Effect.
|
|
140
|
+
*
|
|
141
|
+
* @example
|
|
142
|
+
* ```ts
|
|
143
|
+
* import * as Effect from "effect/Effect";
|
|
144
|
+
* import * as RadioGroup from "@typed/ui/RadioGroup";
|
|
145
|
+
*
|
|
146
|
+
* const program = Effect.scoped(
|
|
147
|
+
* Effect.gen(function* () {
|
|
148
|
+
* const collection = yield* RadioGroup.makeCollection();
|
|
149
|
+
* return yield* collection;
|
|
150
|
+
* }),
|
|
151
|
+
* );
|
|
152
|
+
* ```
|
|
153
|
+
* @since 1.0.0
|
|
154
|
+
* @category State construction
|
|
155
|
+
*/
|
|
156
|
+
export declare const makeCollection: (initial?: Collection.State<string, Element>) => Effect.Effect<RefSubject.RefSubject<Collection.State<string, Element>, never, never>, never, Scope.Scope>;
|
|
157
|
+
/**
|
|
158
|
+
* Sets the selected value and optionally the active element ID.
|
|
159
|
+
*
|
|
160
|
+
* @remarks
|
|
161
|
+
* Omitting activeId preserves the previous active ID. This state update does not look up an
|
|
162
|
+
* item, move DOM focus, or verify that the value belongs to the group.
|
|
163
|
+
* @since 1.0.0
|
|
164
|
+
* @category State transitions
|
|
165
|
+
*/
|
|
166
|
+
export declare function setValue<E, R>(state: RefSubject.RefSubject<State, E, R>, value: string, activeId?: string): Effect.Effect<State, E, R>;
|
|
167
|
+
/**
|
|
168
|
+
* State, optional navigation collection, child content, and group name.
|
|
169
|
+
*
|
|
170
|
+
* @remarks
|
|
171
|
+
* Share the same collection with Item to enable registered keyboard movement. label names the
|
|
172
|
+
* group; each item still needs its own label.
|
|
173
|
+
* @since 1.0.0
|
|
174
|
+
* @category Component options
|
|
175
|
+
*/
|
|
176
|
+
export interface RootOptions extends Dom.HostOptions<HTMLDivElement> {
|
|
177
|
+
/**
|
|
178
|
+
* Renderer-independent RefSubject state consumed by this component or operation.
|
|
179
|
+
* @since 1.0.0
|
|
180
|
+
* @category State connection
|
|
181
|
+
*/
|
|
182
|
+
readonly state: RefSubject.HydratedRefSubject<State, Schema.SchemaError>;
|
|
183
|
+
/**
|
|
184
|
+
* Item registry used for collection-driven keyboard behavior and mounted ordering.
|
|
185
|
+
* @since 1.0.0
|
|
186
|
+
* @category Item registration
|
|
187
|
+
*/
|
|
188
|
+
readonly collection?: RefSubject.RefSubject<Collection.State<string>>;
|
|
189
|
+
/**
|
|
190
|
+
* Renderable child content for the component host.
|
|
191
|
+
* @since 1.0.0
|
|
192
|
+
* @category Rendered content
|
|
193
|
+
*/
|
|
194
|
+
readonly content: Renderable.Any;
|
|
195
|
+
/**
|
|
196
|
+
* Accessible label rendered through aria-label.
|
|
197
|
+
* @since 1.0.0
|
|
198
|
+
* @category Accessible naming
|
|
199
|
+
*/
|
|
200
|
+
readonly label?: Renderable.Any<string | null | undefined>;
|
|
201
|
+
}
|
|
202
|
+
declare function rootInternalProps<const Options extends RootOptions>(options: Options): ({ property }: Dom.InternalPropsHelpers<Options>) => {
|
|
203
|
+
readonly role: "radiogroup";
|
|
204
|
+
readonly "aria-label": Exclude<Dom.Property<Options, "label">, Dom.Nullish> | undefined;
|
|
205
|
+
readonly onkeydown: EventHandler.EventHandler<KeyboardEvent, Schema.SchemaError, never> | undefined;
|
|
206
|
+
readonly ref: RefSubject.HydratedRefSubject<State, Schema.SchemaError, never, never>;
|
|
207
|
+
};
|
|
208
|
+
type RootInternalProps<Options extends RootOptions> = ReturnType<ReturnType<typeof rootInternalProps<Options>>>;
|
|
209
|
+
/**
|
|
210
|
+
* Renders a named radiogroup around native radio items.
|
|
211
|
+
*
|
|
212
|
+
* @remarks
|
|
213
|
+
* Pass the same state to every item and the same native name to items in one group. With a
|
|
214
|
+
* collection, the root handles vertical arrow movement and Home/End, skips disabled
|
|
215
|
+
* registrations, updates selection, and moves real focus. Without a collection, native input
|
|
216
|
+
* behavior remains the keyboard boundary.
|
|
217
|
+
*
|
|
218
|
+
* @example
|
|
219
|
+
* ```ts
|
|
220
|
+
* import { html } from "@typed/template";
|
|
221
|
+
* import { component } from "@typed/template";
|
|
222
|
+
* import * as RadioGroup from "@typed/ui/RadioGroup";
|
|
223
|
+
*
|
|
224
|
+
* export const DeliveryChoice = component(function* () {
|
|
225
|
+
* const state = yield* RadioGroup.makeState({ value: "standard" });
|
|
226
|
+
* const collection = yield* RadioGroup.makeCollection();
|
|
227
|
+
* return RadioGroup.Root({
|
|
228
|
+
* state,
|
|
229
|
+
* collection,
|
|
230
|
+
* label: "Delivery speed",
|
|
231
|
+
* content: html`
|
|
232
|
+
* <label>${RadioGroup.Item({
|
|
233
|
+
* state, collection, id: "delivery-standard", name: "delivery", value: "standard",
|
|
234
|
+
* })} Standard delivery</label>
|
|
235
|
+
* <label>${RadioGroup.Item({
|
|
236
|
+
* state, collection, id: "delivery-express", name: "delivery", value: "express",
|
|
237
|
+
* })} Express delivery</label>
|
|
238
|
+
* `,
|
|
239
|
+
* });
|
|
240
|
+
* });
|
|
241
|
+
* ```
|
|
242
|
+
* @since 1.0.0
|
|
243
|
+
* @category Native controls
|
|
244
|
+
*/
|
|
245
|
+
export declare function Root<const Options extends RootOptions, const Host extends HostResult = never>(options: Options, host?: Dom.HostOverride<Dom.RenderHostProps<Options, RootInternalProps<Options>>, Options["content"], Host>): Fx<RenderEvent, Renderable.Error<Options | Host>, Renderable.Services<Options | Host> | Scope.Scope | RenderTemplate>;
|
|
246
|
+
/**
|
|
247
|
+
* One native choice with stable element ID, application value, and native group name.
|
|
248
|
+
*
|
|
249
|
+
* @remarks
|
|
250
|
+
* Use the same state and name across one radio group, unique IDs across the document, and distinct
|
|
251
|
+
* values across choices. disabled is a boolean used by both rendering and registration.
|
|
252
|
+
* @since 1.0.0
|
|
253
|
+
* @category Component options
|
|
254
|
+
*/
|
|
255
|
+
export interface ItemOptions extends Dom.HostOptions<HTMLInputElement> {
|
|
256
|
+
/**
|
|
257
|
+
* Renderer-independent RefSubject state consumed by this component or operation.
|
|
258
|
+
* @since 1.0.0
|
|
259
|
+
* @category State connection
|
|
260
|
+
*/
|
|
261
|
+
readonly state: RefSubject.HydratedRefSubject<State, Schema.SchemaError>;
|
|
262
|
+
/**
|
|
263
|
+
* Item registry used for collection-driven keyboard behavior and mounted ordering.
|
|
264
|
+
* @since 1.0.0
|
|
265
|
+
* @category Item registration
|
|
266
|
+
*/
|
|
267
|
+
readonly collection?: RefSubject.RefSubject<Collection.State<string>>;
|
|
268
|
+
/**
|
|
269
|
+
* Stable id used for collection identity and ARIA relationships.
|
|
270
|
+
* @since 1.0.0
|
|
271
|
+
* @category Identity and relationships
|
|
272
|
+
*/
|
|
273
|
+
readonly id: string;
|
|
274
|
+
/**
|
|
275
|
+
* Current semantic value selected or edited by the widget.
|
|
276
|
+
* @since 1.0.0
|
|
277
|
+
* @category Value state
|
|
278
|
+
*/
|
|
279
|
+
readonly value: string;
|
|
280
|
+
/**
|
|
281
|
+
* Native radio-group form name shared by related input items.
|
|
282
|
+
* @since 1.0.0
|
|
283
|
+
* @category Native form data
|
|
284
|
+
*/
|
|
285
|
+
readonly name?: string;
|
|
286
|
+
/**
|
|
287
|
+
* Flag used by collection movement and widget handlers to skip activation by default.
|
|
288
|
+
* @since 1.0.0
|
|
289
|
+
* @category Availability
|
|
290
|
+
*/
|
|
291
|
+
readonly disabled?: boolean;
|
|
292
|
+
}
|
|
293
|
+
declare function itemInternalProps<const Options extends ItemOptions>(options: Options): () => {
|
|
294
|
+
readonly id: string;
|
|
295
|
+
readonly type: "radio";
|
|
296
|
+
readonly role: "radio";
|
|
297
|
+
readonly name: string | undefined;
|
|
298
|
+
readonly value: string;
|
|
299
|
+
readonly "?disabled": boolean;
|
|
300
|
+
readonly "aria-checked": RefSubject.Computed<boolean, Schema.SchemaError, never>;
|
|
301
|
+
readonly "aria-disabled": boolean;
|
|
302
|
+
readonly "?checked": RefSubject.Computed<boolean, Schema.SchemaError, never>;
|
|
303
|
+
readonly ".checked": RefSubject.Computed<boolean, Schema.SchemaError, never>;
|
|
304
|
+
readonly onchange: Effect.Effect<void, never, never> | Effect.Effect<State, Schema.SchemaError, never>;
|
|
305
|
+
readonly ref: ((element: Element & HTMLInputElement & RefSubject.HydrationElement) => Effect.Effect<void, any, any>) | undefined;
|
|
306
|
+
};
|
|
307
|
+
type ItemInternalProps<Options extends ItemOptions> = ReturnType<ReturnType<typeof itemInternalProps<Options>>>;
|
|
308
|
+
/**
|
|
309
|
+
* Renders one native radio input and optionally registers it for group navigation.
|
|
310
|
+
*
|
|
311
|
+
* @remarks
|
|
312
|
+
* id identifies the element; value identifies the choice; name establishes the native browser
|
|
313
|
+
* group. A native change updates the selected value and active ID. Supply a wrapping label or an
|
|
314
|
+
* external label linked to id. Registration ends with the rendered Scope.
|
|
315
|
+
* @since 1.0.0
|
|
316
|
+
* @category Native controls
|
|
317
|
+
*/
|
|
318
|
+
export declare function Item<const Options extends ItemOptions, const Host extends HostResult = never>(options: Options, host?: Dom.HostOverride<Dom.RenderHostProps<Options, ItemInternalProps<Options>>, "", Host>): Fx<RenderEvent, Renderable.Error<Options | Host>, Renderable.Services<Options | Host> | Scope.Scope | RenderTemplate>;
|
|
319
|
+
/**
|
|
320
|
+
* Alias of Root.
|
|
321
|
+
*
|
|
322
|
+
* @remarks
|
|
323
|
+
* The alias exposes the same native-input grouping and optional collection behavior; it introduces
|
|
324
|
+
* no additional state or focus policy.
|
|
325
|
+
* @since 1.0.0
|
|
326
|
+
* @category Native controls
|
|
327
|
+
*/
|
|
328
|
+
export declare const RadioGroup: typeof Root;
|
|
329
|
+
export {};
|
|
330
|
+
//# sourceMappingURL=RadioGroup.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RadioGroup.d.ts","sourceRoot":"","sources":["../src/RadioGroup.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Native radio selection with optional registered keyboard movement.
|
|
3
|
+
* Choice values, element IDs, and shared native names have distinct responsibilities.
|
|
4
|
+
*
|
|
5
|
+
* Read the [RadioGroup guide](/explore/ui-radio-group) for a complete example.
|
|
6
|
+
*
|
|
7
|
+
* [APG interaction reference](https://www.w3.org/WAI/ARIA/apg/patterns/radio/).
|
|
8
|
+
* @since 1.0.0
|
|
9
|
+
* @category Overview
|
|
10
|
+
* @packageDocumentation
|
|
11
|
+
*/
|
|
12
|
+
import * as Effect from "effect/Effect";
|
|
13
|
+
import * as Schema from "effect/Schema";
|
|
14
|
+
import { RefSubject } from "@typed/fx";
|
|
15
|
+
import { EventHandler, html, } from "@typed/template";
|
|
16
|
+
import * as Collection from "./Collection.js";
|
|
17
|
+
import * as Composite from "./Composite.js";
|
|
18
|
+
import * as Dom from "./Dom.js";
|
|
19
|
+
/**
|
|
20
|
+
* Effect Schema used by makeState to encode, decode, and hydrate RadioGroup state.
|
|
21
|
+
*
|
|
22
|
+
* @remarks
|
|
23
|
+
* A public schema makes hydration and serialized state use the same runtime validation as direct
|
|
24
|
+
* construction.
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```ts
|
|
28
|
+
* import * as Schema from "effect/Schema";
|
|
29
|
+
* import * as RadioGroup from "@typed/ui/RadioGroup";
|
|
30
|
+
*
|
|
31
|
+
* const decodeState = Schema.decodeUnknownEffect(RadioGroup.StateSchema);
|
|
32
|
+
* ```
|
|
33
|
+
* @since 1.0.0
|
|
34
|
+
* @category Hydration schemas
|
|
35
|
+
*/
|
|
36
|
+
export const StateSchema = Schema.Struct({
|
|
37
|
+
value: Schema.String,
|
|
38
|
+
activeId: Schema.NullOr(Schema.String),
|
|
39
|
+
orientation: Schema.Literals(["vertical"]),
|
|
40
|
+
loop: Schema.Boolean,
|
|
41
|
+
rtl: Schema.Boolean,
|
|
42
|
+
virtualFocus: Schema.Boolean,
|
|
43
|
+
});
|
|
44
|
+
/**
|
|
45
|
+
* Creates hydrated radio selection with a required value, null active ID, and looping enabled by
|
|
46
|
+
* default.
|
|
47
|
+
*
|
|
48
|
+
* @remarks
|
|
49
|
+
* The selected value and element ID are separate. The first keyboard movement can resolve the
|
|
50
|
+
* selected value against the mounted collection. Creation requires Scope; renderers borrow the
|
|
51
|
+
* returned subject.
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```ts
|
|
55
|
+
* import * as Effect from "effect/Effect";
|
|
56
|
+
* import * as RadioGroup from "@typed/ui/RadioGroup";
|
|
57
|
+
*
|
|
58
|
+
* const program = Effect.scoped(
|
|
59
|
+
* Effect.gen(function* () {
|
|
60
|
+
* const state = yield* RadioGroup.makeState({ value: "email" });
|
|
61
|
+
* const collection = yield* RadioGroup.makeCollection();
|
|
62
|
+
* return { state: yield* state, collection: yield* collection };
|
|
63
|
+
* }),
|
|
64
|
+
* );
|
|
65
|
+
* ```
|
|
66
|
+
* @since 1.0.0
|
|
67
|
+
* @category State construction
|
|
68
|
+
*/
|
|
69
|
+
export function makeState(initial) {
|
|
70
|
+
return RefSubject.hydrate(StateSchema, {
|
|
71
|
+
value: initial.value,
|
|
72
|
+
activeId: initial.activeId ?? null,
|
|
73
|
+
orientation: "vertical",
|
|
74
|
+
loop: initial.loop ?? true,
|
|
75
|
+
rtl: false,
|
|
76
|
+
virtualFocus: false,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Creates a scoped Collection for RadioGroup items.
|
|
81
|
+
*
|
|
82
|
+
* @remarks
|
|
83
|
+
* State and collection ownership can be composed and tested independently from any renderer.
|
|
84
|
+
*
|
|
85
|
+
* The returned Effect allocates the RefSubject in the caller's Scope. Each later registration is
|
|
86
|
+
* owned by the Scope that runs register, independently of this construction Effect.
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* ```ts
|
|
90
|
+
* import * as Effect from "effect/Effect";
|
|
91
|
+
* import * as RadioGroup from "@typed/ui/RadioGroup";
|
|
92
|
+
*
|
|
93
|
+
* const program = Effect.scoped(
|
|
94
|
+
* Effect.gen(function* () {
|
|
95
|
+
* const collection = yield* RadioGroup.makeCollection();
|
|
96
|
+
* return yield* collection;
|
|
97
|
+
* }),
|
|
98
|
+
* );
|
|
99
|
+
* ```
|
|
100
|
+
* @since 1.0.0
|
|
101
|
+
* @category State construction
|
|
102
|
+
*/
|
|
103
|
+
export const makeCollection = Collection.makeState;
|
|
104
|
+
/**
|
|
105
|
+
* Sets the selected value and optionally the active element ID.
|
|
106
|
+
*
|
|
107
|
+
* @remarks
|
|
108
|
+
* Omitting activeId preserves the previous active ID. This state update does not look up an
|
|
109
|
+
* item, move DOM focus, or verify that the value belongs to the group.
|
|
110
|
+
* @since 1.0.0
|
|
111
|
+
* @category State transitions
|
|
112
|
+
*/
|
|
113
|
+
export function setValue(state, value, activeId) {
|
|
114
|
+
return RefSubject.update(state, (current) => ({
|
|
115
|
+
...current,
|
|
116
|
+
value,
|
|
117
|
+
activeId: activeId ?? current.activeId,
|
|
118
|
+
}));
|
|
119
|
+
}
|
|
120
|
+
function move(state, collection, direction) {
|
|
121
|
+
return Effect.gen(function* () {
|
|
122
|
+
const current = yield* state;
|
|
123
|
+
const items = yield* collection;
|
|
124
|
+
const activeId = current.activeId ?? items.find((item) => item.value === current.value)?.id ?? null;
|
|
125
|
+
const nextId = Composite.moveActiveId(items, { ...current, activeId }, direction);
|
|
126
|
+
const item = nextId === null ? undefined : items.find((item) => item.id === nextId);
|
|
127
|
+
if (item?.value === undefined)
|
|
128
|
+
return current;
|
|
129
|
+
const next = yield* setValue(state, item.value, item.id);
|
|
130
|
+
yield* Composite.focusActive({ state, collection });
|
|
131
|
+
return next;
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
function rootInternalProps(options) {
|
|
135
|
+
const onkeydown = options.collection === undefined
|
|
136
|
+
? undefined
|
|
137
|
+
: EventHandler.make(Effect.fn(function* (event) {
|
|
138
|
+
const direction = Composite.keyMove(event, { orientation: "vertical" });
|
|
139
|
+
if (direction === undefined)
|
|
140
|
+
return;
|
|
141
|
+
event.preventDefault();
|
|
142
|
+
yield* move(options.state, options.collection, direction);
|
|
143
|
+
}));
|
|
144
|
+
return ({ property }) => ({
|
|
145
|
+
role: "radiogroup",
|
|
146
|
+
"aria-label": property("label", undefined),
|
|
147
|
+
onkeydown,
|
|
148
|
+
ref: options.state,
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Renders a named radiogroup around native radio items.
|
|
153
|
+
*
|
|
154
|
+
* @remarks
|
|
155
|
+
* Pass the same state to every item and the same native name to items in one group. With a
|
|
156
|
+
* collection, the root handles vertical arrow movement and Home/End, skips disabled
|
|
157
|
+
* registrations, updates selection, and moves real focus. Without a collection, native input
|
|
158
|
+
* behavior remains the keyboard boundary.
|
|
159
|
+
*
|
|
160
|
+
* @example
|
|
161
|
+
* ```ts
|
|
162
|
+
* import { html } from "@typed/template";
|
|
163
|
+
* import { component } from "@typed/template";
|
|
164
|
+
* import * as RadioGroup from "@typed/ui/RadioGroup";
|
|
165
|
+
*
|
|
166
|
+
* export const DeliveryChoice = component(function* () {
|
|
167
|
+
* const state = yield* RadioGroup.makeState({ value: "standard" });
|
|
168
|
+
* const collection = yield* RadioGroup.makeCollection();
|
|
169
|
+
* return RadioGroup.Root({
|
|
170
|
+
* state,
|
|
171
|
+
* collection,
|
|
172
|
+
* label: "Delivery speed",
|
|
173
|
+
* content: html`
|
|
174
|
+
* <label>${RadioGroup.Item({
|
|
175
|
+
* state, collection, id: "delivery-standard", name: "delivery", value: "standard",
|
|
176
|
+
* })} Standard delivery</label>
|
|
177
|
+
* <label>${RadioGroup.Item({
|
|
178
|
+
* state, collection, id: "delivery-express", name: "delivery", value: "express",
|
|
179
|
+
* })} Express delivery</label>
|
|
180
|
+
* `,
|
|
181
|
+
* });
|
|
182
|
+
* });
|
|
183
|
+
* ```
|
|
184
|
+
* @since 1.0.0
|
|
185
|
+
* @category Native controls
|
|
186
|
+
*/
|
|
187
|
+
export function Root(options, host) {
|
|
188
|
+
return Dom.renderHost()(options, host, rootInternalProps(options), options.content, (props, content) => {
|
|
189
|
+
return html `<div ...${props}>${content}</div>`;
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
function itemInternalProps(options) {
|
|
193
|
+
const checked = RefSubject.map(options.state, (state) => state.value === options.value);
|
|
194
|
+
const register = options.collection === undefined
|
|
195
|
+
? undefined
|
|
196
|
+
: Collection.ref(options.collection, {
|
|
197
|
+
id: options.id,
|
|
198
|
+
value: options.value,
|
|
199
|
+
textValue: options.value,
|
|
200
|
+
disabled: options.disabled,
|
|
201
|
+
});
|
|
202
|
+
return () => ({
|
|
203
|
+
id: options.id,
|
|
204
|
+
type: "radio",
|
|
205
|
+
role: "radio",
|
|
206
|
+
name: options.name,
|
|
207
|
+
value: options.value,
|
|
208
|
+
"?disabled": options.disabled ?? false,
|
|
209
|
+
"aria-checked": checked,
|
|
210
|
+
"aria-disabled": options.disabled ?? false,
|
|
211
|
+
"?checked": checked,
|
|
212
|
+
".checked": checked,
|
|
213
|
+
onchange: options.disabled === true
|
|
214
|
+
? Effect.void
|
|
215
|
+
: setValue(options.state, options.value, options.id),
|
|
216
|
+
ref: Dom.composeRefs(register, options.ref),
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Renders one native radio input and optionally registers it for group navigation.
|
|
221
|
+
*
|
|
222
|
+
* @remarks
|
|
223
|
+
* id identifies the element; value identifies the choice; name establishes the native browser
|
|
224
|
+
* group. A native change updates the selected value and active ID. Supply a wrapping label or an
|
|
225
|
+
* external label linked to id. Registration ends with the rendered Scope.
|
|
226
|
+
* @since 1.0.0
|
|
227
|
+
* @category Native controls
|
|
228
|
+
*/
|
|
229
|
+
export function Item(options, host) {
|
|
230
|
+
return Dom.renderHost()(options, host, itemInternalProps(options), "", (props) => html `<input ...${props} />`);
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Alias of Root.
|
|
234
|
+
*
|
|
235
|
+
* @remarks
|
|
236
|
+
* The alias exposes the same native-input grouping and optional collection behavior; it introduces
|
|
237
|
+
* no additional state or focus policy.
|
|
238
|
+
* @since 1.0.0
|
|
239
|
+
* @category Native controls
|
|
240
|
+
*/
|
|
241
|
+
export const RadioGroup = Root;
|
package/dist/Role.d.ts
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type * as Scope from "effect/Scope";
|
|
2
|
+
import type { Fx } from "@typed/fx/Fx";
|
|
3
|
+
import { type Renderable, type RenderEvent, type RenderTemplate } from "@typed/template";
|
|
4
|
+
import * as Dom from "./Dom.js";
|
|
5
|
+
import type { HostResult } from "./Dom/Types.js";
|
|
6
|
+
/**
|
|
7
|
+
* Options for assigning explicit ARIA semantics to a generic host.
|
|
8
|
+
* @remarks
|
|
9
|
+
* ## Why
|
|
10
|
+
* This primitive keeps role selection visible when no dedicated component
|
|
11
|
+
* matches the required semantic.
|
|
12
|
+
* ## Ownership and lifetime
|
|
13
|
+
* The model acquires no resources; dynamic values follow the rendered Scope.
|
|
14
|
+
* @since 1.0.0
|
|
15
|
+
* @category Semantic hosts
|
|
16
|
+
*/
|
|
17
|
+
export interface RoleOptions extends Dom.HostOptions<HTMLDivElement> {
|
|
18
|
+
/** Content rendered inside the semantic host.
|
|
19
|
+
* @remarks
|
|
20
|
+
* ## Why
|
|
21
|
+
* Native content remains available to the accessibility tree.
|
|
22
|
+
* ## Ownership and lifetime
|
|
23
|
+
* Dynamic content follows the component Scope.
|
|
24
|
+
* @since 1.0.0
|
|
25
|
+
* @category Rendered content
|
|
26
|
+
*/
|
|
27
|
+
readonly content: Renderable.Any;
|
|
28
|
+
/** The explicit ARIA role.
|
|
29
|
+
* @remarks
|
|
30
|
+
* ## Why
|
|
31
|
+
* Callers must choose semantics appropriate to their interaction model.
|
|
32
|
+
* ## Ownership and lifetime
|
|
33
|
+
* The reflected value retains no resources.
|
|
34
|
+
* @since 1.0.0
|
|
35
|
+
* @category Semantic roles
|
|
36
|
+
*/
|
|
37
|
+
readonly role: Renderable.Any<string | null | undefined>;
|
|
38
|
+
}
|
|
39
|
+
declare function internalProps<const Options extends RoleOptions>({ property, }: Dom.InternalPropsHelpers<Options>): {
|
|
40
|
+
role: Exclude<Dom.Property<Options, "role">, Dom.Nullish> | undefined;
|
|
41
|
+
};
|
|
42
|
+
type RoleInternalProps<Options extends RoleOptions> = ReturnType<typeof internalProps<Options>>;
|
|
43
|
+
/**
|
|
44
|
+
* Renders a generic element with caller-selected ARIA semantics.
|
|
45
|
+
* @remarks
|
|
46
|
+
* ## Why
|
|
47
|
+
* It provides cooperative host composition without pretending every ARIA role
|
|
48
|
+
* has identical keyboard behavior; the caller remains responsible for the
|
|
49
|
+
* chosen role's complete accessibility contract.
|
|
50
|
+
* ## Ownership and lifetime
|
|
51
|
+
* Running the returned Fx owns dynamic attributes and content until its Effect
|
|
52
|
+
* Scope closes. A custom host must preserve the supplied role.
|
|
53
|
+
* @example
|
|
54
|
+
* ```ts
|
|
55
|
+
* import { Role } from "@typed/ui/Role"
|
|
56
|
+
*
|
|
57
|
+
* const status = Role({ role: "status", content: "Ready" })
|
|
58
|
+
* ```
|
|
59
|
+
* @since 1.0.0
|
|
60
|
+
* @category Semantic hosts
|
|
61
|
+
*/
|
|
62
|
+
export declare function Role<const Options extends RoleOptions, const Host extends HostResult = never>(options: Options, host?: Dom.HostOverride<Dom.RenderHostProps<Options, RoleInternalProps<Options>>, Options["content"], Host>): Fx<RenderEvent, Renderable.Error<Options | Host>, Renderable.Services<Options | Host> | Scope.Scope | RenderTemplate>;
|
|
63
|
+
export {};
|
|
64
|
+
//# sourceMappingURL=Role.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Role.d.ts","sourceRoot":"","sources":["../src/Role.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,KAAK,MAAM,cAAc,CAAC;AAC3C,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAQ,KAAK,UAAU,EAAE,KAAK,WAAW,EAAE,KAAK,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAC/F,OAAO,KAAK,GAAG,MAAM,UAAU,CAAC;AAChC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAEjD;;;;;;;;;;GAUG;AACH,MAAM,WAAW,WAAY,SAAQ,GAAG,CAAC,WAAW,CAAC,cAAc,CAAC;IAClE;;;;;;;;OAQG;IACH,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,CAAC;IACjC;;;;;;;;OAQG;IACH,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC,GAAG,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC;CAC1D;AAED,iBAAS,aAAa,CAAC,KAAK,CAAC,OAAO,SAAS,WAAW,EAAE,EACxD,QAAQ,GACT,EAAE,GAAG,CAAC,oBAAoB,CAAC,OAAO,CAAC;IACzB,IAAI;EACd;AAED,KAAK,iBAAiB,CAAC,OAAO,SAAS,WAAW,IAAI,UAAU,CAAC,OAAO,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC;AAEhG;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,IAAI,CAAC,KAAK,CAAC,OAAO,SAAS,WAAW,EAAE,KAAK,CAAC,IAAI,SAAS,UAAU,GAAG,KAAK,EAC3F,OAAO,EAAE,OAAO,EAChB,IAAI,CAAC,EAAE,GAAG,CAAC,YAAY,CACrB,GAAG,CAAC,eAAe,CAAC,OAAO,EAAE,iBAAiB,CAAC,OAAO,CAAC,CAAC,EACxD,OAAO,CAAC,SAAS,CAAC,EAClB,IAAI,CACL,GACA,EAAE,CACH,WAAW,EACX,UAAU,CAAC,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC,EAChC,UAAU,CAAC,QAAQ,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,KAAK,CAAC,KAAK,GAAG,cAAc,CACnE,CAcA"}
|
package/dist/Role.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { html } from "@typed/template";
|
|
2
|
+
import * as Dom from "./Dom.js";
|
|
3
|
+
function internalProps({ property, }) {
|
|
4
|
+
return { role: property("role", undefined) };
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Renders a generic element with caller-selected ARIA semantics.
|
|
8
|
+
* @remarks
|
|
9
|
+
* ## Why
|
|
10
|
+
* It provides cooperative host composition without pretending every ARIA role
|
|
11
|
+
* has identical keyboard behavior; the caller remains responsible for the
|
|
12
|
+
* chosen role's complete accessibility contract.
|
|
13
|
+
* ## Ownership and lifetime
|
|
14
|
+
* Running the returned Fx owns dynamic attributes and content until its Effect
|
|
15
|
+
* Scope closes. A custom host must preserve the supplied role.
|
|
16
|
+
* @example
|
|
17
|
+
* ```ts
|
|
18
|
+
* import { Role } from "@typed/ui/Role"
|
|
19
|
+
*
|
|
20
|
+
* const status = Role({ role: "status", content: "Ready" })
|
|
21
|
+
* ```
|
|
22
|
+
* @since 1.0.0
|
|
23
|
+
* @category Semantic hosts
|
|
24
|
+
*/
|
|
25
|
+
export function Role(options, host) {
|
|
26
|
+
return Dom.renderHost()(options, host, internalProps, options.content, (props, content) => html `<div ...${props}>${content}</div>`);
|
|
27
|
+
}
|