@parallelworks/ui 0.76.0 → 0.78.0

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 (270) hide show
  1. package/README.md +30 -5
  2. package/dist/access/AccessDrawer.d.ts +28 -7
  3. package/dist/access/AccessDrawer.js +216 -35
  4. package/dist/access/AccessList.d.ts +19 -1
  5. package/dist/access/AccessList.js +220 -9
  6. package/dist/access/GrantView.d.ts +3 -1
  7. package/dist/access/GrantView.js +17 -4
  8. package/dist/access/PrincipalPicker.js +5 -5
  9. package/dist/access/focus.js +1 -1
  10. package/dist/access/index.d.ts +2 -2
  11. package/dist/access/index.js +2 -2
  12. package/dist/access/strings.d.ts +18 -0
  13. package/dist/access/strings.js +20 -2
  14. package/dist/access/types.d.ts +26 -0
  15. package/dist/ai/adapter/types.d.ts +1 -0
  16. package/dist/ai/components/AllocationSelector.js +1 -1
  17. package/dist/ai/components/AttachmentManager.js +5 -5
  18. package/dist/ai/components/AttachmentUpload.js +2 -2
  19. package/dist/ai/components/BranchNavigator.js +1 -1
  20. package/dist/ai/components/ChatActivity.d.ts +2 -0
  21. package/dist/ai/components/ChatActivity.js +31 -0
  22. package/dist/ai/components/ChatEmptyState.js +3 -3
  23. package/dist/ai/components/ChatInput.js +3 -5
  24. package/dist/ai/components/ChatLayout.js +1 -1
  25. package/dist/ai/components/ChatMessage.js +1 -1
  26. package/dist/ai/components/ChatMessageList.js +2 -2
  27. package/dist/ai/components/ChatSidebar.js +3 -3
  28. package/dist/ai/components/ChatThread.js +4 -4
  29. package/dist/ai/components/ComposerAddMenu.js +9 -20
  30. package/dist/ai/components/ModelSelector.js +3 -3
  31. package/dist/ai/components/PastedText.js +5 -5
  32. package/dist/ai/components/SessionView.js +5 -2
  33. package/dist/ai/components/ShareDialog.js +3 -3
  34. package/dist/ai/components/SlashMenu.d.ts +31 -4
  35. package/dist/ai/components/SlashMenu.js +36 -63
  36. package/dist/ai/components/agent/ActivityLine.js +1 -1
  37. package/dist/ai/components/agent/AgentMessageParts.d.ts +1 -1
  38. package/dist/ai/components/agent/AgentMessageParts.js +44 -18
  39. package/dist/ai/components/conversationActions.js +3 -3
  40. package/dist/ai/core/ChatProvider.js +11 -2
  41. package/dist/ai/core/config.d.ts +10 -1
  42. package/dist/ai/core/config.js +1 -1
  43. package/dist/ai/index.d.ts +1 -1
  44. package/dist/ai/strings.d.ts +2 -0
  45. package/dist/ai/strings.js +2 -1
  46. package/dist/ai/types.d.ts +3 -0
  47. package/dist/ai/ui/ConversationSidebar.js +3 -3
  48. package/dist/ai/ui/sidebar.js +3 -3
  49. package/dist/assets/yaml.worker-DOBV2lND.js +884 -0
  50. package/dist/components/ActionMenu.d.ts +38 -9
  51. package/dist/components/ActionMenu.js +48 -22
  52. package/dist/components/Avatar.d.ts +66 -6
  53. package/dist/components/Avatar.js +130 -18
  54. package/dist/components/Breadcrumbs.d.ts +4 -0
  55. package/dist/components/Breadcrumbs.js +26 -10
  56. package/dist/components/Button.d.ts +3 -2
  57. package/dist/components/Button.js +11 -1
  58. package/dist/components/Callout.d.ts +3 -2
  59. package/dist/components/Callout.js +3 -2
  60. package/dist/components/Card.d.ts +33 -9
  61. package/dist/components/Card.js +24 -8
  62. package/dist/components/Checkbox.d.ts +3 -1
  63. package/dist/components/Checkbox.js +4 -2
  64. package/dist/components/ColorInput.js +1 -1
  65. package/dist/components/Combobox.d.ts +23 -0
  66. package/dist/components/Combobox.js +252 -86
  67. package/dist/components/ConfirmModal.d.ts +26 -2
  68. package/dist/components/ConfirmModal.js +81 -15
  69. package/dist/components/ContextMenu.d.ts +29 -2
  70. package/dist/components/ContextMenu.js +60 -8
  71. package/dist/components/CopyButton.d.ts +21 -8
  72. package/dist/components/CopyButton.js +29 -9
  73. package/dist/components/CreateModal.d.ts +16 -4
  74. package/dist/components/CreateModal.js +27 -16
  75. package/dist/components/DatePicker.d.ts +31 -1
  76. package/dist/components/DatePicker.js +178 -47
  77. package/dist/components/DescriptionList.d.ts +13 -3
  78. package/dist/components/DescriptionList.js +43 -11
  79. package/dist/components/Disclosure.d.ts +10 -2
  80. package/dist/components/Disclosure.js +18 -7
  81. package/dist/components/Drawer.js +5 -5
  82. package/dist/components/EmptyState.d.ts +12 -4
  83. package/dist/components/EmptyState.js +18 -10
  84. package/dist/components/ErrorPage.d.ts +40 -0
  85. package/dist/components/ErrorPage.js +101 -0
  86. package/dist/components/ExternalLink.d.ts +4 -1
  87. package/dist/components/ExternalLink.js +4 -5
  88. package/dist/components/Field.d.ts +21 -6
  89. package/dist/components/Field.js +32 -16
  90. package/dist/components/FileButton.d.ts +19 -0
  91. package/dist/components/FileButton.js +32 -0
  92. package/dist/components/HoverCard.d.ts +26 -6
  93. package/dist/components/HoverCard.js +11 -5
  94. package/dist/components/IconButton.js +4 -2
  95. package/dist/components/InfoTip.js +3 -3
  96. package/dist/components/Input.d.ts +33 -3
  97. package/dist/components/Input.js +149 -14
  98. package/dist/components/Kbd.d.ts +40 -0
  99. package/dist/components/Kbd.js +168 -0
  100. package/dist/components/Listbox.d.ts +103 -0
  101. package/dist/components/Listbox.js +190 -0
  102. package/dist/components/Loader.d.ts +8 -2
  103. package/dist/components/Loader.js +16 -1
  104. package/dist/components/Markdown.js +1 -1
  105. package/dist/components/MarkdownImpl.js +1 -1
  106. package/dist/components/Menu.d.ts +20 -2
  107. package/dist/components/Menu.js +48 -19
  108. package/dist/components/MenuEntries.d.ts +38 -2
  109. package/dist/components/MenuEntries.js +266 -39
  110. package/dist/components/Meter.d.ts +50 -11
  111. package/dist/components/Meter.js +71 -21
  112. package/dist/components/Modal.d.ts +9 -3
  113. package/dist/components/Modal.js +68 -29
  114. package/dist/components/OneTimeCodeInput.js +1 -1
  115. package/dist/components/PageHeader.js +111 -7
  116. package/dist/components/PageHeaderAction.d.ts +8 -3
  117. package/dist/components/PageHeaderAction.js +122 -34
  118. package/dist/components/Pagination.d.ts +13 -1
  119. package/dist/components/Pagination.js +90 -19
  120. package/dist/components/Popover.d.ts +13 -2
  121. package/dist/components/Popover.js +20 -21
  122. package/dist/components/Provider.d.ts +140 -3
  123. package/dist/components/Provider.js +142 -12
  124. package/dist/components/RefreshButton.d.ts +13 -6
  125. package/dist/components/RefreshButton.js +17 -9
  126. package/dist/components/RunStatusIcon.d.ts +16 -7
  127. package/dist/components/RunStatusIcon.js +21 -8
  128. package/dist/components/Section.d.ts +11 -4
  129. package/dist/components/Section.js +33 -22
  130. package/dist/components/SegmentedControl.d.ts +16 -3
  131. package/dist/components/SegmentedControl.js +7 -3
  132. package/dist/components/Select.d.ts +19 -3
  133. package/dist/components/Select.js +114 -68
  134. package/dist/components/SelectionCopy.d.ts +10 -0
  135. package/dist/components/SelectionCopy.js +105 -0
  136. package/dist/components/SettingModeOption.js +1 -1
  137. package/dist/components/SettingsCard.js +1 -1
  138. package/dist/components/Skeleton.js +1 -1
  139. package/dist/components/StatusBadge.d.ts +55 -10
  140. package/dist/components/StatusBadge.js +91 -15
  141. package/dist/components/StickyBar.js +1 -1
  142. package/dist/components/Table.d.ts +22 -4
  143. package/dist/components/Table.js +46 -24
  144. package/dist/components/Tabs.d.ts +9 -4
  145. package/dist/components/Tabs.js +9 -4
  146. package/dist/components/Tag.d.ts +49 -0
  147. package/dist/components/Tag.js +199 -0
  148. package/dist/components/ThemeEditor.js +1 -1
  149. package/dist/components/Toast.js +1 -1
  150. package/dist/components/ToggleGroup.d.ts +4 -1
  151. package/dist/components/ToggleGroup.js +30 -13
  152. package/dist/components/Tooltip.d.ts +9 -3
  153. package/dist/components/Tooltip.js +55 -39
  154. package/dist/components/buttonClasses.d.ts +5 -2
  155. package/dist/components/buttonClasses.js +11 -10
  156. package/dist/components/chart.d.ts +69 -0
  157. package/dist/components/chart.js +145 -0
  158. package/dist/components/comboboxItems.d.ts +7 -1
  159. package/dist/components/comboboxItems.js +6 -2
  160. package/dist/components/dismiss.d.ts +5 -1
  161. package/dist/components/dismiss.js +6 -2
  162. package/dist/components/floating.d.ts +4 -4
  163. package/dist/components/floating.js +5 -5
  164. package/dist/components/headerActionsFit.d.ts +37 -0
  165. package/dist/components/headerActionsFit.js +81 -0
  166. package/dist/components/pageHeaderStore.d.ts +3 -0
  167. package/dist/components/pageHeaderStore.js +3 -0
  168. package/dist/components/pathBreaks.js +2 -2
  169. package/dist/components/popupContainer.d.ts +17 -0
  170. package/dist/components/popupContainer.js +69 -0
  171. package/dist/components/relativeTime.d.ts +21 -10
  172. package/dist/components/relativeTime.js +50 -22
  173. package/dist/components/segmented.d.ts +18 -4
  174. package/dist/components/segmented.js +48 -6
  175. package/dist/components/typedDate.d.ts +5 -0
  176. package/dist/components/typedDate.js +50 -0
  177. package/dist/components/useClosingValue.d.ts +4 -0
  178. package/dist/components/useClosingValue.js +12 -0
  179. package/dist/components/useCopy.d.ts +6 -0
  180. package/dist/components/useCopy.js +3 -3
  181. package/dist/components/useNarrow.d.ts +2 -0
  182. package/dist/components/useNarrow.js +16 -0
  183. package/dist/editor/Editor.js +1 -1
  184. package/dist/editor/FormCodePanel.js +1 -1
  185. package/dist/editor/Monaco.js +1 -1
  186. package/dist/editor/workers.js +1 -1
  187. package/dist/file-explorer/FileExplorer.js +16 -15
  188. package/dist/file-explorer/FileExplorerContext.js +2 -2
  189. package/dist/file-explorer/FilePreview/Viewer.js +3 -3
  190. package/dist/file-explorer/FilePreview/index.js +2 -2
  191. package/dist/file-explorer/FileRowsWindow.js +3 -3
  192. package/dist/file-explorer/FileTable.js +1 -1
  193. package/dist/file-explorer/LoadMoreRow.js +1 -1
  194. package/dist/file-explorer/TreeView.js +5 -5
  195. package/dist/file-explorer/helpers.js +2 -2
  196. package/dist/file-explorer/toasts.js +2 -2
  197. package/dist/form/Fields/CheckboxGroupField.js +1 -1
  198. package/dist/form/Fields/DropdownField.js +1 -1
  199. package/dist/form/Fields/DurationField.js +2 -2
  200. package/dist/form/Fields/MultiDropdownField.js +1 -1
  201. package/dist/form/Fields/NumberField.js +1 -1
  202. package/dist/form/Fields/ObjectField.js +1 -1
  203. package/dist/form/Fields/RangeField.js +1 -1
  204. package/dist/form/Fields/StringField.js +1 -1
  205. package/dist/form/Form.js +3 -3
  206. package/dist/form/FormLayout.js +1 -1
  207. package/dist/form/Wizard/WizardContainer.js +1 -1
  208. package/dist/form/Wizard/WizardNavigation.js +1 -1
  209. package/dist/form/Wizard/WizardStepContent.js +1 -1
  210. package/dist/form/fieldRegistry.js +1 -1
  211. package/dist/form/formEditing.js +1 -1
  212. package/dist/format.d.ts +17 -7
  213. package/dist/format.js +39 -16
  214. package/dist/graph/AnnotationBanner.js +2 -2
  215. package/dist/graph/Connectors.js +5 -5
  216. package/dist/graph/DependencyGraph.js +10 -9
  217. package/dist/graph/GraphEditor.js +4 -4
  218. package/dist/graph/GraphEditorDialogs.js +13 -12
  219. package/dist/graph/GraphNode.js +1 -1
  220. package/dist/graph/InputDialog.js +5 -5
  221. package/dist/graph/InputsEditor.js +7 -7
  222. package/dist/graph/MatrixGroup.js +2 -2
  223. package/dist/graph/ProblemsButton.js +3 -3
  224. package/dist/graph/Reveal.js +1 -1
  225. package/dist/graph/RunWarningsList.js +1 -1
  226. package/dist/graph/ShortcutsButton.js +25 -8
  227. package/dist/graph/StepSummaries.js +1 -1
  228. package/dist/graph/TreeView.js +2 -2
  229. package/dist/graph/WorkflowSettingsDialog.js +3 -3
  230. package/dist/graph/editorFields.js +3 -3
  231. package/dist/graph/editorPrimitives.js +1 -1
  232. package/dist/graph/editorRows.js +5 -5
  233. package/dist/graph/fieldProblems.js +2 -2
  234. package/dist/graph/inputRefs.js +7 -6
  235. package/dist/graph/stepWith.js +2 -2
  236. package/dist/index.d.ts +30 -21
  237. package/dist/index.js +20 -12
  238. package/dist/list/ActionToolbar.d.ts +4 -0
  239. package/dist/list/ActionToolbar.js +35 -12
  240. package/dist/list/ListFilterBar.d.ts +42 -0
  241. package/dist/list/ListFilterBar.js +789 -0
  242. package/dist/list/ListPage.d.ts +42 -4
  243. package/dist/list/ListPage.js +56 -22
  244. package/dist/list/ListTable.d.ts +27 -3
  245. package/dist/list/ListTable.js +48 -23
  246. package/dist/list/ListToolbar.d.ts +31 -0
  247. package/dist/list/ListToolbar.js +43 -0
  248. package/dist/list/ListViewControls.d.ts +8 -4
  249. package/dist/list/ListViewControls.js +22 -14
  250. package/dist/list/UserHoverCard.d.ts +8 -2
  251. package/dist/list/UserHoverCard.js +26 -13
  252. package/dist/list/filterModel.d.ts +122 -0
  253. package/dist/list/filterModel.js +308 -0
  254. package/dist/list/index.d.ts +6 -2
  255. package/dist/list/index.js +6 -2
  256. package/dist/list/listSearch.d.ts +1 -1
  257. package/dist/list/listSearch.js +8 -4
  258. package/dist/list/listView.d.ts +24 -2
  259. package/dist/list/listView.js +47 -45
  260. package/dist/list/rowMenu.d.ts +10 -5
  261. package/dist/list/rowMenu.js +17 -7
  262. package/dist/list/useListFilters.d.ts +68 -0
  263. package/dist/list/useListFilters.js +252 -0
  264. package/dist/logviewer/LogViewer.js +4 -4
  265. package/dist/styles/theme.css +94 -0
  266. package/dist/styles.css +1 -1
  267. package/package.json +11 -11
  268. package/dist/assets/yaml.worker-k9AdOqzf.js +0 -1441
  269. package/dist/components/fullscreen.d.ts +0 -4
  270. package/dist/components/fullscreen.js +0 -18
