@parallelworks/ui 0.77.0 → 0.79.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 (268) hide show
  1. package/README.md +42 -6
  2. package/dist/access/AccessDrawer.d.ts +49 -7
  3. package/dist/access/AccessDrawer.js +243 -38
  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 +25 -1
  13. package/dist/access/strings.js +27 -3
  14. package/dist/access/types.d.ts +26 -0
  15. package/dist/ai/components/AllocationSelector.js +1 -1
  16. package/dist/ai/components/AttachmentManager.js +5 -5
  17. package/dist/ai/components/AttachmentUpload.js +2 -2
  18. package/dist/ai/components/BranchNavigator.js +1 -1
  19. package/dist/ai/components/ChatActivity.js +1 -1
  20. package/dist/ai/components/ChatEmptyState.js +3 -3
  21. package/dist/ai/components/ChatInput.js +3 -5
  22. package/dist/ai/components/ChatLayout.js +1 -1
  23. package/dist/ai/components/ChatMessage.js +1 -1
  24. package/dist/ai/components/ChatMessageList.js +23 -8
  25. package/dist/ai/components/ChatSidebar.js +3 -3
  26. package/dist/ai/components/ChatThread.js +4 -4
  27. package/dist/ai/components/ComposerAddMenu.js +9 -20
  28. package/dist/ai/components/ModelSelector.js +3 -3
  29. package/dist/ai/components/PastedText.js +5 -5
  30. package/dist/ai/components/SessionView.js +1 -1
  31. package/dist/ai/components/ShareDialog.js +3 -3
  32. package/dist/ai/components/SlashMenu.d.ts +31 -4
  33. package/dist/ai/components/SlashMenu.js +36 -63
  34. package/dist/ai/components/agent/ActivityLine.js +1 -1
  35. package/dist/ai/components/agent/AgentMessageParts.js +13 -13
  36. package/dist/ai/components/conversationActions.js +3 -3
  37. package/dist/ai/core/ChatProvider.js +1 -1
  38. package/dist/ai/core/config.js +1 -1
  39. package/dist/ai/ui/ConversationSidebar.js +3 -3
  40. package/dist/ai/ui/sidebar.js +3 -3
  41. package/dist/assets/yaml.worker-DOBV2lND.js +884 -0
  42. package/dist/components/ActionMenu.d.ts +38 -9
  43. package/dist/components/ActionMenu.js +48 -22
  44. package/dist/components/Avatar.d.ts +66 -6
  45. package/dist/components/Avatar.js +130 -18
  46. package/dist/components/Breadcrumbs.d.ts +4 -0
  47. package/dist/components/Breadcrumbs.js +26 -10
  48. package/dist/components/Button.d.ts +3 -2
  49. package/dist/components/Button.js +11 -1
  50. package/dist/components/Callout.d.ts +3 -2
  51. package/dist/components/Callout.js +3 -2
  52. package/dist/components/Card.d.ts +33 -9
  53. package/dist/components/Card.js +24 -8
  54. package/dist/components/Checkbox.d.ts +3 -1
  55. package/dist/components/Checkbox.js +4 -2
  56. package/dist/components/ColorInput.js +1 -1
  57. package/dist/components/Combobox.d.ts +23 -0
  58. package/dist/components/Combobox.js +252 -86
  59. package/dist/components/ConfirmModal.d.ts +28 -2
  60. package/dist/components/ConfirmModal.js +100 -15
  61. package/dist/components/ContextMenu.d.ts +29 -2
  62. package/dist/components/ContextMenu.js +60 -8
  63. package/dist/components/CopyButton.d.ts +21 -8
  64. package/dist/components/CopyButton.js +29 -9
  65. package/dist/components/CreateModal.d.ts +20 -4
  66. package/dist/components/CreateModal.js +28 -17
  67. package/dist/components/DatePicker.d.ts +31 -1
  68. package/dist/components/DatePicker.js +178 -47
  69. package/dist/components/DescriptionList.d.ts +13 -3
  70. package/dist/components/DescriptionList.js +43 -11
  71. package/dist/components/Disclosure.d.ts +10 -2
  72. package/dist/components/Disclosure.js +18 -7
  73. package/dist/components/Drawer.js +5 -5
  74. package/dist/components/EmptyState.d.ts +12 -4
  75. package/dist/components/EmptyState.js +18 -10
  76. package/dist/components/ErrorPage.d.ts +40 -0
  77. package/dist/components/ErrorPage.js +101 -0
  78. package/dist/components/ExternalLink.d.ts +4 -1
  79. package/dist/components/ExternalLink.js +4 -5
  80. package/dist/components/Field.d.ts +21 -6
  81. package/dist/components/Field.js +32 -16
  82. package/dist/components/FileButton.d.ts +19 -0
  83. package/dist/components/FileButton.js +32 -0
  84. package/dist/components/HoverCard.d.ts +26 -6
  85. package/dist/components/HoverCard.js +11 -5
  86. package/dist/components/IconButton.js +4 -2
  87. package/dist/components/InfoTip.js +3 -3
  88. package/dist/components/Input.d.ts +33 -3
  89. package/dist/components/Input.js +149 -14
  90. package/dist/components/Kbd.d.ts +40 -0
  91. package/dist/components/Kbd.js +168 -0
  92. package/dist/components/Listbox.d.ts +103 -0
  93. package/dist/components/Listbox.js +190 -0
  94. package/dist/components/Loader.d.ts +8 -2
  95. package/dist/components/Loader.js +16 -1
  96. package/dist/components/Markdown.js +1 -1
  97. package/dist/components/MarkdownImpl.js +1 -1
  98. package/dist/components/Menu.d.ts +20 -2
  99. package/dist/components/Menu.js +48 -19
  100. package/dist/components/MenuEntries.d.ts +41 -4
  101. package/dist/components/MenuEntries.js +266 -39
  102. package/dist/components/Meter.d.ts +50 -11
  103. package/dist/components/Meter.js +71 -21
  104. package/dist/components/Modal.d.ts +9 -3
  105. package/dist/components/Modal.js +68 -29
  106. package/dist/components/OneTimeCodeInput.js +1 -1
  107. package/dist/components/PageHeader.js +111 -7
  108. package/dist/components/PageHeaderAction.d.ts +8 -3
  109. package/dist/components/PageHeaderAction.js +122 -34
  110. package/dist/components/Pagination.d.ts +13 -1
  111. package/dist/components/Pagination.js +90 -19
  112. package/dist/components/Popover.d.ts +16 -2
  113. package/dist/components/Popover.js +20 -21
  114. package/dist/components/Provider.d.ts +172 -5
  115. package/dist/components/Provider.js +157 -14
  116. package/dist/components/RefreshButton.d.ts +13 -6
  117. package/dist/components/RefreshButton.js +17 -9
  118. package/dist/components/RunStatusIcon.d.ts +16 -7
  119. package/dist/components/RunStatusIcon.js +21 -8
  120. package/dist/components/Section.d.ts +11 -4
  121. package/dist/components/Section.js +33 -22
  122. package/dist/components/SegmentedControl.d.ts +16 -3
  123. package/dist/components/SegmentedControl.js +7 -3
  124. package/dist/components/Select.d.ts +19 -3
  125. package/dist/components/Select.js +114 -68
  126. package/dist/components/SelectionCopy.d.ts +10 -0
  127. package/dist/components/SelectionCopy.js +105 -0
  128. package/dist/components/SettingModeOption.js +1 -1
  129. package/dist/components/SettingsCard.js +1 -1
  130. package/dist/components/Skeleton.js +1 -1
  131. package/dist/components/StatusBadge.d.ts +55 -10
  132. package/dist/components/StatusBadge.js +91 -15
  133. package/dist/components/StickyBar.js +1 -1
  134. package/dist/components/Table.d.ts +22 -4
  135. package/dist/components/Table.js +46 -24
  136. package/dist/components/Tabs.d.ts +9 -4
  137. package/dist/components/Tabs.js +9 -4
  138. package/dist/components/Tag.d.ts +49 -0
  139. package/dist/components/Tag.js +199 -0
  140. package/dist/components/ThemeEditor.js +1 -1
  141. package/dist/components/Toast.js +1 -1
  142. package/dist/components/ToggleGroup.d.ts +4 -1
  143. package/dist/components/ToggleGroup.js +30 -13
  144. package/dist/components/Tooltip.d.ts +9 -3
  145. package/dist/components/Tooltip.js +55 -39
  146. package/dist/components/buttonClasses.d.ts +5 -2
  147. package/dist/components/buttonClasses.js +11 -10
  148. package/dist/components/chart.d.ts +69 -0
  149. package/dist/components/chart.js +145 -0
  150. package/dist/components/comboboxItems.d.ts +7 -1
  151. package/dist/components/comboboxItems.js +6 -2
  152. package/dist/components/dismiss.d.ts +5 -1
  153. package/dist/components/dismiss.js +6 -2
  154. package/dist/components/floating.d.ts +4 -4
  155. package/dist/components/floating.js +5 -5
  156. package/dist/components/headerActionsFit.d.ts +37 -0
  157. package/dist/components/headerActionsFit.js +81 -0
  158. package/dist/components/pageHeaderStore.d.ts +3 -0
  159. package/dist/components/pageHeaderStore.js +3 -0
  160. package/dist/components/pathBreaks.js +2 -2
  161. package/dist/components/popupContainer.d.ts +17 -0
  162. package/dist/components/popupContainer.js +69 -0
  163. package/dist/components/relativeTime.d.ts +21 -10
  164. package/dist/components/relativeTime.js +50 -22
  165. package/dist/components/segmented.d.ts +18 -4
  166. package/dist/components/segmented.js +48 -6
  167. package/dist/components/typedDate.d.ts +5 -0
  168. package/dist/components/typedDate.js +50 -0
  169. package/dist/components/useClosingValue.d.ts +4 -0
  170. package/dist/components/useClosingValue.js +12 -0
  171. package/dist/components/useCopy.d.ts +6 -0
  172. package/dist/components/useCopy.js +3 -3
  173. package/dist/components/useNarrow.d.ts +2 -0
  174. package/dist/components/useNarrow.js +16 -0
  175. package/dist/editor/Editor.js +1 -1
  176. package/dist/editor/FormCodePanel.js +1 -1
  177. package/dist/editor/Monaco.js +1 -1
  178. package/dist/editor/workers.js +1 -1
  179. package/dist/file-explorer/FileExplorer.js +16 -15
  180. package/dist/file-explorer/FileExplorerContext.js +2 -2
  181. package/dist/file-explorer/FilePreview/Viewer.js +3 -3
  182. package/dist/file-explorer/FilePreview/index.js +2 -2
  183. package/dist/file-explorer/FileRowsWindow.js +3 -3
  184. package/dist/file-explorer/FileTable.js +1 -1
  185. package/dist/file-explorer/LoadMoreRow.js +1 -1
  186. package/dist/file-explorer/TreeView.js +5 -5
  187. package/dist/file-explorer/helpers.js +2 -2
  188. package/dist/file-explorer/toasts.js +2 -2
  189. package/dist/form/Fields/CheckboxGroupField.js +1 -1
  190. package/dist/form/Fields/DropdownField.js +1 -1
  191. package/dist/form/Fields/DurationField.js +2 -2
  192. package/dist/form/Fields/MultiDropdownField.js +1 -1
  193. package/dist/form/Fields/NumberField.js +1 -1
  194. package/dist/form/Fields/ObjectField.js +1 -1
  195. package/dist/form/Fields/RangeField.js +1 -1
  196. package/dist/form/Fields/StringField.js +1 -1
  197. package/dist/form/Form.js +3 -3
  198. package/dist/form/FormLayout.js +1 -1
  199. package/dist/form/Wizard/WizardContainer.js +1 -1
  200. package/dist/form/Wizard/WizardNavigation.js +1 -1
  201. package/dist/form/Wizard/WizardStepContent.js +1 -1
  202. package/dist/form/fieldRegistry.js +1 -1
  203. package/dist/form/formEditing.js +1 -1
  204. package/dist/format.d.ts +17 -7
  205. package/dist/format.js +39 -16
  206. package/dist/graph/AnnotationBanner.js +2 -2
  207. package/dist/graph/Connectors.js +5 -5
  208. package/dist/graph/DependencyGraph.js +10 -9
  209. package/dist/graph/GraphEditor.js +4 -4
  210. package/dist/graph/GraphEditorDialogs.js +13 -12
  211. package/dist/graph/GraphNode.js +1 -1
  212. package/dist/graph/InputDialog.js +5 -5
  213. package/dist/graph/InputsEditor.js +10 -9
  214. package/dist/graph/MatrixGroup.js +2 -2
  215. package/dist/graph/ProblemPageLink.d.ts +9 -0
  216. package/dist/graph/ProblemPageLink.js +21 -0
  217. package/dist/graph/ProblemsButton.js +26 -16
  218. package/dist/graph/Reveal.js +1 -1
  219. package/dist/graph/RunWarningsList.js +21 -12
  220. package/dist/graph/ShortcutsButton.js +25 -8
  221. package/dist/graph/StepSummaries.js +1 -1
  222. package/dist/graph/TreeView.js +2 -2
  223. package/dist/graph/WorkflowSettingsDialog.js +3 -3
  224. package/dist/graph/editorApi.d.ts +10 -0
  225. package/dist/graph/editorFields.js +3 -3
  226. package/dist/graph/editorPrimitives.js +1 -1
  227. package/dist/graph/editorRows.js +8 -6
  228. package/dist/graph/editorStrings.d.ts +1 -0
  229. package/dist/graph/editorStrings.js +1 -0
  230. package/dist/graph/fieldProblems.js +2 -2
  231. package/dist/graph/inputRefs.js +7 -6
  232. package/dist/graph/runWarnings.d.ts +12 -1
  233. package/dist/graph/stepWith.js +2 -2
  234. package/dist/index.d.ts +30 -21
  235. package/dist/index.js +20 -12
  236. package/dist/list/ActionToolbar.d.ts +4 -0
  237. package/dist/list/ActionToolbar.js +35 -12
  238. package/dist/list/ListFilterBar.d.ts +42 -0
  239. package/dist/list/ListFilterBar.js +789 -0
  240. package/dist/list/ListPage.d.ts +42 -4
  241. package/dist/list/ListPage.js +56 -22
  242. package/dist/list/ListTable.d.ts +27 -3
  243. package/dist/list/ListTable.js +48 -23
  244. package/dist/list/ListToolbar.d.ts +31 -0
  245. package/dist/list/ListToolbar.js +43 -0
  246. package/dist/list/ListViewControls.d.ts +8 -4
  247. package/dist/list/ListViewControls.js +22 -14
  248. package/dist/list/UserHoverCard.d.ts +8 -2
  249. package/dist/list/UserHoverCard.js +26 -13
  250. package/dist/list/filterModel.d.ts +122 -0
  251. package/dist/list/filterModel.js +308 -0
  252. package/dist/list/index.d.ts +6 -2
  253. package/dist/list/index.js +6 -2
  254. package/dist/list/listSearch.d.ts +1 -1
  255. package/dist/list/listSearch.js +8 -4
  256. package/dist/list/listView.d.ts +24 -2
  257. package/dist/list/listView.js +47 -45
  258. package/dist/list/rowMenu.d.ts +10 -5
  259. package/dist/list/rowMenu.js +17 -7
  260. package/dist/list/useListFilters.d.ts +68 -0
  261. package/dist/list/useListFilters.js +252 -0
  262. package/dist/logviewer/LogViewer.js +4 -4
  263. package/dist/styles/theme.css +94 -0
  264. package/dist/styles.css +1 -1
  265. package/package.json +11 -11
  266. package/dist/assets/yaml.worker-k9AdOqzf.js +0 -1441
  267. package/dist/components/fullscreen.d.ts +0 -4
  268. package/dist/components/fullscreen.js +0 -18
