@typed/ui 1.0.0-beta.0 → 1.0.0-beta.10

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 (156) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +78 -26
  3. package/dist/Alert.d.ts +72 -0
  4. package/dist/Alert.d.ts.map +1 -0
  5. package/dist/Alert.js +40 -0
  6. package/dist/Button.d.ts +100 -0
  7. package/dist/Button.d.ts.map +1 -0
  8. package/dist/Button.js +42 -0
  9. package/dist/Carousel.d.ts +346 -0
  10. package/dist/Carousel.d.ts.map +1 -0
  11. package/dist/Carousel.js +264 -0
  12. package/dist/Checkbox.d.ts +168 -0
  13. package/dist/Checkbox.d.ts.map +1 -0
  14. package/dist/Checkbox.js +146 -0
  15. package/dist/Collection.d.ts +254 -0
  16. package/dist/Collection.d.ts.map +1 -0
  17. package/dist/Collection.js +218 -0
  18. package/dist/Combobox.d.ts +367 -0
  19. package/dist/Combobox.d.ts.map +1 -0
  20. package/dist/Combobox.js +300 -0
  21. package/dist/Composite.d.ts +823 -0
  22. package/dist/Composite.d.ts.map +1 -0
  23. package/dist/Composite.js +615 -0
  24. package/dist/Dialog.d.ts +544 -0
  25. package/dist/Dialog.d.ts.map +1 -0
  26. package/dist/Dialog.js +357 -0
  27. package/dist/Disclosure.d.ts +219 -0
  28. package/dist/Disclosure.d.ts.map +1 -0
  29. package/dist/Disclosure.js +128 -0
  30. package/dist/Dom/Events.d.ts +122 -0
  31. package/dist/Dom/Events.d.ts.map +1 -0
  32. package/dist/Dom/Events.js +192 -0
  33. package/dist/Dom/Props.d.ts +161 -0
  34. package/dist/Dom/Props.d.ts.map +1 -0
  35. package/dist/Dom/Props.js +110 -0
  36. package/dist/Dom/Refs.d.ts +58 -0
  37. package/dist/Dom/Refs.d.ts.map +1 -0
  38. package/dist/Dom/Refs.js +61 -0
  39. package/dist/Dom/Render.d.ts +59 -0
  40. package/dist/Dom/Render.d.ts.map +1 -0
  41. package/dist/Dom/Render.js +71 -0
  42. package/dist/Dom/Types.d.ts +570 -0
  43. package/dist/Dom/Types.d.ts.map +1 -0
  44. package/dist/Dom/Types.js +1 -0
  45. package/dist/Dom/index.d.ts +20 -0
  46. package/dist/Dom/index.d.ts.map +1 -0
  47. package/dist/Dom/index.js +8 -0
  48. package/dist/Dom.d.ts +14 -0
  49. package/dist/Dom.d.ts.map +1 -0
  50. package/dist/Dom.js +13 -0
  51. package/dist/Focusable.d.ts +85 -0
  52. package/dist/Focusable.d.ts.map +1 -0
  53. package/dist/Focusable.js +35 -0
  54. package/dist/Form.d.ts +1727 -0
  55. package/dist/Form.d.ts.map +1 -0
  56. package/dist/Form.js +1142 -0
  57. package/dist/Grid.d.ts +388 -0
  58. package/dist/Grid.d.ts.map +1 -0
  59. package/dist/Grid.js +284 -0
  60. package/dist/Group.d.ts +128 -0
  61. package/dist/Group.d.ts.map +1 -0
  62. package/dist/Group.js +71 -0
  63. package/dist/Heading.d.ts +87 -0
  64. package/dist/Heading.d.ts.map +1 -0
  65. package/dist/Heading.js +58 -0
  66. package/dist/Hovercard.d.ts +297 -0
  67. package/dist/Hovercard.d.ts.map +1 -0
  68. package/dist/Hovercard.js +188 -0
  69. package/dist/HttpRouter.d.ts +129 -6
  70. package/dist/HttpRouter.d.ts.map +1 -1
  71. package/dist/HttpRouter.js +199 -56
  72. package/dist/Link.d.ts +63 -28
  73. package/dist/Link.d.ts.map +1 -1
  74. package/dist/Link.js +84 -37
  75. package/dist/Listbox.d.ts +305 -0
  76. package/dist/Listbox.d.ts.map +1 -0
  77. package/dist/Listbox.js +245 -0
  78. package/dist/Menu.d.ts +663 -0
  79. package/dist/Menu.d.ts.map +1 -0
  80. package/dist/Menu.js +569 -0
  81. package/dist/Menubar.d.ts +249 -0
  82. package/dist/Menubar.d.ts.map +1 -0
  83. package/dist/Menubar.js +207 -0
  84. package/dist/Meter.d.ts +157 -0
  85. package/dist/Meter.d.ts.map +1 -0
  86. package/dist/Meter.js +87 -0
  87. package/dist/NativeDetails.d.ts +41 -0
  88. package/dist/NativeDetails.d.ts.map +1 -0
  89. package/dist/NativeDetails.js +40 -0
  90. package/dist/NativeDialog.d.ts +66 -0
  91. package/dist/NativeDialog.d.ts.map +1 -0
  92. package/dist/NativeDialog.js +88 -0
  93. package/dist/NativePopover.d.ts +43 -0
  94. package/dist/NativePopover.d.ts.map +1 -0
  95. package/dist/NativePopover.js +84 -0
  96. package/dist/Popover.d.ts +240 -0
  97. package/dist/Popover.d.ts.map +1 -0
  98. package/dist/Popover.js +140 -0
  99. package/dist/RadioGroup.d.ts +330 -0
  100. package/dist/RadioGroup.d.ts.map +1 -0
  101. package/dist/RadioGroup.js +241 -0
  102. package/dist/Role.d.ts +64 -0
  103. package/dist/Role.d.ts.map +1 -0
  104. package/dist/Role.js +27 -0
  105. package/dist/Select.d.ts +418 -0
  106. package/dist/Select.d.ts.map +1 -0
  107. package/dist/Select.js +357 -0
  108. package/dist/Separator.d.ts +58 -0
  109. package/dist/Separator.d.ts.map +1 -0
  110. package/dist/Separator.js +32 -0
  111. package/dist/Slider.d.ts +141 -0
  112. package/dist/Slider.d.ts.map +1 -0
  113. package/dist/Slider.js +101 -0
  114. package/dist/SpinButton.d.ts +141 -0
  115. package/dist/SpinButton.d.ts.map +1 -0
  116. package/dist/SpinButton.js +101 -0
  117. package/dist/Storybook.d.ts +76 -0
  118. package/dist/Storybook.d.ts.map +1 -0
  119. package/dist/Storybook.js +102 -0
  120. package/dist/Switch.d.ts +148 -0
  121. package/dist/Switch.d.ts.map +1 -0
  122. package/dist/Switch.js +110 -0
  123. package/dist/Tab.d.ts +26 -0
  124. package/dist/Tab.d.ts.map +1 -0
  125. package/dist/Tab.js +25 -0
  126. package/dist/Tabs.d.ts +411 -0
  127. package/dist/Tabs.d.ts.map +1 -0
  128. package/dist/Tabs.js +262 -0
  129. package/dist/Toolbar.d.ts +248 -0
  130. package/dist/Toolbar.d.ts.map +1 -0
  131. package/dist/Toolbar.js +187 -0
  132. package/dist/Tooltip.d.ts +296 -0
  133. package/dist/Tooltip.d.ts.map +1 -0
  134. package/dist/Tooltip.js +172 -0
  135. package/dist/Tree.d.ts +405 -0
  136. package/dist/Tree.d.ts.map +1 -0
  137. package/dist/Tree.js +333 -0
  138. package/dist/TreeGrid.d.ts +426 -0
  139. package/dist/TreeGrid.d.ts.map +1 -0
  140. package/dist/TreeGrid.js +308 -0
  141. package/dist/VisuallyHidden.d.ts +68 -0
  142. package/dist/VisuallyHidden.d.ts.map +1 -0
  143. package/dist/VisuallyHidden.js +44 -0
  144. package/dist/WindowSplitter.d.ts +336 -0
  145. package/dist/WindowSplitter.d.ts.map +1 -0
  146. package/dist/WindowSplitter.js +305 -0
  147. package/dist/index.d.ts +48 -0
  148. package/dist/index.d.ts.map +1 -1
  149. package/dist/index.js +48 -0
  150. package/package.json +47 -14
  151. package/src/HttpRouter.test.ts +0 -294
  152. package/src/HttpRouter.ts +0 -168
  153. package/src/Link.test.ts +0 -85
  154. package/src/Link.ts +0 -107
  155. package/src/index.ts +0 -2
  156. package/tsconfig.json +0 -6
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023-present The Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -2,50 +2,77 @@
2
2
 
