@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.
- package/README.md +53 -9
- package/dist/Alert.d.ts +78 -0
- package/dist/Alert.d.ts.map +1 -0
- package/dist/Alert.js +37 -0
- package/dist/Button.d.ts +144 -0
- package/dist/Button.d.ts.map +1 -0
- package/dist/Button.js +38 -0
- package/dist/Carousel.d.ts +547 -0
- package/dist/Carousel.d.ts.map +1 -0
- package/dist/Carousel.js +387 -0
- package/dist/Checkbox.d.ts +203 -0
- package/dist/Checkbox.d.ts.map +1 -0
- package/dist/Checkbox.js +140 -0
- package/dist/Collection.d.ts +254 -0
- package/dist/Collection.d.ts.map +1 -0
- package/dist/Collection.js +218 -0
- package/dist/Combobox.d.ts +516 -0
- package/dist/Combobox.d.ts.map +1 -0
- package/dist/Combobox.js +371 -0
- package/dist/Component.d.ts +127 -0
- package/dist/Component.d.ts.map +1 -0
- package/dist/Component.js +60 -0
- package/dist/Composite.d.ts +823 -0
- package/dist/Composite.d.ts.map +1 -0
- package/dist/Composite.js +615 -0
- package/dist/Dialog.d.ts +544 -0
- package/dist/Dialog.d.ts.map +1 -0
- package/dist/Dialog.js +355 -0
- package/dist/Disclosure.d.ts +219 -0
- package/dist/Disclosure.d.ts.map +1 -0
- package/dist/Disclosure.js +128 -0
- package/dist/Dom/Events.d.ts +122 -0
- package/dist/Dom/Events.d.ts.map +1 -0
- package/dist/Dom/Events.js +192 -0
- package/dist/Dom/Props.d.ts +161 -0
- package/dist/Dom/Props.d.ts.map +1 -0
- package/dist/Dom/Props.js +110 -0
- package/dist/Dom/Refs.d.ts +58 -0
- package/dist/Dom/Refs.d.ts.map +1 -0
- package/dist/Dom/Refs.js +61 -0
- package/dist/Dom/Render.d.ts +59 -0
- package/dist/Dom/Render.d.ts.map +1 -0
- package/dist/Dom/Render.js +71 -0
- package/dist/Dom/Types.d.ts +570 -0
- package/dist/Dom/Types.d.ts.map +1 -0
- package/dist/Dom/Types.js +1 -0
- package/dist/Dom/index.d.ts +20 -0
- package/dist/Dom/index.d.ts.map +1 -0
- package/dist/Dom/index.js +8 -0
- package/dist/Dom.d.ts +14 -0
- package/dist/Dom.d.ts.map +1 -0
- package/dist/Dom.js +13 -0
- package/dist/Focusable.d.ts +85 -0
- package/dist/Focusable.d.ts.map +1 -0
- package/dist/Focusable.js +35 -0
- package/dist/Form.d.ts +1695 -0
- package/dist/Form.d.ts.map +1 -0
- package/dist/Form.js +987 -0
- package/dist/Grid.d.ts +569 -0
- package/dist/Grid.d.ts.map +1 -0
- package/dist/Grid.js +379 -0
- package/dist/Group.d.ts +147 -0
- package/dist/Group.d.ts.map +1 -0
- package/dist/Group.js +63 -0
- package/dist/Heading.d.ts +86 -0
- package/dist/Heading.d.ts.map +1 -0
- package/dist/Heading.js +48 -0
- package/dist/Hovercard.d.ts +297 -0
- package/dist/Hovercard.d.ts.map +1 -0
- package/dist/Hovercard.js +188 -0
- package/dist/HttpRouter.d.ts +129 -6
- package/dist/HttpRouter.d.ts.map +1 -1
- package/dist/HttpRouter.js +196 -53
- package/dist/Link.d.ts +67 -28
- package/dist/Link.d.ts.map +1 -1
- package/dist/Link.js +91 -37
- package/dist/Listbox.d.ts +437 -0
- package/dist/Listbox.d.ts.map +1 -0
- package/dist/Listbox.js +316 -0
- package/dist/Menu.d.ts +972 -0
- package/dist/Menu.d.ts.map +1 -0
- package/dist/Menu.js +731 -0
- package/dist/Menubar.d.ts +367 -0
- package/dist/Menubar.d.ts.map +1 -0
- package/dist/Menubar.js +265 -0
- package/dist/Meter.d.ts +217 -0
- package/dist/Meter.d.ts.map +1 -0
- package/dist/Meter.js +94 -0
- package/dist/NativeDetails.d.ts +41 -0
- package/dist/NativeDetails.d.ts.map +1 -0
- package/dist/NativeDetails.js +40 -0
- package/dist/NativeDialog.d.ts +64 -0
- package/dist/NativeDialog.d.ts.map +1 -0
- package/dist/NativeDialog.js +50 -0
- package/dist/NativePopover.d.ts +41 -0
- package/dist/NativePopover.d.ts.map +1 -0
- package/dist/NativePopover.js +46 -0
- package/dist/Popover.d.ts +241 -0
- package/dist/Popover.d.ts.map +1 -0
- package/dist/Popover.js +141 -0
- package/dist/RadioGroup.d.ts +432 -0
- package/dist/RadioGroup.d.ts.map +1 -0
- package/dist/RadioGroup.js +291 -0
- package/dist/Role.d.ts +64 -0
- package/dist/Role.d.ts.map +1 -0
- package/dist/Role.js +27 -0
- package/dist/Select.d.ts +529 -0
- package/dist/Select.d.ts.map +1 -0
- package/dist/Select.js +407 -0
- package/dist/Separator.d.ts +54 -0
- package/dist/Separator.d.ts.map +1 -0
- package/dist/Separator.js +26 -0
- package/dist/Slider.d.ts +188 -0
- package/dist/Slider.d.ts.map +1 -0
- package/dist/Slider.js +96 -0
- package/dist/SpinButton.d.ts +188 -0
- package/dist/SpinButton.d.ts.map +1 -0
- package/dist/SpinButton.js +96 -0
- package/dist/Storybook.d.ts +76 -0
- package/dist/Storybook.d.ts.map +1 -0
- package/dist/Storybook.js +102 -0
- package/dist/Switch.d.ts +187 -0
- package/dist/Switch.d.ts.map +1 -0
- package/dist/Switch.js +116 -0
- package/dist/Tab.d.ts +26 -0
- package/dist/Tab.d.ts.map +1 -0
- package/dist/Tab.js +25 -0
- package/dist/Tabs.d.ts +591 -0
- package/dist/Tabs.d.ts.map +1 -0
- package/dist/Tabs.js +346 -0
- package/dist/Toolbar.d.ts +366 -0
- package/dist/Toolbar.d.ts.map +1 -0
- package/dist/Toolbar.js +245 -0
- package/dist/Tooltip.d.ts +296 -0
- package/dist/Tooltip.d.ts.map +1 -0
- package/dist/Tooltip.js +172 -0
- package/dist/Tree.d.ts +591 -0
- package/dist/Tree.d.ts.map +1 -0
- package/dist/Tree.js +434 -0
- package/dist/TreeGrid.d.ts +645 -0
- package/dist/TreeGrid.d.ts.map +1 -0
- package/dist/TreeGrid.js +420 -0
- package/dist/VisuallyHidden.d.ts +54 -0
- package/dist/VisuallyHidden.d.ts.map +1 -0
- package/dist/VisuallyHidden.js +27 -0
- package/dist/WindowSplitter.d.ts +376 -0
- package/dist/WindowSplitter.d.ts.map +1 -0
- package/dist/WindowSplitter.js +222 -0
- package/dist/index.d.ts +49 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +49 -0
- package/package.json +45 -18
- package/src/HttpRouter.test.ts +0 -256
- package/src/HttpRouter.ts +0 -165
- package/src/Link.test.ts +0 -84
- package/src/Link.ts +0 -107
- package/src/index.ts +0 -2
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
import * as Effect from "effect/Effect";
|
|
2
|
+
import type * as Scope from "effect/Scope";
|
|
3
|
+
import * as Schema from "effect/Schema";
|
|
4
|
+
import type { Fx } from "@typed/fx/Fx";
|
|
5
|
+
import { RefSubject } from "@typed/fx";
|
|
6
|
+
import { EventHandler, type Renderable, type RenderEvent, type RenderTemplate } from "@typed/template";
|
|
7
|
+
import * as Dom from "./Dom.js";
|
|
8
|
+
import type { HostResult } from "./Dom/Types.js";
|
|
9
|
+
/** Current renderer-independent popover visibility.
|
|
10
|
+
* @remarks
|
|
11
|
+
* ## Why
|
|
12
|
+
* Open state can be controlled and tested without rendering the top layer.
|
|
13
|
+
* ## Ownership and lifetime
|
|
14
|
+
* Plain data retains no resources; RefSubject lifetime is Scope-owned.
|
|
15
|
+
* @since 1.0.0
|
|
16
|
+
* @category state
|
|
17
|
+
*/
|
|
18
|
+
export interface State {
|
|
19
|
+
/** Whether native popover content should be open.
|
|
20
|
+
* @remarks
|
|
21
|
+
* ## Why
|
|
22
|
+
* The value coordinates trigger ARIA state and native Popover API state.
|
|
23
|
+
* ## Ownership and lifetime
|
|
24
|
+
* Plain state acquires no resources.
|
|
25
|
+
* @since 1.0.0
|
|
26
|
+
* @category state
|
|
27
|
+
*/
|
|
28
|
+
readonly open: boolean;
|
|
29
|
+
}
|
|
30
|
+
/** Optional initial popover visibility.
|
|
31
|
+
* @remarks
|
|
32
|
+
* ## Why
|
|
33
|
+
* A false default gives SSR and hydration a deterministic closed snapshot.
|
|
34
|
+
* ## Ownership and lifetime
|
|
35
|
+
* Configuration is inert.
|
|
36
|
+
* @since 1.0.0
|
|
37
|
+
* @category state
|
|
38
|
+
*/
|
|
39
|
+
export interface InitialState {
|
|
40
|
+
/** Initial open state, defaulting to false.
|
|
41
|
+
* @remarks
|
|
42
|
+
* ## Why
|
|
43
|
+
* The value seeds the serializable hydration contract.
|
|
44
|
+
* ## Ownership and lifetime
|
|
45
|
+
* Plain data retains no resources.
|
|
46
|
+
* @since 1.0.0
|
|
47
|
+
* @category state
|
|
48
|
+
*/
|
|
49
|
+
readonly open?: boolean;
|
|
50
|
+
}
|
|
51
|
+
/** Schema for serialized popover state.
|
|
52
|
+
* @remarks
|
|
53
|
+
* ## Why
|
|
54
|
+
* A shared boolean shape keeps server and browser hydration compatible.
|
|
55
|
+
* ## Ownership and lifetime
|
|
56
|
+
* The immutable schema acquires no resources.
|
|
57
|
+
* @since 1.0.0
|
|
58
|
+
* @category schemas
|
|
59
|
+
*/
|
|
60
|
+
export declare const StateSchema: Schema.Struct<{
|
|
61
|
+
readonly open: Schema.Boolean;
|
|
62
|
+
}>;
|
|
63
|
+
/** Creates hydrated popover state.
|
|
64
|
+
* @remarks
|
|
65
|
+
* ## Why
|
|
66
|
+
* Applications can own and test visibility independently of a component.
|
|
67
|
+
* ## Ownership and lifetime
|
|
68
|
+
* The calling Effect Scope owns the returned RefSubject.
|
|
69
|
+
* @example
|
|
70
|
+
* ```ts
|
|
71
|
+
* import { Effect } from "effect"
|
|
72
|
+
* import * as Popover from "@typed/ui/Popover"
|
|
73
|
+
*
|
|
74
|
+
* const program = Effect.gen(function* () {
|
|
75
|
+
* return yield* Popover.makeState()
|
|
76
|
+
* })
|
|
77
|
+
* ```
|
|
78
|
+
* @since 1.0.0
|
|
79
|
+
* @category constructors
|
|
80
|
+
*/
|
|
81
|
+
export declare function makeState(initial?: InitialState): Effect.Effect<RefSubject.HydratedRefSubject<{
|
|
82
|
+
readonly open: boolean;
|
|
83
|
+
}, Schema.SchemaError, never, never>, never, Scope.Scope>;
|
|
84
|
+
/** Sets popover visibility atomically.
|
|
85
|
+
* @remarks
|
|
86
|
+
* ## Why
|
|
87
|
+
* Explicit state transitions coordinate trigger and content without hidden
|
|
88
|
+
* component-local state.
|
|
89
|
+
* ## Ownership and lifetime
|
|
90
|
+
* The Effect uses the existing RefSubject lifetime and acquires no resource.
|
|
91
|
+
* @example
|
|
92
|
+
* ```ts
|
|
93
|
+
* import { Effect } from "effect"
|
|
94
|
+
* import * as Popover from "@typed/ui/Popover"
|
|
95
|
+
*
|
|
96
|
+
* const program = Effect.gen(function* () {
|
|
97
|
+
* const state = yield* Popover.makeState()
|
|
98
|
+
* yield* Popover.setOpen(state, true)
|
|
99
|
+
* })
|
|
100
|
+
* ```
|
|
101
|
+
* @since 1.0.0
|
|
102
|
+
* @category state
|
|
103
|
+
*/
|
|
104
|
+
export declare function setOpen<E, R>(state: RefSubject.RefSubject<State, E, R>, open: boolean): Effect.Effect<State, E, R>;
|
|
105
|
+
/** Options for the native popover trigger.
|
|
106
|
+
* @remarks
|
|
107
|
+
* ## Why
|
|
108
|
+
* The trigger exposes native target attributes when an id is supplied and a
|
|
109
|
+
* state-driven fallback otherwise.
|
|
110
|
+
* ## Ownership and lifetime
|
|
111
|
+
* Options are inert; rendering owns listeners/subscriptions by Scope.
|
|
112
|
+
* @since 1.0.0
|
|
113
|
+
* @category models
|
|
114
|
+
*/
|
|
115
|
+
export interface TriggerOptions extends Dom.HostOptions<HTMLButtonElement> {
|
|
116
|
+
/** Hydrated state shared with popover content.
|
|
117
|
+
* @remarks
|
|
118
|
+
* ## Why
|
|
119
|
+
* It drives `aria-expanded` and fallback activation from one source.
|
|
120
|
+
* ## Ownership and lifetime
|
|
121
|
+
* The trigger borrows state; its original Scope owns it.
|
|
122
|
+
* @since 1.0.0
|
|
123
|
+
* @category state
|
|
124
|
+
*/
|
|
125
|
+
readonly state: RefSubject.HydratedRefSubject<State, Schema.SchemaError>;
|
|
126
|
+
/** Id of content targeted through native `popovertarget`.
|
|
127
|
+
* @remarks
|
|
128
|
+
* ## Why
|
|
129
|
+
* Native targeting lets the browser run the Popover API lifecycle directly.
|
|
130
|
+
* ## Ownership and lifetime
|
|
131
|
+
* The string is reflected and retains no resources.
|
|
132
|
+
* @since 1.0.0
|
|
133
|
+
* @category relationships
|
|
134
|
+
*/
|
|
135
|
+
readonly controls?: string;
|
|
136
|
+
/** Visible trigger content and accessible name.
|
|
137
|
+
* @remarks
|
|
138
|
+
* ## Why
|
|
139
|
+
* A trigger needs a discoverable accessible name.
|
|
140
|
+
* ## Ownership and lifetime
|
|
141
|
+
* Dynamic content follows the trigger Scope.
|
|
142
|
+
* @since 1.0.0
|
|
143
|
+
* @category content
|
|
144
|
+
*/
|
|
145
|
+
readonly content: Renderable.Any;
|
|
146
|
+
}
|
|
147
|
+
declare function triggerInternalProps<const Options extends TriggerOptions>(options: Options): ({ property }: Dom.InternalPropsHelpers<Options>) => {
|
|
148
|
+
readonly type: "button";
|
|
149
|
+
readonly "aria-expanded": RefSubject.Computed<boolean, Schema.SchemaError, never>;
|
|
150
|
+
readonly popovertarget: Exclude<Dom.Property<Options, "controls">, Dom.Nullish> | undefined;
|
|
151
|
+
readonly popovertargetaction: "show" | undefined;
|
|
152
|
+
readonly onclick: Effect.Effect<State, Schema.SchemaError, never> | undefined;
|
|
153
|
+
readonly onkeydown: EventHandler.EventHandler<KeyboardEvent, Schema.SchemaError, never>;
|
|
154
|
+
};
|
|
155
|
+
type TriggerInternalProps<Options extends TriggerOptions> = ReturnType<ReturnType<typeof triggerInternalProps<Options>>>;
|
|
156
|
+
/** Renders a native button that opens popover content.
|
|
157
|
+
* @remarks
|
|
158
|
+
* ## Why
|
|
159
|
+
* It preserves button keyboard behavior, native target commands, real DOM
|
|
160
|
+
* events, and an explicit state fallback when no target id is supplied.
|
|
161
|
+
* ## Ownership and lifetime
|
|
162
|
+
* Running the Fx owns reactive ARIA state and listeners in its Scope. A custom
|
|
163
|
+
* host must preserve button type, target props, `aria-expanded`, and handlers.
|
|
164
|
+
* @example
|
|
165
|
+
* ```ts
|
|
166
|
+
* import { Effect } from "effect"
|
|
167
|
+
* import * as Popover from "@typed/ui/Popover"
|
|
168
|
+
*
|
|
169
|
+
* const program = Effect.gen(function* () {
|
|
170
|
+
* const state = yield* Popover.makeState()
|
|
171
|
+
* return Popover.Trigger({ state, controls: "account", content: "Account" })
|
|
172
|
+
* })
|
|
173
|
+
* ```
|
|
174
|
+
* @since 1.0.0
|
|
175
|
+
* @category components
|
|
176
|
+
*/
|
|
177
|
+
export declare function Trigger<const Options extends TriggerOptions, const Host extends HostResult = never>(options: Options, host?: Dom.HostOverride<Dom.RenderHostProps<Options, TriggerInternalProps<Options>>, Options["content"], Host>): Fx<RenderEvent, Renderable.Error<Options | Host>, Renderable.Services<Options | Host> | Scope.Scope | RenderTemplate>;
|
|
178
|
+
/** Options for manually controlled native popover content.
|
|
179
|
+
* @remarks
|
|
180
|
+
* ## Why
|
|
181
|
+
* Content and state remain explicit while the browser owns top-layer behavior.
|
|
182
|
+
* ## Ownership and lifetime
|
|
183
|
+
* Options are inert; rendering owns the native ref and subscriptions by Scope.
|
|
184
|
+
* @since 1.0.0
|
|
185
|
+
* @category models
|
|
186
|
+
*/
|
|
187
|
+
export interface ContentOptions extends Dom.HostOptions<HTMLDivElement> {
|
|
188
|
+
/** Hydrated state synchronized with native popover visibility.
|
|
189
|
+
* @remarks
|
|
190
|
+
* ## Why
|
|
191
|
+
* Native toggle events and application updates converge on one source.
|
|
192
|
+
* ## Ownership and lifetime
|
|
193
|
+
* The content borrows the state; its original Scope owns it.
|
|
194
|
+
* @since 1.0.0
|
|
195
|
+
* @category state
|
|
196
|
+
*/
|
|
197
|
+
readonly state: RefSubject.HydratedRefSubject<State, Schema.SchemaError>;
|
|
198
|
+
/** Content rendered in the top layer.
|
|
199
|
+
* @remarks
|
|
200
|
+
* ## Why
|
|
201
|
+
* Renderable output retains Typed error and service channels.
|
|
202
|
+
* ## Ownership and lifetime
|
|
203
|
+
* Dynamic content follows the content Scope.
|
|
204
|
+
* @since 1.0.0
|
|
205
|
+
* @category content
|
|
206
|
+
*/
|
|
207
|
+
readonly content: Renderable.Any;
|
|
208
|
+
}
|
|
209
|
+
declare function contentInternalProps<const Options extends ContentOptions>(options: Options): () => {
|
|
210
|
+
readonly popover: "manual";
|
|
211
|
+
readonly onkeydown: EventHandler.EventHandler<KeyboardEvent, Schema.SchemaError, never>;
|
|
212
|
+
readonly onbeforetoggle: EventHandler.EventHandler<Event, Schema.SchemaError, never>;
|
|
213
|
+
readonly ontoggle: EventHandler.EventHandler<Event, Schema.SchemaError, never>;
|
|
214
|
+
readonly ref: import("./Dom/Refs.js").ComposedRef<RefSubject.HydratedRefSubject<State, Schema.SchemaError, never, never>, (element: HTMLElement) => Effect.Effect<void, Schema.SchemaError, Scope.Scope>> | undefined;
|
|
215
|
+
};
|
|
216
|
+
type ContentInternalProps<Options extends ContentOptions> = ReturnType<ReturnType<typeof contentInternalProps<Options>>>;
|
|
217
|
+
/** Renders manually controlled native popover content.
|
|
218
|
+
* @remarks
|
|
219
|
+
* ## Why
|
|
220
|
+
* The component delegates top-layer lifecycle to the Popover API, synchronizes
|
|
221
|
+
* real `beforetoggle`/`toggle` events, and handles Escape through native events.
|
|
222
|
+
* ## Ownership and lifetime
|
|
223
|
+
* Running the Fx owns listeners and the NativePopover observer in its Effect
|
|
224
|
+
* Scope. A custom host must preserve `popover="manual"`, toggle handlers, and
|
|
225
|
+
* the single composed hydration ref.
|
|
226
|
+
* @example
|
|
227
|
+
* ```ts
|
|
228
|
+
* import { Effect } from "effect"
|
|
229
|
+
* import * as Popover from "@typed/ui/Popover"
|
|
230
|
+
*
|
|
231
|
+
* const program = Effect.gen(function* () {
|
|
232
|
+
* const state = yield* Popover.makeState()
|
|
233
|
+
* return Popover.Content({ state, content: "Preferences" })
|
|
234
|
+
* })
|
|
235
|
+
* ```
|
|
236
|
+
* @since 1.0.0
|
|
237
|
+
* @category components
|
|
238
|
+
*/
|
|
239
|
+
export declare function Content<const Options extends ContentOptions, const Host extends HostResult = never>(options: Options, host?: Dom.HostOverride<Dom.RenderHostProps<Options, ContentInternalProps<Options>>, Options["content"], Host>): Fx<RenderEvent, Renderable.Error<Options | Host>, Renderable.Services<Options | Host> | Scope.Scope | RenderTemplate>;
|
|
240
|
+
export {};
|
|
241
|
+
//# sourceMappingURL=Popover.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Popover.d.ts","sourceRoot":"","sources":["../src/Popover.ts"],"names":[],"mappings":"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"}
|
package/dist/Popover.js
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
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
|
+
import * as NativePopover from "./NativePopover.js";
|
|
7
|
+
/** Schema for serialized popover state.
|
|
8
|
+
* @remarks
|
|
9
|
+
* ## Why
|
|
10
|
+
* A shared boolean shape keeps server and browser hydration compatible.
|
|
11
|
+
* ## Ownership and lifetime
|
|
12
|
+
* The immutable schema acquires no resources.
|
|
13
|
+
* @since 1.0.0
|
|
14
|
+
* @category schemas
|
|
15
|
+
*/
|
|
16
|
+
export const StateSchema = Schema.Struct({ open: Schema.Boolean });
|
|
17
|
+
/** Creates hydrated popover state.
|
|
18
|
+
* @remarks
|
|
19
|
+
* ## Why
|
|
20
|
+
* Applications can own and test visibility independently of a component.
|
|
21
|
+
* ## Ownership and lifetime
|
|
22
|
+
* The calling Effect Scope owns the returned RefSubject.
|
|
23
|
+
* @example
|
|
24
|
+
* ```ts
|
|
25
|
+
* import { Effect } from "effect"
|
|
26
|
+
* import * as Popover from "@typed/ui/Popover"
|
|
27
|
+
*
|
|
28
|
+
* const program = Effect.gen(function* () {
|
|
29
|
+
* return yield* Popover.makeState()
|
|
30
|
+
* })
|
|
31
|
+
* ```
|
|
32
|
+
* @since 1.0.0
|
|
33
|
+
* @category constructors
|
|
34
|
+
*/
|
|
35
|
+
export function makeState(initial = {}) {
|
|
36
|
+
return RefSubject.hydrate(StateSchema, { open: initial.open ?? false });
|
|
37
|
+
}
|
|
38
|
+
/** Sets popover visibility atomically.
|
|
39
|
+
* @remarks
|
|
40
|
+
* ## Why
|
|
41
|
+
* Explicit state transitions coordinate trigger and content without hidden
|
|
42
|
+
* component-local state.
|
|
43
|
+
* ## Ownership and lifetime
|
|
44
|
+
* The Effect uses the existing RefSubject lifetime and acquires no resource.
|
|
45
|
+
* @example
|
|
46
|
+
* ```ts
|
|
47
|
+
* import { Effect } from "effect"
|
|
48
|
+
* import * as Popover from "@typed/ui/Popover"
|
|
49
|
+
*
|
|
50
|
+
* const program = Effect.gen(function* () {
|
|
51
|
+
* const state = yield* Popover.makeState()
|
|
52
|
+
* yield* Popover.setOpen(state, true)
|
|
53
|
+
* })
|
|
54
|
+
* ```
|
|
55
|
+
* @since 1.0.0
|
|
56
|
+
* @category state
|
|
57
|
+
*/
|
|
58
|
+
export function setOpen(state, open) {
|
|
59
|
+
return RefSubject.update(state, (current) => ({ ...current, open }));
|
|
60
|
+
}
|
|
61
|
+
function triggerInternalProps(options) {
|
|
62
|
+
const open = RefSubject.map(options.state, (state) => state.open);
|
|
63
|
+
return ({ property }) => ({
|
|
64
|
+
type: "button",
|
|
65
|
+
"aria-expanded": open,
|
|
66
|
+
popovertarget: property("controls", undefined),
|
|
67
|
+
popovertargetaction: options.controls === undefined ? undefined : "show",
|
|
68
|
+
onclick: options.controls === undefined ? setOpen(options.state, true) : undefined,
|
|
69
|
+
onkeydown: EventHandler.make(Effect.fn(function* (event) {
|
|
70
|
+
if (event.key !== "Escape")
|
|
71
|
+
return;
|
|
72
|
+
event.preventDefault();
|
|
73
|
+
yield* setOpen(options.state, false);
|
|
74
|
+
})),
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
/** Renders a native button that opens popover content.
|
|
78
|
+
* @remarks
|
|
79
|
+
* ## Why
|
|
80
|
+
* It preserves button keyboard behavior, native target commands, real DOM
|
|
81
|
+
* events, and an explicit state fallback when no target id is supplied.
|
|
82
|
+
* ## Ownership and lifetime
|
|
83
|
+
* Running the Fx owns reactive ARIA state and listeners in its Scope. A custom
|
|
84
|
+
* host must preserve button type, target props, `aria-expanded`, and handlers.
|
|
85
|
+
* @example
|
|
86
|
+
* ```ts
|
|
87
|
+
* import { Effect } from "effect"
|
|
88
|
+
* import * as Popover from "@typed/ui/Popover"
|
|
89
|
+
*
|
|
90
|
+
* const program = Effect.gen(function* () {
|
|
91
|
+
* const state = yield* Popover.makeState()
|
|
92
|
+
* return Popover.Trigger({ state, controls: "account", content: "Account" })
|
|
93
|
+
* })
|
|
94
|
+
* ```
|
|
95
|
+
* @since 1.0.0
|
|
96
|
+
* @category components
|
|
97
|
+
*/
|
|
98
|
+
export function Trigger(options, host) {
|
|
99
|
+
return Dom.renderHost()(options, host, triggerInternalProps(options), options.content, (props, content) => html `<button ...${props}>${content}</button>`);
|
|
100
|
+
}
|
|
101
|
+
function contentInternalProps(options) {
|
|
102
|
+
return () => ({
|
|
103
|
+
popover: "manual",
|
|
104
|
+
onkeydown: EventHandler.make(Effect.fn(function* (event) {
|
|
105
|
+
if (event.key !== "Escape")
|
|
106
|
+
return;
|
|
107
|
+
event.preventDefault();
|
|
108
|
+
yield* setOpen(options.state, false);
|
|
109
|
+
})),
|
|
110
|
+
onbeforetoggle: EventHandler.make(Effect.fn((event) => setOpen(options.state, Dom.toggleState(event) === "open"))),
|
|
111
|
+
ontoggle: EventHandler.make(Effect.fn((event) => setOpen(options.state, Dom.toggleState(event) === "open"))),
|
|
112
|
+
ref: Dom.composeRefs(options.state, NativePopover.ref(options.state)),
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
/** Renders manually controlled native popover content.
|
|
116
|
+
* @remarks
|
|
117
|
+
* ## Why
|
|
118
|
+
* The component delegates top-layer lifecycle to the Popover API, synchronizes
|
|
119
|
+
* real `beforetoggle`/`toggle` events, and handles Escape through native events.
|
|
120
|
+
* ## Ownership and lifetime
|
|
121
|
+
* Running the Fx owns listeners and the NativePopover observer in its Effect
|
|
122
|
+
* Scope. A custom host must preserve `popover="manual"`, toggle handlers, and
|
|
123
|
+
* the single composed hydration ref.
|
|
124
|
+
* @example
|
|
125
|
+
* ```ts
|
|
126
|
+
* import { Effect } from "effect"
|
|
127
|
+
* import * as Popover from "@typed/ui/Popover"
|
|
128
|
+
*
|
|
129
|
+
* const program = Effect.gen(function* () {
|
|
130
|
+
* const state = yield* Popover.makeState()
|
|
131
|
+
* return Popover.Content({ state, content: "Preferences" })
|
|
132
|
+
* })
|
|
133
|
+
* ```
|
|
134
|
+
* @since 1.0.0
|
|
135
|
+
* @category components
|
|
136
|
+
*/
|
|
137
|
+
export function Content(options, host) {
|
|
138
|
+
return Dom.renderHost()(options, host, contentInternalProps(options), options.content, (props, content) => {
|
|
139
|
+
return html `<div ...${props}>${content}</div>`;
|
|
140
|
+
});
|
|
141
|
+
}
|