@@ -27,6 +27,9 @@ export interface ToggleGroupProps<T extends string> {
27
27
  } | undefined;
28
28
  size?: 'sm' | 'md' | undefined;
29
29
  disabled?: boolean | undefined;
30
+ /** Names an element that says more about the group, such as a live summary
31
+ * of what the filter lets through. */
32
+ 'aria-describedby'?: string | undefined;
30
33
  testId?: string;
31
34
  }
32
35
  /** Options that narrow a list, such as run statuses or job states, as a row of
@@ -39,4 +42,4 @@ export interface ToggleGroupProps<T extends string> {
39
42
  * value, such as a time range, what to group by, or which view of the same
40
43
  * data to show. A filter that may be off, or takes several values, is a
41
44
  * `ToggleGroup`. */
42
- export declare function ToggleGroup<T extends string>({ label, options, value, onValueChange, multiple, all, size, disabled, testId, }: ToggleGroupProps<T>): import("react").JSX.Element;
45
+ export declare function ToggleGroup<T extends string>({ label, options, value, onValueChange, multiple, all, size, disabled, 'aria-describedby': describedBy, testId, }: ToggleGroupProps<T>): import("react").JSX.Element;
@@ -1,6 +1,7 @@
1
1
  import { cx } from "../cx.js";
