@typed/ui 1.0.0-beta.3 → 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 +197 -54
  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 +42 -15
  153. package/src/HttpRouter.test.ts +0 -294
  154. package/src/HttpRouter.ts +0 -168
  155. package/src/Link.test.ts +0 -84
  156. package/src/Link.ts +0 -107
  157. package/src/index.ts +0 -2
package/README.md CHANGED
@@ -6,26 +6,42 @@
6
6
 
7
7
  ## Capabilities
8
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.
9
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).
10
- - **SSR** — `ssrForHttp` compiles a router Matcher into HttpRouter GET handlers for server-side rendering. Requests are parsed, matched, and the corresponding Fx is rendered to HTML. `handleHttpServerError` adds global middleware for 404/400/500.
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.
11
13
 
12
14
  ## Dependencies
13
15
 
14
16
  - `effect`
15
- - `@effect/platform-node`
16
17
  - `@typed/fx`
18
+ - `@typed/id`
17
19
  - `@typed/navigation`
18
20
  - `@typed/router`
19
21
  - `@typed/template`
20
- - `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`.
21
24
 
22
25
  ## API overview
23
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.
24
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).
25
- - **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.
26
32
 
27
33
  ## API reference
28
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
+
29
45
  ### `Link`
30
46
 
31
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`).
@@ -54,7 +70,9 @@ In addition, `LinkOptions` accepts standard anchor event handlers (e.g. `onclick
54
70
 
55
71
  ### `ssrForHttp`
56
72
 
57
- 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.
58
76
 
59
77
  **Overloads:**
60
78
 
@@ -63,12 +81,22 @@ Registers route handlers on an Effect **HttpRouter** for server-side rendering.
63
81
  function ssrForHttp<E, R>(
64
82
  router: HttpRouter,
65
83
  input: Matcher<RenderEvent, E, R>,
66
- ): Effect.Effect<void, never, Exclude<R, Scope | Router>>;
84
+ ): Effect.Effect<
85
+ void,
86
+ never,
87
+ Exclude<R, Scope | Router> | HttpRouter.Request.From<"Error", E | HttpServerError>
88
+ >;
67
89
 
68
90
  // (matcher)(router) — curried
69
91
  function ssrForHttp<E, R>(
70
92
  input: Matcher<RenderEvent, E, R>,
71
- ): (router: HttpRouter) => Effect.Effect<void, never, Exclude<R, Scope | Router>>;
93
+ ): (
94
+ router: HttpRouter,
95
+ ) => Effect.Effect<
96
+ void,
97
+ never,
98
+ Exclude<R, Scope | Router> | HttpRouter.Request.From<"Error", E | HttpServerError>
99
+ >;
72
100
  ```
73
101
 
74
102
  - **`router`** — Effect `HttpRouter` to attach GET handlers to.
@@ -76,6 +104,14 @@ function ssrForHttp<E, R>(
76
104
 
77
105
  ---
78
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
+
79
115
  ### `handleHttpServerError`
80
116
 
81
117
  Adds global middleware to an **HttpRouter** that catches `HttpServerError` and returns appropriate HTTP responses:
@@ -86,8 +122,16 @@ Adds global middleware to an **HttpRouter** that catches `HttpServerError` and r
86
122
  | `RequestParseError` | 400 |
87
123
  | `InternalError` / `ResponseError` | 500 |
88
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.
126
+
89
127
  ```ts
90
- 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
+ >;
91
135
  ```
92
136
 
93
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.
@@ -104,4 +148,4 @@ const nav = html`<nav>
104
148
  </nav>`;
105
149
  ```
106
150
 
