@typed/ui 1.0.0-beta.6 → 1.0.0-beta.7

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 (128) hide show
  1. package/dist/Alert.d.ts +35 -41
  2. package/dist/Alert.d.ts.map +1 -1
  3. package/dist/Alert.js +23 -20
  4. package/dist/Button.d.ts +34 -78
  5. package/dist/Button.d.ts.map +1 -1
  6. package/dist/Button.js +16 -12
  7. package/dist/Carousel.d.ts +35 -236
  8. package/dist/Carousel.d.ts.map +1 -1
  9. package/dist/Carousel.js +13 -136
  10. package/dist/Checkbox.d.ts +55 -90
  11. package/dist/Checkbox.d.ts.map +1 -1
  12. package/dist/Checkbox.js +44 -38
  13. package/dist/Collection.d.ts +15 -15
  14. package/dist/Collection.js +7 -7
  15. package/dist/Combobox.d.ts +38 -187
  16. package/dist/Combobox.d.ts.map +1 -1
  17. package/dist/Combobox.js +9 -80
  18. package/dist/Component.d.ts +30 -24
  19. package/dist/Component.d.ts.map +1 -1
  20. package/dist/Component.js +23 -12
  21. package/dist/Composite.d.ts +50 -50
  22. package/dist/Composite.js +20 -20
  23. package/dist/Dialog.d.ts +34 -34
  24. package/dist/Dialog.d.ts.map +1 -1
  25. package/dist/Dialog.js +16 -14
  26. package/dist/Disclosure.d.ts +15 -15
  27. package/dist/Disclosure.js +6 -6
  28. package/dist/Dom/Events.d.ts +4 -4
  29. package/dist/Dom/Events.js +4 -4
  30. package/dist/Dom/Props.d.ts +9 -9
  31. package/dist/Dom/Props.js +4 -4
  32. package/dist/Dom/Refs.d.ts +2 -2
  33. package/dist/Dom/Refs.js +1 -1
  34. package/dist/Dom/Render.d.ts +2 -2
  35. package/dist/Dom/Render.js +2 -2
  36. package/dist/Dom/Types.d.ts +33 -33
  37. package/dist/Dom/index.d.ts +5 -5
  38. package/dist/Dom/index.d.ts.map +1 -1
  39. package/dist/Dom/index.js +4 -4
  40. package/dist/Dom.d.ts +1 -1
  41. package/dist/Dom.js +1 -1
  42. package/dist/Focusable.d.ts +5 -5
  43. package/dist/Focusable.js +1 -1
  44. package/dist/Form.d.ts +565 -533
  45. package/dist/Form.d.ts.map +1 -1
  46. package/dist/Form.js +350 -195
  47. package/dist/Grid.d.ts +39 -220
  48. package/dist/Grid.d.ts.map +1 -1
  49. package/dist/Grid.js +12 -107
  50. package/dist/Group.d.ts +50 -69
  51. package/dist/Group.d.ts.map +1 -1
  52. package/dist/Group.js +33 -25
  53. package/dist/Heading.d.ts +41 -40
  54. package/dist/Heading.d.ts.map +1 -1
  55. package/dist/Heading.js +26 -16
  56. package/dist/Hovercard.d.ts +18 -18
  57. package/dist/Hovercard.js +6 -6
  58. package/dist/HttpRouter.d.ts +3 -3
  59. package/dist/HttpRouter.js +5 -5
  60. package/dist/Link.d.ts +17 -21
  61. package/dist/Link.d.ts.map +1 -1
  62. package/dist/Link.js +11 -0
  63. package/dist/Listbox.d.ts +31 -163
  64. package/dist/Listbox.d.ts.map +1 -1
  65. package/dist/Listbox.js +9 -80
  66. package/dist/Menu.d.ts +67 -376
  67. package/dist/Menu.d.ts.map +1 -1
  68. package/dist/Menu.js +17 -179
  69. package/dist/Menubar.d.ts +24 -142
  70. package/dist/Menubar.d.ts.map +1 -1
  71. package/dist/Menubar.js +8 -66
  72. package/dist/Meter.d.ts +72 -132
  73. package/dist/Meter.d.ts.map +1 -1
  74. package/dist/Meter.js +35 -42
  75. package/dist/NativeDetails.d.ts +1 -1
  76. package/dist/NativeDetails.js +1 -1
  77. package/dist/NativeDialog.d.ts +7 -5
  78. package/dist/NativeDialog.d.ts.map +1 -1
  79. package/dist/NativeDialog.js +42 -4
  80. package/dist/NativePopover.d.ts +6 -4
  81. package/dist/NativePopover.d.ts.map +1 -1
  82. package/dist/NativePopover.js +43 -5
  83. package/dist/Popover.d.ts +18 -19
  84. package/dist/Popover.d.ts.map +1 -1
  85. package/dist/Popover.js +7 -8
  86. package/dist/RadioGroup.d.ts +86 -188
  87. package/dist/RadioGroup.d.ts.map +1 -1
  88. package/dist/RadioGroup.js +55 -105
  89. package/dist/Role.d.ts +4 -4
  90. package/dist/Role.js +1 -1
  91. package/dist/Select.d.ts +109 -220
  92. package/dist/Select.d.ts.map +1 -1
  93. package/dist/Select.js +67 -117
  94. package/dist/Separator.d.ts +30 -26
  95. package/dist/Separator.d.ts.map +1 -1
  96. package/dist/Separator.js +16 -10
  97. package/dist/Slider.d.ts +64 -111
  98. package/dist/Slider.d.ts.map +1 -1
  99. package/dist/Slider.js +47 -42
  100. package/dist/SpinButton.d.ts +64 -111
  101. package/dist/SpinButton.d.ts.map +1 -1
  102. package/dist/SpinButton.js +47 -42
  103. package/dist/Storybook.d.ts +2 -2
  104. package/dist/Storybook.js +1 -1
  105. package/dist/Switch.d.ts +52 -91
  106. package/dist/Switch.d.ts.map +1 -1
  107. package/dist/Switch.js +30 -36
  108. package/dist/Tabs.d.ts +44 -224
  109. package/dist/Tabs.d.ts.map +1 -1
  110. package/dist/Tabs.js +10 -94
  111. package/dist/Toolbar.d.ts +24 -142
  112. package/dist/Toolbar.d.ts.map +1 -1
  113. package/dist/Toolbar.js +8 -66
  114. package/dist/Tooltip.d.ts +20 -20
  115. package/dist/Tooltip.js +6 -6
  116. package/dist/Tree.d.ts +43 -229
  117. package/dist/Tree.d.ts.map +1 -1
  118. package/dist/Tree.js +12 -113
  119. package/dist/TreeGrid.d.ts +45 -264
  120. package/dist/TreeGrid.d.ts.map +1 -1
  121. package/dist/TreeGrid.js +13 -125
  122. package/dist/VisuallyHidden.d.ts +41 -27
  123. package/dist/VisuallyHidden.d.ts.map +1 -1
  124. package/dist/VisuallyHidden.js +27 -10
  125. package/dist/WindowSplitter.d.ts +68 -108
  126. package/dist/WindowSplitter.d.ts.map +1 -1
  127. package/dist/WindowSplitter.js +106 -23
  128. package/package.json +9 -8
