@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,367 @@
1
+ /**
2
+ * Menubar is a persistent horizontal composite. Its root establishes DOM-order roving focus and
3
+ * typeahead; items expose menuitem semantics and invoke caller-provided activation Effects.
4
+ *
5
+ * @remarks
6
+ * The module keeps policy, state transitions, and DOM rendering separable so applications can use
7
+ * the state and pure operations without mounting UI, or supply custom hosts without replacing native
8
+ * events and browser-owned focus.
9
+ *
10
+ * @since 1.0.0
11
+ * @category modules
12
+ * @packageDocumentation
13
+ */
14
+ import * as Effect from "effect/Effect";
15
+ import type * as Scope from "effect/Scope";
16
+ import * as Schema from "effect/Schema";
17
+ import type { Fx } from "@typed/fx/Fx";
18
+ import { RefSubject } from "@typed/fx";
19
+ import { EventHandler, type Renderable, type RenderEvent, type RenderTemplate } from "@typed/template";
20
+ import * as Collection from "./Collection.js";
21
+ import * as Composite from "./Composite.js";
22
+ import * as Dom from "./Dom.js";
23
+ import type { HostResult } from "./Dom/Types.js";
24
+ /**
25
+ * Complete renderer-independent state for Menubar.
26
+ *
27
+ * @remarks
28
+ * ## Why
29
+ *
30
+ * Applications can inspect, update, and test Menubar behavior without mounting or coupling the
31
+ * state to a renderer.
32
+ *
33
+ * ## Ownership and lifetime
34
+ *
35
+ * This declaration is data or schema metadata and acquires no resources.
36
+ *
37
+ * ## Example
38
+ *
39
+ * Import with `import type { State } from "@typed/ui/Menubar";` Extend the [Menubar.makeState
40
+ * runnable setup](/reference/%40typed%2Fui%2FMenubar%23makeState). Inside the linked program,
41
+ * `const snapshot: State = yield* state` exposes the shared composite focus policy.
42
+ * @since 1.0.0
43
+ * @category models
44
+ */
45
+ export interface State extends Composite.State {
46
+ }
47
+ /**
48
+ * Initial Menubar values. Uses Composite defaults unless overridden.
49
+ *
50
+ * @remarks
51
+ * ## Why
52
+ *
53
+ * Making initialization explicit documents hydration-sensitive defaults and lets servers and
54
+ * clients construct matching state.
55
+ *
56
+ * ## Ownership and lifetime
57
+ *
58
+ * This declaration is data or schema metadata and acquires no resources.
59
+ *
60
+ * ## Example
61
+ *
62
+ * Import with `import type { InitialState } from "@typed/ui/Menubar";` Extend the
63
+ * [Menubar.makeState runnable setup](/reference/%40typed%2Fui%2FMenubar%23makeState). Construct a
64
+ * horizontal menubar with
65
+ * `const initial: InitialState = { orientation: "horizontal" }; const state = yield* Menubar.makeState(initial)`.
66
+ * @since 1.0.0
67
+ * @category models
68
+ */
69
+ export type InitialState = Composite.InitialState;
70
+ /**
71
+ * Effect Schema used by makeState to encode, decode, and hydrate Menubar state.
72
+ *
73
+ * @remarks
74
+ * ## Why
75
+ *
76
+ * A public schema makes hydration and serialized state use the same runtime validation as direct
77
+ * construction.
78
+ *
79
+ * ## Ownership and lifetime
80
+ *
81
+ * This declaration is data or schema metadata and acquires no resources.
82
+ *
83
+ * @example
84
+ * ```ts
85
+ * import * as Schema from "effect/Schema";
86
+ * import * as Menubar from "@typed/ui/Menubar";
87
+ *
88
+ * const decodeState = Schema.decodeUnknownEffect(Menubar.StateSchema);
89
+ * ```
90
+ * @since 1.0.0
91
+ * @category schemas
92
+ */
93
+ export declare const StateSchema: Schema.Struct<{
94
+ readonly activeId: Schema.NullOr<Schema.String>;
95
+ readonly orientation: Schema.Literals<readonly ["horizontal", "vertical", "both"]>;
96
+ readonly loop: Schema.Boolean;
97
+ readonly rtl: Schema.Boolean;
98
+ readonly virtualFocus: Schema.Boolean;
99
+ }>;
100
+ /**
101
+ * Creates hydrated Menubar state. Uses Composite defaults unless overridden.
102
+ *
103
+ * @remarks
104
+ * ## Why
105
+ *
106
+ * State and collection ownership can be composed and tested independently from any renderer.
107
+ *
108
+ * ## Ownership and lifetime
109
+ *
110
+ * The returned Effect creates the RefSubject when run. That state is renderer-independent;
111
+ * collection registrations belong to the separate Scope that runs register or ref, not to state
112
+ * creation.
113
+ *
114
+ * @example
115
+ * ```ts
116
+ * import * as Effect from "effect/Effect";
117
+ * import * as Menubar from "@typed/ui/Menubar";
118
+ *
119
+ * const program = Effect.scoped(
120
+ * Effect.gen(function* () {
121
+ * const state = yield* Menubar.makeState({});
122
+ * const collection = yield* Menubar.makeCollection();
123
+ * return { state: yield* state, collection: yield* collection };
124
+ * }),
125
+ * );
126
+ * ```
127
+ * @since 1.0.0
128
+ * @category constructors
129
+ */
130
+ export declare function makeState(initial?: InitialState): Effect.Effect<RefSubject.HydratedRefSubject<{
131
+ readonly activeId: string | null;
132
+ readonly orientation: "both" | "horizontal" | "vertical";
133
+ readonly loop: boolean;
134
+ readonly rtl: boolean;
135
+ readonly virtualFocus: boolean;
136
+ }, Schema.SchemaError, never, never>, never, Scope.Scope>;
137
+ /**
138
+ * Creates a scoped Collection for Menubar items.
139
+ *
140
+ * @remarks
141
+ * ## Why
142
+ *
143
+ * State and collection ownership can be composed and tested independently from any renderer.
144
+ *
145
+ * ## Ownership and lifetime
146
+ *
147
+ * The returned Effect allocates the RefSubject in the caller's Scope. Each later registration is
148
+ * owned by the Scope that runs register, independently of this construction Effect.
149
+ *
150
+ * @example
151
+ * ```ts
152
+ * import * as Effect from "effect/Effect";
153
+ * import * as Menubar from "@typed/ui/Menubar";
154
+ *
155
+ * const program = Effect.scoped(
156
+ * Effect.gen(function* () {
157
+ * const collection = yield* Menubar.makeCollection();
158
+ * return yield* collection;
159
+ * }),
160
+ * );
161
+ * ```
162
+ * @since 1.0.0
163
+ * @category constructors
164
+ */
165
+ export declare const makeCollection: (initial?: Collection.State<string, Element>) => Effect.Effect<RefSubject.RefSubject<Collection.State<string, Element>, never, never>, never, Scope.Scope>;
166
+ /**
167
+ * Inputs accepted by Menubar.Root in addition to the shared DOM host options.
168
+ *
169
+ * @remarks
170
+ * ## Why
171
+ *
172
+ * The options type makes required state, content, accessible relationships, and custom-host inputs
173
+ * visible before rendering.
174
+ *
175
+ * ## Ownership and lifetime
176
+ *
177
+ * This declaration is data or schema metadata and acquires no resources.
178
+ *
179
+ * ## Example
180
+ *
181
+ * Import with `import type { RootOptions } from "@typed/ui/Menubar";` Extend the [Menubar.makeState
182
+ * runnable setup](/reference/%40typed%2Fui%2FMenubar%23makeState). Enable top-level menu movement
183
+ * with `const options: RootOptions = { state, collection, label: "Application", content: "Menus" }`.
184
+ * @since 1.0.0
185
+ * @category models
186
+ */
187
+ export interface RootOptions extends Dom.HostOptions<HTMLDivElement> {
188
+ /**
189
+ * Renderer-independent RefSubject state consumed by this component or operation.
190
+ * @since 1.0.0
191
+ * @category models
192
+ */
193
+ readonly state: RefSubject.HydratedRefSubject<State, Schema.SchemaError>;
194
+ /**
195
+ * Item registry used for collection-driven keyboard behavior and mounted ordering.
196
+ * @since 1.0.0
197
+ * @category models
198
+ */
199
+ readonly collection?: RefSubject.RefSubject<Collection.State<string>>;
200
+ /**
201
+ * Renderable child content for the component host.
202
+ * @since 1.0.0
203
+ * @category models
204
+ */
205
+ readonly content: Renderable.Any;
206
+ /**
207
+ * Accessible label rendered through aria-label.
208
+ * @since 1.0.0
209
+ * @category models
210
+ */
211
+ readonly label?: Renderable.Any<string | null | undefined>;
212
+ }
213
+ declare function rootProps<const Options extends RootOptions>(options: Options): ({ property }: Dom.InternalPropsHelpers<Options>) => {
214
+ readonly role: "menubar";
215
+ readonly "aria-label": Exclude<Dom.Property<Options, "label">, Dom.Nullish> | undefined;
216
+ readonly "aria-orientation": RefSubject.Computed<Composite.Orientation, Schema.SchemaError, never>;
217
+ readonly tabindex: RefSubject.Computed<-1 | 0, Schema.SchemaError, never>;
218
+ readonly onfocus: Effect.Effect<void, Schema.SchemaError, never> | undefined;
219
+ readonly onkeydown: EventHandler.EventHandler<KeyboardEvent, Schema.SchemaError, never> | undefined;
220
+ readonly ref: RefSubject.HydratedRefSubject<State, Schema.SchemaError, never, never>;
221
+ };
222
+ type RootProps<Options extends RootOptions> = ReturnType<ReturnType<typeof rootProps<Options>>>;
223
+ /**
224
+ * Renders the persistent menubar root with roving focus, orientation-aware keys, and typeahead.
225
+ *
226
+ * @remarks
227
+ * ## Why
228
+ *
229
+ * The component applies the family behavior while leaving callers free to supply a custom host
230
+ * through the shared DOM boundary.
231
+ *
232
+ * ## Ownership and lifetime
233
+ *
234
+ * The returned Fx installs DOM refs, native listeners, state subscriptions, and optional
235
+ * collection registrations only when rendered. The rendering Scope removes those resources;
236
+ * unrelated nodes and attributes remain caller-owned.
237
+ *
238
+ * ## Example
239
+ *
240
+ * Import with `import { Root } from "@typed/ui/Menubar";` Extend the [Menubar.makeState runnable
241
+ * setup](/reference/%40typed%2Fui%2FMenubar%23makeState). Replace the linked program's final
242
+ * snapshot read with `Root({ state, label: "Application", content: "Menus" })`; render that Fx
243
+ * before the same Scope closes.
244
+ * @since 1.0.0
245
+ * @category components
246
+ */
247
+ export declare function Root<const Options extends RootOptions, const Host extends HostResult = never>(options: Options, host?: Dom.HostOverride<Dom.RenderHostProps<Options, RootProps<Options>>, Options["content"], Host>): Fx<RenderEvent, Renderable.Error<Options | Host>, Renderable.Services<Options | Host> | Scope.Scope | RenderTemplate>;
248
+ /**
249
+ * Consumer-facing alias of the canonical Menubar component with identical behavior and lifetime.
250
+ *
251
+ * @remarks
252
+ * ## Why
253
+ *
254
+ * The component applies the family behavior while leaving callers free to supply a custom host
255
+ * through the shared DOM boundary.
256
+ *
257
+ * ## Ownership and lifetime
258
+ *
259
+ * The alias acquires nothing. Rendering it has exactly the canonical component's Scope and DOM
260
+ * ownership contract.
261
+ *
262
+ * ## Example
263
+ *
264
+ * Import with `import { Menubar } from "@typed/ui/Menubar";` Extend the [Menubar.makeState runnable
265
+ * setup](/reference/%40typed%2Fui%2FMenubar%23makeState). Replace the linked program's final
266
+ * snapshot read with `Menubar({ state, label: "Application", content: "Menus" })`; render that Fx
267
+ * before the same Scope closes.
268
+ * @since 1.0.0
269
+ * @category components
270
+ */
271
+ export declare const Menubar: typeof Root;
272
+ /**
273
+ * Inputs accepted by Menubar.Item in addition to the shared DOM host options.
274
+ *
275
+ * @remarks
276
+ * ## Why
277
+ *
278
+ * The options type makes required state, content, accessible relationships, and custom-host inputs
279
+ * visible before rendering.
280
+ *
281
+ * ## Ownership and lifetime
282
+ *
283
+ * This declaration is data or schema metadata and acquires no resources.
284
+ *
285
+ * ## Example
286
+ *
287
+ * Import with `import type { ItemOptions } from "@typed/ui/Menubar";` Extend the [Menubar.makeState
288
+ * runnable setup](/reference/%40typed%2Fui%2FMenubar%23makeState). A top-level menu item is
289
+ * `const options: ItemOptions = { state, collection, id: "file", content: "File" }`.
290
+ * @since 1.0.0
291
+ * @category models
292
+ */
293
+ export interface ItemOptions extends Dom.HostOptions<HTMLDivElement> {
294
+ /**
295
+ * Renderer-independent RefSubject state consumed by this component or operation.
296
+ * @since 1.0.0
297
+ * @category models
298
+ */
299
+ readonly state: RefSubject.HydratedRefSubject<State, Schema.SchemaError>;
300
+ /**
301
+ * Item registry used for collection-driven keyboard behavior and mounted ordering.
302
+ * @since 1.0.0
303
+ * @category models
304
+ */
305
+ readonly collection?: RefSubject.RefSubject<Collection.State<string>>;
306
+ /**
307
+ * Stable id used for collection identity and ARIA relationships.
308
+ * @since 1.0.0
309
+ * @category models
310
+ */
311
+ readonly id: string;
312
+ /**
313
+ * Renderable child content for the component host.
314
+ * @since 1.0.0
315
+ * @category models
316
+ */
317
+ readonly content: Renderable.Any;
318
+ /**
319
+ * Search text used by typeahead independently of rendered markup.
320
+ * @since 1.0.0
321
+ * @category models
322
+ */
323
+ readonly textValue?: string;
324
+ /**
325
+ * Flag used by collection movement and widget handlers to skip activation by default.
326
+ * @since 1.0.0
327
+ * @category models
328
+ */
329
+ readonly disabled?: boolean;
330
+ }
331
+ declare function itemProps<const Options extends ItemOptions>(options: Options): () => {
332
+ readonly id: string;
333
+ readonly role: "menuitem";
334
+ readonly "aria-disabled": boolean;
335
+ readonly tabindex: RefSubject.Computed<-1 | 0, Schema.SchemaError, never>;
336
+ readonly onfocus: Effect.Effect<State, Schema.SchemaError, never>;
337
+ readonly onclick: Effect.Effect<void, never, never> | Effect.Effect<State, Schema.SchemaError, never>;
338
+ readonly ref: ((element: Element & HTMLDivElement & RefSubject.HydrationElement) => Effect.Effect<void, any, any>) | undefined;
339
+ };
340
+ type ItemProps<Options extends ItemOptions> = ReturnType<ReturnType<typeof itemProps<Options>>>;
341
+ /**
342
+ * Renders a registered menuitem and runs onActivate for native focus or click unless disabled.
343
+ *
344
+ * @remarks
345
+ * ## Why
346
+ *
347
+ * The component applies the family behavior while leaving callers free to supply a custom host
348
+ * through the shared DOM boundary.
349
+ *
350
+ * ## Ownership and lifetime
351
+ *
352
+ * The returned Fx installs DOM refs, native listeners, state subscriptions, and optional
353
+ * collection registrations only when rendered. The rendering Scope removes those resources;
354
+ * unrelated nodes and attributes remain caller-owned.
355
+ *
356
+ * ## Example
357
+ *
358
+ * Import with `import { Item } from "@typed/ui/Menubar";` Extend the [Menubar.makeState runnable
359
+ * setup](/reference/%40typed%2Fui%2FMenubar%23makeState). Replace the linked program's final
360
+ * snapshot read with `Item({ state, id: "file", content: "File" })`; render that Fx before the same
361
+ * Scope closes.
362
+ * @since 1.0.0
363
+ * @category components
364
+ */
365
+ export declare function Item<const Options extends ItemOptions, const Host extends HostResult = never>(options: Options, host?: Dom.HostOverride<Dom.RenderHostProps<Options, ItemProps<Options>>, Options["content"], Host>): Fx<RenderEvent, Renderable.Error<Options | Host>, Renderable.Services<Options | Host> | Scope.Scope | RenderTemplate>;
366
+ export {};
367
+ //# sourceMappingURL=Menubar.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Menubar.d.ts","sourceRoot":"","sources":["../src/Menubar.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,265 @@
1
+ /**
2
+ * Menubar is a persistent horizontal composite. Its root establishes DOM-order roving focus and
3
+ * typeahead; items expose menuitem semantics and invoke caller-provided activation Effects.
4
+ *
5
+ * @remarks
6
+ * The module keeps policy, state transitions, and DOM rendering separable so applications can use
7
+ * the state and pure operations without mounting UI, or supply custom hosts without replacing native
8
+ * events and browser-owned focus.
9
+ *
10
+ * @since 1.0.0
11
+ * @category modules
12
+ * @packageDocumentation
13
+ */
14
+ import * as Effect from "effect/Effect";
15
+ import { RefSubject } from "@typed/fx";
16
+ import { EventHandler, html, } from "@typed/template";
17
+ import * as Collection from "./Collection.js";
18
+ import * as Composite from "./Composite.js";
19
+ import * as Dom from "./Dom.js";
20
+ /**
21
+ * Effect Schema used by makeState to encode, decode, and hydrate Menubar state.
22
+ *
23
+ * @remarks
24
+ * ## Why
25
+ *
26
+ * A public schema makes hydration and serialized state use the same runtime validation as direct
27
+ * construction.
28
+ *
29
+ * ## Ownership and lifetime
30
+ *
31
+ * This declaration is data or schema metadata and acquires no resources.
32
+ *
33
+ * @example
34
+ * ```ts
35
+ * import * as Schema from "effect/Schema";
36
+ * import * as Menubar from "@typed/ui/Menubar";
37
+ *
38
+ * const decodeState = Schema.decodeUnknownEffect(Menubar.StateSchema);
39
+ * ```
40
+ * @since 1.0.0
41
+ * @category schemas
42
+ */
43
+ export const StateSchema = Composite.StateSchema;
44
+ /**
45
+ * Creates hydrated Menubar state. Uses Composite defaults unless overridden.
46
+ *
47
+ * @remarks
48
+ * ## Why
49
+ *
50
+ * State and collection ownership can be composed and tested independently from any renderer.
51
+ *
52
+ * ## Ownership and lifetime
53
+ *
54
+ * The returned Effect creates the RefSubject when run. That state is renderer-independent;
55
+ * collection registrations belong to the separate Scope that runs register or ref, not to state
56
+ * creation.
57
+ *
58
+ * @example
59
+ * ```ts
60
+ * import * as Effect from "effect/Effect";
61
+ * import * as Menubar from "@typed/ui/Menubar";
62
+ *
63
+ * const program = Effect.scoped(
64
+ * Effect.gen(function* () {
65
+ * const state = yield* Menubar.makeState({});
66
+ * const collection = yield* Menubar.makeCollection();
67
+ * return { state: yield* state, collection: yield* collection };
68
+ * }),
69
+ * );
70
+ * ```
71
+ * @since 1.0.0
72
+ * @category constructors
73
+ */
74
+ export function makeState(initial = {}) {
75
+ return Composite.makeState({ ...initial, orientation: initial.orientation ?? "horizontal" });
76
+ }
77
+ /**
78
+ * Creates a scoped Collection for Menubar items.
79
+ *
80
+ * @remarks
81
+ * ## Why
82
+ *
83
+ * State and collection ownership can be composed and tested independently from any renderer.
84
+ *
85
+ * ## Ownership and lifetime
86
+ *
87
+ * The returned Effect allocates the RefSubject in the caller's Scope. Each later registration is
88
+ * owned by the Scope that runs register, independently of this construction Effect.
89
+ *
90
+ * @example
91
+ * ```ts
92
+ * import * as Effect from "effect/Effect";
93
+ * import * as Menubar from "@typed/ui/Menubar";
94
+ *
95
+ * const program = Effect.scoped(
96
+ * Effect.gen(function* () {
97
+ * const collection = yield* Menubar.makeCollection();
98
+ * return yield* collection;
99
+ * }),
100
+ * );
101
+ * ```
102
+ * @since 1.0.0
103
+ * @category constructors
104
+ */
105
+ export const makeCollection = Collection.makeState;
106
+ function rootProps(options) {
107
+ let typeahead = { value: "", updatedAt: 0 };
108
+ const onfocus = options.collection === undefined
109
+ ? undefined
110
+ : Effect.gen(function* () {
111
+ if ((yield* options.state).activeId !== null)
112
+ return;
113
+ yield* Composite.moveAndFocus({
114
+ state: options.state,
115
+ collection: options.collection,
116
+ includeDisabled: true,
117
+ }, "first");
118
+ });
119
+ const onkeydown = options.collection === undefined
120
+ ? undefined
121
+ : EventHandler.make(Effect.fn(function* (event) {
122
+ if (event.key === "ArrowDown" || event.key === "Enter" || event.key === " ") {
123
+ const activeId = (yield* options.state).activeId;
124
+ const item = activeId === null
125
+ ? undefined
126
+ : (yield* options.collection).find((item) => item.id === activeId);
127
+ const shouldActivate = event.key !== "ArrowDown" || item?.submenu === true;
128
+ const element = shouldActivate && item?.disabled !== true ? item?.element : undefined;
129
+ const click = element === undefined ? undefined : Reflect.get(element, "click");
130
+ if (typeof click === "function") {
131
+ event.preventDefault();
132
+ yield* Effect.sync(() => click.call(element));
133
+ return;
134
+ }
135
+ }
136
+ const direction = Composite.keyMove(event, yield* options.state);
137
+ if (direction !== undefined) {
138
+ event.preventDefault();
139
+ yield* Composite.moveAndFocus({ state: options.state, collection: options.collection, includeDisabled: true }, direction);
140
+ return;
141
+ }
142
+ const key = Composite.typeaheadKey(event);
143
+ if (key === null)
144
+ return;
145
+ typeahead = Composite.updateTypeaheadBuffer(typeahead, key, Date.now());
146
+ const activeId = Composite.typeaheadFrom(yield* options.collection, typeahead.value, (yield* options.state).activeId, undefined, true);
147
+ if (activeId === null)
148
+ return;
149
+ event.preventDefault();
150
+ yield* RefSubject.update(options.state, (state) => ({ ...state, activeId }));
151
+ yield* Composite.focusActive({ state: options.state, collection: options.collection });
152
+ }));
153
+ return ({ property }) => ({
154
+ role: "menubar",
155
+ "aria-label": property("label", undefined),
156
+ "aria-orientation": RefSubject.map(options.state, (state) => state.orientation),
157
+ tabindex: Composite.rootTabIndex(options.state),
158
+ onfocus,
159
+ onkeydown,
160
+ ref: options.state,
161
+ });
162
+ }
163
+ /**
164
+ * Renders the persistent menubar root with roving focus, orientation-aware keys, and typeahead.
165
+ *
166
+ * @remarks
167
+ * ## Why
168
+ *
169
+ * The component applies the family behavior while leaving callers free to supply a custom host
170
+ * through the shared DOM boundary.
171
+ *
172
+ * ## Ownership and lifetime
173
+ *
174
+ * The returned Fx installs DOM refs, native listeners, state subscriptions, and optional
175
+ * collection registrations only when rendered. The rendering Scope removes those resources;
176
+ * unrelated nodes and attributes remain caller-owned.
177
+ *
178
+ * ## Example
179
+ *
180
+ * Import with `import { Root } from "@typed/ui/Menubar";` Extend the [Menubar.makeState runnable
181
+ * setup](/reference/%40typed%2Fui%2FMenubar%23makeState). Replace the linked program's final
182
+ * snapshot read with `Root({ state, label: "Application", content: "Menus" })`; render that Fx
183
+ * before the same Scope closes.
184
+ * @since 1.0.0
185
+ * @category components
186
+ */
187
+ export function Root(options, host) {
188
+ return Dom.renderHost()(options, host, rootProps(options), options.content, (props, content) => {
189
+ return html `<div ...${props}>${content}</div>`;
190
+ });
191
+ }
192
+ /**
193
+ * Consumer-facing alias of the canonical Menubar component with identical behavior and lifetime.
194
+ *
195
+ * @remarks
196
+ * ## Why
197
+ *
198
+ * The component applies the family behavior while leaving callers free to supply a custom host
199
+ * through the shared DOM boundary.
200
+ *
201
+ * ## Ownership and lifetime
202
+ *
203
+ * The alias acquires nothing. Rendering it has exactly the canonical component's Scope and DOM
204
+ * ownership contract.
205
+ *
206
+ * ## Example
207
+ *
208
+ * Import with `import { Menubar } from "@typed/ui/Menubar";` Extend the [Menubar.makeState runnable
209
+ * setup](/reference/%40typed%2Fui%2FMenubar%23makeState). Replace the linked program's final
210
+ * snapshot read with `Menubar({ state, label: "Application", content: "Menus" })`; render that Fx
211
+ * before the same Scope closes.
212
+ * @since 1.0.0
213
+ * @category components
214
+ */
215
+ export const Menubar = Root;
216
+ function itemProps(options) {
217
+ const activate = options.disabled === true
218
+ ? Effect.void
219
+ : RefSubject.update(options.state, (state) => ({ ...state, activeId: options.id }));
220
+ const focus = RefSubject.update(options.state, (state) => ({ ...state, activeId: options.id }));
221
+ const register = options.collection === undefined
222
+ ? undefined
223
+ : Collection.ref(options.collection, {
224
+ id: options.id,
225
+ value: options.id,
226
+ textValue: options.textValue ?? options.id,
227
+ disabled: options.disabled,
228
+ });
229
+ return () => ({
230
+ id: options.id,
231
+ role: "menuitem",
232
+ "aria-disabled": options.disabled ?? false,
233
+ tabindex: Composite.tabIndex(options.state, options.id),
234
+ onfocus: focus,
235
+ onclick: activate,
236
+ ref: Dom.composeRefs(register, options.ref),
237
+ });
238
+ }
239
+ /**
240
+ * Renders a registered menuitem and runs onActivate for native focus or click unless disabled.
241
+ *
242
+ * @remarks
243
+ * ## Why
244
+ *
245
+ * The component applies the family behavior while leaving callers free to supply a custom host
246
+ * through the shared DOM boundary.
247
+ *
248
+ * ## Ownership and lifetime
249
+ *
250
+ * The returned Fx installs DOM refs, native listeners, state subscriptions, and optional
251
+ * collection registrations only when rendered. The rendering Scope removes those resources;
252
+ * unrelated nodes and attributes remain caller-owned.
253
+ *
254
+ * ## Example
255
+ *
256
+ * Import with `import { Item } from "@typed/ui/Menubar";` Extend the [Menubar.makeState runnable
257
+ * setup](/reference/%40typed%2Fui%2FMenubar%23makeState). Replace the linked program's final
258
+ * snapshot read with `Item({ state, id: "file", content: "File" })`; render that Fx before the same
259
+ * Scope closes.
260
+ * @since 1.0.0
261
+ * @category components
262
+ */
263
+ export function Item(options, host) {
264
+ return Dom.renderHost()(options, host, itemProps(options), options.content, (props, content) => html `<div ...${props}>${content}</div>`);
265
+ }