3
3
  > **Beta:** This package is in beta; APIs may change.
4
4
 
5
- `@typed/ui` provides **web integration** for the router and template: **Link** (typed anchor that uses Navigation for same-origin clicks) and **HttpRouter**-related helpers for SSR (`ssrForHttp`, `handleHttpServerError`). Use it when you need navigation-aware links and/or server-side rendering of the router with Effect’s HTTP server.
5
+ `@typed/ui` is the **web integration layer** for `@typed/router` and `@typed/template`. It bridges typed's routing and template system with the browser and Effect's HTTP stack.
6
+
7
+ ## Capabilities
8
+
9
+ - **UI substrate** — `Dom` provides typed native host props, exact Effect/Fx channel preservation, user-first event composition, and hydration-aware ref composition. Stateful components use `RefSubject.hydrate` / `hydrateAll` directly; there is no parallel UI state abstraction.
10
+ - **Button** — A headless native `<button>` host with a safe `type="button"` default, reactive disabled state, typed click handling, caller props, and custom-host support.
11
+ - **Link** — A typed anchor component that intercepts same-origin clicks and navigates via `Navigation.navigate` instead of a full page reload. Keeps routing SPA-style while preserving normal `<a>` semantics (href, target, keyboard, right-click).
12
+ - **SSR** — `ssrForHttp` compiles a router Matcher into HttpRouter GET handlers for buffered server-side rendering. `streamingSsrForHttp` uses the same routing pipeline but streams HTML chunks as they are rendered. `handleHttpServerError` adds global middleware for 404/400/500.
6
13
 