2
2
  import { buttonClasses } from "./buttonClasses.js";
3
- import { useStrings } from "./Provider.js";
3
+ import { CheckIcon } from "../icons.js";
4
+ import { useLocale, useStrings } from "./Provider.js";
4
5
  import { formatCount } from "../format.js";
5
6
  import { jsx, jsxs } from "react/jsx-runtime";
6
7
  import { Toggle } from "@base-ui/react/toggle";
@@ -17,12 +18,13 @@ var ALL = "\0all";
17
18
  * value, such as a time range, what to group by, or which view of the same
18
19
  * data to show. A filter that may be off, or takes several values, is a
19
20
  * `ToggleGroup`. */
20
- function ToggleGroup$1({ label, options, value, onValueChange, multiple = true, all = false, size = "sm", disabled = false, testId }) {
21
+ function ToggleGroup$1({ label, options, value, onValueChange, multiple = true, all = false, size = "sm", disabled = false, "aria-describedby": describedBy, testId }) {
21
22
  const strings = useStrings();
22
23
  const allCount = typeof all === "object" ? all.count : void 0;
23
24
  const pressed = all && value.length === 0 ? [ALL] : value;
24
25
  return /* @__PURE__ */ jsxs(ToggleGroup, {
25
26
  "aria-label": label,
27
+ "aria-describedby": describedBy,
26
28
  "data-testid": testId,
27
29
  className: "flex flex-wrap items-center gap-1",
28
30
  multiple,
@@ -35,18 +37,26 @@ function ToggleGroup$1({ label, options, value, onValueChange, multiple = true,
35
37
  }
36
38
  onValueChange(options.filter((option) => next.includes(option.value)).map((option) => option.value));
37
39
  },
38
- children: [all && /* @__PURE__ */ jsx(Chip, {
39
- value: ALL,
40
- label: strings.common.all,
41
- count: allCount,
42
- size
43
- }), options.map((option) => /* @__PURE__ */ jsx(Chip, {
44
- ...option,
45
- size
46
- }, option.value))]
40
+ children: [
41
+ all && /* @__PURE__ */ jsx(Chip, {
42
+ value: ALL,
43
+ label: strings.common.all,
44
+ count: allCount,
45
+ size
46
+ }),
47
+ all && options.length > 0 && /* @__PURE__ */ jsx("span", {
48
+ "aria-hidden": "true",
49
+ className: "mx-0.5 h-5 w-px shrink-0 bg-(--theme-border)"
50
+ }),
51
+ options.map((option) => /* @__PURE__ */ jsx(Chip, {
52
+ ...option,
53
+ size
54
+ }, option.value))
55
+ ]
47
56
  });
48
57
  }
49
58
  function Chip({ value, label, icon, count, disabled, testId, size }) {
59
+ const locale = useLocale();
50
60
  return /* @__PURE__ */ jsxs(Toggle, {
51
61
  value,
52
62
  disabled,
@@ -56,11 +66,18 @@ function Chip({ value, label, icon, count, disabled, testId, size }) {
56
66
  size
57
67
  })),
58
68
  children: [
59
- icon,
69
+ icon && /* @__PURE__ */ jsx("span", {
70
+ className: "inline-flex shrink-0 transition-opacity group-not-aria-pressed:opacity-55",
71
+ children: icon
72
+ }),
60
73
  label,
61
74
  count !== void 0 && /* @__PURE__ */ jsx("span", {
62
75
  className: "tabular-nums text-(--theme-muted-text-color) group-aria-pressed:text-(--theme-app)",
63
- children: formatCount(count)
76
+ children: formatCount(count, locale)
77
+ }),
78
+ /* @__PURE__ */ jsx(CheckIcon, {
79
+ "aria-hidden": "true",
80
+ className: "hidden shrink-0 group-aria-pressed:block"
64
81
  })
65
82
  ]
66
83
  });
@@ -14,12 +14,18 @@ export interface TooltipProps extends Omit<BaseTooltip.Trigger.Props, 'content'
14
14
  /** The anchor. It receives the trigger's props and ref, so it must pass them to its element. */
15
15
  children: ReactElement;
16
16
  side?: TooltipSide;