@@ -1,172 +1,130 @@
1
1
  import * as Effect from "effect/Effect";
2
+ import * as Scope from "effect/Scope";
2
3
  import * as Schema from "effect/Schema";
3
- import { RefSubject } from "@typed/fx";
4
+ import { Fx, RefSubject } from "@typed/fx";
4
5
  import { EventHandler, type Renderable } from "@typed/template";
5
6
  import * as Dom from "./Dom.js";
7
+ import type { ComposedRef } from "./Dom/Refs.js";
6
8
  import type { HostResult } from "./Dom/Types.js";
7
9
  /** Visual orientation of the separator between panes.
8
10
  * @remarks
9
- * ## Why
10
11
  * A vertical separator adjusts with Left/Right; a horizontal separator adjusts
11
12
  * with Up/Down, matching the axis perpendicular to the dividing line.
12
- * ## Ownership and lifetime
13
- * This pure type acquires no resources.
14
13
  * @since 1.0.0
15
- * @category models
14
+ * @category Resize axis
16
15
  */
17
16
  export type Orientation = "horizontal" | "vertical";
18
17
  /** Current value and keyboard policy for a window splitter.
19
18
  * @remarks
20
- * ## Why
21
19
  * All range and collapse information remains renderer-independent and directly
22
20
  * testable.
23
- * ## Ownership and lifetime
24
21
  * Plain state retains no resources; its hydrated RefSubject is Scope-owned.
25
22
  * @since 1.0.0
26
- * @category state
23
+ * @category Pane sizing state
27
24
  */
