@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.
Files changed (157) hide show
  1. package/README.md +53 -9
  2. package/dist/Alert.d.ts +78 -0
  3. package/dist/Alert.d.ts.map +1 -0
  4. package/dist/Alert.js +37 -0
  5. package/dist/Button.d.ts +144 -0
  6. package/dist/Button.d.ts.map +1 -0
  7. package/dist/Button.js +38 -0
  8. package/dist/Carousel.d.ts +547 -0
  9. package/dist/Carousel.d.ts.map +1 -0
  10. package/dist/Carousel.js +387 -0
  11. package/dist/Checkbox.d.ts +203 -0
  12. package/dist/Checkbox.d.ts.map +1 -0
  13. package/dist/Checkbox.js +140 -0
  14. package/dist/Collection.d.ts +254 -0
  15. package/dist/Collection.d.ts.map +1 -0
  16. package/dist/Collection.js +218 -0
  17. package/dist/Combobox.d.ts +516 -0
  18. package/dist/Combobox.d.ts.map +1 -0
  19. package/dist/Combobox.js +371 -0
  20. package/dist/Component.d.ts +127 -0
  21. package/dist/Component.d.ts.map +1 -0
  22. package/dist/Component.js +60 -0
  23. package/dist/Composite.d.ts +823 -0
  24. package/dist/Composite.d.ts.map +1 -0
  25. package/dist/Composite.js +615 -0
  26. package/dist/Dialog.d.ts +544 -0
  27. package/dist/Dialog.d.ts.map +1 -0
  28. package/dist/Dialog.js +355 -0
  29. package/dist/Disclosure.d.ts +219 -0
  30. package/dist/Disclosure.d.ts.map +1 -0
  31. package/dist/Disclosure.js +128 -0
  32. package/dist/Dom/Events.d.ts +122 -0
  33. package/dist/Dom/Events.d.ts.map +1 -0
  34. package/dist/Dom/Events.js +192 -0
  35. package/dist/Dom/Props.d.ts +161 -0
  36. package/dist/Dom/Props.d.ts.map +1 -0
  37. package/dist/Dom/Props.js +110 -0
  38. package/dist/Dom/Refs.d.ts +58 -0
  39. package/dist/Dom/Refs.d.ts.map +1 -0
  40. package/dist/Dom/Refs.js +61 -0
  41. package/dist/Dom/Render.d.ts +59 -0
  42. package/dist/Dom/Render.d.ts.map +1 -0
  43. package/dist/Dom/Render.js +71 -0
  44. package/dist/Dom/Types.d.ts +570 -0
  45. package/dist/Dom/Types.d.ts.map +1 -0
  46. package/dist/Dom/Types.js +1 -0
  47. package/dist/Dom/index.d.ts +20 -0
  48. package/dist/Dom/index.d.ts.map +1 -0
  49. package/dist/Dom/index.js +8 -0
  50. package/dist/Dom.d.ts +14 -0
  51. package/dist/Dom.d.ts.map +1 -0
  52. package/dist/Dom.js +13 -0
  53. package/dist/Focusable.d.ts +85 -0
  54. package/dist/Focusable.d.ts.map +1 -0
  55. package/dist/Focusable.js +35 -0
  56. package/dist/Form.d.ts +1695 -0
  57. package/dist/Form.d.ts.map +1 -0
  58. package/dist/Form.js +987 -0
  59. package/dist/Grid.d.ts +569 -0
  60. package/dist/Grid.d.ts.map +1 -0
  61. package/dist/Grid.js +379 -0
  62. package/dist/Group.d.ts +147 -0
  63. package/dist/Group.d.ts.map +1 -0
  64. package/dist/Group.js +63 -0
  65. package/dist/Heading.d.ts +86 -0
  66. package/dist/Heading.d.ts.map +1 -0
  67. package/dist/Heading.js +48 -0
  68. package/dist/Hovercard.d.ts +297 -0
  69. package/dist/Hovercard.d.ts.map +1 -0
  70. package/dist/Hovercard.js +188 -0
  71. package/dist/HttpRouter.d.ts +129 -6
  72. package/dist/HttpRouter.d.ts.map +1 -1
  73. package/dist/HttpRouter.js +196 -53
  74. package/dist/Link.d.ts +67 -28
  75. package/dist/Link.d.ts.map +1 -1
  76. package/dist/Link.js +91 -37
  77. package/dist/Listbox.d.ts +437 -0
  78. package/dist/Listbox.d.ts.map +1 -0
  79. package/dist/Listbox.js +316 -0
  80. package/dist/Menu.d.ts +972 -0
  81. package/dist/Menu.d.ts.map +1 -0
  82. package/dist/Menu.js +731 -0
  83. package/dist/Menubar.d.ts +367 -0
  84. package/dist/Menubar.d.ts.map +1 -0
  85. package/dist/Menubar.js +265 -0
  86. package/dist/Meter.d.ts +217 -0
  87. package/dist/Meter.d.ts.map +1 -0
  88. package/dist/Meter.js +94 -0
  89. package/dist/NativeDetails.d.ts +41 -0
  90. package/dist/NativeDetails.d.ts.map +1 -0
  91. package/dist/NativeDetails.js +40 -0
  92. package/dist/NativeDialog.d.ts +64 -0
  93. package/dist/NativeDialog.d.ts.map +1 -0
  94. package/dist/NativeDialog.js +50 -0
  95. package/dist/NativePopover.d.ts +41 -0
  96. package/dist/NativePopover.d.ts.map +1 -0
  97. package/dist/NativePopover.js +46 -0
  98. package/dist/Popover.d.ts +241 -0
  99. package/dist/Popover.d.ts.map +1 -0
  100. package/dist/Popover.js +141 -0
  101. package/dist/RadioGroup.d.ts +432 -0
  102. package/dist/RadioGroup.d.ts.map +1 -0
  103. package/dist/RadioGroup.js +291 -0
  104. package/dist/Role.d.ts +64 -0
  105. package/dist/Role.d.ts.map +1 -0
  106. package/dist/Role.js +27 -0
  107. package/dist/Select.d.ts +529 -0
  108. package/dist/Select.d.ts.map +1 -0
  109. package/dist/Select.js +407 -0
  110. package/dist/Separator.d.ts +54 -0
  111. package/dist/Separator.d.ts.map +1 -0
  112. package/dist/Separator.js +26 -0
  113. package/dist/Slider.d.ts +188 -0
  114. package/dist/Slider.d.ts.map +1 -0
  115. package/dist/Slider.js +96 -0
  116. package/dist/SpinButton.d.ts +188 -0
  117. package/dist/SpinButton.d.ts.map +1 -0
  118. package/dist/SpinButton.js +96 -0
  119. package/dist/Storybook.d.ts +76 -0
  120. package/dist/Storybook.d.ts.map +1 -0
  121. package/dist/Storybook.js +102 -0
  122. package/dist/Switch.d.ts +187 -0
  123. package/dist/Switch.d.ts.map +1 -0
  124. package/dist/Switch.js +116 -0
  125. package/dist/Tab.d.ts +26 -0
  126. package/dist/Tab.d.ts.map +1 -0
  127. package/dist/Tab.js +25 -0
  128. package/dist/Tabs.d.ts +591 -0
  129. package/dist/Tabs.d.ts.map +1 -0
  130. package/dist/Tabs.js +346 -0
  131. package/dist/Toolbar.d.ts +366 -0
  132. package/dist/Toolbar.d.ts.map +1 -0
  133. package/dist/Toolbar.js +245 -0
  134. package/dist/Tooltip.d.ts +296 -0
  135. package/dist/Tooltip.d.ts.map +1 -0
  136. package/dist/Tooltip.js +172 -0
  137. package/dist/Tree.d.ts +591 -0
  138. package/dist/Tree.d.ts.map +1 -0
  139. package/dist/Tree.js +434 -0
  140. package/dist/TreeGrid.d.ts +645 -0
  141. package/dist/TreeGrid.d.ts.map +1 -0
  142. package/dist/TreeGrid.js +420 -0
  143. package/dist/VisuallyHidden.d.ts +54 -0
  144. package/dist/VisuallyHidden.d.ts.map +1 -0
  145. package/dist/VisuallyHidden.js +27 -0
  146. package/dist/WindowSplitter.d.ts +376 -0
  147. package/dist/WindowSplitter.d.ts.map +1 -0
  148. package/dist/WindowSplitter.js +222 -0
  149. package/dist/index.d.ts +49 -0
  150. package/dist/index.d.ts.map +1 -1
  151. package/dist/index.js +49 -0
  152. package/package.json +45 -18
  153. package/src/HttpRouter.test.ts +0 -256
  154. package/src/HttpRouter.ts +0 -165
  155. package/src/Link.test.ts +0 -84
  156. package/src/Link.ts +0 -107
  157. package/src/index.ts +0 -2