7
14
  ## Dependencies
8
15
 
9
16
  - `effect`
10
- - `@effect/platform-node`
11
17
  - `@typed/fx`
18
+ - `@typed/id`
12
19
  - `@typed/navigation`
13
20
  - `@typed/router`
14
21
  - `@typed/template`
15
- - `happy-dom` (dev)
22
+
23
+ The Node HTTP platform and `happy-dom` are development dependencies used by the integration tests; browser consumers do not install them through `@typed/ui`.
16
24
 
17
25
  ## API overview
18
26
 
27
+ - **Button** — `Button.Button(options)` renders a native `<button>` and accepts `content`, `type`, `disabled`, `onclick`, standard button props, and an optional custom host.
28
+ - **Dom** — Typed host/ref/event composition shared by the UI components. Its host attributes target Baseline 2026 and include native popover and invoker-command attributes.
29
+ - **APG components** — Stateful controls use callable `RefSubject.hydrate` state on their owning host. `Alert` is a non-modal live region; `Meter`, `Slider`, and `SpinButton` use native HTML controls; `Switch` uses a button host; `WindowSplitter`, `Carousel`, `Tree`, `Grid`, and `TreeGrid` provide their APG keyboard and ARIA contracts without a portal or positioning runtime.
19
30
  - **Link** — `Link(options)` renders an `<a href="...">` that intercepts same-origin, same-document clicks and calls `Navigation.navigate` instead of a full page load. Options include `href`, `content`, `replace`, and standard anchor props. Requires **Navigation** and **RenderTemplate** in context (e.g. browser router).
20
- - **SSR:** `ssrForHttp(router, matcher)` — registers route handlers on an Effect **HttpRouter** for server-side rendering; `handleHttpServerError(router)` — global middleware for HTTP server errors.
31
+ - **SSR:** `ssrForHttp(router, matcher)` — registers buffered route handlers on an Effect **HttpRouter**; `streamingSsrForHttp(router, matcher)` — same routing with streamed HTML output; `handleHttpServerError(router)` — global middleware for HTTP server errors.
21
32
 
22
33
  ## API reference
23
34
 
35
+ ### APG component families
36
+
37
+ `Alert.Alert({ content })` renders `role="alert"` and never moves focus. Use `Dialog.Content` with `props: { role: "alertdialog" }` when a message must interrupt the user.
38
+
39
+ `Meter`, `Slider`, and `SpinButton` each take a hydratable `state` made by `makeState({ value })`; slider and spin button synchronize their native range/number input changes into that state. `Switch.makeState({ checked })` drives `Switch.Switch({ state, content })`.
40
+
41
+ `WindowSplitter.makeState({ value, min, max, step, orientation })` drives a focusable separator with APG arrow keys, Home/End, and Enter collapse/restore. Applications own pane sizing from its state.
42
+
43
+ `Carousel`, `Tree`, `Grid`, and `TreeGrid` each expose `makeState`, `makeCollection`, and structural parts. Their hydration state holds serializable selection/expansion state; their collections only register mounted DOM elements for navigation. `Tree.Group` and `TreeGrid.Group` define the nested collapsed DOM boundary; `Grid` and `TreeGrid` retain DOM focus on the root with `aria-activedescendant`.
44
+
24
45
  ### `Link`
25
46
 
26
47
  Renders an `<a href="...">` that intercepts same-origin, same-document clicks and navigates via `Navigation.navigate` instead of a full page load. Requires **Navigation** and **RenderTemplate** in the Effect context (e.g. `BrowserRouter`).
27
48
 