28
25
  export interface State {
29
26
  /** Current pane size value.
30
27
  * @remarks
31
- * ## Why
32
28
  * It drives `aria-valuenow` and keyboard adjustments.
33
- * ## Ownership and lifetime
34
- * Plain numeric data acquires no resources.
35
29
  * @since 1.0.0
36
- * @category state
30
+ * @category Current value
37
31
  */
38
32
  readonly value: number;
39
33
  /** Restore value used by `toggleCollapsed`.
40
34
  * @remarks
41
- * ## Why
42
35
  * It starts at the initial clamped value. `toggleCollapsed` overwrites it only
43
36
  * when collapsing from a non-minimum value, then reads it when restoring.
44
37
  * Ordinary `setValue` and `adjust` calls do not update it.
45
- * ## Ownership and lifetime
46
- * Plain numeric data acquires no resources.
47
38
  * @since 1.0.0
48
- * @category state
39
+ * @category Collapse and restore
49
40
  */
50
41
  readonly previousValue: number;
51
42
  /** Inclusive minimum pane value.
52
43
  * @remarks
53
- * ## Why
54
44
  * Updates clamp to this bound and Home jumps to it.
55
- * ## Ownership and lifetime
56
- * Plain numeric data acquires no resources.
57
45
  * @since 1.0.0
58
- * @category constraints
46
+ * @category Range constraints
59
47
  */
60
48
  readonly min: number;
61
49
  /** Inclusive maximum pane value.
62
50
  * @remarks
63
- * ## Why
64
51
  * Updates clamp to this bound and End jumps to it.
65
- * ## Ownership and lifetime
66
- * Plain numeric data acquires no resources.
67
52
  * @since 1.0.0
68
- * @category constraints
53
+ * @category Range constraints
69
54
  */
70
55
  readonly max: number;
71
56
  /** Keyboard adjustment increment.
72
57
  * @remarks
73
- * ## Why
74
58
  * Arrow keys require a deterministic application-defined change size. The
75
59
  * state constructor does not enforce positivity; callers must provide a
76
60
  * positive value for conventional keyboard direction.
77
- * ## Ownership and lifetime
78
- * Plain numeric data acquires no resources.
79
61
  * @since 1.0.0
80
- * @category constraints
62
+ * @category Keyboard adjustment
81
63
  */
82
64
  readonly step: number;
83
65
  /** Separator orientation and keyboard axis.
84
66
  * @remarks
85
- * ## Why
86
67
  * The value drives both `aria-orientation` and valid arrow keys.
87
- * ## Ownership and lifetime
88
- * Plain data acquires no resources.
89
68
  * @since 1.0.0
90
- * @category accessibility
69
+ * @category Keyboard navigation
91
70
  */
92
71
  readonly orientation: Orientation;
93
72
  }
94
73
  /** Initial splitter range and keyboard configuration.
95
74
  * @remarks
96
- * ## Why
97
75
  * Defaults give the widget a complete deterministic state before rendering.
98
76
  * Callers remain responsible for `min <= max` and `step > 0`.
99
- * ## Ownership and lifetime
100
- * Configuration is inert.
101
77
  * @since 1.0.0
102
- * @category state
78
+ * @category Pane sizing state
103
79
  */
104
80
  export interface InitialState {
105
81
  /** Initial pane size, clamped to min/max.
106
82
  * @remarks
107
- * ## Why
108
83
  * Invalid out-of-range starts become a valid accessible value.
109
- * ## Ownership and lifetime
110
- * Plain data is copied into state.
111
84
  * @since 1.0.0
112
- * @category state
85
+ * @category Current value
113
86
  */
114
87
  readonly value: number;
115
88
  /** Minimum value, defaulting to zero.
116
89
  * @remarks
117
- * ## Why
118
90
  * It defines the collapsed boundary and Home result. Callers must ensure it is
119
91
  * 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
92
  * @since 1.0.0
123
- * @category constraints
93
+ * @category Range constraints
124
94
  */
125
95
  readonly min?: number;
126
96
  /** Maximum value, defaulting to one hundred.
127
97
  * @remarks
128
- * ## Why
129
98
  * It defines the upper keyboard and ARIA bound. Callers must ensure it is
130
99
  * 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
100
  * @since 1.0.0
134
- * @category constraints
101
+ * @category Range constraints
135
102
  */
136
103
  readonly max?: number;
137
104
  /** Arrow-key increment, defaulting to ten.
138
105
  * @remarks
139
- * ## Why
140
106
  * The widget needs an explicit adjustment granularity. Callers must provide a
141
107
  * positive value; `Schema.Finite` rejects infinities and NaN but accepts zero
142
108
  * and negative numbers.
143
- * ## Ownership and lifetime
144
- * Plain data is copied into state.
145
109
  * @since 1.0.0
146
- * @category constraints
110
+ * @category Keyboard adjustment
147
111
  */
148
112
  readonly step?: number;
149
113
  /** Separator orientation, defaulting to vertical.
150
114
  * @remarks
151
- * ## Why
152
115
  * Orientation determines ARIA output and arrow-key mapping.
153
- * ## Ownership and lifetime
154
- * Plain data is copied into state.
155
116
  * @since 1.0.0
156
- * @category accessibility
117
+ * @category Keyboard navigation
157
118
  */
158
119
  readonly orientation?: Orientation;
159
120
  }