@@ -1,9 +1,10 @@
1
1
  import { cx } from "../cx.js";
2
2
  import { fieldBox } from "./fieldBox.js";
3
3
  import { Field, RevealToggle } from "./Field.js";
4
+ import { useCallback, useEffect, useLayoutEffect, useRef, useState } from "react";
4
5
  import { jsx, jsxs } from "react/jsx-runtime";
5
- import { useState } from "react";
6
6
  import { Input } from "@base-ui/react/input";
7
+ import { flushSync } from "react-dom";
7
8
  //#region src/components/Input.tsx
8
9
  /** The Field around a control when it has a label; the control alone when it doesn't. */
9
10
  function framed({ label, hint, help, actions, description, error, size }, { id, required, disabled }, control) {
@@ -61,9 +62,48 @@ function Input$1({ label, hint, help, description, error, className, mono, size,
61
62
  }) : input;
62
63
  });
63
64
  }
64
- /** A multi-line text field that grows by hand. Placed in a Field, it takes the Field's label,
65
- * description and invalid state. */
66
- function Textarea({ label, hint, help, description, error, className, mono, size, ref, ...props }) {
65
+ var boxEdges = {
66
+ sm: "0.5rem + 2px",
67
+ md: "0.75rem + 2px",
68
+ lg: "1rem + 2px"
69
+ };
70
+ var sizesToContent = () => typeof CSS !== "undefined" && CSS.supports?.("field-sizing", "content") === true;
71
+ /** Sets a textarea's height to its text's while the browser can't, from its value. */
72
+ function useAutosize(enabled, value) {
73
+ const element = useRef(null);
74
+ const [native] = useState(sizesToContent);
75
+ const resize = useCallback(() => {
76
+ const el = element.current;
77
+ if (!el || native) return;
78
+ el.style.height = "auto";
79
+ el.style.height = `${el.scrollHeight + el.offsetHeight - el.clientHeight}px`;
80
+ }, [native]);
81
+ useLayoutEffect(() => {
82
+ if (enabled) resize();
83
+ }, [
84
+ enabled,
85
+ resize,
86
+ value
87
+ ]);
88
+ return {
89
+ element,
90
+ resize: enabled && !native ? resize : void 0
91
+ };
92
+ }
93
+ /** A multi-line text field that grows by hand, or with its text with `autosize`. Placed in a
94
+ * Field, it takes the Field's label, description and invalid state. */
95
+ function Textarea({ label, hint, help, description, error, className, mono, size = "md", ref, autosize, bare = false, secret = false, style, ...props }) {
96
+ const [revealed, setRevealed] = useState(false);
97
+ const autosizing = Boolean(autosize);
98
+ const maxRows = typeof autosize === "object" ? autosize.maxRows : void 0;
99
+ const { element, resize } = useAutosize(autosizing, props.value);
100
+ const edges = bare ? "0px" : boxEdges[size];
101
+ const setRef = useCallback((el) => {
102
+ element.current = el;
103
+ if (typeof ref === "function") ref(el);
104
+ else if (ref) ref.current = el;
105
+ }, [ref, element]);
106
+ const masked = secret && !revealed;
67
107
  return framed({
68
108
  label,
69
109
  hint,
@@ -71,16 +111,111 @@ function Textarea({ label, hint, help, description, error, className, mono, size
71
111
  description,
72
112
  error,
73
113
  size
74
- }, props, (control) => /* @__PURE__ */ jsx(Input, {
114
+ }, props, (control) => {
115
+ const textarea = /* @__PURE__ */ jsx(Input, {
116
+ ...secret && {
117
+ spellCheck: false,
118
+ autoComplete: "off",
119
+ autoCorrect: "off",
120
+ autoCapitalize: "off",
121
+ "data-1p-ignore": true
122
+ },
123
+ ...props,
124
+ ...joined(control, props),
125
+ onInput: (event) => {
126
+ resize?.();
127
+ props.onInput?.(event);
128
+ },
129
+ ref: setRef,
130
+ render: /* @__PURE__ */ jsx("textarea", {}),
131
+ style: {
132
+ ...autosizing && {
133
+ minHeight: `calc(${props.rows ?? 2}lh + ${edges})`,
134
+ ...maxRows !== void 0 && { maxHeight: `calc(${maxRows}lh + ${edges})` }
135
+ },
136
+ ...style
137
+ },
138
+ className: cx(bare ? "w-full min-w-0 border-0 bg-transparent p-0 text-(--theme-app) outline-none placeholder:text-(--theme-placeholder) disabled:cursor-not-allowed disabled:text-(--theme-placeholder)" : fieldBox({
139
+ size,
140
+ multiline: true
141
+ }), bare && {
142
+ sm: "text-xs",
143
+ md: "text-sm",
144
+ lg: "text-base"
145
+ }[size], autosizing ? "resize-none [field-sizing:content]" : cx(size === "sm" ? "min-h-16" : "min-h-24", !bare && "resize-y"), bare && !autosizing && "resize-none", (mono || secret) && "font-mono", secret && "pr-9", masked && "[-webkit-text-security:disc]", className)
146
+ });
147
+ return secret ? /* @__PURE__ */ jsxs("div", {
148
+ className: "relative w-full",
149
+ children: [textarea, /* @__PURE__ */ jsx(RevealToggle, {
150
+ revealed,
151
+ onRevealedChange: setRevealed,
152
+ disabled: props.disabled,
153
+ align: "top",
154
+ size
155
+ })]
156
+ }) : textarea;
157
+ });
158
+ }
159
+ /** A title edited where it reads: one line that wraps and grows, with no box until the
160
+ * pointer or focus is on it. Enter saves, Escape puts the saved title back, and leaving the
161
+ * field saves. */
162
+ function TitleInput({ value, onCommit, autoSelect = false, size = "xl", readOnly, className, onBlur, onFocus, onKeyDown, ref, ...props }) {
163
+ const [draft, setDraft] = useState(value);
164
+ const editing = useRef(false);
165
+ const element = useRef(null);
166
+ const [shown, setShown] = useState(value);
167
+ if (value !== shown) {
168
+ setShown(value);
169
+ if (!editing.current) setDraft(value);
170
+ }
171
+ const { resize } = useAutosize(true, draft);
172
+ useEffect(() => {
173
+ if (autoSelect && element.current) {
174
+ element.current.focus();
175
+ element.current.select();
176
+ }
177
+ }, []);
178
+ const setRef = useCallback((el) => {
179
+ element.current = el;
180
+ if (typeof ref === "function") ref(el);
181
+ else if (ref) ref.current = el;
182
+ }, [ref]);
183
+ return /* @__PURE__ */ jsx("textarea", {
75
184
  ...props,
76
- ...joined(control, props),
77
- ref,
78
- render: /* @__PURE__ */ jsx("textarea", {}),
79
- className: cx(fieldBox({
80
- size,
81
- multiline: true
82
- }), size === "sm" ? "min-h-16" : "min-h-24", "resize-y", mono && "font-mono", className)
83
- }));
185
+ ref: setRef,
186
+ rows: 1,
187
+ value: draft,
188
+ readOnly,
189
+ spellCheck: props.spellCheck ?? true,
190
+ onChange: (event) => {
191
+ setDraft(event.target.value.replace(/\s*\n+\s*/g, " "));
192
+ resize?.();
193
+ },
194
+ onFocus: (event) => {
195
+ editing.current = true;
196
+ onFocus?.(event);
197
+ },
198
+ onBlur: (event) => {
199
+ editing.current = false;
200
+ const title = draft.trim();
201
+ if (title && title !== value) onCommit(title);
202
+ else setDraft(value);
203
+ onBlur?.(event);
204
+ },
205
+ onKeyDown: (event) => {
206
+ onKeyDown?.(event);
207
+ if (event.defaultPrevented || event.nativeEvent.isComposing) return;
208
+ if (event.key === "Enter") {
209
+ event.preventDefault();
210
+ event.currentTarget.blur();
211
+ } else if (event.key === "Escape") {
212
+ event.preventDefault();
213
+ flushSync(() => setDraft(value));
214
+ event.currentTarget.blur();
215
+ }
216
+ },
217
+ className: cx("-mx-1.5 block w-[calc(100%+0.75rem)] min-w-0 resize-none overflow-hidden rounded-md border-0 bg-transparent px-1.5 py-0.5 font-semibold tracking-tight text-(--theme-app) outline-none transition-colors [field-sizing:content] placeholder:text-(--theme-placeholder)", size === "xl" ? "text-2xl leading-tight" : "text-lg leading-snug", !readOnly && "hover:bg-(--theme-hover) focus-visible:bg-transparent focus-visible:ring-1 focus-visible:ring-(--theme-focus)", className)
218
+ });
84
219
  }
85
220
  //#endregion
86
- export { Input$1 as Input, Textarea, framed };
221
+ export { Input$1 as Input, Textarea, TitleInput, framed };
@@ -0,0 +1,40 @@
1
+ import { type UIStrings } from './Provider.js';
2
+ type KeyNames = UIStrings['keys'];
3
+ /** Whether the keyboard is an Apple one, whose Command key does what Control does elsewhere. */
4
+ export declare function isApplePlatform(): boolean;
5
+ /** A shortcut's platform: `apple` shows ⌘ ⌥ ⇧ ⌃ and takes Command for `Mod`; `other` names
6
+ * the keys and takes Control. */
7
+ export type KeyPlatform = 'apple' | 'other';
8
+ /** The keys of a shortcut as its keycaps read: `Mod+K` is ⌘ K on an Apple keyboard and Ctrl K
9
+ * elsewhere. A string is a combination joined by `+`; an array lists its keys as given, such
10
+ * as `['[', ']']` or `['1–9']`. Pass `names` from the strings, so key names are localized. */
11
+ export declare function formatShortcut(keys: string | readonly string[], names?: KeyNames, platform?: KeyPlatform): string[];
12
+ /** A shortcut as one line of text, for a title or a sentence: ⌘K, or Ctrl+K. */
13
+ export declare function shortcutText(keys: string | readonly string[], names?: KeyNames, platform?: KeyPlatform): string;
14
+ /** The `aria-keyshortcuts` value for a combination: `Mod+K` is `Meta+K` on an Apple keyboard
15
+ * and `Control+K` elsewhere. Set it on the control the shortcut presses. */
16
+ export declare function ariaKeyShortcuts(keys: string, platform?: KeyPlatform): string;
17
+ /** `formatShortcut` and `shortcutText` in the host's key names. */
18
+ export declare function useShortcutFormat(platform?: KeyPlatform): {
19
+ format: (keys: string | readonly string[]) => string[];
20
+ text: (keys: string | readonly string[]) => string;
21
+ };
22
+ export type KbdVariant = 'keycap' | 'plain';
23
+ export type KbdSize = 'xs' | 'sm';
24
+ export interface KbdProps {
25
+ /** A combination joined by `+`, such as `Mod+K` (Command on an Apple keyboard, Control
26
+ * elsewhere) or `Shift+Enter`; or keys side by side, as given: `['↑', '↓']`, `['1–9']`. */
27
+ keys: string | readonly string[];
28
+ /** `keycap`, the default, draws each key; `plain` is muted text, for a menu row. */
29
+ variant?: KbdVariant | undefined;
30
+ /** `xs` (16px, 10px text) for a hint inside a row or a field; `sm` (18px, 11px) otherwise. */
31
+ size?: KbdSize | undefined;
32
+ /** Which keyboard to show the keys for; the reader's own by default. */
33
+ platform?: KeyPlatform | undefined;
34
+ className?: string | undefined;
35
+ }
36
+ /** Keys to press, as keycaps: a muted fill, a hairline border and monospace text. Off an
37
+ * Apple keyboard the keys of a combination are joined with a plus, as the platform writes
38
+ * them. Renders `<kbd>`, with a `<kbd>` for each key of a combination. */
39
+ export declare function Kbd({ keys, variant, size, platform, className }: KbdProps): import("react").JSX.Element;
40
+ export {};
@@ -0,0 +1,168 @@
1
+ import { cx } from "../cx.js";
2
+ import { useStrings } from "./Provider.js";
3
+ import { Fragment } from "react";
4
+ import { jsx, jsxs } from "react/jsx-runtime";
5
+ //#region src/components/Kbd.tsx
6
+ /** Whether the keyboard is an Apple one, whose Command key does what Control does elsewhere. */
7
+ function isApplePlatform() {
8
+ if (typeof navigator === "undefined") return false;
9
+ const data = navigator.userAgentData;
10
+ return /Mac|iPhone|iPad|iPod/i.test(data?.platform || navigator.userAgent);
11
+ }
12
+ var currentPlatform = () => isApplePlatform() ? "apple" : "other";
13
+ var DEFAULT_NAMES = {
14
+ ctrl: "Ctrl",
15
+ alt: "Alt",
16
+ shift: "Shift",
17
+ meta: "Meta",
18
+ enter: "Enter",
19
+ escape: "Esc",
20
+ space: "Space",
21
+ tab: "Tab",
22
+ backspace: "Backspace",
23
+ delete: "Delete"
24
+ };
25
+ var ALIASES = {
26
+ mod: "mod",
27
+ cmd: "meta",
28
+ command: "meta",
29
+ meta: "meta",
30
+ ctrl: "ctrl",
31
+ control: "ctrl",
32
+ alt: "alt",
33
+ option: "alt",
34
+ opt: "alt",
35
+ shift: "shift",
36
+ enter: "enter",
37
+ return: "enter",
38
+ esc: "escape",
39
+ escape: "escape",
40
+ space: "space",
41
+ tab: "tab",
42
+ backspace: "backspace",
43
+ delete: "delete",
44
+ del: "delete",
45
+ up: "up",
46
+ arrowup: "up",
47
+ down: "down",
48
+ arrowdown: "down",
49
+ left: "left",
50
+ arrowleft: "left",
51
+ right: "right",
52
+ arrowright: "right"
53
+ };
54
+ var ARROWS = {
55
+ up: "↑",
56
+ down: "↓",
57
+ left: "←",
58
+ right: "→"
59
+ };
60
+ var APPLE = {
61
+ meta: "⌘",
62
+ alt: "⌥",
63
+ shift: "⇧",
64
+ ctrl: "⌃",
65
+ enter: "↵"
66
+ };
67
+ var ARIA = {
68
+ meta: "Meta",
69
+ ctrl: "Control",
70
+ alt: "Alt",
71
+ shift: "Shift",
72
+ enter: "Enter",
73
+ escape: "Escape",
74
+ space: "Space",
75
+ tab: "Tab",
76
+ backspace: "Backspace",
77
+ delete: "Delete",
78
+ up: "ArrowUp",
79
+ down: "ArrowDown",
80
+ left: "ArrowLeft",
81
+ right: "ArrowRight"
82
+ };
83
+ /** Splits a combination such as `Mod+Shift+K` into its keys; `Mod++` ends with the plus key. */
84
+ function splitCombo(keys) {
85
+ const trimmed = keys.trim();
86
+ if (trimmed === "+") return ["+"];
87
+ const plusKey = trimmed.endsWith("++");
88
+ const parts = (plusKey ? trimmed.slice(0, -2) : trimmed).split("+").map((part) => part.trim()).filter(Boolean);
89
+ return plusKey ? [...parts, "+"] : parts;
90
+ }
91
+ function canonical(key, platform) {
92
+ const name = ALIASES[key.toLowerCase()];
93
+ if (name === "mod") return platform === "apple" ? "meta" : "ctrl";
94
+ return name;
95
+ }
96
+ function label(key, names, platform) {
97
+ const name = canonical(key, platform);
98
+ if (!name) return key.length === 1 ? key.toUpperCase() : key;
99
+ if (ARROWS[name]) return ARROWS[name];
100
+ if (platform === "apple" && APPLE[name]) return APPLE[name];
101
+ return names[name] ?? key;
102
+ }
103
+ /** The keys of a shortcut as its keycaps read: `Mod+K` is ⌘ K on an Apple keyboard and Ctrl K
104
+ * elsewhere. A string is a combination joined by `+`; an array lists its keys as given, such
105
+ * as `['[', ']']` or `['1–9']`. Pass `names` from the strings, so key names are localized. */
106
+ function formatShortcut(keys, names = DEFAULT_NAMES, platform = currentPlatform()) {
107
+ return (typeof keys === "string" ? splitCombo(keys) : keys).map((key) => label(key, names, platform));
108
+ }
109
+ /** A shortcut as one line of text, for a title or a sentence: ⌘K, or Ctrl+K. */
110
+ function shortcutText(keys, names = DEFAULT_NAMES, platform = currentPlatform()) {
111
+ const parts = formatShortcut(keys, names, platform);
112
+ if (typeof keys !== "string") return parts.join(" ");
113
+ return parts.join(platform === "apple" ? "" : "+");
114
+ }
115
+ /** The `aria-keyshortcuts` value for a combination: `Mod+K` is `Meta+K` on an Apple keyboard
116
+ * and `Control+K` elsewhere. Set it on the control the shortcut presses. */
117
+ function ariaKeyShortcuts(keys, platform = currentPlatform()) {
118
+ return splitCombo(keys).map((key) => {
119
+ const name = canonical(key, platform);
120
+ if (name) return ARIA[name] ?? key;
121
+ return key.length === 1 ? key.toUpperCase() : key;
122
+ }).join("+");
123
+ }
124
+ /** `formatShortcut` and `shortcutText` in the host's key names. */
125
+ function useShortcutFormat(platform) {
126
+ const { keys: names } = useStrings();
127
+ const on = platform ?? currentPlatform();
128
+ return {
129
+ format: (keys) => formatShortcut(keys, names, on),
130
+ text: (keys) => shortcutText(keys, names, on)
131
+ };
132
+ }
133
+ var keycap = {
134
+ xs: "min-h-4 min-w-4 px-[3px] py-px text-[10px]",
135
+ sm: "min-h-[18px] min-w-[18px] px-1 py-px text-[11px]"
136
+ };
137
+ /** Keys to press, as keycaps: a muted fill, a hairline border and monospace text. Off an
138
+ * Apple keyboard the keys of a combination are joined with a plus, as the platform writes
139
+ * them. Renders `<kbd>`, with a `<kbd>` for each key of a combination. */
140
+ function Kbd({ keys, variant = "keycap", size = "sm", platform, className }) {
141
+ const { keys: names } = useStrings();
142
+ const on = platform ?? currentPlatform();
143
+ const parts = formatShortcut(keys, names, on);
144
+ const chord = typeof keys === "string";
145
+ if (variant === "plain") return /* @__PURE__ */ jsx("kbd", {
146
+ className: cx("font-sans text-(--theme-muted-text-color) tabular-nums tracking-wide", size === "xs" ? "text-[10px]" : "text-[11px]", className),
147
+ children: chord ? shortcutText(keys, names, on) : parts.join(" ")
148
+ });
149
+ const cap = cx("inline-flex items-center justify-center rounded border border-(--theme-border) bg-(--theme-muted-panel-bg) font-mono leading-none font-normal text-(--theme-app) not-italic", keycap[size]);
150
+ if (parts.length === 1) return /* @__PURE__ */ jsx("kbd", {
151
+ className: cx(cap, className),
152
+ children: parts[0]
153
+ });
154
+ const plus = chord && on !== "apple";
155
+ return /* @__PURE__ */ jsx("kbd", {
156
+ className: cx("inline-flex flex-wrap items-center gap-0.5 align-middle", className),
157
+ children: parts.map((part, i) => /* @__PURE__ */ jsxs(Fragment, { children: [plus && i > 0 && /* @__PURE__ */ jsx("span", {
158
+ "aria-hidden": "true",
159
+ className: "text-[10px] text-(--theme-muted-text-color)",
160
+ children: "+"
161
+ }), /* @__PURE__ */ jsx("kbd", {
162
+ className: cap,
163
+ children: part
164
+ })] }, i))
165
+ });
166
+ }
167
+ //#endregion
168
+ export { Kbd, ariaKeyShortcuts, formatShortcut, isApplePlatform, shortcutText, useShortcutFormat };
@@ -0,0 +1,103 @@
1
+ import { type KeyboardEvent as ReactKeyboardEvent, type ReactNode } from 'react';
2
+ import { type FloatingAnchor } from './floating.js';
3
+ export interface ListboxNavigationOptions<T> {
4
+ items: readonly T[];
5
+ /** Called with the highlighted item on Enter, a `chooseKeys` key or a click. */
6
+ onChoose: (item: T, index: number) => void;
7
+ /** Called on Escape, such as to close the list until the text changes. */
8
+ onDismiss?: (() => void) | undefined;
9
+ /** False while the list isn't shown: the keys are then the host's own. Default true. */
10
+ open?: boolean | undefined;
11
+ /** Past the end comes the start, and before the start the end. Default true. */
12
+ loop?: boolean | undefined;
13
+ /** Keys that choose besides Enter. Default `['Tab']`. */
14
+ chooseKeys?: readonly string[] | undefined;
15
+ /** Home and End move to the first and last items rather than the caret, for a host whose
16
+ * text is a short query rather than prose. Default false. */
17
+ homeEnd?: boolean | undefined;
18
+ /** An item that can't be chosen, which the highlight passes over. */
19
+ isDisabled?: ((item: T) => boolean) | undefined;
20
+ }
21
+ /** Keys are DOM or React keyboard events alike, as an editor plugin and an input pass them. */
22
+ type AnyKeyboardEvent = KeyboardEvent | ReactKeyboardEvent;
23
+ /** The parts a highlighted list needs while focus stays on the box the reader types in, such
24
+ * as a text box, an editor or a search input: the highlight and its keys, and the ids that
25
+ * let assistive technology follow the highlight. Spread `hostProps` on the focused box,
26
+ * `listProps` on the list and `optionProps(i)` on each option, or draw them with
27
+ * ListboxPanel and ListboxOption. */
28
+ export declare function useListboxNavigation<T>({ items, onChoose, onDismiss, open, loop, chooseKeys, homeEnd, isDisabled, }: ListboxNavigationOptions<T>): {
29
+ /** The highlighted item's index, or -1 with nothing to show. */
30
+ active: number;
31
+ setActive: import("react").Dispatch<import("react").SetStateAction<number>>;
32
+ handleKey: (event: AnyKeyboardEvent) => boolean;
33
+ listId: string;
34
+ /** For the box that keeps focus: it points at the list and its highlighted option. */
35
+ hostProps: {
36
+ 'aria-autocomplete': 'list';
37
+ 'aria-controls': string | undefined;
38
+ 'aria-activedescendant': string | undefined;
39
+ };
40
+ listProps: {
41
+ id: string;
42
+ role: 'listbox';
43
+ };
44
+ optionProps: (index: number) => {
45
+ id: string;
46
+ role: 'option';
47
+ tabIndex: number;
48
+ 'aria-selected': boolean;
49
+ 'aria-disabled': true | undefined;
50
+ 'data-highlighted': true | undefined;
51
+ 'data-disabled': true | undefined;
52
+ onMouseDown: (event: {
53
+ preventDefault: () => void;
54
+ }) => void;
55
+ onMouseMove: () => void;
56
+ onClick: () => void;
57
+ };
58
+ };
59
+ export type ListboxNavigation<T> = ReturnType<typeof useListboxNavigation<T>>;
60
+ export interface ListboxPanelProps {
61
+ /** `listProps` from useListboxNavigation. */
62
+ listProps: {
63
+ id: string;
64
+ role: 'listbox';
65
+ };
66
+ /** Names the list for assistive technology. */
67
+ 'aria-label': string;
68
+ /** Under the list, such as which keys choose and dismiss. */
69
+ footer?: ReactNode;
70
+ /** In place of the options while there are none. */
71
+ empty?: ReactNode;
72
+ /** Opens at this element or point, such as an editor's caret, over the page and inside a
73
+ * modal dialog alike; without one the panel stands where the host places it. */
74
+ at?: FloatingAnchor | undefined;
75
+ /** With `at`: called when a press outside closes it. */
76
+ onDismiss?: (() => void) | undefined;
77
+ /** On the panel: its width or place. */
78
+ className?: string | undefined;
79
+ children: ReactNode;
80
+ }
81
+ /** The panel of a highlighted list that the reader drives from a box that keeps focus. */
82
+ export declare function ListboxPanel({ listProps, 'aria-label': label, footer, empty, at, onDismiss, className, children, }: ListboxPanelProps): import("react").JSX.Element;
83
+ export interface ListboxOptionProps {
84
+ /** `optionProps(index)` from useListboxNavigation. */
85
+ option: ReturnType<ListboxNavigation<unknown>['optionProps']>;
86
+ icon?: ReactNode;
87
+ label: ReactNode;
88
+ /** Under the label, or beside it with `inline`. */
89
+ description?: ReactNode;
90
+ /** The description on the label's line, as a command's summary beside its name. */
91
+ inline?: boolean | undefined;
92
+ /** Short muted text at the row's end, such as a key. */
93
+ hint?: ReactNode;
94
+ className?: string | undefined;
95
+ }
96
+ /** One option of a ListboxPanel: an icon, its label and description, and a hint at its end. */
97
+ export declare function ListboxOption({ option, icon, label, description, inline, hint, className, }: ListboxOptionProps): import("react").JSX.Element;
98
+ /** Options under a heading in a ListboxPanel. */
99
+ export declare function ListboxGroup({ label, children }: {
100
+ label: ReactNode;
101
+ children: ReactNode;
102
+ }): import("react").JSX.Element;
103
+ export {};
@@ -0,0 +1,190 @@
1
+ import { cx } from "../cx.js";
2
+ import { panelClassName, panelItemClassName } from "./floating.js";
3
+ import { Popover } from "./Popover.js";
4
+ import "./comboboxItems.js";
5
+ import { useEffect, useId, useState } from "react";
6
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
7
+ //#region src/components/Listbox.tsx
8
+ /** The parts a highlighted list needs while focus stays on the box the reader types in, such
9
+ * as a text box, an editor or a search input: the highlight and its keys, and the ids that
10
+ * let assistive technology follow the highlight. Spread `hostProps` on the focused box,
11
+ * `listProps` on the list and `optionProps(i)` on each option, or draw them with
12
+ * ListboxPanel and ListboxOption. */
13
+ function useListboxNavigation({ items, onChoose, onDismiss, open = true, loop = true, chooseKeys = ["Tab"], homeEnd = false, isDisabled }) {
14
+ const listId = useId();
15
+ const [active, setActive] = useState(0);
16
+ const count = items.length;
17
+ const shown = count === 0 ? -1 : Math.min(Math.max(active, 0), count - 1);
18
+ const shownOpen = open && count > 0;
19
+ const optionId = (index) => `${listId}-${index}`;
20
+ useEffect(() => {
21
+ if (!shownOpen || shown < 0) return;
22
+ document.getElementById(`${listId}-${shown}`)?.scrollIntoView?.({ block: "nearest" });
23
+ }, [
24
+ shownOpen,
25
+ shown,
26
+ listId
27
+ ]);
28
+ const step = (from, by) => {
29
+ for (let moved = 1; moved <= count; moved++) {
30
+ let next = from + by * moved;
31
+ if (next < 0 || next >= count) {
32
+ if (!loop) return from;
33
+ next = (next + count) % count;
34
+ }
35
+ const item = items[next];
36
+ if (item !== void 0 && !isDisabled?.(item)) return next;
37
+ }
38
+ return from;
39
+ };
40
+ const choose = (index) => {
41
+ const item = items[index];
42
+ if (item !== void 0 && !isDisabled?.(item)) onChoose(item, index);
43
+ };
44
+ /** Handles a key the list owns, and says whether it did; leave the rest to the host. */
45
+ const handleKey = (event) => {
46
+ const composing = "nativeEvent" in event ? event.nativeEvent.isComposing : event.isComposing;
47
+ if (!shownOpen || composing) return false;
48
+ const ctrlOnly = event.ctrlKey && !event.metaKey && !event.altKey;
49
+ switch (true) {
50
+ case event.key === "ArrowDown" || ctrlOnly && event.key === "n":
51
+ setActive(step(shown, 1));
52
+ break;
53
+ case event.key === "ArrowUp" || ctrlOnly && event.key === "p":
54
+ setActive(step(shown, -1));
55
+ break;
56
+ case homeEnd && event.key === "Home":
57
+ setActive(step(-1, 1));
58
+ break;
59
+ case homeEnd && event.key === "End":
60
+ setActive(step(count, -1));
61
+ break;
62
+ case event.key === "Escape":
63
+ if (!onDismiss) return false;
64
+ onDismiss();
65
+ break;
66
+ case event.key === "Enter" || chooseKeys.includes(event.key):
67
+ if (event.shiftKey || event.altKey || event.metaKey || event.ctrlKey) return false;
68
+ choose(shown);
69
+ break;
70
+ default: return false;
71
+ }
72
+ event.preventDefault();
73
+ return true;
74
+ };
75
+ return {
76
+ /** The highlighted item's index, or -1 with nothing to show. */
77
+ active: shown,
78
+ setActive,
79
+ handleKey,
80
+ listId,
81
+ /** For the box that keeps focus: it points at the list and its highlighted option. */
82
+ hostProps: {
83
+ "aria-autocomplete": "list",
84
+ "aria-controls": shownOpen ? listId : void 0,
85
+ "aria-activedescendant": shownOpen && shown >= 0 ? optionId(shown) : void 0
86
+ },
87
+ listProps: {
88
+ id: listId,
89
+ role: "listbox"
90
+ },
91
+ optionProps: (index) => {
92
+ const item = items[index];
93
+ const disabled = item !== void 0 && isDisabled?.(item) === true;
94
+ return {
95
+ id: optionId(index),
96
+ role: "option",
97
+ tabIndex: -1,
98
+ "aria-selected": index === shown,
99
+ "aria-disabled": disabled || void 0,
100
+ "data-highlighted": index === shown || void 0,
101
+ "data-disabled": disabled || void 0,
102
+ onMouseDown: (event) => event.preventDefault(),
103
+ onMouseMove: () => {
104
+ if (index !== shown && !disabled) setActive(index);
105
+ },
106
+ onClick: () => choose(index)
107
+ };
108
+ }
109
+ };
110
+ }
111
+ /** The panel of a highlighted list that the reader drives from a box that keeps focus. */
112
+ function ListboxPanel({ listProps, "aria-label": label, footer, empty, at, onDismiss, className, children }) {
113
+ const hasOptions = Array.isArray(children) ? children.some(Boolean) : Boolean(children);
114
+ const body = /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("div", {
115
+ id: listProps.id,
116
+ role: "listbox",
117
+ "aria-label": label,
118
+ className: cx("max-h-96 overflow-y-auto overscroll-contain", "p-1"),
119
+ children: hasOptions ? children : empty ? /* @__PURE__ */ jsx("div", {
120
+ className: "px-2 py-1.5 text-(--theme-muted-text-color)",
121
+ children: empty
122
+ }) : null
123
+ }), footer && /* @__PURE__ */ jsx("div", {
124
+ className: "border-t border-(--theme-border) px-3 py-1.5 text-xs text-(--theme-muted-text-color)",
125
+ children: footer
126
+ })] });
127
+ if (at) return /* @__PURE__ */ jsx(Popover, {
128
+ at,
129
+ open: true,
130
+ onOpenChange: (next) => {
131
+ if (!next) onDismiss?.();
132
+ },
133
+ side: "bottom",
134
+ align: "start",
135
+ initialFocus: "none",
136
+ finalFocus: false,
137
+ "aria-label": label,
138
+ className: cx("w-72 overflow-hidden p-0", className),
139
+ children: body
140
+ });
141
+ return /* @__PURE__ */ jsx("div", {
142
+ className: cx("overflow-hidden", panelClassName, className),
143
+ children: body
144
+ });
145
+ }
146
+ /** One option of a ListboxPanel: an icon, its label and description, and a hint at its end. */
147
+ function ListboxOption({ option, icon, label, description, inline = false, hint, className }) {
148
+ return /* @__PURE__ */ jsxs("div", {
149
+ ...option,
150
+ className: cx(panelItemClassName, inline && "items-baseline", className),
151
+ children: [
152
+ icon && /* @__PURE__ */ jsx("span", {
153
+ className: "flex shrink-0 items-center self-center",
154
+ children: icon
155
+ }),
156
+ /* @__PURE__ */ jsxs("span", {
157
+ className: cx("flex min-w-0", inline ? "items-baseline gap-3" : "flex-col"),
158
+ children: [/* @__PURE__ */ jsx("span", {
159
+ className: "truncate",
160
+ children: label
161
+ }), description && /* @__PURE__ */ jsx("span", {
162
+ className: cx("text-xs text-(--theme-muted-text-color)", inline ? "truncate" : "leading-snug"),
163
+ children: description
164
+ })]
165
+ }),
166
+ hint && /* @__PURE__ */ jsx("span", {
167
+ className: "ml-auto flex h-[1lh] shrink-0 items-center gap-2 self-start pl-2",
168
+ children: /* @__PURE__ */ jsx("span", {
169
+ className: "text-xs tabular-nums text-(--theme-muted-text-color)",
170
+ children: hint
171
+ })
172
+ })
173
+ ]
174
+ });
175
+ }
176
+ /** Options under a heading in a ListboxPanel. */
177
+ function ListboxGroup({ label, children }) {
178
+ const id = useId();
179
+ return /* @__PURE__ */ jsxs("div", {
180
+ role: "group",
181
+ "aria-labelledby": id,
182
+ children: [/* @__PURE__ */ jsx("div", {
183
+ id,
184
+ className: "px-2 pt-2 pb-1 text-xs text-(--theme-muted-text-color)",
185
+ children: label
186
+ }), children]
187
+ });
188
+ }
189
+ //#endregion
190
+ export { ListboxGroup, ListboxOption, ListboxPanel, useListboxNavigation };