@ui-sdk/react 0.0.0-stage → 0.1.0-beta.1

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 (247) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +10 -2
  3. package/dist/accordion.d.ts +331 -0
  4. package/dist/accordion.js +25 -0
  5. package/dist/agent.d.ts +2 -0
  6. package/dist/agent.js +8 -0
  7. package/dist/alert-dialog.d.ts +56 -0
  8. package/dist/alert-dialog.js +45 -0
  9. package/dist/async-options.d.ts +22 -0
  10. package/dist/async-options.js +56 -0
  11. package/dist/autocomplete.d.ts +102 -0
  12. package/dist/autocomplete.js +195 -0
  13. package/dist/avatar.d.ts +301 -0
  14. package/dist/avatar.js +17 -0
  15. package/dist/button.d.ts +21 -0
  16. package/dist/button.js +45 -0
  17. package/dist/calendar-context.d.ts +10 -0
  18. package/dist/calendar-context.js +9 -0
  19. package/dist/calendar.d.ts +80 -0
  20. package/dist/calendar.js +257 -0
  21. package/dist/carousel.d.ts +52 -0
  22. package/dist/carousel.js +151 -0
  23. package/dist/checkbox.d.ts +24 -0
  24. package/dist/checkbox.js +98 -0
  25. package/dist/children.d.ts +38 -0
  26. package/dist/children.js +63 -0
  27. package/dist/collapsible.d.ts +302 -0
  28. package/dist/collapsible.js +19 -0
  29. package/dist/color-picker.d.ts +72 -0
  30. package/dist/color-picker.js +133 -0
  31. package/dist/color.d.ts +2 -0
  32. package/dist/color.js +22 -0
  33. package/dist/combobox.d.ts +152 -0
  34. package/dist/combobox.js +338 -0
  35. package/dist/command.d.ts +88 -0
  36. package/dist/command.js +233 -0
  37. package/dist/controller-target.d.ts +3 -0
  38. package/dist/controller-target.js +59 -0
  39. package/dist/date-input.d.ts +19 -0
  40. package/dist/date-input.js +58 -0
  41. package/dist/date-picker.d.ts +47 -0
  42. package/dist/date-picker.js +310 -0
  43. package/dist/date.d.ts +2 -0
  44. package/dist/date.js +60 -0
  45. package/dist/dialog-parts.d.ts +23 -0
  46. package/dist/dialog-parts.js +142 -0
  47. package/dist/dialog.d.ts +57 -0
  48. package/dist/dialog.js +32 -0
  49. package/dist/drawer.d.ts +70 -0
  50. package/dist/drawer.js +158 -0
  51. package/dist/editor-context.d.ts +4 -0
  52. package/dist/editor-context.js +9 -0
  53. package/dist/field-context.d.ts +47 -0
  54. package/dist/field-context.js +87 -0
  55. package/dist/field.d.ts +49 -0
  56. package/dist/field.js +169 -0
  57. package/dist/file-input.d.ts +46 -0
  58. package/dist/file-input.js +170 -0
  59. package/dist/form-inputs.d.ts +5 -0
  60. package/dist/form-inputs.js +22 -0
  61. package/dist/gesture.d.ts +1 -0
  62. package/dist/gesture.js +16 -0
  63. package/dist/history.d.ts +2 -0
  64. package/dist/history.js +12 -0
  65. package/dist/hover-card.d.ts +33 -0
  66. package/dist/hover-card.js +84 -0
  67. package/dist/image-cropper.d.ts +333 -0
  68. package/dist/image-cropper.js +37 -0
  69. package/dist/image.d.ts +2 -0
  70. package/dist/image.js +6 -0
  71. package/dist/input.d.ts +22 -0
  72. package/dist/input.js +51 -0
  73. package/dist/label.d.ts +294 -0
  74. package/dist/label.js +9 -0
  75. package/dist/list-items.d.ts +15 -0
  76. package/dist/list-items.js +39 -0
  77. package/dist/list-text.d.ts +4 -0
  78. package/dist/list-text.js +15 -0
  79. package/dist/listbox.d.ts +56 -0
  80. package/dist/listbox.js +122 -0
  81. package/dist/menu.d.ts +116 -0
  82. package/dist/menu.js +426 -0
  83. package/dist/menubar-context.d.ts +4 -0
  84. package/dist/menubar-context.js +7 -0
  85. package/dist/menubar.d.ts +11 -0
  86. package/dist/menubar.js +32 -0
  87. package/dist/meter.d.ts +312 -0
  88. package/dist/meter.js +30 -0
  89. package/dist/navigation-menu.d.ts +61 -0
  90. package/dist/navigation-menu.js +169 -0
  91. package/dist/number-input.d.ts +44 -0
  92. package/dist/number-input.js +185 -0
  93. package/dist/number.d.ts +2 -0
  94. package/dist/number.js +40 -0
  95. package/dist/observe.d.ts +2 -0
  96. package/dist/observe.js +8 -0
  97. package/dist/otp-input.d.ts +29 -0
  98. package/dist/otp-input.js +94 -0
  99. package/dist/overlays.d.ts +26 -0
  100. package/dist/overlays.js +82 -0
  101. package/dist/pagination.d.ts +336 -0
  102. package/dist/pagination.js +71 -0
  103. package/dist/password-input.d.ts +23 -0
  104. package/dist/password-input.js +65 -0
  105. package/dist/popover.d.ts +54 -0
  106. package/dist/popover.js +151 -0
  107. package/dist/popup.d.ts +41 -0
  108. package/dist/popup.js +180 -0
  109. package/dist/preferences.d.ts +35 -0
  110. package/dist/preferences.js +93 -0
  111. package/dist/primitive.d.ts +2 -0
  112. package/dist/primitive.js +14 -0
  113. package/dist/progress.d.ts +312 -0
  114. package/dist/progress.js +30 -0
  115. package/dist/radio.d.ts +22 -0
  116. package/dist/radio.js +86 -0
  117. package/dist/rating.d.ts +20 -0
  118. package/dist/rating.js +94 -0
  119. package/dist/render-element.d.ts +35 -0
  120. package/dist/render-element.js +103 -0
  121. package/dist/resizable.d.ts +302 -0
  122. package/dist/resizable.js +23 -0
  123. package/dist/scroll-area.d.ts +324 -0
  124. package/dist/scroll-area.js +49 -0
  125. package/dist/segmented-control.d.ts +24 -0
  126. package/dist/segmented-control.js +78 -0
  127. package/dist/segmented-input.d.ts +15 -0
  128. package/dist/segmented-input.js +48 -0
  129. package/dist/select.d.ts +125 -0
  130. package/dist/select.js +330 -0
  131. package/dist/separator.d.ts +290 -0
  132. package/dist/separator.js +9 -0
  133. package/dist/shortcuts.d.ts +32 -0
  134. package/dist/shortcuts.js +61 -0
  135. package/dist/slider.d.ts +38 -0
  136. package/dist/slider.js +163 -0
  137. package/dist/switch.d.ts +15 -0
  138. package/dist/switch.js +39 -0
  139. package/dist/tabs.d.ts +331 -0
  140. package/dist/tabs.js +28 -0
  141. package/dist/text-control.d.ts +22 -0
  142. package/dist/text-control.js +24 -0
  143. package/dist/text-match.d.ts +2 -0
  144. package/dist/text-match.js +8 -0
  145. package/dist/textarea.d.ts +10 -0
  146. package/dist/textarea.js +48 -0
  147. package/dist/time-input.d.ts +19 -0
  148. package/dist/time-input.js +63 -0
  149. package/dist/timeline.d.ts +327 -0
  150. package/dist/timeline.js +31 -0
  151. package/dist/toast-parts.d.ts +63 -0
  152. package/dist/toast-parts.js +144 -0
  153. package/dist/toast.d.ts +2 -0
  154. package/dist/toast.js +22 -0
  155. package/dist/toggle.d.ts +23 -0
  156. package/dist/toggle.js +76 -0
  157. package/dist/token-input.d.ts +35 -0
  158. package/dist/token-input.js +100 -0
  159. package/dist/toolbar-context.d.ts +6 -0
  160. package/dist/toolbar-context.js +16 -0
  161. package/dist/toolbar.d.ts +38 -0
  162. package/dist/toolbar.js +63 -0
  163. package/dist/tooltip.d.ts +39 -0
  164. package/dist/tooltip.js +108 -0
  165. package/dist/tree.d.ts +51 -0
  166. package/dist/tree.js +150 -0
  167. package/dist/trigger-menu.d.ts +83 -0
  168. package/dist/trigger-menu.js +167 -0
  169. package/dist/use-primitive.d.ts +178 -0
  170. package/dist/use-primitive.js +674 -0
  171. package/dist/waterfall.d.ts +80 -0
  172. package/dist/waterfall.js +108 -0
  173. package/docs/README.md +89 -0
  174. package/docs/agents.md +1523 -0
  175. package/docs/components/accordion.md +1391 -0
  176. package/docs/components/alert-dialog.md +850 -0
  177. package/docs/components/autocomplete.md +1963 -0
  178. package/docs/components/avatar.md +252 -0
  179. package/docs/components/button.md +444 -0
  180. package/docs/components/calendar.md +1687 -0
  181. package/docs/components/carousel.md +1244 -0
  182. package/docs/components/checkbox.md +1069 -0
  183. package/docs/components/collapsible.md +567 -0
  184. package/docs/components/color-picker.md +736 -0
  185. package/docs/components/combobox.md +3647 -0
  186. package/docs/components/command.md +1573 -0
  187. package/docs/components/date-input.md +608 -0
  188. package/docs/components/date-picker.md +1266 -0
  189. package/docs/components/dialog.md +1469 -0
  190. package/docs/components/drawer.md +1197 -0
  191. package/docs/components/field.md +549 -0
  192. package/docs/components/file-input.md +609 -0
  193. package/docs/components/hover-card.md +514 -0
  194. package/docs/components/image-cropper.md +579 -0
  195. package/docs/components/input.md +301 -0
  196. package/docs/components/label.md +217 -0
  197. package/docs/components/listbox.md +1130 -0
  198. package/docs/components/menu.md +1286 -0
  199. package/docs/components/menubar.md +455 -0
  200. package/docs/components/meter.md +304 -0
  201. package/docs/components/navigation-menu.md +1581 -0
  202. package/docs/components/number-input.md +1086 -0
  203. package/docs/components/otp-input.md +565 -0
  204. package/docs/components/pagination.md +648 -0
  205. package/docs/components/password-input.md +737 -0
  206. package/docs/components/popover.md +1552 -0
  207. package/docs/components/preferences.md +220 -0
  208. package/docs/components/progress.md +443 -0
  209. package/docs/components/radio.md +846 -0
  210. package/docs/components/rating.md +458 -0
  211. package/docs/components/resizable.md +982 -0
  212. package/docs/components/scroll-area.md +980 -0
  213. package/docs/components/segmented-control.md +465 -0
  214. package/docs/components/select.md +2133 -0
  215. package/docs/components/separator.md +243 -0
  216. package/docs/components/slider.md +1169 -0
  217. package/docs/components/switch.md +613 -0
  218. package/docs/components/tabs.md +1014 -0
  219. package/docs/components/textarea.md +318 -0
  220. package/docs/components/time-input.md +231 -0
  221. package/docs/components/timeline.md +677 -0
  222. package/docs/components/toast.md +1395 -0
  223. package/docs/components/toggle.md +541 -0
  224. package/docs/components/token-input.md +1007 -0
  225. package/docs/components/toolbar.md +787 -0
  226. package/docs/components/tooltip.md +884 -0
  227. package/docs/components/tree.md +1346 -0
  228. package/docs/components/trigger-menu.md +1257 -0
  229. package/docs/components/waterfall.md +754 -0
  230. package/docs/controllers.md +89 -0
  231. package/docs/core.md +8027 -0
  232. package/docs/custom-parts.md +120 -0
  233. package/docs/first-component.md +83 -0
  234. package/docs/forms.md +148 -0
  235. package/docs/hooks/async-options.md +366 -0
  236. package/docs/hooks/shortcuts.md +221 -0
  237. package/docs/installation.md +45 -0
  238. package/docs/introduction.md +32 -0
  239. package/docs/lists-and-menus.md +170 -0
  240. package/docs/llms.txt +1844 -0
  241. package/docs/parts-and-composition.md +93 -0
  242. package/docs/popups.md +117 -0
  243. package/docs/rendering.md +121 -0
  244. package/docs/server-rendering.md +253 -0
  245. package/docs/state-and-events.md +105 -0
  246. package/docs/styling-and-animation.md +176 -0
  247. package/package.json +333 -3