28
49
  ```ts
29
50
  function Link<const Opts extends LinkOptions>(
30
- options: Opts
31
- ): Fx<RenderEvent, Renderable.ErrorFromObject<Opts>, Renderable.ServicesFromObject<Opts> | Scope | RenderTemplate>
51
+ options: Opts,
52
+ ): Fx<
53
+ RenderEvent,
54
+ Renderable.ErrorFromObject<Opts>,
55
+ Renderable.ServicesFromObject<Opts> | Scope | RenderTemplate
56
+ >;
32
57
  ```
33
58
 
34
59
  **`LinkOptions`**
35
60
 
36
- | Property | Type | Required | Description |
37
- |-----------|------|----------|-------------|
38
- | `href` | `Renderable<string, any, any>` | Yes | Target URL. |
39
- | `content` | `Renderable<string \| number \| boolean \| null \| undefined \| void \| RenderEvent, any, any>` | Yes | Link body (text or template content). |
40
- | `replace` | `boolean` | No | If `true`, use history replace instead of push. Default: `false`. |
61
+ | Property | Type | Required | Description |
62
+ | --------- | ----------------------------------------------------------------------------------------------- | -------- | ----------------------------------------------------------------- |
63
+ | `href` | `Renderable<string, any, any>` | Yes | Target URL. |
64
+ | `content` | `Renderable<string \| number \| boolean \| null \| undefined \| void \| RenderEvent, any, any>` | Yes | Link body (text or template content). |
65
+ | `replace` | `boolean` | No | If `true`, use history replace instead of push. Default: `false`. |
41
66
 
42
- In addition, `LinkOptions` accepts standard anchor event handlers (e.g. `onclick`), `ref`, and other writable `HTMLAnchorElement` properties. Custom `onclick` runs first; if the event is not `preventDefault`’d, the built-in navigation handler runs.
67
+ In addition, `LinkOptions` accepts standard anchor event handlers (e.g. `onclick`), `ref`, and other writable `HTMLAnchorElement` properties. Custom `onclick` runs first; if the event is not `preventDefault`'d, the built-in navigation handler runs.
43
68
 
44
69
  ---
45
70
 
46
71
  ### `ssrForHttp`
47
72
 
48
- Registers route handlers on an Effect **HttpRouter** for server-side rendering. The matcher’s routes are compiled and each case is exposed as a GET route; requests are parsed, matched, and the corresponding Fx is rendered to HTML. Requires **Router** and **Scope** to be provided elsewhere; other matcher services remain in the effect requirement.
73
+ Registers route handlers on an Effect **HttpRouter** for server-side rendering. The matcher's routes are compiled and each case is exposed as a GET route; requests are parsed, matched, and the corresponding Fx is rendered to HTML. Rendering is buffered: the complete HTML string is produced before the response begins. Requires **Router** and **Scope** to be provided elsewhere; other matcher services remain in the effect requirement. Matcher and render failures remain in Effect HTTP's request error channel so middleware can handle them.
74
+
75
+ Path captures are authoritative. If a request supplies the same name in the query string, the matched path value is passed to route decoding. The adapter initializes navigation state from Effect's request URL conversion, including the request host and `x-forwarded-proto`; deployments must only accept forwarding headers behind a trusted proxy.
49
76
 
50
77
  **Overloads:**
51
78
 
@@ -53,13 +80,23 @@ Registers route handlers on an Effect **HttpRouter** for server-side rendering.
53
80
  // (router, matcher)
54
81
  function ssrForHttp<E, R>(
55
82
  router: HttpRouter,
56
- input: Matcher<RenderEvent, E, R>
57
- ): Effect.Effect<void, never, Exclude<R, Scope | Router>>
83
+ input: Matcher<RenderEvent, E, R>,
84
+ ): Effect.Effect<
85
+ void,
86
+ never,
87
+ Exclude<R, Scope | Router> | HttpRouter.Request.From<"Error", E | HttpServerError>
88
+ >;
58
89
 
59
90
  // (matcher)(router) — curried