107
- 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,78 @@
1
+ import type * as Scope from "effect/Scope";
2
+ import type { Fx } from "@typed/fx/Fx";
3
+ import { type Renderable, type RenderEvent, type RenderTemplate } from "@typed/template";
4
+ import * as Dom from "./Dom.js";
5
+ import type { HostResult } from "./Dom/Types.js";
6
+ /**
7
+ * Options for the assertive alert live region.
8
+ *
9
+ * @remarks
10
+ * ## Why
11
+ *
12
+ * Alerts announce important, time-sensitive output without moving focus or
13
+ * requiring a modal interaction.
14
+ *
15
+ * ## Ownership and lifetime
16
+ *
17
+ * The options are inert. Rendering owns only the alert host and subscriptions
18
+ * for renderable option values; the running Effect Scope removes them.
19
+ *
20
+ * @since 1.0.0
21
+ * @category models
22
+ */
23
+ export interface AlertOptions extends Dom.HostOptions<HTMLDivElement> {
24
+ /**
25
+ * Content announced by the `role="alert"` live region.
26
+ *
27
+ * @remarks
28
+ * ## Why
29
+ *
30
+ * Keeping the announcement renderable lets applications publish Effect- or
31
+ * Fx-backed status while retaining the platform accessibility tree.
32
+ *
33
+ * ## Ownership and lifetime
34
+ *
35
+ * The value acquires no resources itself. Rendering subscribes to dynamic
36
+ * content for the lifetime of the alert's Scope.
37
+ *
38
+ * @since 1.0.0
39
+ * @category content
40
+ */
41
+ readonly content: Renderable.Any;
42
+ }
43
+ declare function internalProps(): {
44
+ readonly role: "alert";
45
+ };
46
+ type AlertInternalProps = ReturnType<typeof internalProps>;
47
+ /**
48
+ * Renders a non-modal, assertive live region.
49
+ *
50
+ * For an interrupting confirmation, use `Dialog.Content` with
51
+ * `role="alertdialog"`; an alert must not take focus or require dismissal.
52
+ *
53
+ * @remarks
54
+ * ## Why
55
+ *
56
+ * `Alert` supplies the native ARIA live-region contract while leaving content,
57
+ * host choice, and Effect requirements composable. It does not synthesize an
58
+ * event or introduce an application-owned announcement queue.
59
+ *
60
+ * ## Ownership and lifetime
61
+ *
62
+ * Calling `Alert` starts no work. Running the returned Fx owns the rendered
63
+ * host, dynamic values, and listeners in its Effect Scope; finalization removes
64
+ * only those resources. A custom host must preserve the supplied `role`.
65
+ *
66
+ * @example
67
+ * ```ts
68
+ * import { Alert } from "@typed/ui/Alert"
69
+ *
70
+ * const saved = Alert({ content: "Changes saved" })
71
+ * ```
72
+ *
73
+ * @since 1.0.0
74
+ * @category components
75
+ */
76
+ 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>;
77
+ export {};
78
+ //# sourceMappingURL=Alert.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Alert.d.ts","sourceRoot":"","sources":["../src/Alert.ts"],"names":[],"mappings":"AAAA,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;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,WAAW,YAAa,SAAQ,GAAG,CAAC,WAAW,CAAC,cAAc,CAAC;IACnE;;;;;;;;;;;;;;;;OAgBG;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;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;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,37 @@
1
+ import { html } from "@typed/template";
2
+ import * as Dom from "./Dom.js";
3
+ function internalProps() {
4
+ return { role: "alert" };
5
+ }
6
+ /**
7
+ * Renders a non-modal, assertive live region.
8
+ *
9
+ * For an interrupting confirmation, use `Dialog.Content` with
10
+ * `role="alertdialog"`; an alert must not take focus or require dismissal.
11
+ *
12
+ * @remarks
13
+ * ## Why
14
+ *
15
+ * `Alert` supplies the native ARIA live-region contract while leaving content,
16
+ * host choice, and Effect requirements composable. It does not synthesize an
17
+ * event or introduce an application-owned announcement queue.
18
+ *
19
+ * ## Ownership and lifetime
20
+ *
21
+ * Calling `Alert` starts no work. Running the returned Fx owns the rendered
22
+ * host, dynamic values, and listeners in its Effect Scope; finalization removes
23
+ * only those resources. A custom host must preserve the supplied `role`.
24
+ *
25
+ * @example
26
+ * ```ts
27
+ * import { Alert } from "@typed/ui/Alert"
28
+ *
29
+ * const saved = Alert({ content: "Changes saved" })
30
+ * ```
31
+ *
32
+ * @since 1.0.0
33
+ * @category components
34
+ */
35
+ export function Alert(options, host) {
36
+ return Dom.renderHost()(options, host, internalProps, options.content, (props, content) => html `<div ...${props}>${content}</div>`);
37
+ }
@@ -0,0 +1,144 @@
1
+ import type * as Scope from "effect/Scope";
2
+ import type { Fx } from "@typed/fx/Fx";
3
+ import { type Renderable, type RenderEvent, type RenderTemplate } from "@typed/template";
4
+ import * as Dom from "./Dom.js";
5
+ import type { HostResult } from "./Dom/Types.js";
6
+ /**
7
+ * Native button submission behavior.
8
+ *
9
+ * @remarks
10
+ * ## Why
11
+ *
12
+ * The union exposes the exact HTML button types and defaults components to the
13
+ * non-submitting `button` behavior.
14
+ *
15
+ * ## Ownership and lifetime
16
+ *
17
+ * This is a pure type and acquires no resources.
18
+ *
19
+ * @since 1.0.0
20
+ * @category models
21
+ */
22
+ export type ButtonType = "button" | "submit" | "reset";
23
+ /**
24
+ * Renderable state and host options for a native button.
25
+ *
26
+ * @remarks
27
+ * ## Why
28
+ *
29
+ * The model keeps native button semantics while allowing content, disabled
30
+ * state, and handlers to come from any Typed renderable source.
31
+ *
32
+ * ## Ownership and lifetime
33
+ *
34
+ * The options are inert. The rendered component's Scope owns dynamic option
35
+ * subscriptions and listener cleanup.
36
+ *
37
+ * @since 1.0.0
38
+ * @category models
39
+ */
40
+ export interface ButtonOptions extends Dom.HostOptions<HTMLButtonElement> {
41
+ /**
42
+ * The button's visible and accessible content.
43
+ *
44
+ * @remarks
45
+ * ## Why
46
+ *
47
+ * Native content supplies the accessible name unless the host explicitly
48
+ * provides another naming mechanism.
49
+ *
50
+ * ## Ownership and lifetime
51
+ *
52
+ * Dynamic content is subscribed to only while the component Scope is open.
53
+ *
54
+ * @since 1.0.0
55
+ * @category content
56
+ */
57
+ readonly content: Renderable.Any;
58
+ /**
59
+ * The native `type` attribute; defaults to `"button"`.
60
+ *
61
+ * @remarks
62
+ * ## Why
63
+ *
64
+ * An explicit non-submitting default prevents a reusable button from
65
+ * accidentally submitting an enclosing form.
66
+ *
67
+ * ## Ownership and lifetime
68
+ *
69
+ * The value is reflected by the renderer and retains no resources.
70
+ *
71
+ * @since 1.0.0
72
+ * @category attributes
73
+ */
74
+ readonly type?: Renderable.Any<ButtonType | null | undefined>;
75
+ /**
76
+ * Whether the native control is disabled.
77
+ *
78
+ * @remarks
79
+ * ## Why
80
+ *
81
+ * Using the native disabled state removes the button from interaction and
82
+ * form submission according to browser semantics.
83
+ *
84
+ * ## Ownership and lifetime
85
+ *
86
+ * Dynamic values are observed for the component Scope and then released.
87
+ *
88
+ * @since 1.0.0
89
+ * @category attributes
90
+ */
91
+ readonly disabled?: Renderable.Any<boolean | null | undefined>;
92
+ /**
93
+ * A real DOM click handler supplied by the consumer.
94
+ *
95
+ * @remarks
96
+ * ## Why
97
+ *
98
+ * `Button` has no internal activation handler. The supplied handler receives
99
+ * the real DOM click event; browser default actions remain native.
100
+ *
101
+ * ## Ownership and lifetime
102
+ *
103
+ * Rendering installs the listener and the component Scope removes it.
104
+ *
105
+ * @since 1.0.0
106
+ * @category events
107
+ */
108
+ readonly onclick?: Dom.EventHandlerInput<Dom.EventOf<HTMLButtonElement["onclick"]>>;
109
+ }
110
+ declare function internalProps<const Options extends ButtonOptions>({ property, }: Dom.InternalPropsHelpers<Options>): {
111
+ type: "button" | Exclude<Dom.Property<Options, "type">, Dom.Nullish>;
112
+ "?disabled": false | Exclude<Dom.Property<Options, "disabled">, Dom.Nullish>;
113
+ };
114
+ type ButtonInternalProps<Options extends ButtonOptions> = ReturnType<typeof internalProps<Options>>;
115
+ /**
116
+ * Renders a semantic native button with cooperative host customization.
117
+ *
118
+ * @remarks
119
+ * ## Why
120
+ *
121
+ * `Button` retains browser keyboard, form, focus, and accessibility behavior.
122
+ * Its internal props only establish the default type and disabled state. Any
123
+ * `onclick` behavior belongs entirely to the consumer and receives a real DOM
124
+ * event; there is no component-internal click action to chain or cancel.
125
+ *
126
+ * ## Ownership and lifetime
127
+ *
128
+ * Calling the factory is inert. Running its Fx owns the host's dynamic parts
129
+ * and listeners in an Effect Scope. A custom host must apply the supplied props
130
+ * and content so disabled and button-type semantics are not lost.
131
+ *
132
+ * @example
133
+ * ```ts
134
+ * import { Button } from "@typed/ui/Button"
135
+ *
136
+ * const submit = Button({ type: "submit", content: "Save" })
137
+ * ```
138
+ *
139
+ * @since 1.0.0
140
+ * @category components
141
+ */
142
+ 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>;
143
+ export {};
144
+ //# sourceMappingURL=Button.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Button.d.ts","sourceRoot":"","sources":["../src/Button.ts"],"names":[],"mappings":"AAAA,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;;;;;;;;;;;;;;;GAeG;AACH,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,QAAQ,GAAG,OAAO,CAAC;AAEvD;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,WAAW,aAAc,SAAQ,GAAG,CAAC,WAAW,CAAC,iBAAiB,CAAC;IACvE;;;;;;;;;;;;;;;OAeG;IACH,QAAQ,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,CAAC;IACjC;;;;;;;;;;;;;;;OAeG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,UAAU,CAAC,GAAG,CAAC,UAAU,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC;IAC9D;;;;;;;;;;;;;;;OAeG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,UAAU,CAAC,GAAG,CAAC,OAAO,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC;IAC/D;;;;;;;;;;;;;;;OAeG;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;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;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,38 @@
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
+ * ## Why
14
+ *
15
+ * `Button` retains browser keyboard, form, focus, and accessibility behavior.
16
+ * Its internal props only establish the default type and disabled state. Any
17
+ * `onclick` behavior belongs entirely to the consumer and receives a real DOM
18
+ * event; there is no component-internal click action to chain or cancel.
19
+ *
20
+ * ## Ownership and lifetime
21
+ *
22
+ * Calling the factory is inert. Running its Fx owns the host's dynamic parts
23
+ * and listeners in an Effect Scope. A custom host must apply the supplied props
24
+ * and content so disabled and button-type semantics are not lost.
25
+ *
26
+ * @example
27
+ * ```ts
28
+ * import { Button } from "@typed/ui/Button"
29
+ *
30
+ * const submit = Button({ type: "submit", content: "Save" })
31
+ * ```
32
+ *
33
+ * @since 1.0.0
34
+ * @category components
35
+ */
36
+ export function Button(options, host) {
37
+ return Dom.renderHost()(options, host, internalProps, options.content, (props, content) => html `<button ...${props}>${content}</button>`);
38
+ }