@@ -0,0 +1,376 @@
1
+ import * as Effect from "effect/Effect";
2
+ import * as Schema from "effect/Schema";
3
+ import { RefSubject } from "@typed/fx";
4
+ import { EventHandler, type Renderable } from "@typed/template";
5
+ import * as Dom from "./Dom.js";
6
+ import type { HostResult } from "./Dom/Types.js";
7
+ /** Visual orientation of the separator between panes.
8
+ * @remarks
9
+ * ## Why
10
+ * A vertical separator adjusts with Left/Right; a horizontal separator adjusts
11
+ * with Up/Down, matching the axis perpendicular to the dividing line.
12
+ * ## Ownership and lifetime
13
+ * This pure type acquires no resources.
14
+ * @since 1.0.0
15
+ * @category models
16
+ */
17
+ export type Orientation = "horizontal" | "vertical";
18
+ /** Current value and keyboard policy for a window splitter.
19
+ * @remarks
20
+ * ## Why
21
+ * All range and collapse information remains renderer-independent and directly
22
+ * testable.
23
+ * ## Ownership and lifetime
24
+ * Plain state retains no resources; its hydrated RefSubject is Scope-owned.
25
+ * @since 1.0.0
26
+ * @category state
27
+ */
28
+ export interface State {
29
+ /** Current pane size value.
30
+ * @remarks
31
+ * ## Why
32
+ * It drives `aria-valuenow` and keyboard adjustments.
33
+ * ## Ownership and lifetime
34
+ * Plain numeric data acquires no resources.
35
+ * @since 1.0.0
36
+ * @category state
37
+ */
38
+ readonly value: number;
39
+ /** Restore value used by `toggleCollapsed`.
40
+ * @remarks
41
+ * ## Why
42
+ * It starts at the initial clamped value. `toggleCollapsed` overwrites it only
43
+ * when collapsing from a non-minimum value, then reads it when restoring.
44
+ * Ordinary `setValue` and `adjust` calls do not update it.
45
+ * ## Ownership and lifetime
46
+ * Plain numeric data acquires no resources.
47
+ * @since 1.0.0
48
+ * @category state
49
+ */
50
+ readonly previousValue: number;
51
+ /** Inclusive minimum pane value.
52
+ * @remarks
53
+ * ## Why
54
+ * Updates clamp to this bound and Home jumps to it.
55
+ * ## Ownership and lifetime
56
+ * Plain numeric data acquires no resources.
57
+ * @since 1.0.0
58
+ * @category constraints
59
+ */
60
+ readonly min: number;
61
+ /** Inclusive maximum pane value.
62
+ * @remarks
63
+ * ## Why
64
+ * Updates clamp to this bound and End jumps to it.
65
+ * ## Ownership and lifetime
66
+ * Plain numeric data acquires no resources.
67
+ * @since 1.0.0
68
+ * @category constraints
69
+ */
70
+ readonly max: number;
71
+ /** Keyboard adjustment increment.
72
+ * @remarks
73
+ * ## Why
74
+ * Arrow keys require a deterministic application-defined change size. The
75
+ * state constructor does not enforce positivity; callers must provide a
76
+ * positive value for conventional keyboard direction.
77
+ * ## Ownership and lifetime
78
+ * Plain numeric data acquires no resources.
79
+ * @since 1.0.0
80
+ * @category constraints
81
+ */
82
+ readonly step: number;
83
+ /** Separator orientation and keyboard axis.
84
+ * @remarks
85
+ * ## Why
86
+ * The value drives both `aria-orientation` and valid arrow keys.
87
+ * ## Ownership and lifetime
88
+ * Plain data acquires no resources.
89
+ * @since 1.0.0
90
+ * @category accessibility
91
+ */
92
+ readonly orientation: Orientation;
93
+ }
94
+ /** Initial splitter range and keyboard configuration.
95
+ * @remarks
96
+ * ## Why
97
+ * Defaults give the widget a complete deterministic state before rendering.
98
+ * Callers remain responsible for `min <= max` and `step > 0`.
99
+ * ## Ownership and lifetime
100
+ * Configuration is inert.
101
+ * @since 1.0.0
102
+ * @category state
103
+ */
104
+ export interface InitialState {
105
+ /** Initial pane size, clamped to min/max.
106
+ * @remarks
107
+ * ## Why
108
+ * Invalid out-of-range starts become a valid accessible value.
109
+ * ## Ownership and lifetime
110
+ * Plain data is copied into state.
111
+ * @since 1.0.0
112
+ * @category state
113
+ */
114
+ readonly value: number;
115
+ /** Minimum value, defaulting to zero.
116
+ * @remarks
117
+ * ## Why
118
+ * It defines the collapsed boundary and Home result. Callers must ensure it is
119
+ * less than or equal to `max`; neither the schema nor constructor compares them.
120
+ * ## Ownership and lifetime
121
+ * Plain data is copied into state.
122
+ * @since 1.0.0
123
+ * @category constraints
124
+ */
125
+ readonly min?: number;
126
+ /** Maximum value, defaulting to one hundred.
127
+ * @remarks
128
+ * ## Why
129
+ * It defines the upper keyboard and ARIA bound. Callers must ensure it is
130
+ * greater than or equal to `min`; neither the schema nor constructor compares them.
131
+ * ## Ownership and lifetime
132
+ * Plain data is copied into state.
133
+ * @since 1.0.0
134
+ * @category constraints
135
+ */
136
+ readonly max?: number;
137
+ /** Arrow-key increment, defaulting to ten.
138
+ * @remarks
139
+ * ## Why
140
+ * The widget needs an explicit adjustment granularity. Callers must provide a
141
+ * positive value; `Schema.Finite` rejects infinities and NaN but accepts zero
142
+ * and negative numbers.
143
+ * ## Ownership and lifetime
144
+ * Plain data is copied into state.
145
+ * @since 1.0.0
146
+ * @category constraints
147
+ */
148
+ readonly step?: number;
149
+ /** Separator orientation, defaulting to vertical.
150
+ * @remarks
151
+ * ## Why
152
+ * Orientation determines ARIA output and arrow-key mapping.
153
+ * ## Ownership and lifetime
154
+ * Plain data is copied into state.
155
+ * @since 1.0.0
156
+ * @category accessibility
157
+ */
158
+ readonly orientation?: Orientation;
159
+ }
160
+ /** Schema for the structural splitter hydration state.
161
+ * @remarks
162
+ * ## Why
163
+ * It validates finite numeric fields and the orientation union. It does not
164
+ * enforce `min <= max`, a positive `step`, or any relationship among fields;
165
+ * callers must satisfy those semantic preconditions.
166
+ * ## Ownership and lifetime
167
+ * The immutable schema acquires no resources.
168
+ * @since 1.0.0
169
+ * @category schemas
170
+ */
171
+ export declare const StateSchema: Schema.Struct<{
172
+ readonly value: Schema.Finite;
173
+ readonly previousValue: Schema.Finite;
174
+ readonly min: Schema.Finite;
175
+ readonly max: Schema.Finite;
176
+ readonly step: Schema.Finite;
177
+ readonly orientation: Schema.Literals<readonly ["horizontal", "vertical"]>;
178
+ }>;
179
+ /** Creates hydrated splitter state and clamps the initial value.
180
+ * @remarks
181
+ * ## Why
182
+ * Pane sizing behavior can be composed and tested without mounting a separator.
183
+ * Callers must supply `min <= max` and `step > 0`; the constructor defaults
184
+ * omitted bounds/step but does not validate those relationships.
185
+ * ## Ownership and lifetime
186
+ * The calling Effect Scope owns the returned RefSubject.
187
+ * @example
188
+ * ```ts
189
+ * import { Effect } from "effect"
190
+ * import * as WindowSplitter from "@typed/ui/WindowSplitter"
191
+ *
192
+ * const program = Effect.gen(function* () {
193
+ * return yield* WindowSplitter.makeState({ value: 320, min: 180, max: 640 })
194
+ * })
195
+ * ```
196
+ * @since 1.0.0
197
+ * @category constructors
198
+ */
199
+ export declare function makeState(initial: InitialState): Effect.Effect<RefSubject.HydratedRefSubject<{
200
+ readonly value: number;
201
+ readonly previousValue: number;
202
+ readonly min: number;
203
+ readonly max: number;
204
+ readonly step: number;
205
+ readonly orientation: "horizontal" | "vertical";
206
+ }, Schema.SchemaError, never, never>, never, import("effect/Scope").Scope>;
207
+ /** Sets and clamps the current splitter value.
208
+ * @remarks
209
+ * ## Why
210
+ * All callers share one transition bounded by the state's `min` and `max`.
211
+ * Correct range ordering remains a caller precondition. This operation does not
212
+ * change `previousValue`.
213
+ * ## Ownership and lifetime
214
+ * The Effect uses the existing RefSubject lifetime and acquires no resource.
215
+ * @example
216
+ * ```ts
217
+ * import { Effect } from "effect"
218
+ * import * as WindowSplitter from "@typed/ui/WindowSplitter"
219
+ *
220
+ * const program = Effect.gen(function* () {
221
+ * const state = yield* WindowSplitter.makeState({ value: 320 })
222
+ * yield* WindowSplitter.setValue(state, 400)
223
+ * })
224
+ * ```
225
+ * @since 1.0.0
226
+ * @category state
227
+ */
228
+ export declare function setValue<E, R>(state: RefSubject.RefSubject<State, E, R>, value: number): Effect.Effect<State, E, R>;
229
+ /** Adds a delta and clamps the resulting splitter value.
230
+ * @remarks
231
+ * ## Why
232
+ * Arrow-key behavior can be tested independently of DOM events. Correct range
233
+ * ordering remains a caller precondition, and this operation does not change
234
+ * `previousValue`.
235
+ * ## Ownership and lifetime
236
+ * The Effect uses the existing RefSubject lifetime and acquires no resource.
237
+ * @example
238
+ * ```ts
239
+ * import { Effect } from "effect"
240
+ * import * as WindowSplitter from "@typed/ui/WindowSplitter"
241
+ *
242
+ * const program = Effect.gen(function* () {
243
+ * const state = yield* WindowSplitter.makeState({ value: 320, step: 24 })
244
+ * yield* WindowSplitter.adjust(state, 24)
245
+ * })
246
+ * ```
247
+ * @since 1.0.0
248
+ * @category state
249
+ */
250
+ export declare function adjust<E, R>(state: RefSubject.RefSubject<State, E, R>, delta: number): Effect.Effect<State, E, R>;
251
+ /** Collapses to min or restores the recorded collapse value.
252
+ * @remarks
253
+ * ## Why
254
+ * When the current value is not `min`, the operation records that exact value in
255
+ * `previousValue` and collapses. At `min`, it restores the stored value after
256
+ * clamping it to the current range. Other updates do not maintain a history.
257
+ * ## Ownership and lifetime
258
+ * The Effect updates existing state atomically and acquires no resource.
259
+ * @example
260
+ * ```ts
261
+ * import { Effect } from "effect"
262
+ * import * as WindowSplitter from "@typed/ui/WindowSplitter"
263
+ *
264
+ * const program = Effect.gen(function* () {
265
+ * const state = yield* WindowSplitter.makeState({ value: 320 })
266
+ * yield* WindowSplitter.toggleCollapsed(state)
267
+ * })
268
+ * ```
269
+ * @since 1.0.0
270
+ * @category state
271
+ */
272
+ export declare function toggleCollapsed<E, R>(state: RefSubject.RefSubject<State, E, R>): Effect.Effect<State, E, R>;
273
+ /** Options for the focusable ARIA window splitter.
274
+ * @remarks
275
+ * ## Why
276
+ * The model connects renderer-independent sizing to its controlled pane and
277
+ * accessible range metadata. Its state must already satisfy `min <= max` and a
278
+ * positive `step`; the component does not repair invalid state.
279
+ * ## Ownership and lifetime
280
+ * Options are inert; rendering owns subscriptions/listeners by Scope.
281
+ * @since 1.0.0
282
+ * @category models
283
+ */
284
+ export interface WindowSplitterOptions extends Dom.HostOptions<HTMLDivElement> {
285
+ /** Hydrated sizing state.
286
+ * @remarks
287
+ * ## Why
288
+ * One source drives keyboard updates and every ARIA range attribute.
289
+ * ## Ownership and lifetime
290
+ * The splitter borrows state; its original Scope owns it.
291
+ * @since 1.0.0
292
+ * @category state
293
+ */
294
+ readonly state: RefSubject.HydratedRefSubject<State, Schema.SchemaError>;
295
+ /** Id of the pane controlled by the splitter.
296
+ * @remarks
297
+ * ## Why
298
+ * `aria-controls` makes the resizing relationship explicit.
299
+ * ## Ownership and lifetime
300
+ * Dynamic values follow the component Scope.
301
+ * @since 1.0.0
302
+ * @category relationships
303
+ */
304
+ readonly primaryPaneId: Renderable.Any<string | null | undefined>;
305
+ /** Accessible name when no external label is supplied.
306
+ * @remarks
307
+ * ## Why
308
+ * A focusable separator needs a discoverable purpose.
309
+ * ## Ownership and lifetime
310
+ * Dynamic values follow the component Scope.
311
+ * @since 1.0.0
312
+ * @category accessibility
313
+ */
314
+ readonly label?: Renderable.Any<string | null | undefined>;
315
+ /** Human-readable value text supplementing the number.
316
+ * @remarks
317
+ * ## Why
318
+ * Pane sizes such as percentages or labels may be clearer than raw values.
319
+ * ## Ownership and lifetime
320
+ * Dynamic values follow the component Scope.
321
+ * @since 1.0.0
322
+ * @category accessibility
323
+ */
324
+ readonly valueText?: Renderable.Any<string | null | undefined>;
325
+ /** Whether keyboard adjustments are disabled.
326
+ * @remarks
327
+ * ## Why
328
+ * ARIA disabled state and handler behavior must agree.
329
+ * ## Ownership and lifetime
330
+ * Dynamic values follow the component Scope.
331
+ * @since 1.0.0
332
+ * @category accessibility
333
+ */
334
+ readonly disabled?: Renderable.Any<boolean | null | undefined>;
335
+ }
336
+ declare function internalProps<const Options extends WindowSplitterOptions>(options: Options): ({ property }: Dom.InternalPropsHelpers<Options>) => {
337
+ readonly role: "separator";
338
+ readonly tabindex: 0;
339
+ readonly "aria-orientation": RefSubject.Computed<Orientation, Schema.SchemaError, never>;
340
+ readonly "aria-valuenow": RefSubject.Computed<number, Schema.SchemaError, never>;
341
+ readonly "aria-valuemin": RefSubject.Computed<number, Schema.SchemaError, never>;
342
+ readonly "aria-valuemax": RefSubject.Computed<number, Schema.SchemaError, never>;
343
+ readonly "aria-controls": Exclude<Dom.Property<Options, "primaryPaneId">, Dom.Nullish> | undefined;
344
+ readonly "aria-label": Exclude<Dom.Property<Options, "label">, Dom.Nullish> | undefined;
345
+ readonly "aria-valuetext": Exclude<Dom.Property<Options, "valueText">, Dom.Nullish> | undefined;
346
+ readonly "aria-disabled": false | Exclude<Dom.Property<Options, "disabled">, Dom.Nullish>;
347
+ readonly onkeydown: EventHandler.EventHandler<KeyboardEvent, Schema.SchemaError, never>;
348
+ readonly ref: RefSubject.HydratedRefSubject<State, Schema.SchemaError, never, never>;
349
+ };
350
+ type WindowSplitterInternalProps<Options extends WindowSplitterOptions> = ReturnType<ReturnType<typeof internalProps<Options>>>;
351
+ /** Renders a focusable ARIA separator for resizing a pane.
352
+ * @remarks
353
+ * ## Why
354
+ * The component exposes native DOM focus/events and the ARIA window-splitter
355
+ * range contract: arrows adjust by step, Home/End reach bounds, and Enter
356
+ * collapses/restores. Disabled state leaves key events inert.
357
+ * ## Ownership and lifetime
358
+ * Running the returned Fx owns real key listeners, reactive ARIA attributes,
359
+ * and the hydration ref in its Effect Scope. A custom host must preserve role,
360
+ * tab index, range/relationship attributes, handler, and one hydration owner.
361
+ * @example
362
+ * ```ts
363
+ * import { Effect } from "effect"
364
+ * import * as WindowSplitter from "@typed/ui/WindowSplitter"
365
+ *
366
+ * const program = Effect.gen(function* () {
367
+ * const state = yield* WindowSplitter.makeState({ value: 320, min: 180, max: 640 })
368
+ * return WindowSplitter.WindowSplitter({ state, primaryPaneId: "navigation" })
369
+ * })
370
+ * ```
371
+ * @since 1.0.0
372
+ * @category components
373
+ */
374
+ export declare function WindowSplitter<const Options extends WindowSplitterOptions, const Host extends HostResult = never>(options: Options, host?: Dom.HostOverride<Dom.RenderHostProps<Options, WindowSplitterInternalProps<Options>>, "", Host>): import("./Dom/Types.js").HostComponent<Host | Options>;
375
+ export {};
376
+ //# sourceMappingURL=WindowSplitter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WindowSplitter.d.ts","sourceRoot":"","sources":["../src/WindowSplitter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,222 @@
1
+ import * as Effect from "effect/Effect";
2
+ import * as Schema from "effect/Schema";
3
+ import { RefSubject } from "@typed/fx";
4
+ import { EventHandler, html } from "@typed/template";
5
+ import * as Dom from "./Dom.js";
6
+ /** Schema for the structural splitter hydration state.
7
+ * @remarks
8
+ * ## Why
9
+ * It validates finite numeric fields and the orientation union. It does not
10
+ * enforce `min <= max`, a positive `step`, or any relationship among fields;
11
+ * callers must satisfy those semantic preconditions.
12
+ * ## Ownership and lifetime
13
+ * The immutable schema acquires no resources.
14
+ * @since 1.0.0
15
+ * @category schemas
16
+ */
17
+ export const StateSchema = Schema.Struct({
18
+ value: Schema.Finite,
19
+ previousValue: Schema.Finite,
20
+ min: Schema.Finite,
21
+ max: Schema.Finite,
22
+ step: Schema.Finite,
23
+ orientation: Schema.Literals(["horizontal", "vertical"]),
24
+ });
25
+ /** Creates hydrated splitter state and clamps the initial value.
26
+ * @remarks
27
+ * ## Why
28
+ * Pane sizing behavior can be composed and tested without mounting a separator.
29
+ * Callers must supply `min <= max` and `step > 0`; the constructor defaults
30
+ * omitted bounds/step but does not validate those relationships.
31
+ * ## Ownership and lifetime
32
+ * The calling Effect Scope owns the returned RefSubject.
33
+ * @example
34
+ * ```ts
35
+ * import { Effect } from "effect"
36
+ * import * as WindowSplitter from "@typed/ui/WindowSplitter"
37
+ *
38
+ * const program = Effect.gen(function* () {
39
+ * return yield* WindowSplitter.makeState({ value: 320, min: 180, max: 640 })
40
+ * })
41
+ * ```
42
+ * @since 1.0.0
43
+ * @category constructors
44
+ */
45
+ export function makeState(initial) {
46
+ const min = initial.min ?? 0;
47
+ const max = initial.max ?? 100;
48
+ const value = clamp(initial.value, min, max);
49
+ return RefSubject.hydrate(StateSchema, {
50
+ value,
51
+ previousValue: value,
52
+ min,
53
+ max,
54
+ step: initial.step ?? 10,
55
+ orientation: initial.orientation ?? "vertical",
56
+ });
57
+ }
58
+ /** Sets and clamps the current splitter value.
59
+ * @remarks
60
+ * ## Why
61
+ * All callers share one transition bounded by the state's `min` and `max`.
62
+ * Correct range ordering remains a caller precondition. This operation does not
63
+ * change `previousValue`.
64
+ * ## Ownership and lifetime
65
+ * The Effect uses the existing RefSubject lifetime and acquires no resource.
66
+ * @example
67
+ * ```ts
68
+ * import { Effect } from "effect"
69
+ * import * as WindowSplitter from "@typed/ui/WindowSplitter"
70
+ *
71
+ * const program = Effect.gen(function* () {
72
+ * const state = yield* WindowSplitter.makeState({ value: 320 })
73
+ * yield* WindowSplitter.setValue(state, 400)
74
+ * })
75
+ * ```
76
+ * @since 1.0.0
77
+ * @category state
78
+ */
79
+ export function setValue(state, value) {
80
+ return RefSubject.update(state, (current) => ({
81
+ ...current,
82
+ value: clamp(value, current.min, current.max),
83
+ }));
84
+ }
85
+ /** Adds a delta and clamps the resulting splitter value.
86
+ * @remarks
87
+ * ## Why
88
+ * Arrow-key behavior can be tested independently of DOM events. Correct range
89
+ * ordering remains a caller precondition, and this operation does not change
90
+ * `previousValue`.
91
+ * ## Ownership and lifetime
92
+ * The Effect uses the existing RefSubject lifetime and acquires no resource.
93
+ * @example
94
+ * ```ts
95
+ * import { Effect } from "effect"
96
+ * import * as WindowSplitter from "@typed/ui/WindowSplitter"
97
+ *
98
+ * const program = Effect.gen(function* () {
99
+ * const state = yield* WindowSplitter.makeState({ value: 320, step: 24 })
100
+ * yield* WindowSplitter.adjust(state, 24)
101
+ * })
102
+ * ```
103
+ * @since 1.0.0
104
+ * @category state
105
+ */
106
+ export function adjust(state, delta) {
107
+ return RefSubject.update(state, (current) => ({
108
+ ...current,
109
+ value: clamp(current.value + delta, current.min, current.max),
110
+ }));
111
+ }
112
+ /** Collapses to min or restores the recorded collapse value.
113
+ * @remarks
114
+ * ## Why
115
+ * When the current value is not `min`, the operation records that exact value in
116
+ * `previousValue` and collapses. At `min`, it restores the stored value after
117
+ * clamping it to the current range. Other updates do not maintain a history.
118
+ * ## Ownership and lifetime
119
+ * The Effect updates existing state atomically and acquires no resource.
120
+ * @example
121
+ * ```ts
122
+ * import { Effect } from "effect"
123
+ * import * as WindowSplitter from "@typed/ui/WindowSplitter"
124
+ *
125
+ * const program = Effect.gen(function* () {
126
+ * const state = yield* WindowSplitter.makeState({ value: 320 })
127
+ * yield* WindowSplitter.toggleCollapsed(state)
128
+ * })
129
+ * ```
130
+ * @since 1.0.0
131
+ * @category state
132
+ */
133
+ export function toggleCollapsed(state) {
134
+ return RefSubject.update(state, (current) => current.value === current.min
135
+ ? { ...current, value: clamp(current.previousValue, current.min, current.max) }
136
+ : { ...current, previousValue: current.value, value: current.min });
137
+ }
138
+ function internalProps(options) {
139
+ const onkeydown = EventHandler.make(Effect.fn(function* (event) {
140
+ const current = yield* options.state;
141
+ if (Dom.currentTarget(event).getAttribute("aria-disabled") === "true") {
142
+ return current;
143
+ }
144
+ const delta = keyDelta(event.key, current);
145
+ if (delta !== undefined) {
146
+ event.preventDefault();
147
+ return yield* adjust(options.state, delta);
148
+ }
149
+ if (event.key === "Home") {
150
+ event.preventDefault();
151
+ return yield* setValue(options.state, current.min);
152
+ }
153
+ if (event.key === "End") {
154
+ event.preventDefault();
155
+ return yield* setValue(options.state, current.max);
156
+ }
157
+ if (event.key === "Enter") {
158
+ event.preventDefault();
159
+ return yield* toggleCollapsed(options.state);
160
+ }
161
+ return current;
162
+ }));
163
+ return ({ property }) => ({
164
+ role: "separator",
165
+ tabindex: 0,
166
+ "aria-orientation": RefSubject.map(options.state, (state) => state.orientation),
167
+ "aria-valuenow": RefSubject.map(options.state, (state) => state.value),
168
+ "aria-valuemin": RefSubject.map(options.state, (state) => state.min),
169
+ "aria-valuemax": RefSubject.map(options.state, (state) => state.max),
170
+ "aria-controls": property("primaryPaneId", undefined),
171
+ "aria-label": property("label", undefined),
172
+ "aria-valuetext": property("valueText", undefined),
173
+ "aria-disabled": property("disabled", false),
174
+ onkeydown,
175
+ ref: options.state,
176
+ });
177
+ }
178
+ /** Renders a focusable ARIA separator for resizing a pane.
179
+ * @remarks
180
+ * ## Why
181
+ * The component exposes native DOM focus/events and the ARIA window-splitter
182
+ * range contract: arrows adjust by step, Home/End reach bounds, and Enter
183
+ * collapses/restores. Disabled state leaves key events inert.
184
+ * ## Ownership and lifetime
185
+ * Running the returned Fx owns real key listeners, reactive ARIA attributes,
186
+ * and the hydration ref in its Effect Scope. A custom host must preserve role,
187
+ * tab index, range/relationship attributes, handler, and one hydration owner.
188
+ * @example
189
+ * ```ts
190
+ * import { Effect } from "effect"
191
+ * import * as WindowSplitter from "@typed/ui/WindowSplitter"
192
+ *
193
+ * const program = Effect.gen(function* () {
194
+ * const state = yield* WindowSplitter.makeState({ value: 320, min: 180, max: 640 })
195
+ * return WindowSplitter.WindowSplitter({ state, primaryPaneId: "navigation" })
196
+ * })
197
+ * ```
198
+ * @since 1.0.0
199
+ * @category components
200
+ */
201
+ export function WindowSplitter(options, host) {
202
+ return Dom.renderHost()(options, host, internalProps(options), "", (props) => {
203
+ return html `<div ...${props}></div>`;
204
+ });
205
+ }
206
+ function keyDelta(key, state) {
207
+ if (state.orientation === "vertical") {
208
+ if (key === "ArrowLeft")
209
+ return -state.step;
210
+ if (key === "ArrowRight")
211
+ return state.step;
212
+ return undefined;
213
+ }
214
+ if (key === "ArrowUp")
215
+ return -state.step;
216
+ if (key === "ArrowDown")
217
+ return state.step;
218
+ return undefined;
219
+ }
220
+ function clamp(value, min, max) {
221
+ return Math.min(Math.max(value, min), max);
222
+ }
package/dist/index.d.ts CHANGED
@@ -1,3 +1,52 @@
1
+ /**
2
+ * Typed UI: DOM-cooperative components built on Effect, Fx, Router, and Template.
3
+ *
4
+ * @remarks
5
+ * Namespace exports group related component families while direct exports expose
6
+ * the component constructor, HTTP SSR adapters, and navigation link. The DOM is
7
+ * the integration boundary: hosts receive real nodes, events, attributes, refs,
8
+ * and web-standard behavior. Running Effect Scopes own subscriptions and cleanup.
9
+ *
10
+ * @since 1.0.0
11
+ * @category ui
12
+ */
13
+ export * as Button from "./Button.js";
14
+ export * as Alert from "./Alert.js";
15
+ export * as Checkbox from "./Checkbox.js";
16
+ export * as Carousel from "./Carousel.js";
17
+ export * as Collection from "./Collection.js";
18
+ export * as Combobox from "./Combobox.js";
19
+ export * from "./Component.js";
20
+ export * as Composite from "./Composite.js";
21
+ export * as Dialog from "./Dialog.js";
22
+ export * as Disclosure from "./Disclosure.js";
23
+ export * as Dom from "./Dom.js";
24
+ export * as Focusable from "./Focusable.js";
25
+ export * as Form from "./Form.js";
26
+ export * as Group from "./Group.js";
27
+ export * as Grid from "./Grid.js";
28
+ export * as Heading from "./Heading.js";
29
+ export * as Hovercard from "./Hovercard.js";
1
30
  export * from "./HttpRouter.js";