60
91
  function ssrForHttp<E, R>(
61
- input: Matcher<RenderEvent, E, R>
62
- ): (router: HttpRouter) => Effect.Effect<void, never, Exclude<R, Scope | Router>>
92
+ input: Matcher<RenderEvent, E, R>,
93
+ ): (
94
+ router: HttpRouter,
95
+ ) => Effect.Effect<
96
+ void,
97
+ never,
98
+ Exclude<R, Scope | Router> | HttpRouter.Request.From<"Error", E | HttpServerError>
99
+ >;
63
100
  ```
64
101
 
65
102
  - **`router`** — Effect `HttpRouter` to attach GET handlers to.
@@ -67,18 +104,34 @@ function ssrForHttp<E, R>(
67
104
 
68
105
  ---
69
106
 
107
+ ### `streamingSsrForHttp`
108
+
109
+ Same routing and decoding behavior as `ssrForHttp`, but renders with `renderToHtml` and returns `HttpServerResponse.stream` so HTML chunks can be sent before rendering completes. Choose `ssrForHttp` when you need a fully buffered body (for example, middleware that inspects the complete HTML string) and `streamingSsrForHttp` when you want time-to-first-byte improvements.
110
+
111
+ **Overloads:** identical curried and uncurried shapes to `ssrForHttp`.
112
+
113
+ ---
114
+
70
115
  ### `handleHttpServerError`
71
116
 
72
117
  Adds global middleware to an **HttpRouter** that catches `HttpServerError` and returns appropriate HTTP responses:
73
118
 
74
- | Error reason | Status |
75
- |------------------|--------|
76
- | `RouteNotFound` | 404 |
77
- | `RequestParseError` | 400 |
78
- | `InternalError` / `ResponseError` | 500 |
119
+ | Error reason | Status |
120
+ | --------------------------------- | ------ |
121
+ | `RouteNotFound` | 404 |
122
+ | `RequestParseError` | 400 |
123
+ | `InternalError` / `ResponseError` | 500 |
124
+
125
+ All four responses have empty bodies so request URLs, parse descriptions, service names, upstream response details, and other internal data are not reflected to clients. Non-`HttpServerError` failures are re-failed and remain visible in Effect HTTP's global error channel.
79
126
 
80
127
  ```ts
81
- function handleHttpServerError(router: HttpRouter): Effect.Effect<void, never, HttpRouter>
128
+ function handleHttpServerError(
129
+ router: HttpRouter,
130
+ ): Effect.Effect<
131
+ void,
132
+ never,
133
+ import("effect/unstable/http/HttpRouter").Request<"GlobalError", unknown>
134
+ >;
82
135
  ```
83
136
 
84
137
  Use after registering routes (e.g. after `ssrForHttp`) so unhandled route and parse errors are converted to 404/400/500 instead of failing the server.
@@ -91,9 +144,8 @@ import { html } from "@typed/template";
91
144
 
92
145
  // In a template: link that navigates via Navigation (no full reload)
93
146
  const nav = html`<nav>
94
- ${Link({ href: "/", content: "Home" })}
95
- ${Link({ href: "/todos", content: "Todos" })}
147
+ ${Link({ href: "/", content: "Home" })} ${Link({ href: "/todos", content: "Todos" })}
96
148
  </nav>`;
97
149
  ```
98
150
 