@@ -0,0 +1,151 @@
1
+ "use client";
2
+ // src/popover.tsx
3
+ import {
4
+ popover
5
+ } from "@ui-sdk/core/popover";
6
+ import * as React from "react";
7
+ import {
8
+ Connected,
9
+ renderPopup,
10
+ sheetViewport,
11
+ useOwnContainer,
12
+ usePopupContainer,
13
+ useControllerEntry
14
+ } from "./popup.js";
15
+ import {
16
+ createParts,
17
+ HandleScope,
18
+ renderElement,
19
+ useHandle,
20
+ useNearest,
21
+ usePart,
22
+ usePrimitive
23
+ } from "./use-primitive.js";
24
+ import { createPopoverController } from "@ui-sdk/core/popover";
25
+ import { jsx } from "react/jsx-runtime";
26
+ var parts = createParts(popover, {
27
+ trigger: "button",
28
+ title: "h2",
29
+ description: "p",
30
+ close: "button",
31
+ arrow: "div"
32
+ });
33
+ var ContainerContext = React.createContext(void 0);
34
+ var TriggerContext = React.createContext(null);
35
+ function Popover({ children, container, ...options }) {
36
+ const handle = usePrimitive(popover, options);
37
+ useControllerEntry(options.controller, handle);
38
+ return /* @__PURE__ */ jsx(HandleScope, { handle, children: /* @__PURE__ */ jsx(ContainerContext.Provider, { value: container, children }) });
39
+ }
40
+ function PopoverTrigger({
41
+ controller,
42
+ ...props
43
+ }) {
44
+ const {
45
+ disabled,
46
+ focusableWhenDisabled,
47
+ payload: _,
48
+ shortcut,
49
+ render,
50
+ ...rest
51
+ } = props;
52
+ const unconnected = () => renderElement(
53
+ "button",
54
+ {
55
+ type: "button",
56
+ disabled: disabled && !focusableWhenDisabled,
57
+ "aria-disabled": disabled && focusableWhenDisabled || void 0,
58
+ ...rest
59
+ },
60
+ render,
61
+ {
62
+ open: false,
63
+ disabled: !!disabled
64
+ }
65
+ );
66
+ return /* @__PURE__ */ jsx(TriggerContext.Provider, { value: { shortcut }, children: /* @__PURE__ */ jsx(
67
+ Connected,
68
+ {
69
+ primitive: popover,
70
+ controller,
71
+ fallback: unconnected,
72
+ children: /* @__PURE__ */ jsx(parts.Trigger, { ...props })
73
+ }
74
+ ) });
75
+ }
76
+ function PopoverContent({
77
+ side,
78
+ align,
79
+ sideOffset,
80
+ alignOffset,
81
+ collisionPadding,
82
+ arrowPadding,
83
+ anchor,
84
+ initialFocus,
85
+ finalFocus,
86
+ keepMounted,
87
+ container,
88
+ render,
89
+ ...props
90
+ }) {
91
+ const target = usePopupContainer(useOwnContainer(container, ContainerContext));
92
+ const content = {
93
+ side,
94
+ align,
95
+ sideOffset,
96
+ alignOffset,
97
+ collisionPadding,
98
+ arrowPadding,
99
+ anchor,
100
+ initialFocus,
101
+ finalFocus,
102
+ keepMounted
103
+ };
104
+ const handle = useHandle(popover);
105
+ const partProps = {
106
+ ...props,
107
+ render: sheetViewport(handle, render)
108
+ };
109
+ const element = usePart(handle, "content", content, partProps);
110
+ return element && renderPopup(element, target);
111
+ }
112
+ var PopoverTitle = parts.Title;
113
+ var PopoverDescription = parts.Description;
114
+ var PopoverClose = parts.Close;
115
+ var PopoverArrow = parts.Arrow;
116
+ function PopoverShortcut(props) {
117
+ const trigger = React.useContext(TriggerContext);
118
+ if (useNearest(popover)) {
119
+ return /* @__PURE__ */ jsx(ShortcutPart, { inherited: trigger?.shortcut, ...props });
120
+ }
121
+ if (trigger) {
122
+ return null;
123
+ }
124
+ throw new Error("Popover parts must be used inside <Popover>.");
125
+ }
126
+ var text = (state) => state.text;
127
+ function ShortcutPart({
128
+ inherited,
129
+ shortcut,
130
+ children = text,
131
+ ...props
132
+ }) {
133
+ return usePart(
134
+ popover,
135
+ "shortcut",
136
+ { shortcut: shortcut ?? inherited },
137
+ { ...props, children },
138
+ "span"
139
+ );
140
+ }
141
+ export {
142
+ Popover,
143
+ PopoverArrow,
144
+ PopoverClose,
145
+ PopoverContent,
146
+ PopoverDescription,
147
+ PopoverShortcut,
148
+ PopoverTitle,
149
+ PopoverTrigger,
150
+ createPopoverController
151
+ };
@@ -0,0 +1,41 @@
1
+ import type { Primitive } from "@ui-sdk/core";
2
+ import * as React from "react";
3
+ import { type PrimitiveHandle, type RenderProp } from "./use-primitive.js";
4
+ type PopupContainer = Element | DocumentFragment | null | undefined;
5
+ declare function usePopupContainer(own: PopupContainer): PopupContainer;
6
+ declare function useOwnContainer(own: PopupContainer, root: React.Context<PopupContainer>): PopupContainer;
7
+ declare function renderPopup(element: React.ReactElement, container: PopupContainer): React.JSX.Element;
8
+ /**
9
+ * A popup content's `render`: the content, inside the full-screen viewport a
10
+ * sheet sits in while its `viewport` slot is present: always for a drawer,
11
+ * and for a popup while it presents as a sheet. The viewport is what goes
12
+ * into the top layer. Its attributes are a subset of the content's, so the
13
+ * content's render keeps it current.
14
+ */
15
+ declare function sheetViewport<State>(popup: PrimitiveHandle<Primitive>, render?: RenderProp<State>): (props: Record<string, any>, state: State) => React.JSX.Element;
16
+ /**
17
+ * Where an input renders while its popup presents as a sheet: in a header the
18
+ * content renders at its top. The root keeps the header element, the content
19
+ * renders it with `sheetHeader`, and the input renders into it with
20
+ * `inSheetHeader`, so there's one input at a time.
21
+ */
22
+ declare const SheetHeaderContext: React.Context<[HTMLElement | null, (header: HTMLElement | null) => void]>;
23
+ /** The header at the top of a sheet's content, while the popup's `header` slot is present. */
24
+ declare function sheetHeader(popup: PrimitiveHandle<Primitive>, setHeader: (header: HTMLElement | null) => void): React.JSX.Element | null;
25
+ /** Renders an input into the sheet's header while there is one. */
26
+ declare function inSheetHeader(element: React.ReactElement, header: HTMLElement | null): React.ReactElement<unknown, string | React.JSXElementConstructor<any>>;
27
+ /**
28
+ * A part that can sit outside its component, like a trigger in a table row:
29
+ * its children render with the instance `controller` connects them to, once
30
+ * that one mounts, or else with the nearest instance of `primitive`, and
31
+ * `fallback` renders until there is one. `fallback` is a function, so a
32
+ * connected part never builds it.
33
+ */
34
+ declare function Connected({ primitive, controller, fallback, children, }: {
35
+ primitive: Primitive;
36
+ controller: object | undefined;
37
+ fallback: () => React.ReactNode;
38
+ children: React.ReactNode;
39
+ }): string | number | bigint | boolean | Iterable<React.ReactNode> | Promise<string | number | bigint | boolean | React.ReactPortal | React.ReactElement<unknown, string | React.JSXElementConstructor<any>> | Iterable<React.ReactNode> | null | undefined> | React.JSX.Element | null | undefined;
40
+ export { useControllerEntry, useControllerTarget } from "./controller-target.js";
41
+ export { Connected, inSheetHeader, type PopupContainer, renderPopup, sheetHeader, SheetHeaderContext, sheetViewport, useOwnContainer, usePopupContainer, };
package/dist/popup.js ADDED
@@ -0,0 +1,180 @@
1
+ "use client";
2
+ // src/popup.tsx
3
+ import { portalTarget } from "@ui-sdk/core/renderer";
4
+ import * as React from "react";
5
+ import { createPortal } from "react-dom";
6
+ import { useControllerTarget } from "./controller-target.js";
7
+ import { mergeRefs } from "./render-element.js";
8
+ import {
9
+ HandleScope,
10
+ presentIn,
11
+ renderElement,
12
+ slotIn,
13
+ useNearest
14
+ } from "./use-primitive.js";
15
+ import { useControllerEntry, useControllerTarget as useControllerTarget2 } from "./controller-target.js";
16
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
17
+ var InheritedContainer = React.createContext(void 0);
18
+ function usePopupContainer(own) {
19
+ const inherited = React.useContext(InheritedContainer);
20
+ return own ?? inherited;
21
+ }
22
+ function useOwnContainer(own, root) {
23
+ const fromRoot = React.useContext(root);
24
+ return own ?? fromRoot;
25
+ }
26
+ function renderPopup(element, container) {
27
+ return /* @__PURE__ */ jsx(Popup, { element, container });
28
+ }
29
+ function Popup({
30
+ element,
31
+ container
32
+ }) {
33
+ const target = portalTarget(container);
34
+ const [tree] = React.useState(followTree);
35
+ React.useInsertionEffect(() => {
36
+ if (target) {
37
+ tree.placed(target);
38
+ }
39
+ }, [tree, target]);
40
+ const part = element;
41
+ const tracked = React.cloneElement(part, {
42
+ ref: mergeRefs(part.props.ref ?? null, tree.track)
43
+ });
44
+ const content = container ? /* @__PURE__ */ jsx(InheritedContainer.Provider, { value: container, children: tracked }) : tracked;
45
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
46
+ /* @__PURE__ */ jsx(TreeEffect, { tree, target }),
47
+ target ? createPortal(content, target) : content
48
+ ] });
49
+ }
50
+ function followTree() {
51
+ let els = [];
52
+ let isShown = false;
53
+ let show;
54
+ let lastBefore = null;
55
+ const hideLater = () => queueMicrotask(() => {
56
+ if (isShown || show) {
57
+ return;
58
+ }
59
+ const shows = els.filter((el) => el.isConnected).map(hide);
60
+ if (shows.length) {
61
+ show = () => shows.forEach((run) => run());
62
+ }
63
+ });
64
+ const track = (next) => {
65
+ if (next instanceof HTMLElement && !els.includes(next)) {
66
+ els = [...els.filter((el) => el.isConnected), next];
67
+ }
68
+ };
69
+ return {
70
+ // The ref for the popup's element. React lets go of it while the tree is hidden, so it's kept.
71
+ track,
72
+ // Notes the container's last node before the portal appends the popup to it.
73
+ placing(target) {
74
+ lastBefore = target.lastChild;
75
+ },
76
+ // The nodes the portal appended after that one, if the popup rendered
77
+ // any. A render that waits a commit to render an element adds none, and
78
+ // the last node then belongs to someone else. They hide unless the tree shows.
79
+ placed(target) {
80
+ if (target.lastChild === lastBefore) {
81
+ return;
82
+ }
83
+ const first = !lastBefore ? target.firstChild : lastBefore.parentNode === target ? lastBefore.nextSibling : target.lastChild;
84
+ for (let node = first; node; node = node.nextSibling) {
85
+ track(node);
86
+ }
87
+ if (!isShown) {
88
+ hideLater();
89
+ }
90
+ },
91
+ shown() {
92
+ isShown = true;
93
+ show?.();
94
+ show = void 0;
95
+ },
96
+ hidden() {
97
+ isShown = false;
98
+ hideLater();
99
+ }
100
+ };
101
+ }
102
+ function TreeEffect({
103
+ tree,
104
+ target
105
+ }) {
106
+ React.useInsertionEffect(() => {
107
+ if (target) {
108
+ tree.placing(target);
109
+ }
110
+ }, [tree, target]);
111
+ React.useLayoutEffect(() => {
112
+ tree.shown();
113
+ return tree.hidden;
114
+ }, [tree]);
115
+ return null;
116
+ }
117
+ function hide(el) {
118
+ const doc = el.ownerDocument;
119
+ if (el.contains(doc.activeElement)) {
120
+ ;
121
+ doc.activeElement.blur();
122
+ }
123
+ for (const popover of [
124
+ el,
125
+ ...el.querySelectorAll("[popover]")
126
+ ]) {
127
+ try {
128
+ popover.hidePopover();
129
+ } catch {
130
+ }
131
+ }
132
+ const { style } = el;
133
+ if (style.display === "none") {
134
+ return () => {
135
+ };
136
+ }
137
+ const value = style.getPropertyValue("display");
138
+ const priority = style.getPropertyPriority("display");
139
+ style.setProperty("display", "none", "important");
140
+ return () => style.setProperty("display", value, priority);
141
+ }
142
+ function sheetViewport(popup, render) {
143
+ return (props, state) => {
144
+ const element = renderElement("div", props, render, state);
145
+ return presentIn(popup, "viewport") ? /* @__PURE__ */ jsx("div", { ...slotIn(popup, "viewport", {}), children: element }) : element;
146
+ };
147
+ }
148
+ var SheetHeaderContext = /* @__PURE__ */ React.createContext([null, () => {
149
+ }]);
150
+ function sheetHeader(popup, setHeader) {
151
+ return presentIn(popup, "header") ? /* @__PURE__ */ jsx("div", { ...slotIn(popup, "header", {}, { ref: setHeader }) }) : null;
152
+ }
153
+ function inSheetHeader(element, header) {
154
+ return header ? createPortal(element, header) : element;
155
+ }
156
+ function Connected({
157
+ primitive,
158
+ controller,
159
+ fallback,
160
+ children
161
+ }) {
162
+ const nearest = useNearest(primitive);
163
+ const handle = useControllerTarget(controller, nearest);
164
+ if (!handle) {
165
+ return fallback();
166
+ }
167
+ return controller ? /* @__PURE__ */ jsx(HandleScope, { handle, children }) : children;
168
+ }
169
+ export {
170
+ Connected,
171
+ SheetHeaderContext,
172
+ inSheetHeader,
173
+ renderPopup,
174
+ sheetHeader,
175
+ sheetViewport,
176
+ useControllerEntry,
177
+ useControllerTarget2 as useControllerTarget,
178
+ useOwnContainer,
179
+ usePopupContainer
180
+ };
@@ -0,0 +1,35 @@
1
+ import { type PreferenceLike } from "@ui-sdk/core";
2
+ import * as React from "react";
3
+ /**
4
+ * Props of `Preferences`.
5
+ * @experimental
6
+ */
7
+ type PreferencesProps = Omit<React.ComponentProps<"div">, "children"> & {
8
+ /** The preferences to show, from `createPreference` or `createColorScheme`. */
9
+ preferences: readonly PreferenceLike[];
10
+ /** The nonce your Content Security Policy gives inline scripts. */
11
+ nonce?: string;
12
+ children?: React.ReactNode;
13
+ };
14
+ /**
15
+ * Shows preferences on `data-*` attributes, so CSS styles by them from the
16
+ * first paint: global ones on `<html>`, the rest on its own element, which
17
+ * has `display: contents`. On the server it renders one inline script as its
18
+ * first child, which puts every saved value on its attribute as the page
19
+ * loads, before hydration. Content that reads a preference, through
20
+ * `usePreference`, catches up after hydration.
21
+ * @experimental
22
+ */
23
+ declare function Preferences({ preferences, nonce, children, style, ref, ...props }: PreferencesProps): React.JSX.Element;
24
+ /**
25
+ * A preference's state, like `{ value: "dark" }`, or a color scheme's. It's
26
+ * the server's while hydrating, so the page hydrates without a mismatch, and
27
+ * the saved value right after.
28
+ * @experimental
29
+ */
30
+ declare function usePreference<State>(preference: {
31
+ get: () => State;
32
+ initialState: State;
33
+ subscribe: (listener: () => void) => () => void;
34
+ }): State;
35
+ export { Preferences, type PreferencesProps, usePreference };
@@ -0,0 +1,93 @@
1
+ "use client";
2
+ // src/preferences.tsx
3
+ import { preferencesScript } from "@ui-sdk/core";
4
+ import * as React from "react";
5
+ import { mergeRefs } from "./render-element.js";
6
+ import { jsx, jsxs } from "react/jsx-runtime";
7
+ var noSubscribe = () => () => {
8
+ };
9
+ function useStable(preferences) {
10
+ const ref = React.useRef(preferences);
11
+ const same = ref.current.length === preferences.length && ref.current.every((preference, index) => preference === preferences[index]);
12
+ if (!same) {
13
+ ref.current = preferences;
14
+ }
15
+ return ref.current;
16
+ }
17
+ function Preferences({
18
+ preferences,
19
+ nonce,
20
+ children,
21
+ style,
22
+ ref,
23
+ ...props
24
+ }) {
25
+ const list = useStable(preferences);
26
+ const element = React.useRef(null);
27
+ const fromServer = React.useSyncExternalStore(
28
+ noSubscribe,
29
+ () => false,
30
+ () => true
31
+ );
32
+ const subscribe = React.useCallback(
33
+ (listener) => {
34
+ const stops = list.map((preference) => preference.subscribe(listener));
35
+ return () => stops.forEach((stop) => stop());
36
+ },
37
+ [list]
38
+ );
39
+ const values = React.useSyncExternalStore(
40
+ subscribe,
41
+ () => JSON.stringify(list.map((preference) => preference.get().value)),
42
+ () => JSON.stringify(list.map((preference) => preference.initialState.value))
43
+ );
44
+ React.useEffect(() => {
45
+ for (const preference of list) {
46
+ ;
47
+ (preference.global ? document.documentElement : element.current)?.setAttribute(preference.attribute, preference.get().value);
48
+ }
49
+ }, [list, values]);
50
+ const shown = JSON.parse(values);
51
+ const attributes = {};
52
+ list.forEach((preference, index) => {
53
+ if (!preference.global) {
54
+ attributes[preference.attribute] = shown[index];
55
+ }
56
+ });
57
+ return (
58
+ // The script changes these attributes before hydration, so they may differ from the server's HTML.
59
+ /* @__PURE__ */ jsxs(
60
+ "div",
61
+ {
62
+ "data-slot": "preferences",
63
+ ...attributes,
64
+ ...props,
65
+ ref: mergeRefs(element, ref ?? null),
66
+ style: { display: "contents", ...style },
67
+ suppressHydrationWarning: true,
68
+ children: [
69
+ fromServer ? /* @__PURE__ */ jsx(
70
+ "script",
71
+ {
72
+ nonce,
73
+ suppressHydrationWarning: true,
74
+ dangerouslySetInnerHTML: { __html: preferencesScript(list) }
75
+ }
76
+ ) : null,
77
+ children
78
+ ]
79
+ }
80
+ )
81
+ );
82
+ }
83
+ function usePreference(preference) {
84
+ return React.useSyncExternalStore(
85
+ preference.subscribe,
86
+ preference.get,
87
+ () => preference.initialState
88
+ );
89
+ }
90
+ export {
91
+ Preferences,
92
+ usePreference
93
+ };
@@ -0,0 +1,2 @@
1
+ export { mergeProps, renderElement, type RenderProp } from "./render-element.js";
2
+ export { createParts, type GenericPartComponent, type PartComponent, usePart, usePrimitive, type PartProps, type Parts, type PrimitiveHandle, } from "./use-primitive.js";
@@ -0,0 +1,14 @@
1
+ // src/primitive.ts
2
+ import { mergeProps, renderElement } from "./render-element.js";
3
+ import {
4
+ createParts,
5
+ usePart,
6
+ usePrimitive
7
+ } from "./use-primitive.js";
8
+ export {
9
+ createParts,
10
+ mergeProps,
11
+ renderElement,
12
+ usePart,
13
+ usePrimitive
14
+ };