2
31
  export * from "./Link.js";
32
+ export * as Listbox from "./Listbox.js";
33
+ export * as Menu from "./Menu.js";
34
+ export * as Menubar from "./Menubar.js";
35
+ export * as Meter from "./Meter.js";
36
+ export * as Role from "./Role.js";
37
+ export * as RadioGroup from "./RadioGroup.js";
38
+ export * as Popover from "./Popover.js";
39
+ export * as Separator from "./Separator.js";
40
+ export * as Select from "./Select.js";
41
+ export * as Slider from "./Slider.js";
42
+ export * as SpinButton from "./SpinButton.js";
43
+ export * as Switch from "./Switch.js";
44
+ export * as Tooltip from "./Tooltip.js";
45
+ export * as Toolbar from "./Toolbar.js";
46
+ export * as Tree from "./Tree.js";
47
+ export * as TreeGrid from "./TreeGrid.js";
48
+ export * as Tab from "./Tab.js";
49
+ export * as Tabs from "./Tabs.js";
50
+ export * as VisuallyHidden from "./VisuallyHidden.js";
51
+ export * as WindowSplitter from "./WindowSplitter.js";
3
52
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC;AAChC,cAAc,WAAW,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,MAAM,MAAM,aAAa,CAAC;AACtC,OAAO,KAAK,KAAK,MAAM,YAAY,CAAC;AACpC,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAC;AAC1C,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAC;AAC1C,OAAO,KAAK,UAAU,MAAM,iBAAiB,CAAC;AAC9C,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAC;AAC1C,cAAc,gBAAgB,CAAC;AAC/B,OAAO,KAAK,SAAS,MAAM,gBAAgB,CAAC;AAC5C,OAAO,KAAK,MAAM,MAAM,aAAa,CAAC;AACtC,OAAO,KAAK,UAAU,MAAM,iBAAiB,CAAC;AAC9C,OAAO,KAAK,GAAG,MAAM,UAAU,CAAC;AAChC,OAAO,KAAK,SAAS,MAAM,gBAAgB,CAAC;AAC5C,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,KAAK,KAAK,MAAM,YAAY,CAAC;AACpC,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,KAAK,OAAO,MAAM,cAAc,CAAC;AACxC,OAAO,KAAK,SAAS,MAAM,gBAAgB,CAAC;AAC5C,cAAc,iBAAiB,CAAC;AAChC,cAAc,WAAW,CAAC;AAC1B,OAAO,KAAK,OAAO,MAAM,cAAc,CAAC;AACxC,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,KAAK,OAAO,MAAM,cAAc,CAAC;AACxC,OAAO,KAAK,KAAK,MAAM,YAAY,CAAC;AACpC,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,KAAK,UAAU,MAAM,iBAAiB,CAAC;AAC9C,OAAO,KAAK,OAAO,MAAM,cAAc,CAAC;AACxC,OAAO,KAAK,SAAS,MAAM,gBAAgB,CAAC;AAC5C,OAAO,KAAK,MAAM,MAAM,aAAa,CAAC;AACtC,OAAO,KAAK,MAAM,MAAM,aAAa,CAAC;AACtC,OAAO,KAAK,UAAU,MAAM,iBAAiB,CAAC;AAC9C,OAAO,KAAK,MAAM,MAAM,aAAa,CAAC;AACtC,OAAO,KAAK,OAAO,MAAM,cAAc,CAAC;AACxC,OAAO,KAAK,OAAO,MAAM,cAAc,CAAC;AACxC,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAC;AAC1C,OAAO,KAAK,GAAG,MAAM,UAAU,CAAC;AAChC,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,KAAK,cAAc,MAAM,qBAAqB,CAAC;AACtD,OAAO,KAAK,cAAc,MAAM,qBAAqB,CAAC"}