160
121
  /** Schema for the structural splitter hydration state.
161
122
  * @remarks
162
- * ## Why
163
123
  * It validates finite numeric fields and the orientation union. It does not
164
124
  * enforce `min <= max`, a positive `step`, or any relationship among fields;
165
125
  * callers must satisfy those semantic preconditions.
166
- * ## Ownership and lifetime
167
- * The immutable schema acquires no resources.
168
126
  * @since 1.0.0
169
- * @category schemas
127
+ * @category Pane sizing state
170
128
  */
171
129
  export declare const StateSchema: Schema.Struct<{
172
130
  readonly value: Schema.Finite;
@@ -178,11 +136,9 @@ export declare const StateSchema: Schema.Struct<{
178
136
  }>;
179
137
  /** Creates hydrated splitter state and clamps the initial value.
180
138
  * @remarks
181
- * ## Why
182
139
  * Pane sizing behavior can be composed and tested without mounting a separator.
183
140
  * Callers must supply `min <= max` and `step > 0`; the constructor defaults
184
141
  * omitted bounds/step but does not validate those relationships.
185
- * ## Ownership and lifetime
186
142
  * The calling Effect Scope owns the returned RefSubject.
187
143
  * @example
188
144
  * ```ts
@@ -194,7 +150,7 @@ export declare const StateSchema: Schema.Struct<{
194
150
  * })
195
151
  * ```
196
152
  * @since 1.0.0
197
- * @category constructors
153
+ * @category Pane sizing state
198
154
  */
199
155
  export declare function makeState(initial: InitialState): Effect.Effect<RefSubject.HydratedRefSubject<{
200
156
  readonly value: number;
@@ -203,14 +159,12 @@ export declare function makeState(initial: InitialState): Effect.Effect<RefSubje
203
159
  readonly max: number;
204
160
  readonly step: number;
205
161
  readonly orientation: "horizontal" | "vertical";
206
- }, Schema.SchemaError, never, never>, never, import("effect/Scope").Scope>;
162
+ }, Schema.SchemaError, never, never>, never, Scope.Scope>;
207
163
  /** Sets and clamps the current splitter value.
208
164
  * @remarks
209
- * ## Why
210
165
  * All callers share one transition bounded by the state's `min` and `max`.
211
166
  * Correct range ordering remains a caller precondition. This operation does not
212
167
  * change `previousValue`.
213
- * ## Ownership and lifetime
214
168
  * The Effect uses the existing RefSubject lifetime and acquires no resource.
215
169
  * @example
216
170
  * ```ts
@@ -223,16 +177,14 @@ export declare function makeState(initial: InitialState): Effect.Effect<RefSubje
223
177
  * })
224
178
  * ```
225
179
  * @since 1.0.0
226
- * @category state
180
+ * @category Bounded resizing
227
181
  */
228
182
  export declare function setValue<E, R>(state: RefSubject.RefSubject<State, E, R>, value: number): Effect.Effect<State, E, R>;
229
183
  /** Adds a delta and clamps the resulting splitter value.
230
184
  * @remarks
231
- * ## Why
232
185
  * Arrow-key behavior can be tested independently of DOM events. Correct range
233
186
  * ordering remains a caller precondition, and this operation does not change
234
187
  * `previousValue`.
235
- * ## Ownership and lifetime
236
188
  * The Effect uses the existing RefSubject lifetime and acquires no resource.
237
189
  * @example
238
190
  * ```ts
@@ -245,16 +197,14 @@ export declare function setValue<E, R>(state: RefSubject.RefSubject<State, E, R>
245
197
  * })
246
198
  * ```
247
199
  * @since 1.0.0
248
- * @category state
200
+ * @category Bounded resizing
249
201
  */
250
202
  export declare function adjust<E, R>(state: RefSubject.RefSubject<State, E, R>, delta: number): Effect.Effect<State, E, R>;
251
203
  /** Collapses to min or restores the recorded collapse value.
252
204
  * @remarks
253
- * ## Why
254
205
  * When the current value is not `min`, the operation records that exact value in
255
206
  * `previousValue` and collapses. At `min`, it restores the stored value after
256
207
  * clamping it to the current range. Other updates do not maintain a history.
257
- * ## Ownership and lifetime
258
208
  * The Effect updates existing state atomically and acquires no resource.
259
209
  * @example
260
210
  * ```ts
@@ -267,94 +217,104 @@ export declare function adjust<E, R>(state: RefSubject.RefSubject<State, E, R>,
267
217
  * })
268
218
  * ```
269
219
  * @since 1.0.0
270
- * @category state
220
+ * @category Collapse and restore
271
221
  */
272
222
  export declare function toggleCollapsed<E, R>(state: RefSubject.RefSubject<State, E, R>): Effect.Effect<State, E, R>;