99
- For SSR, provide the router and matcher to `ssrForHttp` when setting up the HTTP server; see Effect’s `HttpRouter` and the TodoMVC example structure.
151
+ For SSR, provide the router and matcher to `ssrForHttp` or `streamingSsrForHttp` when setting up the HTTP server; see Effect's `HttpRouter` and `examples/fullstack/src/server.ts` for the workspace's server wiring.
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Assertive live-region content without focus movement or an announcement queue.
3
+ * Use urgent text updates deliberately; routine feedback usually belongs in a status region.
4
+ *
5
+ * Read the [Alert guide](/explore/ui-alert) for a complete example.
6
+ *
7
+ * [APG interaction reference](https://www.w3.org/WAI/ARIA/apg/patterns/alert/).
8
+ * @since 1.0.0
9
+ * @category Overview
10
+ * @packageDocumentation
11
+ */
12
+ import type * as Scope from "effect/Scope";
13
+ import type { Fx } from "@typed/fx/Fx";
14
+ import { type Renderable, type RenderEvent, type RenderTemplate } from "@typed/template";
15
+ import * as Dom from "./Dom.js";
16
+ import type { HostResult } from "./Dom/Types.js";
17
+ /**
18
+ * Options for the assertive alert live region.
19
+ *
20
+ * @remarks
21
+ * Alerts announce important, time-sensitive output without moving focus or
22
+ * requiring a modal interaction.
23
+ * @since 1.0.0
24
+ * @category Component options
25
+ */
26
+ export interface AlertOptions extends Dom.HostOptions<HTMLDivElement> {
27
+ /**
28
+ * Content announced by the `role="alert"` live region.
29
+ * @since 1.0.0
30
+ * @category Rendered content
31
+ */
32
+ readonly content: Renderable.Any;
33
+ }
34
+ declare function internalProps(): {
35
+ readonly role: "alert";
36
+ };
37
+ type AlertInternalProps = ReturnType<typeof internalProps>;
38
+ /**
39
+ * Renders an assertive alert region without moving focus.
40
+ *
41
+ * @remarks
42
+ * Keep the region mounted and change its text when an urgent event occurs. Initial page content
43
+ * or repeated identical messages may not announce as expected. This primitive does not queue
44
+ * announcements, schedule dismissal, or provide an acknowledgement dialog. Prefer a status
45
+ * region for routine updates.
46
+ *
47
+ * @example
48
+ * ```ts
49
+ * import { RefSubject } from "@typed/fx";
50
+ * import { html } from "@typed/template";
51
+ * import { Alert } from "@typed/ui/Alert";
52
+ * import { Button } from "@typed/ui/Button";
53
+ * import { component } from "@typed/template";
54
+ *
55
+ * export const AlertPreview = component(function* () {
56
+ * const message = yield* RefSubject.make("");
57
+ * return html`<section>
58
+ * <p>Preview the message shown when an upload fails.</p>
59
+ * ${Button({
60
+ * content: "Preview upload failure",
61
+ * onclick: RefSubject.set(message, "Upload failed. Your file is still available; try again."),
62
+ * })}
63
+ * ${Alert({ content: message, props: { class: "upload-alert" } })}
64
+ * </section>`;
65
+ * });
66
+ * ```
67
+ * @since 1.0.0
68
+ * @category Controls
69
+ */
70
+ export declare function Alert<const Options extends AlertOptions, const Host extends HostResult = never>(options: Options, host?: Dom.HostOverride<Dom.RenderHostProps<Options, AlertInternalProps>, Options["content"], Host>): Fx<RenderEvent, Renderable.Error<Options | Host>, Renderable.Services<Options | Host> | Scope.Scope | RenderTemplate>;
71
+ export {};
72
+ //# sourceMappingURL=Alert.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Alert.d.ts","sourceRoot":"","sources":["../src/Alert.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,KAAK,KAAK,MAAM,cAAc,CAAC;AAC3C,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAQ,KAAK,UAAU,EAAE,KAAK,WAAW,EAAE,KAAK,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAC/F,OAAO,KAAK,GAAG,MAAM,UAAU,CAAC;AAChC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAEjD;;;;;;;;GAQG;AACH,MAAM,WAAW,YAAa,SAAQ,GAAG,CAAC,WAAW,CAAC,cAAc,CAAC;IACnE;;;;OAIG;IACH,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,CAAC;CAClC;AAED,iBAAS,aAAa;aACX,IAAI,EAAE,OAAO;EACvB;AACD,KAAK,kBAAkB,GAAG,UAAU,CAAC,OAAO,aAAa,CAAC,CAAC;AAE3D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,KAAK,CAAC,KAAK,CAAC,OAAO,SAAS,YAAY,EAAE,KAAK,CAAC,IAAI,SAAS,UAAU,GAAG,KAAK,EAC7F,OAAO,EAAE,OAAO,EAChB,IAAI,CAAC,EAAE,GAAG,CAAC,YAAY,CACrB,GAAG,CAAC,eAAe,CAAC,OAAO,EAAE,kBAAkB,CAAC,EAChD,OAAO,CAAC,SAAS,CAAC,EAClB,IAAI,CACL,GACA,EAAE,CACH,WAAW,EACX,UAAU,CAAC,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC,EAChC,UAAU,CAAC,QAAQ,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,KAAK,CAAC,KAAK,GAAG,cAAc,CACnE,CAQA"}
package/dist/Alert.js ADDED
@@ -0,0 +1,40 @@
1
+ import { html } from "@typed/template";
2
+ import * as Dom from "./Dom.js";
3
+ function internalProps() {
4
+ return { role: "alert" };
5
+ }
6
+ /**
7
+ * Renders an assertive alert region without moving focus.
8
+ *
9
+ * @remarks
10
+ * Keep the region mounted and change its text when an urgent event occurs. Initial page content
11
+ * or repeated identical messages may not announce as expected. This primitive does not queue
12
+ * announcements, schedule dismissal, or provide an acknowledgement dialog. Prefer a status
13
+ * region for routine updates.
14
+ *
15
+ * @example
16
+ * ```ts
17
+ * import { RefSubject } from "@typed/fx";
18
+ * import { html } from "@typed/template";
19
+ * import { Alert } from "@typed/ui/Alert";
20
+ * import { Button } from "@typed/ui/Button";
21
+ * import { component } from "@typed/template";
22
+ *
23
+ * export const AlertPreview = component(function* () {
24
+ * const message = yield* RefSubject.make("");
25
+ * return html`<section>
26
+ * <p>Preview the message shown when an upload fails.</p>
27
+ * ${Button({
28
+ * content: "Preview upload failure",
29
+ * onclick: RefSubject.set(message, "Upload failed. Your file is still available; try again."),
30
+ * })}
31
+ * ${Alert({ content: message, props: { class: "upload-alert" } })}
32
+ * </section>`;
33
+ * });
34
+ * ```
35
+ * @since 1.0.0
36
+ * @category Controls
37
+ */
38
+ export function Alert(options, host) {
39
+ return Dom.renderHost()(options, host, internalProps, options.content, (props, content) => html `<div ...${props}>${content}</div>`);
40
+ }
@@ -0,0 +1,100 @@
1
+ /**
2
+ * Native command activation and explicit button/submit/reset behavior.
3
+ * The control has no internal click action; return application Effects from its handler.
4
+ *
5
+ * Read the [Button guide](/explore/ui-button) for a complete example.
6
+ *
7
+ * [APG interaction reference](https://www.w3.org/WAI/ARIA/apg/patterns/button/).
8
+ * @since 1.0.0
9
+ * @category Overview
10
+ * @packageDocumentation
11
+ */
12
+ import type * as Scope from "effect/Scope";
13
+ import type { Fx } from "@typed/fx/Fx";
14
+ import { type Renderable, type RenderEvent, type RenderTemplate } from "@typed/template";
15
+ import * as Dom from "./Dom.js";
16
+ import type { HostResult } from "./Dom/Types.js";
17
+ /**
18
+ * Native button submission behavior.
19
+ *
20
+ * @remarks
21
+ * The union exposes the exact HTML button types and defaults components to the
22
+ * non-submitting `button` behavior.
23
+ * @since 1.0.0
24
+ * @category State models
25
+ */
26
+ export type ButtonType = "button" | "submit" | "reset";
27
+ /**
28
+ * Renderable state and host options for a native button.
29
+ *
30
+ * @remarks
31
+ * The model keeps native button semantics while allowing content, disabled
32
+ * state, and handlers to come from any Typed renderable source.
33
+ * @since 1.0.0
34
+ * @category Component options
35
+ */
36
+ export interface ButtonOptions extends Dom.HostOptions<HTMLButtonElement> {
37
+ /**
38
+ * The button's visible and accessible content.
39
+ * @since 1.0.0
40
+ * @category Rendered content
41
+ */
42
+ readonly content: Renderable.Any;
43
+ /**
44
+ * The native `type` attribute; defaults to `"button"`.
45
+ * @since 1.0.0
46
+ * @category Native attributes
47
+ */
48
+ readonly type?: Renderable.Any<ButtonType | null | undefined>;
49
+ /**
50
+ * Whether the native control is disabled.
51
+ * @since 1.0.0
52
+ * @category Availability
53
+ */
54
+ readonly disabled?: Renderable.Any<boolean | null | undefined>;
55
+ /**
56
+ * A real DOM click handler supplied by the consumer.
57
+ * @since 1.0.0
58
+ * @category Event handlers
59
+ */
60
+ readonly onclick?: Dom.EventHandlerInput<Dom.EventOf<HTMLButtonElement["onclick"]>>;
61
+ }
62
+ declare function internalProps<const Options extends ButtonOptions>({ property, }: Dom.InternalPropsHelpers<Options>): {
63
+ type: "button" | Exclude<Dom.Property<Options, "type">, Dom.Nullish>;
64
+ "?disabled": false | Exclude<Dom.Property<Options, "disabled">, Dom.Nullish>;
65
+ };
66
+ type ButtonInternalProps<Options extends ButtonOptions> = ReturnType<typeof internalProps<Options>>;
67
+ /**
68
+ * Renders a semantic native button with cooperative host customization.
69
+ *
70
+ * @remarks
71
+ * `Button` retains browser keyboard, form, focus, and accessibility behavior.
72
+ * Its internal props only establish the default type and disabled state. Any
73
+ * `onclick` behavior belongs entirely to the consumer and receives a real DOM
74
+ * event; there is no component-internal click action to chain or cancel.
75
+ *
76
+ * @example
77
+ * ```ts
78
+ * import { RefSubject } from "@typed/fx";
79
+ * import { html } from "@typed/template";
80
+ * import { Button } from "@typed/ui/Button";
81
+ * import { component } from "@typed/template";
82
+ *
83
+ * export const PreviewCounter = component(function* () {
84
+ * const previews = yield* RefSubject.make(0);
85
+ * return html`<section>
86
+ * ${Button({
87
+ * content: "Recalculate preview",
88
+ * props: { class: "preview-action" },
89
+ * onclick: RefSubject.update(previews, (count) => count + 1),
90
+ * })}
91
+ * <p role="status">Preview calculations: ${previews}</p>
92
+ * </section>`;
93
+ * });
94
+ * ```
95
+ * @since 1.0.0
96
+ * @category Native controls
97
+ */
98
+ export declare function Button<const Options extends ButtonOptions, const Host extends HostResult = never>(options: Options, host?: Dom.HostOverride<Dom.RenderHostProps<Options, ButtonInternalProps<Options>>, Options["content"], Host>): Fx<RenderEvent, Renderable.Error<Options | Host>, Renderable.Services<Options | Host> | Scope.Scope | RenderTemplate>;
99
+ export {};
100
+ //# sourceMappingURL=Button.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Button.d.ts","sourceRoot":"","sources":["../src/Button.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,KAAK,KAAK,MAAM,cAAc,CAAC;AAC3C,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAQ,KAAK,UAAU,EAAE,KAAK,WAAW,EAAE,KAAK,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAC/F,OAAO,KAAK,GAAG,MAAM,UAAU,CAAC;AAChC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAEjD;;;;;;;;GAQG;AACH,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,QAAQ,GAAG,OAAO,CAAC;AAEvD;;;;;;;;GAQG;AACH,MAAM,WAAW,aAAc,SAAQ,GAAG,CAAC,WAAW,CAAC,iBAAiB,CAAC;IACvE;;;;OAIG;IACH,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,CAAC;IACjC;;;;OAIG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,UAAU,CAAC,GAAG,CAAC,UAAU,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC;IAC9D;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,UAAU,CAAC,GAAG,CAAC,OAAO,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC;IAC/D;;;;OAIG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,GAAG,CAAC,iBAAiB,CAAC,GAAG,CAAC,OAAO,CAAC,iBAAiB,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;CACrF;AAED,iBAAS,aAAa,CAAC,KAAK,CAAC,OAAO,SAAS,aAAa,EAAE,EAC1D,QAAQ,GACT,EAAE,GAAG,CAAC,oBAAoB,CAAC,OAAO,CAAC;IAEhC,IAAI;IACJ,WAAW;EAEd;AAED,KAAK,mBAAmB,CAAC,OAAO,SAAS,aAAa,IAAI,UAAU,CAAC,OAAO,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC;AAEpG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAgB,MAAM,CAAC,KAAK,CAAC,OAAO,SAAS,aAAa,EAAE,KAAK,CAAC,IAAI,SAAS,UAAU,GAAG,KAAK,EAC/F,OAAO,EAAE,OAAO,EAChB,IAAI,CAAC,EAAE,GAAG,CAAC,YAAY,CACrB,GAAG,CAAC,eAAe,CAAC,OAAO,EAAE,mBAAmB,CAAC,OAAO,CAAC,CAAC,EAC1D,OAAO,CAAC,SAAS,CAAC,EAClB,IAAI,CACL,GACA,EAAE,CACH,WAAW,EACX,UAAU,CAAC,KAAK,CAAC,OAAO,GAAG,IAAI,CAAC,EAChC,UAAU,CAAC,QAAQ,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,KAAK,CAAC,KAAK,GAAG,cAAc,CACnE,CAQA"}
package/dist/Button.js ADDED
@@ -0,0 +1,42 @@
1
+ import { html } from "@typed/template";
2
+ import * as Dom from "./Dom.js";
3
+ function internalProps({ property, }) {
4
+ return {
5
+ type: property("type", "button"),
6
+ "?disabled": property("disabled", false),
7
+ };
8
+ }
9
+ /**
10
+ * Renders a semantic native button with cooperative host customization.
11
+ *
12
+ * @remarks
13
+ * `Button` retains browser keyboard, form, focus, and accessibility behavior.
14
+ * Its internal props only establish the default type and disabled state. Any
15
+ * `onclick` behavior belongs entirely to the consumer and receives a real DOM
16
+ * event; there is no component-internal click action to chain or cancel.
17
+ *
18
+ * @example
19
+ * ```ts
20
+ * import { RefSubject } from "@typed/fx";
21
+ * import { html } from "@typed/template";
22
+ * import { Button } from "@typed/ui/Button";
23
+ * import { component } from "@typed/template";
24
+ *
25
+ * export const PreviewCounter = component(function* () {
26
+ * const previews = yield* RefSubject.make(0);
27
+ * return html`<section>
28
+ * ${Button({
29
+ * content: "Recalculate preview",
30
+ * props: { class: "preview-action" },
31
+ * onclick: RefSubject.update(previews, (count) => count + 1),
32
+ * })}
33
+ * <p role="status">Preview calculations: ${previews}</p>
34
+ * </section>`;
35
+ * });
36
+ * ```
37
+ * @since 1.0.0
38
+ * @category Native controls
39
+ */
40
+ export function Button(options, host) {
41
+ return Dom.renderHost()(options, host, internalProps, options.content, (props, content) => html `<button ...${props}>${content}</button>`);
42
+ }