17
- /** Keys shown beside the content, joined with +, such as ⌘+F. */
17
+ /** Keys shown beside the content as keycaps, written as `Kbd` takes them, such as
18
+ * `Mod+F`: Command on an Apple keyboard, Control elsewhere. */
18
19
  shortcut?: string | undefined;
19
20
  disabled?: boolean | undefined;
20
21
  /** Opens only while the anchor's text is clipped, such as a truncated label. */
21
22
  overflowOnly?: boolean;
23
+ /** Also the anchor's accessible description, for a hint that adds to its name
24
+ * rather than repeating it, such as what Make default changes. Assistive
25
+ * technology reads it with the anchor whether or not the tooltip is open. */
26
+ describesAnchor?: boolean | undefined;
22
27
  }
23
28
  /** A visual hint for sighted pointer and keyboard users. The anchor still needs
24
- * its own accessible name; use InfoTip for content everyone must reach. */
25
- export declare function Tooltip({ content, children, side, shortcut, disabled, overflowOnly, ...anchorProps }: TooltipProps): import("react").JSX.Element;
29
+ * its own accessible name; `describesAnchor` also gives assistive technology the
30
+ * hint. Use InfoTip for content everyone must reach, such as on a touch screen. */
31
+ export declare function Tooltip({ content, children, side, shortcut, disabled, overflowOnly, describesAnchor, ...anchorProps }: TooltipProps): import("react").JSX.Element;
@@ -1,54 +1,51 @@
1
- import { positionerClassName, tipArrowClassName, tipClassName } from "./floating.js";
2
- import { useFullscreenContainer } from "./fullscreen.js";
3
- import { keyedByContent } from "./keys.js";
4
- import { jsx, jsxs } from "react/jsx-runtime";
5
- import { Fragment as Fragment$1, createContext, use, useState } from "react";
1
+ import { positionerClassName, tipClassName } from "./floating.js";
2
+ import { usePopupContainer } from "./popupContainer.js";
3
+ import { Kbd } from "./Kbd.js";
4
+ import { cloneElement, createContext, use, useId, useState } from "react";
5
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
6
6
  import { Tooltip } from "@base-ui/react/tooltip";
7
7
  //#region src/components/Tooltip.tsx
8
8
  var TooltipHandleContext = createContext(null);
