@typed/ui 1.0.0-beta.4 → 1.0.0-beta.6
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/Carousel.js
ADDED
|
@@ -0,0 +1,387 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Carousel state keeps the active slide and rotation pause policy outside the renderer. Root
|
|
3
|
+
* pauses rotation on focus and pointer entry; slides retain DOM identity while hidden; controls
|
|
4
|
+
* use native button clicks.
|
|
5
|
+
*
|
|
6
|
+
* @remarks
|
|
7
|
+
* The module keeps policy, state transitions, and DOM rendering separable so applications can use
|
|
8
|
+
* the state and pure operations without mounting UI, or supply custom hosts without replacing native
|
|
9
|
+
* events and browser-owned focus.
|
|
10
|
+
*
|
|
11
|
+
* @since 1.0.0
|
|
12
|
+
* @category modules
|
|
13
|
+
* @packageDocumentation
|
|
14
|
+
*/
|
|
15
|
+
import * as Effect from "effect/Effect";
|
|
16
|
+
import * as Schema from "effect/Schema";
|
|
17
|
+
import { RefSubject } from "@typed/fx";
|
|
18
|
+
import { html } from "@typed/template";
|
|
19
|
+
import * as Collection from "./Collection.js";
|
|
20
|
+
import * as Composite from "./Composite.js";
|
|
21
|
+
import * as Dom from "./Dom.js";
|
|
22
|
+
/**
|
|
23
|
+
* Effect Schema used by makeState to encode, decode, and hydrate Carousel state.
|
|
24
|
+
*
|
|
25
|
+
* @remarks
|
|
26
|
+
* ## Why
|
|
27
|
+
*
|
|
28
|
+
* A public schema makes hydration and serialized state use the same runtime validation as direct
|
|
29
|
+
* construction.
|
|
30
|
+
*
|
|
31
|
+
* ## Ownership and lifetime
|
|
32
|
+
*
|
|
33
|
+
* This declaration is data or schema metadata and acquires no resources.
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```ts
|
|
37
|
+
* import * as Schema from "effect/Schema";
|
|
38
|
+
* import * as Carousel from "@typed/ui/Carousel";
|
|
39
|
+
*
|
|
40
|
+
* const decodeState = Schema.decodeUnknownEffect(Carousel.StateSchema);
|
|
41
|
+
* ```
|
|
42
|
+
* @since 1.0.0
|
|
43
|
+
* @category schemas
|
|
44
|
+
*/
|
|
45
|
+
export const StateSchema = Schema.Struct({ activeId: Schema.String, paused: Schema.Boolean });
|
|
46
|
+
/**
|
|
47
|
+
* Creates hydrated Carousel state. activeId is required and paused defaults to true.
|
|
48
|
+
*
|
|
49
|
+
* @remarks
|
|
50
|
+
* ## Why
|
|
51
|
+
*
|
|
52
|
+
* State and collection ownership can be composed and tested independently from any renderer.
|
|
53
|
+
*
|
|
54
|
+
* ## Ownership and lifetime
|
|
55
|
+
*
|
|
56
|
+
* The returned Effect creates the RefSubject when run. That state is renderer-independent;
|
|
57
|
+
* collection registrations belong to the separate Scope that runs register or ref, not to state
|
|
58
|
+
* creation.
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* ```ts
|
|
62
|
+
* import * as Effect from "effect/Effect";
|
|
63
|
+
* import * as Carousel from "@typed/ui/Carousel";
|
|
64
|
+
*
|
|
65
|
+
* const program = Effect.scoped(
|
|
66
|
+
* Effect.gen(function* () {
|
|
67
|
+
* const state = yield* Carousel.makeState({ activeId: "slide-1" });
|
|
68
|
+
* const collection = yield* Carousel.makeCollection();
|
|
69
|
+
* return { state: yield* state, collection: yield* collection };
|
|
70
|
+
* }),
|
|
71
|
+
* );
|
|
72
|
+
* ```
|
|
73
|
+
* @since 1.0.0
|
|
74
|
+
* @category constructors
|
|
75
|
+
*/
|
|
76
|
+
export function makeState(initial) {
|
|
77
|
+
return RefSubject.hydrate(StateSchema, {
|
|
78
|
+
activeId: initial.activeId,
|
|
79
|
+
paused: initial.paused ?? true,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Creates a scoped Collection for Carousel items.
|
|
84
|
+
*
|
|
85
|
+
* @remarks
|
|
86
|
+
* ## Why
|
|
87
|
+
*
|
|
88
|
+
* State and collection ownership can be composed and tested independently from any renderer.
|
|
89
|
+
*
|
|
90
|
+
* ## Ownership and lifetime
|
|
91
|
+
*
|
|
92
|
+
* The returned Effect allocates the RefSubject in the caller's Scope. Each later registration is
|
|
93
|
+
* owned by the Scope that runs register, independently of this construction Effect.
|
|
94
|
+
*
|
|
95
|
+
* @example
|
|
96
|
+
* ```ts
|
|
97
|
+
* import * as Effect from "effect/Effect";
|
|
98
|
+
* import * as Carousel from "@typed/ui/Carousel";
|
|
99
|
+
*
|
|
100
|
+
* const program = Effect.scoped(
|
|
101
|
+
* Effect.gen(function* () {
|
|
102
|
+
* const collection = yield* Carousel.makeCollection();
|
|
103
|
+
* return yield* collection;
|
|
104
|
+
* }),
|
|
105
|
+
* );
|
|
106
|
+
* ```
|
|
107
|
+
* @since 1.0.0
|
|
108
|
+
* @category constructors
|
|
109
|
+
*/
|
|
110
|
+
export const makeCollection = Collection.makeState;
|
|
111
|
+
/**
|
|
112
|
+
* Sets activeId without changing paused state.
|
|
113
|
+
*
|
|
114
|
+
* @remarks
|
|
115
|
+
* ## Why
|
|
116
|
+
*
|
|
117
|
+
* The operation exposes Carousel's transition directly so callers can compose it in Effect
|
|
118
|
+
* programs and native event handlers.
|
|
119
|
+
*
|
|
120
|
+
* ## Ownership and lifetime
|
|
121
|
+
*
|
|
122
|
+
* The returned Effect performs the update or DOM side effect only when run, preserves the declared
|
|
123
|
+
* error and service channels, and retains no resources after completion.
|
|
124
|
+
*
|
|
125
|
+
* ## Example
|
|
126
|
+
*
|
|
127
|
+
* Import with `import { select } from "@typed/ui/Carousel";` Extend the [Carousel.makeState
|
|
128
|
+
* runnable setup](/reference/%40typed%2Fui%2FCarousel%23makeState). Inside the linked Effect
|
|
129
|
+
* program invoke `yield* select(state, "slide-2")`, then read state to observe `activeId` become
|
|
130
|
+
* `"slide-2"` without changing `paused`.
|
|
131
|
+
* @since 1.0.0
|
|
132
|
+
* @category combinators
|
|
133
|
+
*/
|
|
134
|
+
export function select(state, activeId) {
|
|
135
|
+
return RefSubject.update(state, (current) => ({ ...current, activeId }));
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Selects the previous or next enabled registered slide; movement wraps and leaves state unchanged
|
|
139
|
+
* for an empty collection.
|
|
140
|
+
*
|
|
141
|
+
* @remarks
|
|
142
|
+
* ## Why
|
|
143
|
+
*
|
|
144
|
+
* The operation exposes Carousel's transition directly so callers can compose it in Effect
|
|
145
|
+
* programs and native event handlers.
|
|
146
|
+
*
|
|
147
|
+
* ## Ownership and lifetime
|
|
148
|
+
*
|
|
149
|
+
* The returned Effect performs the update or DOM side effect only when run, preserves the declared
|
|
150
|
+
* error and service channels, and retains no resources after completion.
|
|
151
|
+
*
|
|
152
|
+
* ## Example
|
|
153
|
+
*
|
|
154
|
+
* Import with `import { move } from "@typed/ui/Carousel";` Extend the [Carousel.makeState runnable
|
|
155
|
+
* setup](/reference/%40typed%2Fui%2FCarousel%23makeState). Inside the linked Effect program invoke
|
|
156
|
+
* `yield* move(state, collection, "next")`, then read the state snapshot to observe the transition
|
|
157
|
+
* described above.
|
|
158
|
+
* @since 1.0.0
|
|
159
|
+
* @category combinators
|
|
160
|
+
*/
|
|
161
|
+
export function move(state, collection, direction) {
|
|
162
|
+
return Effect.gen(function* () {
|
|
163
|
+
const next = Composite.moveActiveId(yield* collection, { activeId: (yield* state).activeId, loop: true }, direction);
|
|
164
|
+
return next === null ? yield* state : yield* select(state, next);
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Flips paused and preserves activeId.
|
|
169
|
+
*
|
|
170
|
+
* @remarks
|
|
171
|
+
* ## Why
|
|
172
|
+
*
|
|
173
|
+
* The operation exposes Carousel's transition directly so callers can compose it in Effect
|
|
174
|
+
* programs and native event handlers.
|
|
175
|
+
*
|
|
176
|
+
* ## Ownership and lifetime
|
|
177
|
+
*
|
|
178
|
+
* The returned Effect performs the update or DOM side effect only when run, preserves the declared
|
|
179
|
+
* error and service channels, and retains no resources after completion.
|
|
180
|
+
*
|
|
181
|
+
* ## Example
|
|
182
|
+
*
|
|
183
|
+
* Import with `import { toggleRotation } from "@typed/ui/Carousel";` Extend the [Carousel.makeState
|
|
184
|
+
* runnable setup](/reference/%40typed%2Fui%2FCarousel%23makeState). Inside the linked Effect
|
|
185
|
+
* program invoke `yield* toggleRotation(state)`, then read state to observe `paused` invert without
|
|
186
|
+
* changing `activeId`.
|
|
187
|
+
* @since 1.0.0
|
|
188
|
+
* @category combinators
|
|
189
|
+
*/
|
|
190
|
+
export function toggleRotation(state) {
|
|
191
|
+
return RefSubject.update(state, (current) => ({ ...current, paused: !current.paused }));
|
|
192
|
+
}
|
|
193
|
+
function rootInternalProps(options) {
|
|
194
|
+
const pause = RefSubject.update(options.state, (current) => current.paused ? current : { ...current, paused: true });
|
|
195
|
+
let resumeOnPointerLeave = false;
|
|
196
|
+
const pauseForFocus = Effect.andThen(Effect.sync(() => {
|
|
197
|
+
resumeOnPointerLeave = false;
|
|
198
|
+
}), pause);
|
|
199
|
+
const pauseForPointer = Effect.flatMap(options.state, (current) => {
|
|
200
|
+
resumeOnPointerLeave = !current.paused;
|
|
201
|
+
return pause;
|
|
202
|
+
});
|
|
203
|
+
const resumeAfterPointer = Effect.suspend(() => {
|
|
204
|
+
if (!resumeOnPointerLeave)
|
|
205
|
+
return Effect.void;
|
|
206
|
+
resumeOnPointerLeave = false;
|
|
207
|
+
return RefSubject.update(options.state, (current) => current.paused ? { ...current, paused: false } : current);
|
|
208
|
+
});
|
|
209
|
+
return ({ property }) => ({
|
|
210
|
+
role: "region",
|
|
211
|
+
"aria-roledescription": "carousel",
|
|
212
|
+
"aria-label": property("label", undefined),
|
|
213
|
+
onfocusin: pauseForFocus,
|
|
214
|
+
onmouseenter: pauseForPointer,
|
|
215
|
+
onmouseleave: resumeAfterPointer,
|
|
216
|
+
ref: options.state,
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Renders the carousel region and pauses automatic rotation on focus or pointer entry without
|
|
221
|
+
* replacing its child nodes.
|
|
222
|
+
*
|
|
223
|
+
* @remarks
|
|
224
|
+
* ## Why
|
|
225
|
+
*
|
|
226
|
+
* The component applies the family behavior while leaving callers free to supply a custom host
|
|
227
|
+
* through the shared DOM boundary.
|
|
228
|
+
*
|
|
229
|
+
* ## Ownership and lifetime
|
|
230
|
+
*
|
|
231
|
+
* The returned Fx installs DOM refs, native listeners, state subscriptions, and optional
|
|
232
|
+
* collection registrations only when rendered. The rendering Scope removes those resources;
|
|
233
|
+
* unrelated nodes and attributes remain caller-owned.
|
|
234
|
+
*
|
|
235
|
+
* ## Example
|
|
236
|
+
*
|
|
237
|
+
* Import with `import { Root } from "@typed/ui/Carousel";` Extend the [Carousel.makeState runnable
|
|
238
|
+
* setup](/reference/%40typed%2Fui%2FCarousel%23makeState). Replace the linked program's final
|
|
239
|
+
* snapshot read with `Root({ state, content: "Slides", label: "Featured" })`; render that Fx before
|
|
240
|
+
* the same Scope closes.
|
|
241
|
+
* @since 1.0.0
|
|
242
|
+
* @category components
|
|
243
|
+
*/
|
|
244
|
+
export function Root(options, host) {
|
|
245
|
+
return Dom.renderHost()(options, host, rootInternalProps(options), options.content, (props, content) => {
|
|
246
|
+
return html `<div ...${props}>${content}</div>`;
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
function slideInternalProps(options) {
|
|
250
|
+
const register = options.collection === undefined
|
|
251
|
+
? undefined
|
|
252
|
+
: Collection.ref(options.collection, {
|
|
253
|
+
id: options.id,
|
|
254
|
+
value: options.id,
|
|
255
|
+
textValue: options.id,
|
|
256
|
+
});
|
|
257
|
+
return ({ property }) => ({
|
|
258
|
+
id: options.id,
|
|
259
|
+
role: "group",
|
|
260
|
+
"aria-roledescription": "slide",
|
|
261
|
+
"aria-label": property("label", undefined),
|
|
262
|
+
"?hidden": RefSubject.map(options.state, (state) => state.activeId !== options.id),
|
|
263
|
+
ref: register,
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Renders one labelled slide, registers it when a collection is supplied, and toggles hidden from
|
|
268
|
+
* activeId.
|
|
269
|
+
*
|
|
270
|
+
* @remarks
|
|
271
|
+
* ## Why
|
|
272
|
+
*
|
|
273
|
+
* The component applies the family behavior while leaving callers free to supply a custom host
|
|
274
|
+
* through the shared DOM boundary.
|
|
275
|
+
*
|
|
276
|
+
* ## Ownership and lifetime
|
|
277
|
+
*
|
|
278
|
+
* The returned Fx installs DOM refs, native listeners, state subscriptions, and optional
|
|
279
|
+
* collection registrations only when rendered. The rendering Scope removes those resources;
|
|
280
|
+
* unrelated nodes and attributes remain caller-owned.
|
|
281
|
+
*
|
|
282
|
+
* ## Example
|
|
283
|
+
*
|
|
284
|
+
* Import with `import { Slide } from "@typed/ui/Carousel";` Extend the [Carousel.makeState runnable
|
|
285
|
+
* setup](/reference/%40typed%2Fui%2FCarousel%23makeState). Replace the linked program's final
|
|
286
|
+
* snapshot read with `Slide({ state, id: "slide-1", label: "1 of 3", content: "First slide" })`;
|
|
287
|
+
* render that Fx before the same Scope closes.
|
|
288
|
+
* @since 1.0.0
|
|
289
|
+
* @category components
|
|
290
|
+
*/
|
|
291
|
+
export function Slide(options, host) {
|
|
292
|
+
return Dom.renderHost()(options, host, slideInternalProps(options), options.content, (props, content) => {
|
|
293
|
+
return html `<div ...${props}>${content}</div>`;
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
function controlInternalProps(options, action) {
|
|
297
|
+
return () => ({ type: "button", onclick: action });
|
|
298
|
+
}
|
|
299
|
+
function control(options, host, action) {
|
|
300
|
+
const internal = controlInternalProps(options, action);
|
|
301
|
+
return Dom.renderHost()(options, host, internal, options.content, (props, content) => html `<button ...${props}>${content}</button>`);
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* Renders a button whose native click selects the previous registered slide with wrapping enabled.
|
|
305
|
+
*
|
|
306
|
+
* @remarks
|
|
307
|
+
* ## Why
|
|
308
|
+
*
|
|
309
|
+
* The component applies the family behavior while leaving callers free to supply a custom host
|
|
310
|
+
* through the shared DOM boundary.
|
|
311
|
+
*
|
|
312
|
+
* ## Ownership and lifetime
|
|
313
|
+
*
|
|
314
|
+
* The returned Fx installs DOM refs, native listeners, state subscriptions, and optional
|
|
315
|
+
* collection registrations only when rendered. The rendering Scope removes those resources;
|
|
316
|
+
* unrelated nodes and attributes remain caller-owned.
|
|
317
|
+
*
|
|
318
|
+
* ## Example
|
|
319
|
+
*
|
|
320
|
+
* Import with `import { Previous } from "@typed/ui/Carousel";` Extend the [Carousel.makeState
|
|
321
|
+
* runnable setup](/reference/%40typed%2Fui%2FCarousel%23makeState). Replace the linked program's
|
|
322
|
+
* final snapshot read with `Previous({ state, content: "Previous" })`; render that Fx before the
|
|
323
|
+
* same Scope closes.
|
|
324
|
+
* @since 1.0.0
|
|
325
|
+
* @category components
|
|
326
|
+
*/
|
|
327
|
+
export function Previous(options, host) {
|
|
328
|
+
return control(options, host, options.collection === undefined
|
|
329
|
+
? Effect.void
|
|
330
|
+
: move(options.state, options.collection, "previous"));
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Renders a button whose native click selects the next registered slide with wrapping enabled.
|
|
334
|
+
*
|
|
335
|
+
* @remarks
|
|
336
|
+
* ## Why
|
|
337
|
+
*
|
|
338
|
+
* The component applies the family behavior while leaving callers free to supply a custom host
|
|
339
|
+
* through the shared DOM boundary.
|
|
340
|
+
*
|
|
341
|
+
* ## Ownership and lifetime
|
|
342
|
+
*
|
|
343
|
+
* The returned Fx installs DOM refs, native listeners, state subscriptions, and optional
|
|
344
|
+
* collection registrations only when rendered. The rendering Scope removes those resources;
|
|
345
|
+
* unrelated nodes and attributes remain caller-owned.
|
|
346
|
+
*
|
|
347
|
+
* ## Example
|
|
348
|
+
*
|
|
349
|
+
* Import with `import { Next } from "@typed/ui/Carousel";` Extend the [Carousel.makeState runnable
|
|
350
|
+
* setup](/reference/%40typed%2Fui%2FCarousel%23makeState). Replace the linked program's final
|
|
351
|
+
* snapshot read with `Next({ state, content: "Next" })`; render that Fx before the same Scope
|
|
352
|
+
* closes.
|
|
353
|
+
* @since 1.0.0
|
|
354
|
+
* @category components
|
|
355
|
+
*/
|
|
356
|
+
export function Next(options, host) {
|
|
357
|
+
return control(options, host, options.collection === undefined
|
|
358
|
+
? Effect.void
|
|
359
|
+
: move(options.state, options.collection, "next"));
|
|
360
|
+
}
|
|
361
|
+
/**
|
|
362
|
+
* Renders a button whose native click toggles the explicit paused state.
|
|
363
|
+
*
|
|
364
|
+
* @remarks
|
|
365
|
+
* ## Why
|
|
366
|
+
*
|
|
367
|
+
* The component applies the family behavior while leaving callers free to supply a custom host
|
|
368
|
+
* through the shared DOM boundary.
|
|
369
|
+
*
|
|
370
|
+
* ## Ownership and lifetime
|
|
371
|
+
*
|
|
372
|
+
* The returned Fx installs DOM refs, native listeners, state subscriptions, and optional
|
|
373
|
+
* collection registrations only when rendered. The rendering Scope removes those resources;
|
|
374
|
+
* unrelated nodes and attributes remain caller-owned.
|
|
375
|
+
*
|
|
376
|
+
* ## Example
|
|
377
|
+
*
|
|
378
|
+
* Import with `import { RotationControl } from "@typed/ui/Carousel";` Extend the
|
|
379
|
+
* [Carousel.makeState runnable setup](/reference/%40typed%2Fui%2FCarousel%23makeState). Replace the
|
|
380
|
+
* linked program's final snapshot read with `RotationControl({ state, content: "Pause rotation"
|
|
381
|
+
* })`; render that Fx before the same Scope closes.
|
|
382
|
+
* @since 1.0.0
|
|
383
|
+
* @category components
|
|
384
|
+
*/
|
|
385
|
+
export function RotationControl(options, host) {
|
|
386
|
+
return control(options, host, toggleRotation(options.state));
|
|
387
|
+
}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import * as Effect from "effect/Effect";
|
|
2
|
+
import * as Schema from "effect/Schema";
|
|
3
|
+
import { RefSubject } from "@typed/fx";
|
|
4
|
+
import { EventHandler } from "@typed/template";
|
|
5
|
+
import * as Dom from "./Dom.js";
|
|
6
|
+
import type { HostResult } from "./Dom/Types.js";
|
|
7
|
+
/** Three-state value accepted by a checkbox.
|
|
8
|
+
* @remarks
|
|
9
|
+
* ## Why
|
|
10
|
+
* `"mixed"` models the platform's indeterminate presentation without
|
|
11
|
+
* conflating it with either submitted boolean state.
|
|
12
|
+
* ## Ownership and lifetime
|
|
13
|
+
* This pure type acquires no resources.
|
|
14
|
+
* @since 1.0.0
|
|
15
|
+
* @category models
|
|
16
|
+
*/
|
|
17
|
+
export type Checked = boolean | "mixed";
|
|
18
|
+
/** Current renderer-independent checkbox state.
|
|
19
|
+
* @remarks
|
|
20
|
+
* ## Why
|
|
21
|
+
* State can be updated and tested through RefSubject before any input mounts.
|
|
22
|
+
* ## Ownership and lifetime
|
|
23
|
+
* The value is plain data; the hydrated RefSubject returned by `makeState`
|
|
24
|
+
* owns observation for its Effect Scope.
|
|
25
|
+
* @since 1.0.0
|
|
26
|
+
* @category state
|
|
27
|
+
*/
|
|
28
|
+
export interface State {
|
|
29
|
+
/** Current checked or mixed value.
|
|
30
|
+
* @remarks
|
|
31
|
+
* ## Why
|
|
32
|
+
* One field drives `checked`, `indeterminate`, and `aria-checked` together.
|
|
33
|
+
* ## Ownership and lifetime
|
|
34
|
+
* Plain state retains no resources.
|
|
35
|
+
* @since 1.0.0
|
|
36
|
+
* @category state
|
|
37
|
+
*/
|
|
38
|
+
readonly checked: Checked;
|
|
39
|
+
}
|
|
40
|
+
/** Initial checkbox state accepted by `makeState`.
|
|
41
|
+
* @remarks
|
|
42
|
+
* ## Why
|
|
43
|
+
* The optional value gives uncontrolled creation a deterministic false default.
|
|
44
|
+
* ## Ownership and lifetime
|
|
45
|
+
* This configuration is inert and retains no resources.
|
|
46
|
+
* @since 1.0.0
|
|
47
|
+
* @category state
|
|
48
|
+
*/
|
|
49
|
+
export interface InitialState {
|
|
50
|
+
/** Initial checked value; defaults to `false`.
|
|
51
|
+
* @remarks
|
|
52
|
+
* ## Why
|
|
53
|
+
* Explicit mixed state can survive SSR hydration.
|
|
54
|
+
* ## Ownership and lifetime
|
|
55
|
+
* The value is copied into hydrated state and retains no resource.
|
|
56
|
+
* @since 1.0.0
|
|
57
|
+
* @category state
|
|
58
|
+
*/
|
|
59
|
+
readonly checked?: Checked;
|
|
60
|
+
}
|
|
61
|
+
/** Schema used to encode and hydrate checkbox state.
|
|
62
|
+
* @remarks
|
|
63
|
+
* ## Why
|
|
64
|
+
* A shared schema keeps server and client state shape identical.
|
|
65
|
+
* ## Ownership and lifetime
|
|
66
|
+
* The schema is immutable and acquires no resources.
|
|
67
|
+
* @since 1.0.0
|
|
68
|
+
* @category schemas
|
|
69
|
+
*/
|
|
70
|
+
export declare const StateSchema: Schema.Struct<{
|
|
71
|
+
readonly checked: Schema.Literals<readonly [true, false, "mixed"]>;
|
|
72
|
+
}>;
|
|
73
|
+
/** Creates hydrated, renderer-independent checkbox state.
|
|
74
|
+
* @remarks
|
|
75
|
+
* ## Why
|
|
76
|
+
* State transitions remain testable without rendering and can be consumed by
|
|
77
|
+
* any UI producer.
|
|
78
|
+
* ## Ownership and lifetime
|
|
79
|
+
* The caller's Effect Scope owns the hydrated RefSubject and its subscriptions.
|
|
80
|
+
* @example
|
|
81
|
+
* ```ts
|
|
82
|
+
* import { Effect } from "effect"
|
|
83
|
+
* import * as Checkbox from "@typed/ui/Checkbox"
|
|
84
|
+
*
|
|
85
|
+
* const program = Effect.gen(function* () {
|
|
86
|
+
* return yield* Checkbox.makeState({ checked: "mixed" })
|
|
87
|
+
* })
|
|
88
|
+
* ```
|
|
89
|
+
* @since 1.0.0
|
|
90
|
+
* @category constructors
|
|
91
|
+
*/
|
|
92
|
+
export declare function makeState(initial?: InitialState): Effect.Effect<RefSubject.HydratedRefSubject<{
|
|
93
|
+
readonly checked: "mixed" | boolean;
|
|
94
|
+
}, Schema.SchemaError, never, never>, never, import("effect/Scope").Scope>;
|
|
95
|
+
/** Sets the checkbox state to a boolean or mixed value.
|
|
96
|
+
* @remarks
|
|
97
|
+
* ## Why
|
|
98
|
+
* A single atomic RefSubject update keeps DOM properties and ARIA state aligned.
|
|
99
|
+
* ## Ownership and lifetime
|
|
100
|
+
* The Effect uses the existing subject lifetime and acquires no new resource.
|
|
101
|
+
* @example
|
|
102
|
+
* ```ts
|
|
103
|
+
* import { Effect } from "effect"
|
|
104
|
+
* import * as Checkbox from "@typed/ui/Checkbox"
|
|
105
|
+
*
|
|
106
|
+
* const program = Effect.gen(function* () {
|
|
107
|
+
* const state = yield* Checkbox.makeState()
|
|
108
|
+
* yield* Checkbox.setChecked(state, true)
|
|
109
|
+
* })
|
|
110
|
+
* ```
|
|
111
|
+
* @since 1.0.0
|
|
112
|
+
* @category state
|
|
113
|
+
*/
|
|
114
|
+
export declare function setChecked<E, R>(state: RefSubject.RefSubject<State, E, R>, checked: Checked): Effect.Effect<State, E, R>;
|
|
115
|
+
/** Toggles checked to false and false or mixed to true.
|
|
116
|
+
* @remarks
|
|
117
|
+
* ## Why
|
|
118
|
+
* User activation of an indeterminate checkbox resolves to a concrete checked
|
|
119
|
+
* state, matching native input behavior.
|
|
120
|
+
* ## Ownership and lifetime
|
|
121
|
+
* The Effect updates the existing RefSubject and acquires no resource.
|
|
122
|
+
* @example
|
|
123
|
+
* ```ts
|
|
124
|
+
* import { Effect } from "effect"
|
|
125
|
+
* import * as Checkbox from "@typed/ui/Checkbox"
|
|
126
|
+
*
|
|
127
|
+
* const program = Effect.gen(function* () {
|
|
128
|
+
* const state = yield* Checkbox.makeState({ checked: "mixed" })
|
|
129
|
+
* yield* Checkbox.toggle(state)
|
|
130
|
+
* })
|
|
131
|
+
* ```
|
|
132
|
+
* @since 1.0.0
|
|
133
|
+
* @category state
|
|
134
|
+
*/
|
|
135
|
+
export declare function toggle<E, R>(state: RefSubject.RefSubject<State, E, R>): Effect.Effect<State, E, R>;
|
|
136
|
+
/** Options for the native checkbox input.
|
|
137
|
+
* @remarks
|
|
138
|
+
* ## Why
|
|
139
|
+
* The state reference is the single source for native and ARIA checked values.
|
|
140
|
+
* ## Ownership and lifetime
|
|
141
|
+
* Options are inert; the component Scope owns DOM subscriptions and refs.
|
|
142
|
+
* @since 1.0.0
|
|
143
|
+
* @category models
|
|
144
|
+
*/
|
|
145
|
+
export interface InputOptions extends Dom.HostOptions<HTMLInputElement> {
|
|
146
|
+
/** Hydrated state synchronized with the input.
|
|
147
|
+
* @remarks
|
|
148
|
+
* ## Why
|
|
149
|
+
* Hydration preserves checked identity and enables state-only tests.
|
|
150
|
+
* ## Ownership and lifetime
|
|
151
|
+
* The input borrows the RefSubject; its original Scope remains the owner.
|
|
152
|
+
* @since 1.0.0
|
|
153
|
+
* @category state
|
|
154
|
+
*/
|
|
155
|
+
readonly state: RefSubject.HydratedRefSubject<State, Schema.SchemaError>;
|
|
156
|
+
}
|
|
157
|
+
declare function internalProps<const Options extends InputOptions>(options: Options): ({ property }: Dom.InternalPropsHelpers<Options>) => {
|
|
158
|
+
type: string;
|
|
159
|
+
"aria-checked": RefSubject.Computed<Checked, Schema.SchemaError, never>;
|
|
160
|
+
"?checked": RefSubject.Computed<boolean, Schema.SchemaError, never>;
|
|
161
|
+
".checked": RefSubject.Computed<boolean, Schema.SchemaError, never>;
|
|
162
|
+
"?disabled": false | Exclude<Dom.Property<Options, "disabled">, Dom.Nullish>;
|
|
163
|
+
"?required": false | Exclude<Dom.Property<Options, "required">, Dom.Nullish>;
|
|
164
|
+
".indeterminate": RefSubject.Computed<boolean, Schema.SchemaError, never>;
|
|
165
|
+
onchange: EventHandler.EventHandler<Event, Schema.SchemaError, never>;
|
|
166
|
+
ref: RefSubject.HydratedRefSubject<State, Schema.SchemaError, never, never>;
|
|
167
|
+
};
|
|
168
|
+
type InputInternalProps<Options extends InputOptions> = ReturnType<ReturnType<typeof internalProps<Options>>>;
|
|
169
|
+
/** Renders a native checkbox input synchronized with hydrated state.
|
|
170
|
+
* @remarks
|
|
171
|
+
* ## Why
|
|
172
|
+
* Native keyboard, form, disabled, required, and accessibility behavior remain
|
|
173
|
+
* available while state is exposed through RefSubject.
|
|
174
|
+
* ## Ownership and lifetime
|
|
175
|
+
* Running the Fx installs native listeners and state subscriptions in its
|
|
176
|
+
* Scope. A custom host must apply `type`, checked, indeterminate, ARIA, and ref
|
|
177
|
+
* props; only one hydration owner may be composed for the element.
|
|
178
|
+
* @example
|
|
179
|
+
* ```ts
|
|
180
|
+
* import { Effect } from "effect"
|
|
181
|
+
* import * as Checkbox from "@typed/ui/Checkbox"
|
|
182
|
+
*
|
|
183
|
+
* const program = Effect.gen(function* () {
|
|
184
|
+
* const state = yield* Checkbox.makeState()
|
|
185
|
+
* return Checkbox.Input({ state })
|
|
186
|
+
* })
|
|
187
|
+
* ```
|
|
188
|
+
* @since 1.0.0
|
|
189
|
+
* @category components
|
|
190
|
+
*/
|
|
191
|
+
export declare function Input<const Options extends InputOptions, const Host extends HostResult = never>(options: Options, host?: Dom.HostOverride<Dom.RenderHostProps<Options, InputInternalProps<Options>>, "", Host>): import("./Dom/Types.js").HostComponent<Host | Options>;
|
|
192
|
+
/** Canonical component alias for `Input`.
|
|
193
|
+
* @remarks
|
|
194
|
+
* ## Why
|
|
195
|
+
* The alias provides the widget name while retaining the explicit input API.
|
|
196
|
+
* ## Ownership and lifetime
|
|
197
|
+
* It has exactly the same Scope and native-element ownership as `Input`.
|
|
198
|
+
* @since 1.0.0
|
|
199
|
+
* @category aliases
|
|
200
|
+
*/
|
|
201
|
+
export declare const Checkbox: typeof Input;
|
|
202
|
+
export {};
|
|
203
|
+
//# sourceMappingURL=Checkbox.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Checkbox.d.ts","sourceRoot":"","sources":["../src/Checkbox.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AACvC,OAAO,EAAE,YAAY,EAAQ,MAAM,iBAAiB,CAAC;AACrD,OAAO,KAAK,GAAG,MAAM,UAAU,CAAC;AAChC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAEjD;;;;;;;;;GASG;AACH,MAAM,MAAM,OAAO,GAAG,OAAO,GAAG,OAAO,CAAC;AAExC;;;;;;;;;GASG;AACH,MAAM,WAAW,KAAK;IACpB;;;;;;;;OAQG;IACH,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;CAC3B;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,YAAY;IAC3B;;;;;;;;OAQG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,WAAW;;EAEtB,CAAC;AAEH;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,SAAS,CAAC,OAAO,GAAE,YAAiB;;2EAEnD;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,UAAU,CAAC,CAAC,EAAE,CAAC,EAC7B,KAAK,EAAE,UAAU,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC,EACzC,OAAO,EAAE,OAAO,GACf,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC,CAE5B;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,MAAM,CAAC,CAAC,EAAE,CAAC,EACzB,KAAK,EAAE,UAAU,CAAC,UAAU,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC,GACxC,MAAM,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC,CAK5B;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,YAAa,SAAQ,GAAG,CAAC,WAAW,CAAC,gBAAgB,CAAC;IACrE;;;;;;;;OAQG;IACH,QAAQ,CAAC,KAAK,EAAE,UAAU,CAAC,kBAAkB,CAAC,KAAK,EAAE,MAAM,CAAC,WAAW,CAAC,CAAC;CAC1E;AAED,iBAAS,aAAa,CAAC,KAAK,CAAC,OAAO,SAAS,YAAY,EAAE,OAAO,EAAE,OAAO,kBASnD,GAAG,CAAC,oBAAoB,CAAC,OAAO,CAAC;IACrD,IAAI;IACJ,cAAc;IACd,UAAU;IACV,UAAU;IACV,WAAW;IACX,WAAW;IACX,gBAAgB;IAChB,QAAQ;IACR,GAAG;EAEN;AAED,KAAK,kBAAkB,CAAC,OAAO,SAAS,YAAY,IAAI,UAAU,CAChE,UAAU,CAAC,OAAO,aAAa,CAAC,OAAO,CAAC,CAAC,CAC1C,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,KAAK,CAAC,KAAK,CAAC,OAAO,SAAS,YAAY,EAAE,KAAK,CAAC,IAAI,SAAS,UAAU,GAAG,KAAK,EAC7F,OAAO,EAAE,OAAO,EAChB,IAAI,CAAC,EAAE,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,eAAe,CAAC,OAAO,EAAE,kBAAkB,CAAC,OAAO,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,CAAC,0DAW7F;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,QAAQ,cAAQ,CAAC"}
|