@typed/ui 1.0.0-beta.1 → 1.0.0-beta.11

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 (155) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +54 -10
  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 +198 -55
  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 +48 -20
  151. package/src/HttpRouter.test.ts +0 -294
  152. package/src/HttpRouter.ts +0 -168
  153. package/src/Link.test.ts +0 -84
  154. package/src/Link.ts +0 -107
  155. package/src/index.ts +0 -2
@@ -0,0 +1,110 @@
1
+ import { chainEvent, isEventKey } from "./Events.js";
2
+ import { composeRefs } from "./Refs.js";
3
+ /**
4
+ * Merges user host props with component-required internal props.
5
+ *
6
+ * @remarks
7
+ * ## Why
8
+ * Internal accessibility/state props must remain authoritative, but user
9
+ * events still run first and may cancel component behavior. Disabled hosts
10
+ * suppress user activation handlers. Refs compose instead of overwriting one
11
+ * another.
12
+ *
13
+ * ## Ownership and lifetime
14
+ * The function allocates only a merged object. Listener and ref effects are
15
+ * run by the eventual template Scope. `composeRefs` rejects two hydration
16
+ * owners because one element can restore only one hydration protocol.
17
+ *
18
+ * @example
19
+ * ```ts
20
+ * import { mergeProps } from "@typed/ui/Dom/Props"
21
+ * import { EventHandler } from "@typed/template"
22
+ * import { Effect } from "effect"
23
+ *
24
+ * const props = mergeProps(
25
+ * {
26
+ * class: "external",
27
+ * onclick: EventHandler.make(() => Effect.log("user activation"))
28
+ * },
29
+ * { role: "button", "aria-disabled": false }
30
+ * )
31
+ * ```
32
+ *
33
+ * @since 1.0.0
34
+ * @category Prop composition
35
+ */
36
+ export function mergeProps(user, internal) {
37
+ if (!user)
38
+ return internal;
39
+ const merged = { ...user, ...internal };
40
+ const internalRecord = internal;
41
+ const mergedRecord = merged;
42
+ const activationDisabled = internalRecord["aria-disabled"] === true || internalRecord["?disabled"] === true;
43
+ for (const [key, value] of Object.entries(user)) {
44
+ if (isEventKey(key)) {
45
+ mergedRecord[key] = chainEvent(activationDisabled && (key === "onclick" || key === "@click")
46
+ ? undefined
47
+ : value, internalRecord[key]);
48
+ }
49
+ }
50
+ mergedRecord["ref"] = composeRefs(internalRecord["ref"], user["ref"]);
51
+ return merged;
52
+ }
53
+ /**
54
+ * Reads a property from an unknown generic value without throwing on nullish input.
55
+ *
56
+ * @remarks
57
+ * ## Why
58
+ * Generic option construction needs runtime behavior matching the public `Property` type.
59
+ *
60
+ * ## Ownership and lifetime
61
+ * Pure read; no value is retained.
62
+ *
63
+ * @since 1.0.0
64
+ * @category Property inspection
65
+ */
66
+ export function getProperty(value, key) {
67
+ return (value === null || value === undefined ? undefined : Reflect.get(Object(value), key));
68
+ }
69
+ /**
70
+ * Builds typed fallback helpers for component-owned host props.
71
+ *
72
+ * @remarks
73
+ * ## Why
74
+ * Components can distinguish an absent option from valid falsy values.
75
+ *
76
+ * ## Ownership and lifetime
77
+ * The helper closes over `options` only during synchronous prop construction.
78
+ *
79
+ * @since 1.0.0
80
+ * @category Internal prop defaults
81
+ */
82
+ export function makeInternalPropsHelpers(options) {
83
+ return {
84
+ property: (key, fallback) => {
85
+ const value = getProperty(options, key);
86
+ return (value === null || value === undefined ? fallback : value);
87
+ },
88
+ };
89
+ }
90
+ /**
91
+ * Extracts top-level refs and event handlers from component options.
92
+ *
93
+ * @remarks
94
+ * ## Why
95
+ * Convenience event/ref options can enter the same deterministic host merge as `props`.
96
+ *
97
+ * ## Ownership and lifetime
98
+ * Returns a shallow object. The rendering Scope owns any contained listener/ref work.
99
+ *
100
+ * @since 1.0.0
101
+ * @category Prop forwarding
102
+ */
103
+ export function forwardHostProps(options) {
104
+ const props = {};
105
+ for (const [key, value] of Object.entries(options)) {
106
+ if (key === "ref" || isEventKey(key))
107
+ props[key] = value;
108
+ }
109
+ return props;
110
+ }
@@ -0,0 +1,58 @@
1
+ import * as Effect from "effect/Effect";
2
+ import { RefSubject } from "@typed/fx";
3
+ import type { Renderable } from "@typed/template";
4
+ type RefInput = (element: never) => unknown;
5
+ type RefTarget<Ref> = NonNullable<Ref> extends (element: infer Target) => unknown ? Target : unknown;
6
+ type RefResult<Ref> = NonNullable<Ref> extends (...args: Array<never>) => infer Result ? Result : never;
7
+ type RefError<Ref> = Renderable.Error<NonNullable<Ref> | RefResult<Ref>>;
8
+ type RefServices<Ref> = Renderable.Services<NonNullable<Ref> | RefResult<Ref>>;
9
+ type HydrationProtocol<Ref> = NonNullable<Ref> extends RefSubject.HydrationRef<infer E, infer R> ? RefSubject.HydrationRef<E, R> : unknown;
10
+ /**
11
+ * Ref callback produced by combining two compatible element refs.
12
+ *
13
+ * @remarks
14
+ * ## Why
15
+ * User and component refs can observe the exact same DOM element without one
16
+ * overwriting the other, while their error/service channels remain visible.
17
+ *
18
+ * ## Ownership and lifetime
19
+ * The callback sequences both refs inside the element's rendering Scope. At
20
+ * most one input may carry `HydrationRef` ownership; that protocol is retained
21
+ * on the composed callback.
22
+ *
23
+ * @since 1.0.0
24
+ * @category Ref composition
25
+ */
26
+ export type ComposedRef<First, Second> = ((element: RefTarget<First> & RefTarget<Second>) => Effect.Effect<void, RefError<First> | RefError<Second>, RefServices<First> | RefServices<Second>>) & HydrationProtocol<First> & HydrationProtocol<Second>;
27
+ /**
28
+ * Composes two element refs in order.
29
+ *
30
+ * @remarks
31
+ * ## Why
32
+ * A component's internal ref and a caller's ref both need the real mounted
33
+ * node. Each return value may be void, Effect, Stream, or Fx, and composition
34
+ * normalizes those forms without hiding failures or services.
35
+ *
36
+ * ## Ownership and lifetime
37
+ * The first ref runs before the second. Streams and Fx values are drained in
38
+ * the caller's Scope and interrupted on unmount. The function throws
39
+ * synchronously when both refs claim hydration ownership because applying two
40
+ * serialized states to one element is ambiguous.
41
+ *
42
+ * @example
43
+ * ```ts
44
+ * import { composeRefs } from "@typed/ui/Dom/Refs"
45
+ * import { Effect } from "effect"
46
+ *
47
+ * const ref = composeRefs(
48
+ * (element: HTMLButtonElement) => Effect.sync(() => element.focus()),
49
+ * (element: HTMLButtonElement) => console.log(element)
50
+ * )
51
+ * ```
52
+ *
53
+ * @since 1.0.0
54
+ * @category Ref composition
55
+ */
56
+ export declare function composeRefs<const First extends RefInput | null | undefined, const Second extends RefInput | null | undefined = undefined>(first: First, second?: Second): ComposedRef<First, Second> | undefined;
57
+ export {};
58
+ //# sourceMappingURL=Refs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Refs.d.ts","sourceRoot":"","sources":["../../src/Dom/Refs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAExC,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAEvC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAElD,KAAK,QAAQ,GAAG,CAAC,OAAO,EAAE,KAAK,KAAK,OAAO,CAAC;AAC5C,KAAK,SAAS,CAAC,GAAG,IAChB,WAAW,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,EAAE,MAAM,MAAM,KAAK,OAAO,GAAG,MAAM,GAAG,OAAO,CAAC;AACjF,KAAK,SAAS,CAAC,GAAG,IAChB,WAAW,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,KAAK,CAAC,KAAK,CAAC,KAAK,MAAM,MAAM,GAAG,MAAM,GAAG,KAAK,CAAC;AACpF,KAAK,QAAQ,CAAC,GAAG,IAAI,UAAU,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC;AACzE,KAAK,WAAW,CAAC,GAAG,IAAI,UAAU,CAAC,QAAQ,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC;AAC/E,KAAK,iBAAiB,CAAC,GAAG,IACxB,WAAW,CAAC,GAAG,CAAC,SAAS,UAAU,CAAC,YAAY,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC,GAC9D,UAAU,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,CAAC,GAC7B,OAAO,CAAC;AAEd;;;;;;;;;;;;;;;GAeG;AACH,MAAM,MAAM,WAAW,CAAC,KAAK,EAAE,MAAM,IAAI,CAAC,CACxC,OAAO,EAAE,SAAS,CAAC,KAAK,CAAC,GAAG,SAAS,CAAC,MAAM,CAAC,KAC1C,MAAM,CAAC,MAAM,CAChB,IAAI,EACJ,QAAQ,CAAC,KAAK,CAAC,GAAG,QAAQ,CAAC,MAAM,CAAC,EAClC,WAAW,CAAC,KAAK,CAAC,GAAG,WAAW,CAAC,MAAM,CAAC,CACzC,CAAC,GACA,iBAAiB,CAAC,KAAK,CAAC,GACxB,iBAAiB,CAAC,MAAM,CAAC,CAAC;AAE5B;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,WAAW,CACzB,KAAK,CAAC,KAAK,SAAS,QAAQ,GAAG,IAAI,GAAG,SAAS,EAC/C,KAAK,CAAC,MAAM,SAAS,QAAQ,GAAG,IAAI,GAAG,SAAS,GAAG,SAAS,EAC5D,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,WAAW,CAAC,KAAK,EAAE,MAAM,CAAC,GAAG,SAAS,CAoBvE"}
@@ -0,0 +1,61 @@
1
+ import * as Effect from "effect/Effect";
2
+ import * as Stream from "effect/Stream";
3
+ import { RefSubject } from "@typed/fx";
4
+ import { drain, isFx } from "@typed/fx/Fx";
5
+ /**
6
+ * Composes two element refs in order.
7
+ *
8
+ * @remarks
9
+ * ## Why
10
+ * A component's internal ref and a caller's ref both need the real mounted
11
+ * node. Each return value may be void, Effect, Stream, or Fx, and composition
12
+ * normalizes those forms without hiding failures or services.
13
+ *
14
+ * ## Ownership and lifetime
15
+ * The first ref runs before the second. Streams and Fx values are drained in
16
+ * the caller's Scope and interrupted on unmount. The function throws
17
+ * synchronously when both refs claim hydration ownership because applying two
18
+ * serialized states to one element is ambiguous.
19
+ *
20
+ * @example
21
+ * ```ts
22
+ * import { composeRefs } from "@typed/ui/Dom/Refs"
23
+ * import { Effect } from "effect"
24
+ *
25
+ * const ref = composeRefs(
26
+ * (element: HTMLButtonElement) => Effect.sync(() => element.focus()),
27
+ * (element: HTMLButtonElement) => console.log(element)
28
+ * )
29
+ * ```
30
+ *
31
+ * @since 1.0.0
32
+ * @category Ref composition
33
+ */
34
+ export function composeRefs(first, second) {
35
+ if (!first && !second)
36
+ return undefined;
37
+ const hydrationOwners = [first, second].filter(RefSubject.isHydrationRef);
38
+ if (hydrationOwners.length > 1) {
39
+ throw new TypeError("Only one hydration ref can own an element");
40
+ }
41
+ const composed = Effect.fn((element) => Effect.andThen(runRef(first, element), runRef(second, element)));
42
+ const hydrationOwner = hydrationOwners[0];
43
+ const ref = hydrationOwner === undefined
44
+ ? composed
45
+ : Object.assign(composed, {
46
+ [RefSubject.HydrationRefTypeId]: hydrationOwner[RefSubject.HydrationRefTypeId],
47
+ });
48
+ return ref;
49
+ }
50
+ function runRef(ref, element) {
51
+ if (!ref)
52
+ return Effect.void;
53
+ const result = ref(element);
54
+ if (Effect.isEffect(result))
55
+ return Effect.asVoid(result);
56
+ if (Stream.isStream(result))
57
+ return Stream.runDrain(result);
58
+ if (isFx(result))
59
+ return drain(result);
60
+ return Effect.void;
61
+ }
@@ -0,0 +1,59 @@
1
+ import { type RenderHostProps } from "./Props.js";
2
+ import type { HostComponent, HostOptions, HostOverride, HostProps, HostResult, InternalPropsHelpers, RenderableInput } from "./Types.js";
3
+ /**
4
+ * Creates the host-rendering boundary for a particular DOM element type.
5
+ *
6
+ * @remarks
7
+ * ## Why
8
+ * Components can compute required props once, merge them with caller props,
9
+ * then delegate either to a custom host or to a native-template fallback. This
10
+ * exposes the boundary needed for external renderers without a framework adapter.
11
+ *
12
+ * ## Ownership and lifetime
13
+ * The returned component is lazy. Its Scope owns the chosen Effect/Fx result,
14
+ * merged listener/ref work, and only the render-event range that result emits.
15
+ * A custom host owns output it creates and must honor the supplied props.
16
+ *
17
+ * @example
18
+ * ```ts
19
+ * import { renderHost } from "@typed/ui/Dom/Render"
20
+ * import { html } from "@typed/template"
21
+ *
22
+ * const renderButton = renderHost<HTMLButtonElement>()
23
+ * const button = renderButton(
24
+ * { props: { class: "action" } },
25
+ * undefined,
26
+ * () => ({ type: "button" }),
27
+ * "Save",
28
+ * (props, content) => html`<button ...${props}>${content}</button>`
29
+ * )
30
+ * ```
31
+ *
32
+ * @since 1.0.0
33
+ * @category Host rendering
34
+ */
35
+ export declare function renderHost<Element extends globalThis.Element>(): <const Options extends HostOptions<Element>, const Internal extends HostProps<Element>, const Content extends RenderableInput, const Fallback extends HostResult, const Host extends HostResult = never>(options: Options, host: HostOverride<RenderHostProps<Options, Internal>, Content, Host> | undefined, buildInternal: (helpers: InternalPropsHelpers<Options>) => Internal, content: Content, fallback: (props: RenderHostProps<Options, Internal>, content: Content) => Fallback) => HostComponent<Options | Host>;
36
+ /**
37
+ * Renders a native `div` host from supplied props and content.
38
+ *
39
+ * @remarks
40
+ * ## Why
41
+ * Many behavior-only components need a standards-based neutral fallback while
42
+ * still allowing callers to replace the host through `renderHost`.
43
+ *
44
+ * ## Ownership and lifetime
45
+ * The returned template is lazy. Its Scope owns reactive parts and the created
46
+ * div; it does not claim surrounding or externally supplied DOM.
47
+ *
48
+ * @example
49
+ * ```ts
50
+ * import { renderDivHost } from "@typed/ui/Dom/Render"
51
+ *
52
+ * const host = renderDivHost({ role: "group", class: "cluster" }, "Actions")
53
+ * ```
54
+ *
55
+ * @since 1.0.0
56
+ * @category Host rendering
57
+ */
58
+ export declare function renderDivHost<const Props extends HostProps<HTMLDivElement>, const Content extends RenderableInput>(props: Props, content: Content): HostComponent<Props | Content>;
59
+ //# sourceMappingURL=Render.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Render.d.ts","sourceRoot":"","sources":["../../src/Dom/Render.ts"],"names":[],"mappings":"AAGA,OAAO,EAKL,KAAK,eAAe,EACrB,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAEV,aAAa,EACb,WAAW,EACX,YAAY,EACZ,SAAS,EACT,UAAU,EACV,oBAAoB,EACpB,eAAe,EAChB,MAAM,YAAY,CAAC;AAEpB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,UAAU,CAAC,OAAO,SAAS,UAAU,CAAC,OAAO,MAEzD,KAAK,CAAC,OAAO,SAAS,WAAW,CAAC,OAAO,CAAC,EAC1C,KAAK,CAAC,QAAQ,SAAS,SAAS,CAAC,OAAO,CAAC,EACzC,KAAK,CAAC,OAAO,SAAS,eAAe,EACrC,KAAK,CAAC,QAAQ,SAAS,UAAU,EACjC,KAAK,CAAC,IAAI,SAAS,UAAU,GAAG,KAAK,WAE5B,OAAO,QACV,YAAY,CAAC,eAAe,CAAC,OAAO,EAAE,QAAQ,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,GAAG,SAAS,iBAClE,CAAC,OAAO,EAAE,oBAAoB,CAAC,OAAO,CAAC,KAAK,QAAQ,WAC1D,OAAO,YACN,CAAC,KAAK,EAAE,eAAe,CAAC,OAAO,EAAE,QAAQ,CAAC,EAAE,OAAO,EAAE,OAAO,KAAK,QAAQ,KAClF,aAAa,CAAC,OAAO,GAAG,IAAI,CAAC,CASjC;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,aAAa,CAC3B,KAAK,CAAC,KAAK,SAAS,SAAS,CAAC,cAAc,CAAC,EAC7C,KAAK,CAAC,OAAO,SAAS,eAAe,EACrC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,GAAG,aAAa,CAAC,KAAK,GAAG,OAAO,CAAC,CAEhE"}
@@ -0,0 +1,71 @@
1
+ import * as Effect from "effect/Effect";
2
+ import { fromEffect } from "@typed/fx/Fx";
3
+ import { html } from "@typed/template";
4
+ import { forwardHostProps, getProperty, makeInternalPropsHelpers, mergeProps, } from "./Props.js";
5
+ /**
6
+ * Creates the host-rendering boundary for a particular DOM element type.
7
+ *
8
+ * @remarks
9
+ * ## Why
10
+ * Components can compute required props once, merge them with caller props,
11
+ * then delegate either to a custom host or to a native-template fallback. This
12
+ * exposes the boundary needed for external renderers without a framework adapter.
13
+ *
14
+ * ## Ownership and lifetime
15
+ * The returned component is lazy. Its Scope owns the chosen Effect/Fx result,
16
+ * merged listener/ref work, and only the render-event range that result emits.
17
+ * A custom host owns output it creates and must honor the supplied props.
18
+ *
19
+ * @example
20
+ * ```ts
21
+ * import { renderHost } from "@typed/ui/Dom/Render"
22
+ * import { html } from "@typed/template"
23
+ *
24
+ * const renderButton = renderHost<HTMLButtonElement>()
25
+ * const button = renderButton(
26
+ * { props: { class: "action" } },
27
+ * undefined,
28
+ * () => ({ type: "button" }),
29
+ * "Save",
30
+ * (props, content) => html`<button ...${props}>${content}</button>`
31
+ * )
32
+ * ```
33
+ *
34
+ * @since 1.0.0
35
+ * @category Host rendering
36
+ */
37
+ export function renderHost() {
38
+ return function (options, host, buildInternal, content, fallback) {
39
+ const props = mergeProps(mergeProps(getProperty(options, "props"), forwardHostProps(options)), buildInternal(makeInternalPropsHelpers(options)));
40
+ const rendered = host ? host(props, content) : fallback(props, content);
41
+ return componentBoundary(rendered);
42
+ };
43
+ }
44
+ /**
45
+ * Renders a native `div` host from supplied props and content.
46
+ *
47
+ * @remarks
48
+ * ## Why
49
+ * Many behavior-only components need a standards-based neutral fallback while
50
+ * still allowing callers to replace the host through `renderHost`.
51
+ *
52
+ * ## Ownership and lifetime
53
+ * The returned template is lazy. Its Scope owns reactive parts and the created
54
+ * div; it does not claim surrounding or externally supplied DOM.
55
+ *
56
+ * @example
57
+ * ```ts
58
+ * import { renderDivHost } from "@typed/ui/Dom/Render"
59
+ *
60
+ * const host = renderDivHost({ role: "group", class: "cluster" }, "Actions")
61
+ * ```
62
+ *
63
+ * @since 1.0.0
64
+ * @category Host rendering
65
+ */
66
+ export function renderDivHost(props, content) {
67
+ return html `<div ...${props}>${content}</div>`;
68
+ }
69
+ function componentBoundary(value) {
70
+ return (Effect.isEffect(value) ? fromEffect(value) : value);
71
+ }