9
- function KbdShortcut({ keys }) {
10
- const parts = keys.split("+").map((part) => part.trim()).filter(Boolean);
11
- return /* @__PURE__ */ jsx("span", {
12
- className: "inline-flex items-center gap-1 align-middle",
13
- children: keyedByContent(parts, (p) => p).map(({ key, item: part }, idx) => /* @__PURE__ */ jsxs(Fragment$1, { children: [idx > 0 && /* @__PURE__ */ jsx("span", {
14
- className: "opacity-60 text-[11px]",
15
- children: "+"
16
- }), /* @__PURE__ */ jsx("kbd", {
17
- className: "inline-flex items-center justify-center min-w-[18px] h-[18px] px-1 rounded border border-current/30 bg-current/10 font-sans text-[11px] font-semibold leading-none",
18
- children: part
19
- })] }, key))
20
- });
21
- }
22
9
  function TooltipPopup({ content, shortcut, side }) {
23
- const fullscreen = useFullscreenContainer();
10
+ const portal = usePopupContainer();
24
11
  return /* @__PURE__ */ jsx(Tooltip.Portal, {
25
- container: fullscreen,
12
+ ...portal,
26
13
  children: /* @__PURE__ */ jsx(Tooltip.Positioner, {
27
14
  side,
28
- sideOffset: 8,
15
+ sideOffset: 6,
29
16
  className: positionerClassName,
30
- children: /* @__PURE__ */ jsxs(Tooltip.Popup, {
31
- className: `max-w-xs ${tipClassName}`,
32
- children: [/* @__PURE__ */ jsx(Tooltip.Arrow, { className: tipArrowClassName }), shortcut ? /* @__PURE__ */ jsxs("span", {
17
+ children: /* @__PURE__ */ jsx(Tooltip.Popup, {
18
+ className: tipClassName,
19
+ children: shortcut ? /* @__PURE__ */ jsxs("span", {
33
20
  className: "inline-flex items-center gap-2",
34
- children: [content, /* @__PURE__ */ jsx(KbdShortcut, { keys: shortcut })]
35
- }) : content]
21
+ children: [content, /* @__PURE__ */ jsx(Kbd, {
22
+ keys: shortcut,
23
+ size: "xs"
24
+ })]
25
+ }) : content
36
26
  })
37
27
  })
38
28
  });
39
29
  }
30
+ /** How long the pointer rests on an anchor before its tooltip opens, in milliseconds.
31
+ * Once one is open, the next opens at once. An anchor's own `delay` overrides it,
32
+ * such as 0 on a collapsed rail where the tooltip is the only label. */
33
+ var OPEN_DELAY = 400;
40
34
  /** One popup serves every Tooltip below it, so each anchor costs only a trigger.
41
35
  * UIProvider mounts it; nothing else needs to. */
42
36
  function TooltipProvider({ children }) {
43
37
  const [handle] = useState(() => Tooltip.createHandle());
44
- return /* @__PURE__ */ jsxs(Tooltip.Provider, { children: [/* @__PURE__ */ jsx(TooltipHandleContext, {
45
- value: handle,
46
- children
47
- }), /* @__PURE__ */ jsx(Tooltip.Root, {
48
- handle,
49
- onOpenChange: skipUnclipped,
50
- children: ({ payload }) => payload && /* @__PURE__ */ jsx(TooltipPopup, { ...payload })
51
- })] });
38
+ return /* @__PURE__ */ jsxs(Tooltip.Provider, {
39
+ delay: OPEN_DELAY,
40
+ children: [/* @__PURE__ */ jsx(TooltipHandleContext, {
41
+ value: handle,
42
+ children
43
+ }), /* @__PURE__ */ jsx(Tooltip.Root, {
44
+ handle,
45
+ onOpenChange: skipUnclipped,
46
+ children: ({ payload }) => payload && /* @__PURE__ */ jsx(TooltipPopup, { ...payload })
47
+ })]
48
+ });
52
49
  }
53
50
  /** An overflowOnly anchor opens only while its text is cut off. */
54
51
  function skipUnclipped(open, details) {
@@ -56,26 +53,45 @@ function skipUnclipped(open, details) {
56
53
  if (open && anchor instanceof HTMLElement && anchor.hasAttribute("data-overflow-only") && anchor.scrollWidth <= anchor.clientWidth) details.cancel();
57
54
  }
58
55
  /** A visual hint for sighted pointer and keyboard users. The anchor still needs
59
- * its own accessible name; use InfoTip for content everyone must reach. */
60
- function Tooltip$1({ content, children, side = "top", shortcut, disabled = false, overflowOnly = false, ...anchorProps }) {
56
+ * its own accessible name; `describesAnchor` also gives assistive technology the
57
+ * hint. Use InfoTip for content everyone must reach, such as on a touch screen. */
58
+ function Tooltip$1({ content, children, side = "top", shortcut, disabled = false, overflowOnly = false, describesAnchor = false, ...anchorProps }) {
61
59
  const handle = use(TooltipHandleContext);
60
+ const descriptionId = useId();
62
61
  const payload = {
63
62
  content,
64
63
  shortcut,
65
64
  side
66
65
  };
66
+ const described = describesAnchor && !disabled && !!content;
67
+ const anchor = children;
68
+ const describedBy = [
69
+ anchor.props["aria-describedby"],
70
+ anchorProps["aria-describedby"],
71
+ descriptionId
72
+ ].filter(Boolean).join(" ");
67
73
  const trigger = /* @__PURE__ */ jsx(Tooltip.Trigger, {
68
74
  ...anchorProps,
75
+ ...!handle && anchorProps.delay === void 0 && { delay: OPEN_DELAY },
69
76
  handle: handle ?? void 0,
70
77
  payload,
71
78
  disabled: disabled || !content,
72
79
  "data-overflow-only": overflowOnly || void 0,
73
- render: children
80
+ render: described ? cloneElement(anchor, { "aria-describedby": describedBy }) : children
81
+ });
82
+ const description = described && /* @__PURE__ */ jsx("span", {
83
+ id: descriptionId,
84
+ hidden: true,
85
+ children: content
74
86
  });
75
- if (handle) return trigger;
87
+ if (handle) return description ? /* @__PURE__ */ jsxs(Fragment$1, { children: [trigger, description] }) : trigger;
76
88
  return /* @__PURE__ */ jsxs(Tooltip.Root, {
77
89
  onOpenChange: skipUnclipped,
78
- children: [trigger, /* @__PURE__ */ jsx(TooltipPopup, { ...payload })]
90
+ children: [
91
+ trigger,
92
+ description,
93
+ /* @__PURE__ */ jsx(TooltipPopup, { ...payload })
94
+ ]
79
95
  });
80
96
  }
81
97
  //#endregion
@@ -1,7 +1,10 @@
1
1
  /** `primary` is the one action a view leads to; `secondary` sits beside it;
2
2
  * `outline` and `ghost` are toolbar and inline actions, bordered or not;
3
- * `danger` confirms what can't be undone. */
4
- export type ButtonVariant = 'primary' | 'secondary' | 'outline' | 'ghost' | 'danger';
3
+ * `danger` confirms what can't be undone; `danger-outline` is a destructive
4
+ * action that isn't the view's confirmation, such as Revoke or Disable on a row. */
5
+ export type ButtonVariant = 'primary' | 'secondary' | 'outline' | 'ghost' | 'danger' | 'danger-outline';
6
+ /** `md` (32px) lines up with inputs and is the default; `lg` (40px) is for a
7
+ * standalone page's one action, such as signing in or approving a device. */
5
8
  export type ButtonSize = 'xs' | 'sm' | 'md' | 'lg';
6
9
  export interface ButtonStyle {
7
10
  variant?: ButtonVariant | undefined;
@@ -1,24 +1,25 @@
1
1
  import { cx } from "../cx.js";
2
2
  //#region src/components/buttonClasses.ts
3
- var base = "relative inline-flex shrink-0 cursor-pointer items-center justify-center gap-1.5 whitespace-nowrap rounded-md font-medium no-underline transition-colors focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-(--theme-focus) disabled:cursor-not-allowed disabled:opacity-50 aria-disabled:cursor-not-allowed aria-disabled:opacity-50";
3
+ var base = "relative inline-flex shrink-0 cursor-pointer items-center justify-center gap-1.5 whitespace-nowrap rounded-md font-medium no-underline transition-[color,background-color,border-color,box-shadow,translate] duration-150 hover:not-disabled:not-aria-disabled:-translate-y-px hover:not-disabled:not-aria-disabled:shadow-(--theme-shadow-sm) active:not-disabled:not-aria-disabled:translate-y-0 active:not-disabled:not-aria-disabled:shadow-none motion-reduce:hover:not-disabled:not-aria-disabled:translate-y-0 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-(--theme-focus) disabled:cursor-not-allowed disabled:opacity-50 aria-disabled:cursor-not-allowed aria-disabled:opacity-50";
4
4
  var variants = {
5
5
  primary: "bg-(--theme-accent) text-(--theme-accent-text) hover:not-disabled:not-aria-disabled:bg-(--theme-accent-hover)",
6
6
  secondary: "border border-(--theme-border) bg-(--theme-panel-bg) text-(--theme-app) hover:not-disabled:not-aria-disabled:bg-(--theme-hover)",
7
7
  outline: "border border-(--theme-border) text-(--theme-muted-text-color) hover:not-disabled:not-aria-disabled:bg-(--theme-muted-panel-bg) hover:not-disabled:not-aria-disabled:text-(--theme-app) aria-pressed:border-(--theme-link) aria-pressed:text-(--theme-app) data-selected:border-(--theme-link) data-selected:text-(--theme-app) data-popup-open:bg-(--theme-muted-panel-bg) data-popup-open:text-(--theme-app)",
8
8
  ghost: "text-(--theme-muted-text-color) hover:not-disabled:not-aria-disabled:bg-(--theme-muted-panel-bg) hover:not-disabled:not-aria-disabled:text-(--theme-app) aria-pressed:bg-(--theme-muted-panel-bg) aria-pressed:text-(--theme-link) data-selected:bg-(--theme-muted-panel-bg) data-selected:text-(--theme-link) data-popup-open:bg-(--theme-muted-panel-bg) data-popup-open:text-(--theme-app)",
9
- danger: "bg-(--theme-error-solid) text-white hover:not-disabled:not-aria-disabled:bg-(--theme-error-solid)/90"
9
+ danger: "bg-(--theme-error-solid) text-white hover:not-disabled:not-aria-disabled:bg-(--theme-error-solid)/90",
10
+ "danger-outline": "border border-(--theme-error)/40 text-(--theme-error-text) hover:not-disabled:not-aria-disabled:border-(--theme-error)/60 hover:not-disabled:not-aria-disabled:bg-(--theme-error-muted) data-popup-open:bg-(--theme-error-muted)"
10
11
  };
11
12
  var sizes = {
12
- xs: "h-6 px-2 text-xs [&_svg]:size-3",
13
- sm: "h-7 px-2.5 text-xs [&_svg]:size-3.5",
14
- md: "h-8 px-3 text-sm [&_svg]:size-4",
15
- lg: "h-10 px-4 text-base [&_svg]:size-5"
13
+ xs: "h-6 px-2 text-xs [:where(&)_svg]:size-3",
14
+ sm: "h-7 px-2.5 text-xs [:where(&)_svg]:size-3.5",
15
+ md: "h-8 px-3 text-sm [:where(&)_svg]:size-4",
16
+ lg: "h-10 px-4 text-base [:where(&)_svg]:size-5"
16
17
  };
17
18
  var squares = {
18
- xs: "size-6 text-xs [&_svg]:size-3",
19
- sm: "size-7 text-xs [&_svg]:size-3.5",
20
- md: "size-8 text-sm [&_svg]:size-4",
21
- lg: "size-10 text-base [&_svg]:size-5"
19
+ xs: "size-6 text-xs [:where(&)_svg]:size-3",
20
+ sm: "size-7 text-xs [:where(&)_svg]:size-3.5",
21
+ md: "size-8 text-sm [:where(&)_svg]:size-4",
22
+ lg: "size-10 text-base [:where(&)_svg]:size-5"
22
23
  };
23
24
  /** The one look for anything pressed: a button, or a link or popup trigger
24
25
  * that acts as one. `Button` and `IconButton` apply it; use it directly on a
@@ -0,0 +1,69 @@
1
+ import { type CSSProperties, type ReactNode } from 'react';
2
+ /** A series' mark color for palette slot 1–8: the theme's category hue, between the slot's
3
+ * soft fill and its text and twice as saturated, so a bar or a line stands out from the page
4
+ * in light and dark alike and keeps the hue the slot has everywhere else. */
5
+ export declare function seriesSlotColor(slot: number): string;
6
+ /** A series' color by its key, any CSS color for a fill, a stroke or a style: the same key
7
+ * gets the same color on every chart, as `categoryOf` gives a name its avatar color. */
8
+ export declare function seriesColor(key: string): string;
9
+ /** Colors for a chart's series, each key its `seriesColor` unless another key took that slot
10
+ * first, when it moves to the next free one: up to eight series never share a color. */
11
+ export declare function seriesColors(keys: readonly string[]): Record<string, string>;
12
+ export type SeriesSwatchShape = 'square' | 'dot' | 'line';
13
+ /** A series' color as a mark, for a legend or a tooltip's row. Only seen: the series' name
14
+ * beside it says which it is. */
15
+ export declare function SeriesSwatch({ color, shape, className, }: {
16
+ color: string;
17
+ shape?: SeriesSwatchShape | undefined;
18
+ className?: string | undefined;
19
+ }): import("react").JSX.Element;
20
+ /** Which series is in focus, from hovering a mark or the legend, and how strongly every other
21
+ * series draws while it is: their marks fade so the one in focus reads alone. */
22
+ export declare function useSeriesHighlight(): {
23
+ highlighted: string | null;
24
+ highlight: (key: string | null) => void;
25
+ /** 1 for the series in focus or when none is, 0.3 for the rest. */
26
+ opacity: (key: string) => number;
27
+ };
28
+ /** A series' opacity while `highlighted` is in focus: full for it, or for all when none is. */
29
+ export declare function seriesOpacity(key: string, highlighted: string | null | undefined): number;
30
+ export interface ChartLegendItem {
31
+ key: string;
32
+ label: ReactNode;
33
+ color: string;
34
+ }
35
+ /** A chart's legend: each series' swatch and name. With `onHighlight` hovering or focusing a
36
+ * name puts its series in focus, and pressing one keeps it there until pressed again. */
37
+ export declare function ChartLegendList({ items, highlighted, onHighlight, shape, className, }: {
38
+ items: readonly ChartLegendItem[];
39
+ highlighted?: string | null | undefined;
40
+ onHighlight?: ((key: string | null) => void) | undefined;
41
+ shape?: SeriesSwatchShape | undefined;
42
+ className?: string | undefined;
43
+ }): import("react").JSX.Element;
44
+ export interface ChartTooltipItem {
45
+ key: string;
46
+ name: ReactNode;
47
+ value: number;
48
+ color: string;
49
+ }
50
+ /** What a chart's tooltip shows for a point: its label, then each series' swatch, name and
51
+ * value, largest first, the series in focus in bold, and a total when there is more than one.
52
+ * A charting library's tooltip renders it as its content. */
53
+ export declare function ChartTooltipContent({ label, items, formatValue, total, highlighted, hideZero, sort, className, style, }: {
54
+ label?: ReactNode;
55
+ items: readonly ChartTooltipItem[];
56
+ /** Formats each value and the total, such as a currency; numbers in the host's locale
57
+ * (`UIProvider locale`) by default. */
58
+ formatValue?: ((n: number) => string) | undefined;
59
+ /** Adds a total row; on by default when more than one series shows. */
60
+ total?: boolean | undefined;
61
+ highlighted?: string | null | undefined;
62
+ /** Leaves out series whose value is zero; on by default. */
63
+ hideZero?: boolean | undefined;
64
+ /** Lists the largest value first; on by default. */
65
+ sort?: boolean | undefined;
66
+ className?: string | undefined;
67
+ /** Places it, such as beside the point it describes. */
68
+ style?: CSSProperties | undefined;
69
+ }): import("react").JSX.Element;
@@ -0,0 +1,145 @@
1
+ import { cx } from "../cx.js";
2
+ import { useLocale, useStrings } from "./Provider.js";
3
+ import { CATEGORY_CLASSES, categoryOf } from "./category.js";
4
+ import { useCallback, useMemo, useState } from "react";
5
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
6
+ //#region src/components/chart.tsx
7
+ var SLOTS = CATEGORY_CLASSES.length;
8
+ /** A series' mark color for palette slot 1–8: the theme's category hue, between the slot's
9
+ * soft fill and its text and twice as saturated, so a bar or a line stands out from the page
10
+ * in light and dark alike and keeps the hue the slot has everywhere else. */
11
+ function seriesSlotColor(slot) {
12
+ const n = ((slot - 1) % SLOTS + SLOTS) % SLOTS + 1;
13
+ return `oklch(from color-mix(in oklch, var(--theme-category-${n}), var(--theme-category-${n}-text)) l calc(c * 2) h)`;
14
+ }
15
+ /** A series' color by its key, any CSS color for a fill, a stroke or a style: the same key
16
+ * gets the same color on every chart, as `categoryOf` gives a name its avatar color. */
17
+ function seriesColor(key) {
18
+ return seriesSlotColor(categoryOf(key));
19
+ }
20
+ /** Colors for a chart's series, each key its `seriesColor` unless another key took that slot
21
+ * first, when it moves to the next free one: up to eight series never share a color. */
22
+ function seriesColors(keys) {
23
+ const taken = /* @__PURE__ */ new Set();
24
+ const colors = {};
25
+ for (const key of keys) {
26
+ if (key in colors) continue;
27
+ let slot = categoryOf(key);
28
+ if (taken.size < SLOTS) while (taken.has(slot)) slot = slot % SLOTS + 1;
29
+ taken.add(slot);
30
+ colors[key] = seriesSlotColor(slot);
31
+ }
32
+ return colors;
33
+ }
34
+ /** A series' color as a mark, for a legend or a tooltip's row. Only seen: the series' name
35
+ * beside it says which it is. */
36
+ function SeriesSwatch({ color, shape = "square", className }) {
37
+ return /* @__PURE__ */ jsx("span", {
38
+ "aria-hidden": "true",
39
+ className: cx("inline-block shrink-0", shape === "line" ? "h-0.5 w-3 rounded-full" : "size-2.5", shape === "dot" && "rounded-full", shape === "square" && "rounded-[3px]", className),
40
+ style: { background: color }
41
+ });
42
+ }
43
+ /** Which series is in focus, from hovering a mark or the legend, and how strongly every other
44
+ * series draws while it is: their marks fade so the one in focus reads alone. */
45
+ function useSeriesHighlight() {
46
+ const [highlighted, highlight] = useState(null);
47
+ return {
48
+ highlighted,
49
+ highlight,
50
+ opacity: useCallback((key) => seriesOpacity(key, highlighted), [highlighted])
51
+ };
52
+ }
53
+ /** A series' opacity while `highlighted` is in focus: full for it, or for all when none is. */
54
+ function seriesOpacity(key, highlighted) {
55
+ return highlighted == null || highlighted === key ? 1 : .3;
56
+ }
57
+ /** A chart's legend: each series' swatch and name. With `onHighlight` hovering or focusing a
58
+ * name puts its series in focus, and pressing one keeps it there until pressed again. */
59
+ function ChartLegendList({ items, highlighted, onHighlight, shape, className }) {
60
+ const [pinned, setPinned] = useState(null);
61
+ const leave = () => onHighlight?.(pinned);
62
+ return /* @__PURE__ */ jsx("ul", {
63
+ className: cx("m-0 flex list-none flex-wrap items-center gap-x-3 gap-y-1 p-0 text-xs text-(--theme-app)", className),
64
+ children: items.map((item) => {
65
+ const faded = highlighted != null && highlighted !== item.key;
66
+ const body = /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(SeriesSwatch, {
67
+ color: item.color,
68
+ shape
69
+ }), /* @__PURE__ */ jsx("span", {
70
+ className: "min-w-0 truncate",
71
+ children: item.label
72
+ })] });
73
+ return /* @__PURE__ */ jsx("li", {
74
+ className: cx("flex min-w-0 items-center transition-opacity motion-reduce:transition-none", faded && "opacity-50"),
75
+ children: onHighlight ? /* @__PURE__ */ jsx("button", {
76
+ type: "button",
77
+ "aria-pressed": pinned === item.key,
78
+ onPointerEnter: () => onHighlight(item.key),
79
+ onPointerLeave: leave,
80
+ onFocus: () => onHighlight(item.key),
81
+ onBlur: leave,
82
+ onClick: () => {
83
+ const next = pinned === item.key ? null : item.key;
84
+ setPinned(next);
85
+ onHighlight(next ?? item.key);
86
+ },
87
+ className: "-mx-1 flex min-w-0 cursor-pointer items-center gap-1.5 rounded px-1 py-0.5 hover:bg-(--theme-muted-panel-bg) focus-visible:outline-2 focus-visible:outline-(--theme-focus) aria-pressed:font-medium",
88
+ children: body
89
+ }) : /* @__PURE__ */ jsx("span", {
90
+ className: "flex min-w-0 items-center gap-1.5",
91
+ children: body
92
+ })
93
+ }, item.key);
94
+ })
95
+ });
96
+ }
97
+ /** What a chart's tooltip shows for a point: its label, then each series' swatch, name and
98
+ * value, largest first, the series in focus in bold, and a total when there is more than one.
99
+ * A charting library's tooltip renders it as its content. */
100
+ function ChartTooltipContent({ label, items, formatValue, total, highlighted, hideZero = true, sort = true, className, style }) {
101
+ const { chart: t } = useStrings();
102
+ const locale = useLocale();
103
+ const number = useMemo(() => new Intl.NumberFormat(locale, { maximumFractionDigits: 2 }), [locale]);
104
+ const format = formatValue ?? ((n) => number.format(n));
105
+ let rows = hideZero ? items.filter((item) => item.value !== 0) : [...items];
106
+ if (sort) rows = [...rows].sort((a, b) => b.value - a.value);
107
+ const sum = rows.reduce((acc, item) => acc + item.value, 0);
108
+ const showTotal = total ?? rows.length > 1;
109
+ return /* @__PURE__ */ jsxs("div", {
110
+ className: cx("min-w-40 rounded-lg border border-(--theme-border) bg-(--theme-panel-bg) p-3 text-xs text-(--theme-app) shadow-(--theme-shadow-lg)", className),
111
+ style,
112
+ children: [
113
+ label != null && label !== "" && /* @__PURE__ */ jsx("div", {
114
+ className: "mb-1.5 font-semibold",
115
+ children: label
116
+ }),
117
+ /* @__PURE__ */ jsx("ul", {
118
+ className: "m-0 list-none space-y-1 p-0",
119
+ children: rows.map((item) => /* @__PURE__ */ jsxs("li", {
120
+ className: cx("flex items-center gap-2", highlighted === item.key ? "font-semibold" : highlighted != null && "text-(--theme-muted-text-color)"),
121
+ children: [
122
+ /* @__PURE__ */ jsx(SeriesSwatch, { color: item.color }),
123
+ /* @__PURE__ */ jsx("span", {
124
+ className: "min-w-0 flex-1 truncate",
125
+ children: item.name
126
+ }),
127
+ /* @__PURE__ */ jsx("span", {
128
+ className: "ml-2 tabular-nums",
129
+ children: format(item.value)
130
+ })
131
+ ]
132
+ }, item.key))
133
+ }),
134
+ showTotal && /* @__PURE__ */ jsxs("div", {
135
+ className: "mt-1.5 flex justify-between gap-4 border-t border-(--theme-border) pt-1.5 font-medium",
136
+ children: [/* @__PURE__ */ jsx("span", { children: t.total }), /* @__PURE__ */ jsx("span", {
137
+ className: "tabular-nums",
138
+ children: format(sum)
139
+ })]
140
+ })
141
+ ]
142
+ });
143
+ }
144
+ //#endregion
145
+ export { ChartLegendList, ChartTooltipContent, SeriesSwatch, seriesColor, seriesColors, seriesOpacity, seriesSlotColor, useSeriesHighlight };
@@ -1,4 +1,8 @@
1
1
  import type { ReactNode } from 'react';
2
+ /** The end of an option's row: its hint, then the check while it is chosen, on the label's
3
+ * line rather than the middle of a row with a description under it. */
4
+ export declare const pickerEndClassName = "ml-auto flex h-[1lh] shrink-0 items-center gap-2 self-start pl-2";
5
+ export declare const pickerHintClassName = "text-xs tabular-nums text-(--theme-muted-text-color)";
2
6
  /** An option's row in a Select's or a Combobox's list, so both lists look alike: the icon, the
3
7
  * label over its description, and the check at the end. */
4
8
  export declare const pickerItemClassName: string;
@@ -13,6 +17,8 @@ export interface ComboboxItem<Value = string> {
13
17
  icon?: ReactNode;
14
18
  /** Beside the label, such as a tag that marks the option out. */
15
19
  badge?: ReactNode;
20
+ /** Short muted text at the row's end, such as a key or a count; read after the label. */
21
+ hint?: string | undefined;
16
22
  disabled?: boolean | undefined;
17
23
  }
18
24
  export interface ComboboxGroup<Value = string> {
@@ -29,7 +35,7 @@ export type ComboboxLeaf<Value = string> = ComboboxItem<Value> | (Value & string
29
35
  /** Items, groups under headings, or both: items between groups list where they sit, without a heading. */
30
36
  export type ComboboxItems<Value = string> = readonly (ComboboxLeaf<Value> | ComboboxGroup<Value>)[];
31
37
  /** How an option is named and described: by its label, with its description read after it. */
32
- export declare function optionNaming(id: string, item: Pick<ComboboxItem<unknown>, 'description' | 'accessibleDescription'>): {
38
+ export declare function optionNaming(id: string, item: Pick<ComboboxItem<unknown>, 'description' | 'accessibleDescription' | 'hint'>): {
33
39
  'aria-labelledby': string;
34
40
  'aria-describedby': string | undefined;
35
41
  };
@@ -1,13 +1,17 @@
1
1
  import { cx } from "../cx.js";
2
2
  import { panelItemClassName } from "./floating.js";
3
3
  //#region src/components/comboboxItems.ts
4
+ /** The end of an option's row: its hint, then the check while it is chosen, on the label's
5
+ * line rather than the middle of a row with a description under it. */
6
+ var pickerEndClassName = "ml-auto flex h-[1lh] shrink-0 items-center gap-2 self-start pl-2";
7
+ var pickerHintClassName = "text-xs tabular-nums text-(--theme-muted-text-color)";
4
8
  /** An option's row in a Select's or a Combobox's list, so both lists look alike: the icon, the
5
9
  * label over its description, and the check at the end. */
6
10
  var pickerItemClassName = cx(panelItemClassName, "data-selected:font-medium");
7
11
  /** How an option is named and described: by its label, with its description read after it. */
8
12
  function optionNaming(id, item) {
9
13
  return {
10
- "aria-labelledby": `${id}label`,
14
+ "aria-labelledby": item.hint ? `${id}label ${id}hint` : `${id}label`,
11
15
  "aria-describedby": item.accessibleDescription || item.description ? `${id}description` : void 0
12
16
  };
13
17
  }
@@ -19,4 +23,4 @@ function comboboxLeaves(items) {
19
23
  return items.flatMap((item) => isComboboxGroup(item) ? item.items : [item]);
20
24
  }
21
25
  //#endregion
22
- export { comboboxLeaves, isComboboxGroup, optionNaming, pickerItemClassName };
26
+ export { comboboxLeaves, isComboboxGroup, optionNaming, pickerEndClassName, pickerHintClassName, pickerItemClassName };
@@ -5,7 +5,11 @@ interface CloseDetails {
5
5
  }
6
6
  /** The `onOpenChange` of a modal or drawer that the host opens and closes:
7
7
  * Escape and a press outside close it unless it's not `dismissible`, and a
8
- * press on a toast never does, since the toast sits above the backdrop. */
8
+ * press on a toast never does, since the toast sits above the backdrop.
9
+ *
10
+ * An Escape whose default a layer inside already prevented is that layer's,
11
+ * such as a picker of the host's own or an editor's suggestions: it closes
12
+ * them, and the next Escape closes the dialog. */
9
13
  export declare function closeHandler(dismissible: boolean, onClose: () => void): (next: boolean, details: CloseDetails) => void;
10
14
  /** The row of a dialog's actions along its bottom edge, ruled off from its body. */
11
15
  export declare const dialogFooterClassName = "flex shrink-0 items-center justify-end gap-2 border-t border-(--theme-border) px-4 py-3";
@@ -2,11 +2,15 @@ import { pressedToast } from "./Toast.js";
2
2
  //#region src/components/dismiss.ts
3
3
  /** The `onOpenChange` of a modal or drawer that the host opens and closes:
4
4
  * Escape and a press outside close it unless it's not `dismissible`, and a
5
- * press on a toast never does, since the toast sits above the backdrop. */
5
+ * press on a toast never does, since the toast sits above the backdrop.
6
+ *
7
+ * An Escape whose default a layer inside already prevented is that layer's,
8
+ * such as a picker of the host's own or an editor's suggestions: it closes
9
+ * them, and the next Escape closes the dialog. */
6
10
  function closeHandler(dismissible, onClose) {
7
11
  return (next, details) => {
8
12
  if (next) return;
9
- if (!dismissible && details.reason === "escape-key" || details.reason === "outside-press" && pressedToast(details.event)) {
13
+ if (details.reason === "escape-key" && (!dismissible || details.event?.defaultPrevented) || details.reason === "outside-press" && pressedToast(details.event)) {
10
14
  details.cancel();
11
15
  return;
12
16
  }
@@ -7,11 +7,11 @@ export declare const panelClassName = "rounded-lg border border-(--theme-border)
7
7
  export declare const panelListClassName = "p-1";
8
8
  /** A row in a panel, inside its `panelListClassName` gutter; its text lines up with a field's. */
9
9
  export declare const panelItemClassName = "flex w-full cursor-pointer select-none items-center gap-2 rounded-md px-2 py-1.5 text-left outline-none data-highlighted:bg-(--theme-hover) data-highlighted:text-(--theme-app) data-disabled:cursor-not-allowed data-disabled:opacity-50";
10
- /** A tooltip's or infotip's small inverted surface. */
11
- export declare const tipClassName = "rounded-md bg-(--theme-app) px-2 py-1 text-xs text-(--theme-app-bg) shadow-(--theme-shadow) whitespace-pre-line break-words data-instant:transition-none origin-(--transform-origin) transition-[transform,opacity] duration-100 data-starting-style:scale-95 data-starting-style:opacity-0 data-ending-style:scale-95 data-ending-style:opacity-0 motion-reduce:data-starting-style:scale-100 motion-reduce:data-ending-style:scale-100";
12
- export declare const tipArrowClassName = "size-2 rotate-45 bg-(--theme-app) data-[side=top]:-bottom-1 data-[side=bottom]:-top-1 data-[side=left]:-right-1 data-[side=right]:-left-1";
10
+ /** A tooltip's, infotip's or popover tip's surface: a small panel in the page's colors, so a
11
+ * hint reads as part of the page rather than a dark patch over it. */
12
+ export declare const tipClassName = "max-w-64 rounded-lg border border-(--theme-border) bg-(--theme-panel-bg) px-2.5 py-1.5 text-xs text-(--theme-app) shadow-(--theme-shadow-lg) whitespace-pre-line break-words data-instant:transition-none origin-(--transform-origin) transition-[transform,opacity] duration-100 data-starting-style:scale-95 data-starting-style:opacity-0 data-ending-style:scale-95 data-ending-style:opacity-0 motion-reduce:data-starting-style:scale-100 motion-reduce:data-ending-style:scale-100";
13
13
  /** A hover card's surface; the card sets its own width and padding. */
14
- export declare const cardClassName = "overflow-hidden rounded-xl border border-(--theme-border) bg-(--theme-panel-bg) text-(--theme-app) shadow-(--theme-shadow-lg) outline-none origin-(--transform-origin) transition-[transform,opacity] duration-100 data-starting-style:scale-95 data-starting-style:opacity-0 data-ending-style:scale-95 data-ending-style:opacity-0 motion-reduce:data-starting-style:scale-100 motion-reduce:data-ending-style:scale-100";
14
+ export declare const cardClassName = "overflow-hidden rounded-lg border border-(--theme-border) bg-(--theme-panel-bg) text-(--theme-app) shadow-(--theme-shadow-lg) outline-none origin-(--transform-origin) transition-[transform,opacity] duration-100 data-starting-style:scale-95 data-starting-style:opacity-0 data-ending-style:scale-95 data-ending-style:opacity-0 motion-reduce:data-starting-style:scale-100 motion-reduce:data-ending-style:scale-100";
15
15
  /** Where a popup opens: under an element, such as the button that opened it, or
16
16
  * at a pointer event's point, which then moves with the element it landed on. */
17
17
  export type FloatingAnchor = Element | {