273
223
  /** Options for the focusable ARIA window splitter.
274
224
  * @remarks
275
- * ## Why
276
225
  * The model connects renderer-independent sizing to its controlled pane and
277
226
  * accessible range metadata. Its state must already satisfy `min <= max` and a
278
227
  * positive `step`; the component does not repair invalid state.
279
- * ## Ownership and lifetime
280
228
  * Options are inert; rendering owns subscriptions/listeners by Scope.
281
229
  * @since 1.0.0
282
- * @category models
230
+ * @category Resize separator
283
231
  */
284
232
  export interface WindowSplitterOptions extends Dom.HostOptions<HTMLDivElement> {
285
233
  /** Hydrated sizing state.
286
234
  * @remarks
287
- * ## Why
288
235
  * One source drives keyboard updates and every ARIA range attribute.
289
- * ## Ownership and lifetime
290
236
  * The splitter borrows state; its original Scope owns it.
291
237
  * @since 1.0.0
292
- * @category state
238
+ * @category State connection
293
239
  */
294
240
  readonly state: RefSubject.HydratedRefSubject<State, Schema.SchemaError>;
295
241
  /** Id of the pane controlled by the splitter.
296
242
  * @remarks
297
- * ## Why
298
243
  * `aria-controls` makes the resizing relationship explicit.
299
- * ## Ownership and lifetime
300
244
  * Dynamic values follow the component Scope.
301
245
  * @since 1.0.0
302
- * @category relationships
246
+ * @category Identity and relationships
303
247
  */
304
248
  readonly primaryPaneId: Renderable.Any<string | null | undefined>;
305
249
  /** Accessible name when no external label is supplied.
306
250
  * @remarks
307
- * ## Why
308
251
  * A focusable separator needs a discoverable purpose.
309
- * ## Ownership and lifetime
310
252
  * Dynamic values follow the component Scope.
311
253
  * @since 1.0.0
312
- * @category accessibility
254
+ * @category Accessible naming
313
255
  */
314
256
  readonly label?: Renderable.Any<string | null | undefined>;
315
257
  /** Human-readable value text supplementing the number.
316
258
  * @remarks
317
- * ## Why
318
259
  * Pane sizes such as percentages or labels may be clearer than raw values.
319
- * ## Ownership and lifetime
320
260
  * Dynamic values follow the component Scope.
321
261
  * @since 1.0.0
322
- * @category accessibility
262
+ * @category Accessible value text
323
263
  */
324
264
  readonly valueText?: Renderable.Any<string | null | undefined>;
325
- /** Whether keyboard adjustments are disabled.
265
+ /** State-value units represented by one CSS pixel of pointer movement.
266
+ * @remarks
267
+ * By default, the usable parent width (vertical separator) or height
268
+ * (horizontal separator), minus the separator thickness, represents 100
269
+ * units. This matches percentage pane sizes. Set `1` for CSS-pixel values.
270
+ * Positive axis-aligned CSS scaling is accounted for; pointer coordinates
271
+ * are converted from viewport pixels to the parent's CSS-pixel scale.
272
+ * Supply a positive finite number when using another unit system.
273
+ * Keyboard step and min/max remain independent of pointer resolution.
274
+ * @since 1.0.0
275
+ * @category Pointer resizing
276
+ */
277
+ readonly valuePerPixel?: number;
278
+ /** Whether keyboard and pointer adjustments are disabled.
326
279
  * @remarks
327
- * ## Why
328
280
  * ARIA disabled state and handler behavior must agree.
329
- * ## Ownership and lifetime
330
281
  * Dynamic values follow the component Scope.
331
282
  * @since 1.0.0
332
- * @category accessibility
283
+ * @category Availability
333
284
  */
334
285
  readonly disabled?: Renderable.Any<boolean | null | undefined>;
335
286
  }
336
- declare function internalProps<const Options extends WindowSplitterOptions>(options: Options): ({ property }: Dom.InternalPropsHelpers<Options>) => {
287
+ type WindowSplitterInternalProps<Options extends WindowSplitterOptions> = {
337
288
  readonly role: "separator";
289
+ readonly style: Fx.Fx<string | Partial<CSSStyleDeclaration>, Renderable.Error<Options>, Renderable.Services<Options>>;
338
290
  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>;
291
+ readonly "aria-orientation": RefSubject.Computed<Orientation, Schema.SchemaError>;
292
+ readonly "aria-valuenow": RefSubject.Computed<number, Schema.SchemaError>;
293
+ readonly "aria-valuemin": RefSubject.Computed<number, Schema.SchemaError>;
294
+ readonly "aria-valuemax": RefSubject.Computed<number, Schema.SchemaError>;
295
+ readonly "aria-controls": Dom.NonNullish<Dom.Property<Options, "primaryPaneId">> | undefined;
296
+ readonly "aria-label": Dom.NonNullish<Dom.Property<Options, "label">> | undefined;
297
+ readonly "aria-valuetext": Dom.NonNullish<Dom.Property<Options, "valueText">> | undefined;
298
+ readonly "aria-disabled": Dom.NonNullish<Dom.Property<Options, "disabled">> | false;
299
+ readonly onkeydown: EventHandler.EventHandler<KeyboardEvent, Schema.SchemaError>;
300
+ readonly onpointerdown: EventHandler.EventHandler<PointerEvent>;
301
+ readonly onpointermove: EventHandler.EventHandler<PointerEvent, Schema.SchemaError>;
302
+ readonly onpointerup: EventHandler.EventHandler<PointerEvent>;
303
+ readonly onpointercancel: EventHandler.EventHandler<PointerEvent>;
304
+ readonly onlostpointercapture: EventHandler.EventHandler<PointerEvent>;
305
+ readonly ref: ComposedRef<RefSubject.HydratedRefSubject<State, Schema.SchemaError>, (element: HTMLDivElement) => Effect.Effect<void, never, Scope.Scope>> | undefined;
349
306
  };
350
- type WindowSplitterInternalProps<Options extends WindowSplitterOptions> = ReturnType<ReturnType<typeof internalProps<Options>>>;
351
307
  /** Renders a focusable ARIA separator for resizing a pane.
352
308
  * @remarks
353
- * ## Why
354
309
  * The component exposes native DOM focus/events and the ARIA window-splitter
355
310
  * 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
311
+ * collapses/restores. Pointer dragging adjusts the same clamped state, using
312
+ * percentage-of-parent movement by default or the supplied `valuePerPixel`.
313
+ * Native pointer capture keeps movement attached outside the separator;
314
+ * release, cancellation, lost capture, and Scope teardown end the drag.
315
+ * The host composes caller styles with `touch-action: none` so touch gestures
316
+ * remain resize interactions. The caller binds state to actual pane layout. Disabled state
317
+ * leaves keyboard and pointer activation inert.
358
318
  * Running the returned Fx owns real key listeners, reactive ARIA attributes,
359
319
  * and the hydration ref in its Effect Scope. A custom host must preserve role,
360
320
  * tab index, range/relationship attributes, handler, and one hydration owner.
@@ -369,7 +329,7 @@ type WindowSplitterInternalProps<Options extends WindowSplitterOptions> = Return
369
329
  * })
370
330
  * ```
371
331
  * @since 1.0.0
372
- * @category components
332
+ * @category Resize separator
373
333
  */
374
334
  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
335
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"WindowSplitter.d.ts","sourceRoot":"","sources":["../src/WindowSplitter.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"WindowSplitter.d.ts","sourceRoot":"","sources":["../src/WindowSplitter.ts"],"names":[],"mappings":"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"}
@@ -1,18 +1,16 @@
1
1
  import * as Effect from "effect/Effect";
2
+ import * as Scope from "effect/Scope";
2
3
  import * as Schema from "effect/Schema";
3
- import { RefSubject } from "@typed/fx";
4
- import { EventHandler, html } from "@typed/template";
4
+ import { Fx, RefSubject } from "@typed/fx";
5
+ import { EventHandler, html, liftRenderableToFx } from "@typed/template";
5
6
  import * as Dom from "./Dom.js";
6
7
  /** Schema for the structural splitter hydration state.
7
8
  * @remarks
8
- * ## Why
9
9
  * It validates finite numeric fields and the orientation union. It does not
10
10
  * enforce `min <= max`, a positive `step`, or any relationship among fields;
11
11
  * callers must satisfy those semantic preconditions.
12
- * ## Ownership and lifetime
13
- * The immutable schema acquires no resources.
14
12
  * @since 1.0.0
15
- * @category schemas
13
+ * @category Pane sizing state
16
14
  */
17
15
  export const StateSchema = Schema.Struct({
18
16
  value: Schema.Finite,
@@ -24,11 +22,9 @@ export const StateSchema = Schema.Struct({
24
22
  });
25
23
  /** Creates hydrated splitter state and clamps the initial value.
26
24
  * @remarks
27
- * ## Why
28
25
  * Pane sizing behavior can be composed and tested without mounting a separator.
29
26
  * Callers must supply `min <= max` and `step > 0`; the constructor defaults
30
27
  * omitted bounds/step but does not validate those relationships.
31
- * ## Ownership and lifetime
32
28
  * The calling Effect Scope owns the returned RefSubject.
33
29
  * @example
34
30
  * ```ts
@@ -40,7 +36,7 @@ export const StateSchema = Schema.Struct({
40
36
  * })
41
37
  * ```
42
38
  * @since 1.0.0
43
- * @category constructors
39
+ * @category Pane sizing state
44
40
  */
45
41
  export function makeState(initial) {
46
42
  const min = initial.min ?? 0;
@@ -57,11 +53,9 @@ export function makeState(initial) {
57
53
  }
58
54
  /** Sets and clamps the current splitter value.
59
55
  * @remarks
60
- * ## Why
61
56
  * All callers share one transition bounded by the state's `min` and `max`.
62
57
  * Correct range ordering remains a caller precondition. This operation does not
63
58
  * change `previousValue`.
64
- * ## Ownership and lifetime
65
59
  * The Effect uses the existing RefSubject lifetime and acquires no resource.
66
60
  * @example
67
61
  * ```ts
@@ -74,7 +68,7 @@ export function makeState(initial) {
74
68
  * })
75
69
  * ```
76
70
  * @since 1.0.0
77
- * @category state
71
+ * @category Bounded resizing
78
72
  */
79
73
  export function setValue(state, value) {
80
74
  return RefSubject.update(state, (current) => ({
@@ -84,11 +78,9 @@ export function setValue(state, value) {
84
78
  }
85
79
  /** Adds a delta and clamps the resulting splitter value.
86
80
  * @remarks
87
- * ## Why
88
81
  * Arrow-key behavior can be tested independently of DOM events. Correct range
89
82
  * ordering remains a caller precondition, and this operation does not change
90
83
  * `previousValue`.
91
- * ## Ownership and lifetime
92
84
  * The Effect uses the existing RefSubject lifetime and acquires no resource.
93
85
  * @example
94
86
  * ```ts
@@ -101,7 +93,7 @@ export function setValue(state, value) {
101
93
  * })
102
94
  * ```
103
95
  * @since 1.0.0
104
- * @category state
96
+ * @category Bounded resizing
105
97
  */
106
98
  export function adjust(state, delta) {
107
99
  return RefSubject.update(state, (current) => ({
@@ -111,11 +103,9 @@ export function adjust(state, delta) {
111
103
  }
112
104
  /** Collapses to min or restores the recorded collapse value.
113
105
  * @remarks
114
- * ## Why
115
106
  * When the current value is not `min`, the operation records that exact value in
116
107
  * `previousValue` and collapses. At `min`, it restores the stored value after
117
108
  * clamping it to the current range. Other updates do not maintain a history.
118
- * ## Ownership and lifetime
119
109
  * The Effect updates existing state atomically and acquires no resource.
120
110
  * @example
121
111
  * ```ts
@@ -128,7 +118,7 @@ export function adjust(state, delta) {
128
118
  * })
129
119
  * ```
130
120
  * @since 1.0.0
131
- * @category state
121
+ * @category Collapse and restore
132
122
  */
133
123
  export function toggleCollapsed(state) {
134
124
  return RefSubject.update(state, (current) => current.value === current.min
@@ -136,6 +126,89 @@ export function toggleCollapsed(state) {
136
126
  : { ...current, previousValue: current.value, value: current.min });
137
127
  }
138
128
  function internalProps(options) {
129
+ const drags = new WeakMap();
130
+ const release = (element) => {
131
+ const drag = drags.get(element);
132
+ drags.delete(element);
133
+ if (drag !== undefined && element.hasPointerCapture(drag.pointerId)) {
134
+ element.releasePointerCapture(drag.pointerId);
135
+ }
136
+ };
137
+ const pointerRef = Effect.fn(function* (element) {
138
+ yield* Scope.addFinalizer(yield* Effect.scope, Effect.sync(() => {
139
+ release(element);
140
+ }));
141
+ });
142
+ const pointerStyle = liftRenderableToFx(options.props?.style).pipe(Fx.map((style) => {
143
+ if (typeof style === "string")
144
+ return `${style};touch-action:none;`;
145
+ if (typeof style?.cssText === "string")
146
+ return `${style.cssText};touch-action:none;`;
147
+ return { ...style, touchAction: "none" };
148
+ }));
149
+ const onpointerdown = EventHandler.make((event) => Effect.sync(() => {
150
+ const element = Dom.currentTarget(event);
151
+ if (event.button !== 0 || !event.isPrimary || element.getAttribute("aria-disabled") === "true")
152
+ return;
153
+ if (drags.has(element))
154
+ return;
155
+ // The visible ARIA snapshot starts the native gesture without yielding to
156
+ // state acquisition before preventDefault and pointer capture.
157
+ const valueAttribute = element.getAttribute("aria-valuenow");
158
+ const value = Number(valueAttribute);
159
+ const orientation = element.getAttribute("aria-orientation");
160
+ if (valueAttribute === null || !Number.isFinite(value))
161
+ return;
162
+ const parent = element.parentElement;
163
+ if (parent === null)
164
+ return;
165
+ const vertical = orientation === "vertical";
166
+ const parentRect = parent.getBoundingClientRect();
167
+ const separatorRect = element.getBoundingClientRect();
168
+ // Pointer coordinates and DOMRects use viewport pixels. Convert the
169
+ // parent's client extent to that same unit, excluding its border/scrollbar.
170
+ const axisScale = vertical
171
+ ? parentRect.width / parent.offsetWidth
172
+ : parentRect.height / parent.offsetHeight;
173
+ if (!Number.isFinite(axisScale) || axisScale <= 0)
174
+ return;
175
+ const extent = vertical
176
+ ? parent.clientWidth * axisScale - separatorRect.width
177
+ : parent.clientHeight * axisScale - separatorRect.height;
178
+ const scale = options.valuePerPixel === undefined
179
+ ? 100 / extent
180
+ : options.valuePerPixel / axisScale;
181
+ if (!Number.isFinite(scale) || scale <= 0)
182
+ return;
183
+ event.preventDefault();
184
+ element.focus();
185
+ element.setPointerCapture(event.pointerId);
186
+ drags.set(element, {
187
+ pointerId: event.pointerId,
188
+ coordinate: vertical ? event.clientX : event.clientY,
189
+ value,
190
+ orientation: vertical ? "vertical" : "horizontal",
191
+ scale,
192
+ });
193
+ }));
194
+ const onpointermove = EventHandler.make(Effect.fn(function* (event) {
195
+ const element = Dom.currentTarget(event);
196
+ const drag = drags.get(element);
197
+ if (drag === undefined || drag.pointerId !== event.pointerId)
198
+ return;
199
+ if (element.getAttribute("aria-disabled") === "true" || (event.buttons & 1) === 0) {
200
+ release(element);
201
+ return;
202
+ }
203
+ event.preventDefault();
204
+ const coordinate = drag.orientation === "vertical" ? event.clientX : event.clientY;
205
+ yield* setValue(options.state, drag.value + (coordinate - drag.coordinate) * drag.scale);
206
+ }));
207
+ const endDrag = EventHandler.make((event) => Effect.sync(() => {
208
+ const element = Dom.currentTarget(event);
209
+ if (drags.get(element)?.pointerId === event.pointerId)
210
+ release(element);
211
+ }));
139
212
  const onkeydown = EventHandler.make(Effect.fn(function* (event) {
140
213
  const current = yield* options.state;
141
214
  if (Dom.currentTarget(event).getAttribute("aria-disabled") === "true") {
@@ -162,6 +235,7 @@ function internalProps(options) {
162
235
  }));
163
236
  return ({ property }) => ({
164
237
  role: "separator",
238
+ style: pointerStyle,
165
239
  tabindex: 0,
166
240
  "aria-orientation": RefSubject.map(options.state, (state) => state.orientation),
167
241
  "aria-valuenow": RefSubject.map(options.state, (state) => state.value),
@@ -172,16 +246,25 @@ function internalProps(options) {
172
246
  "aria-valuetext": property("valueText", undefined),
173
247
  "aria-disabled": property("disabled", false),
174
248
  onkeydown,
175
- ref: options.state,
249
+ onpointerdown,
250
+ onpointermove,
251
+ onpointerup: endDrag,
252
+ onpointercancel: endDrag,
253
+ onlostpointercapture: endDrag,
254
+ ref: Dom.composeRefs(options.state, pointerRef),
176
255
  });
177
256
  }
178
257
  /** Renders a focusable ARIA separator for resizing a pane.
179
258
  * @remarks
180
- * ## Why
181
259
  * The component exposes native DOM focus/events and the ARIA window-splitter
182
260
  * 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
261
+ * collapses/restores. Pointer dragging adjusts the same clamped state, using
262
+ * percentage-of-parent movement by default or the supplied `valuePerPixel`.
263
+ * Native pointer capture keeps movement attached outside the separator;
264
+ * release, cancellation, lost capture, and Scope teardown end the drag.
265
+ * The host composes caller styles with `touch-action: none` so touch gestures
266
+ * remain resize interactions. The caller binds state to actual pane layout. Disabled state
267
+ * leaves keyboard and pointer activation inert.
185
268
  * Running the returned Fx owns real key listeners, reactive ARIA attributes,
186
269
  * and the hydration ref in its Effect Scope. A custom host must preserve role,
187
270
  * tab index, range/relationship attributes, handler, and one hydration owner.
@@ -196,7 +279,7 @@ function internalProps(options) {
196
279
  * })
197
280
  * ```
198
281
  * @since 1.0.0
199
- * @category components
282
+ * @category Resize separator
200
283
  */
201
284
  export function WindowSplitter(options, host) {
202
285
  return Dom.renderHost()(options, host, internalProps(options), "", (props) => {