@parallelworks/ui 0.51.0 → 0.53.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 (250) hide show
  1. package/README.md +197 -17
  2. package/dist/ai/agent/toolStrings.d.ts +2 -0
  3. package/dist/ai/agent/toolStrings.js +20 -18
  4. package/dist/ai/ai.css +17 -3
  5. package/dist/ai/components/AllocationSelector.js +5 -1
  6. package/dist/ai/components/AttachmentManager.js +51 -42
  7. package/dist/ai/components/AttachmentUpload.d.ts +4 -2
  8. package/dist/ai/components/AttachmentUpload.js +9 -9
  9. package/dist/ai/components/BlockedGroupBanner.js +8 -14
  10. package/dist/ai/components/BranchNavigator.js +11 -12
  11. package/dist/ai/components/ChatEmptyState.js +12 -19
  12. package/dist/ai/components/ChatInput.d.ts +4 -3
  13. package/dist/ai/components/ChatInput.js +27 -13
  14. package/dist/ai/components/ChatMessage.js +45 -121
  15. package/dist/ai/components/ChatMessageList.d.ts +5 -2
  16. package/dist/ai/components/ChatMessageList.js +89 -51
  17. package/dist/ai/components/ChatSidebar.js +11 -7
  18. package/dist/ai/components/ChatThread.js +1 -13
  19. package/dist/ai/components/DragOverlay.js +3 -3
  20. package/dist/ai/components/MessageAttachments.d.ts +10 -0
  21. package/dist/ai/components/MessageAttachments.js +78 -0
  22. package/dist/ai/components/ModelSelector.js +3 -3
  23. package/dist/ai/components/PastedText.js +2 -2
  24. package/dist/ai/components/ProviderIssueBanner.js +19 -23
  25. package/dist/ai/components/ShareDialog.js +2 -2
  26. package/dist/ai/components/agent/ActivityLine.d.ts +0 -2
  27. package/dist/ai/components/agent/ActivityLine.js +8 -51
  28. package/dist/ai/components/agent/AgentMessageParts.js +114 -53
  29. package/dist/ai/core/ChatProvider.d.ts +16 -5
  30. package/dist/ai/core/ChatProvider.js +41 -8
  31. package/dist/ai/core/config.js +4 -3
  32. package/dist/ai/index.d.ts +1 -1
  33. package/dist/ai/index.js +3 -3
  34. package/dist/ai/strings.d.ts +29 -3
  35. package/dist/ai/strings.js +80 -26
  36. package/dist/ai/types.d.ts +4 -0
  37. package/dist/ai/ui/Notice.d.ts +2 -2
  38. package/dist/ai/ui/Notice.js +29 -62
  39. package/dist/ai/ui/sidebar.d.ts +5 -3
  40. package/dist/ai/ui/sidebar.js +22 -10
  41. package/dist/components/ActionMenu.d.ts +1 -0
  42. package/dist/components/ActionMenu.js +6 -1
  43. package/dist/components/AppLink.d.ts +26 -0
  44. package/dist/components/AppLink.js +51 -0
  45. package/dist/components/Avatar.d.ts +2 -1
  46. package/dist/components/Avatar.js +4 -2
  47. package/dist/components/Button.d.ts +15 -5
  48. package/dist/components/Button.js +47 -40
  49. package/dist/components/Callout.d.ts +31 -7
  50. package/dist/components/Callout.js +50 -19
  51. package/dist/components/Card.d.ts +11 -6
  52. package/dist/components/Card.js +14 -8
  53. package/dist/components/Checkbox.js +2 -1
  54. package/dist/components/ColorInput.js +5 -3
  55. package/dist/components/Combobox.js +49 -19
  56. package/dist/components/ConfirmModal.d.ts +19 -8
  57. package/dist/components/ConfirmModal.js +31 -53
  58. package/dist/components/CopyButton.d.ts +38 -0
  59. package/dist/components/CopyButton.js +68 -0
  60. package/dist/components/CreateModal.js +118 -111
  61. package/dist/components/DatePicker.js +12 -8
  62. package/dist/components/DescriptionList.d.ts +25 -5
  63. package/dist/components/DescriptionList.js +56 -22
  64. package/dist/components/Disclosure.js +1 -1
  65. package/dist/components/Drawer.js +10 -16
  66. package/dist/components/Field.d.ts +16 -5
  67. package/dist/components/Field.js +63 -8
  68. package/dist/components/IconButton.d.ts +14 -5
  69. package/dist/components/IconButton.js +25 -14
  70. package/dist/components/InfoTip.d.ts +12 -1
  71. package/dist/components/InfoTip.js +13 -2
  72. package/dist/components/Input.d.ts +14 -8
  73. package/dist/components/Input.js +46 -31
  74. package/dist/components/Loader.js +1 -1
  75. package/dist/components/MarkdownImpl.d.ts +1 -0
  76. package/dist/components/MarkdownImpl.js +1 -0
  77. package/dist/components/MenuEntries.d.ts +4 -0
  78. package/dist/components/MenuEntries.js +11 -12
  79. package/dist/components/Meter.js +5 -4
  80. package/dist/components/Modal.d.ts +28 -4
  81. package/dist/components/Modal.js +37 -14
  82. package/dist/components/Overview.d.ts +20 -12
  83. package/dist/components/Overview.js +14 -9
  84. package/dist/components/PageHeader.d.ts +47 -65
  85. package/dist/components/PageHeader.js +275 -153
  86. package/dist/components/PageHeaderAction.d.ts +67 -0
  87. package/dist/components/PageHeaderAction.js +107 -0
  88. package/dist/components/Pagination.js +6 -16
  89. package/dist/components/Popover.d.ts +4 -1
  90. package/dist/components/Popover.js +5 -3
  91. package/dist/components/Provider.d.ts +79 -19
  92. package/dist/components/Provider.js +140 -130
  93. package/dist/components/Radio.js +2 -1
  94. package/dist/components/RefreshButton.js +7 -8
  95. package/dist/components/RequiredMark.js +1 -1
  96. package/dist/components/Section.js +1 -1
  97. package/dist/components/Select.d.ts +4 -9
  98. package/dist/components/Select.js +24 -11
  99. package/dist/components/SettingModeOption.d.ts +1 -1
  100. package/dist/components/SettingModeOption.js +7 -1
  101. package/dist/components/SettingsCard.d.ts +5 -3
  102. package/dist/components/SettingsCard.js +27 -20
  103. package/dist/components/Slider.js +1 -1
  104. package/dist/components/StatusBadge.js +2 -2
  105. package/dist/components/Switch.js +5 -4
  106. package/dist/components/Table.d.ts +30 -20
  107. package/dist/components/Table.js +50 -73
  108. package/dist/components/Tabs.d.ts +3 -7
  109. package/dist/components/Tabs.js +6 -10
  110. package/dist/components/ThemeEditor.js +18 -8
  111. package/dist/components/Toast.d.ts +11 -3
  112. package/dist/components/Toast.js +45 -20
  113. package/dist/components/buttonClasses.js +1 -1
  114. package/dist/components/comboboxItems.d.ts +4 -0
  115. package/dist/components/comboboxItems.js +6 -1
  116. package/dist/components/dismiss.d.ts +12 -0
  117. package/dist/components/dismiss.js +19 -0
  118. package/dist/components/fieldBox.d.ts +4 -0
  119. package/dist/components/fieldBox.js +7 -3
  120. package/dist/components/floating.d.ts +3 -3
  121. package/dist/components/floating.js +1 -1
  122. package/dist/components/focus.d.ts +5 -0
  123. package/dist/components/focus.js +21 -1
  124. package/dist/components/markdownCodeBreaks.js +3 -4
  125. package/dist/components/pageHeaderStore.d.ts +41 -0
  126. package/dist/components/pageHeaderStore.js +67 -0
  127. package/dist/components/pathBreaks.d.ts +8 -0
  128. package/dist/components/pathBreaks.js +28 -0
  129. package/dist/components/segmented.js +1 -1
  130. package/dist/components/shortcutKey.d.ts +2 -1
  131. package/dist/components/shortcutKey.js +19 -2
  132. package/dist/components/splitter.js +1 -1
  133. package/dist/components/useCssIsDark.js +40 -18
  134. package/dist/components/useTheme.js +9 -10
  135. package/dist/dev.d.ts +9 -0
  136. package/dist/dev.js +14 -0
  137. package/dist/editor/Editor.d.ts +3 -2
  138. package/dist/editor/Editor.js +24 -5
  139. package/dist/editor/EditorField.d.ts +2 -1
  140. package/dist/editor/EditorField.js +11 -29
  141. package/dist/editor/FormCodePanel.d.ts +7 -3
  142. package/dist/editor/FormCodePanel.js +14 -7
  143. package/dist/editor/Monaco.d.ts +22 -6
  144. package/dist/editor/Monaco.js +177 -113
  145. package/dist/editor/editorModel.d.ts +1 -1
  146. package/dist/editor/editorModel.js +1 -1
  147. package/dist/editor/index.d.ts +6 -5
  148. package/dist/editor/index.js +5 -4
  149. package/dist/editor/languages.d.ts +24 -0
  150. package/dist/editor/languages.js +31 -0
  151. package/dist/editor/monacoFeatures.d.ts +7 -0
  152. package/dist/editor/monacoFeatures.js +19 -0
  153. package/dist/editor/themes.d.ts +8 -5
  154. package/dist/editor/themes.js +65 -32
  155. package/dist/editor/workers.d.ts +3 -3
  156. package/dist/editor/workers.js +8 -4
  157. package/dist/editor/yaml.d.ts +6 -2
  158. package/dist/editor/yaml.js +11 -2
  159. package/dist/editor/yamlLanguage.js +55 -38
  160. package/dist/file-explorer/FileExplorer.d.ts +18 -4
  161. package/dist/file-explorer/FileExplorer.js +204 -142
  162. package/dist/file-explorer/FileExplorerContext.js +1 -1
  163. package/dist/file-explorer/FilePreview/StreamedBadge.js +3 -1
  164. package/dist/file-explorer/FilePreview/Viewer.js +14 -10
  165. package/dist/file-explorer/FilePreview/index.js +4 -4
  166. package/dist/file-explorer/FileRow.d.ts +6 -2
  167. package/dist/file-explorer/FileRow.js +35 -17
  168. package/dist/file-explorer/FileRowsWindow.d.ts +2 -1
  169. package/dist/file-explorer/FileRowsWindow.js +36 -4
  170. package/dist/file-explorer/FileTable.d.ts +3 -1
  171. package/dist/file-explorer/FileTable.js +6 -3
  172. package/dist/file-explorer/TreeView.d.ts +5 -1
  173. package/dist/file-explorer/TreeView.js +86 -39
  174. package/dist/file-explorer/helpers.d.ts +2 -1
  175. package/dist/file-explorer/helpers.js +24 -23
  176. package/dist/file-explorer/lib/utils.d.ts +3 -0
  177. package/dist/file-explorer/lib/utils.js +6 -1
  178. package/dist/file-explorer/toasts.js +27 -19
  179. package/dist/file-explorer/treeRows.d.ts +6 -0
  180. package/dist/file-explorer/treeRows.js +19 -1
  181. package/dist/file-explorer/useNearEnd.js +3 -6
  182. package/dist/form/Fields/CheckboxGroupField.js +12 -5
  183. package/dist/form/Fields/DurationField.js +1 -1
  184. package/dist/form/Fields/LabelField.js +1 -1
  185. package/dist/form/Fields/ObjectField.d.ts +1 -1
  186. package/dist/form/Fields/ObjectField.js +3 -2
  187. package/dist/form/Fields/StringField.js +16 -29
  188. package/dist/form/Fields/TextAreaField.js +3 -4
  189. package/dist/form/Form.js +3 -8
  190. package/dist/form/Wizard/WizardNavigation.js +0 -3
  191. package/dist/form/Wizard/utils.js +2 -1
  192. package/dist/form/fieldFrame.d.ts +1 -1
  193. package/dist/form/fieldFrame.js +2 -2
  194. package/dist/form/types/fieldComponentTypes.d.ts +2 -1
  195. package/dist/graph/AnnotationBanner.d.ts +1 -2
  196. package/dist/graph/AnnotationBanner.js +30 -32
  197. package/dist/graph/Connectors.js +4 -1
  198. package/dist/graph/DependencyGraph.js +2 -2
  199. package/dist/graph/GraphEditor.js +11 -9
  200. package/dist/graph/GraphEditorDialogs.js +1 -1
  201. package/dist/graph/GraphNode.js +7 -4
  202. package/dist/graph/InputDialog.js +1 -1
  203. package/dist/graph/InputsEditor.js +14 -11
  204. package/dist/graph/MatrixGroup.js +9 -3
  205. package/dist/graph/Reveal.js +18 -10
  206. package/dist/graph/ShortcutsButton.d.ts +11 -2
  207. package/dist/graph/ShortcutsButton.js +14 -3
  208. package/dist/graph/TreeView.js +35 -18
  209. package/dist/graph/WorkflowSettingsDialog.js +1 -1
  210. package/dist/graph/editorFields.js +1 -1
  211. package/dist/graph/editorRows.js +16 -10
  212. package/dist/graph/editorStrings.d.ts +7 -0
  213. package/dist/graph/editorStrings.js +8 -1
  214. package/dist/graph/inputRefs.js +1 -1
  215. package/dist/graph/settingsViews.js +11 -18
  216. package/dist/graph/stepWith.js +1 -1
  217. package/dist/icons.d.ts +2 -0
  218. package/dist/icons.js +4 -2
  219. package/dist/index.d.ts +12 -12
  220. package/dist/index.js +16 -16
  221. package/dist/list/ActionToolbar.d.ts +42 -6
  222. package/dist/list/ActionToolbar.js +298 -101
  223. package/dist/list/ListPage.d.ts +15 -23
  224. package/dist/list/ListPage.js +42 -43
  225. package/dist/list/ListTable.d.ts +37 -7
  226. package/dist/list/ListTable.js +52 -12
  227. package/dist/list/ListViewControls.js +1 -1
  228. package/dist/list/UserHoverCard.js +7 -15
  229. package/dist/list/index.d.ts +2 -2
  230. package/dist/list/index.js +2 -2
  231. package/dist/list/listSearch.js +12 -10
  232. package/dist/list/listView.d.ts +10 -1
  233. package/dist/list/listView.js +15 -1
  234. package/dist/logviewer/LogViewer.d.ts +4 -2
  235. package/dist/logviewer/LogViewer.js +87 -69
  236. package/dist/logviewer/logviewer.css +3 -2
  237. package/dist/reducedMotion.d.ts +5 -0
  238. package/dist/reducedMotion.js +20 -0
  239. package/dist/safeUrl.d.ts +1 -1
  240. package/dist/safeUrl.js +4 -2
  241. package/dist/styles.css +1 -1
  242. package/package.json +5 -2
  243. package/dist/components/Breadcrumbs.d.ts +0 -37
  244. package/dist/components/Breadcrumbs.js +0 -90
  245. package/dist/components/CopyToClipboard.d.ts +0 -17
  246. package/dist/components/CopyToClipboard.js +0 -66
  247. package/dist/components/Sort.d.ts +0 -9
  248. package/dist/components/Sort.js +0 -42
  249. package/dist/file-explorer/FilePreview/CodePreviewEditor.d.ts +0 -6
  250. package/dist/file-explorer/FilePreview/CodePreviewEditor.js +0 -64
@@ -1,22 +1,28 @@
1
1
  import { cx } from "../cx.js";
2
2
  import { Radio } from "./Radio.js";
3
3
  import { jsx, jsxs } from "react/jsx-runtime";
4
+ import { useId } from "react";
4
5
  //#region src/components/SettingModeOption.tsx
5
6
  /** A named and described choice in a SettingsCard, picking between modes such
6
7
  * as default or custom. Stack them in a `RadioGroup`, which holds the value. */
7
8
  function SettingModeOption({ value, label, description, disabled }) {
9
+ const id = useId();
8
10
  return /* @__PURE__ */ jsxs("label", {
9
- className: cx("flex items-start gap-3 px-5 py-4", disabled ? "cursor-default opacity-60" : "cursor-pointer", "border-t border-(--theme-border) first:border-t-0"),
11
+ className: cx("flex items-start gap-3 px-5 py-4", disabled ? "cursor-not-allowed opacity-50" : "cursor-pointer", "border-t border-(--theme-border) first:border-t-0"),
10
12
  children: [/* @__PURE__ */ jsx(Radio, {
11
13
  value,
12
14
  disabled,
15
+ "aria-labelledby": `${id}label`,
16
+ "aria-describedby": `${id}description`,
13
17
  className: "mt-0.5"
14
18
  }), /* @__PURE__ */ jsxs("div", {
15
19
  className: "min-w-0",
16
20
  children: [/* @__PURE__ */ jsx("div", {
21
+ id: `${id}label`,
17
22
  className: "font-semibold theme-text leading-tight",
18
23
  children: label
19
24
  }), /* @__PURE__ */ jsx("div", {
25
+ id: `${id}description`,
20
26
  className: "theme-muted-text text-xs leading-snug mt-0.5",
21
27
  children: description
22
28
  })]
@@ -1,4 +1,4 @@
1
- import type { ReactNode } from 'react';
1
+ import { type ReactNode } from 'react';
2
2
  export interface SettingsCardProps {
3
3
  /** Names the card above it. Leave it out on a page's first card, where the
4
4
  * page title already names it. */
@@ -8,6 +8,8 @@ export interface SettingsCardProps {
8
8
  * header's far edge, such as Save. */
9
9
  action?: ReactNode;
10
10
  actionAlign?: 'beside' | 'end' | undefined;
11
+ /** The title's level in the page's outline; its SettingsHeadings sit one below. */
12
+ headingLevel?: 2 | 3 | undefined;
11
13
  /** Lets content such as an inline menu reach past the card's rounded edge. */
12
14
  overflowVisible?: boolean | undefined;
13
15
  className?: string | undefined;
@@ -16,8 +18,8 @@ export interface SettingsCardProps {
16
18
  }
17
19
  /** A page's settings, grouped: a titled panel of SettingRows, each ruled off from
18
20
  * the next. Cards stack with room between them. */
19
- export declare function SettingsCard({ title, description, action, actionAlign, overflowVisible, className, children, }: SettingsCardProps): import("react").JSX.Element;
20
- /** A heading between groups of rows inside a SettingsCard. */
21
+ export declare function SettingsCard({ title, description, action, actionAlign, headingLevel, overflowVisible, className, children, }: SettingsCardProps): import("react").JSX.Element;
22
+ /** A heading between groups of rows inside a SettingsCard, a level below the card's title. */
21
23
  export declare function SettingsHeading({ children }: {
22
24
  children: ReactNode;
23
25
  }): import("react").JSX.Element;
@@ -1,32 +1,39 @@
1
1
  import { cx } from "../cx.js";
2
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { createContext, useContext } from "react";
3
4
  //#region src/components/SettingsCard.tsx
5
+ var HeadingLevel = createContext(3);
4
6
  /** A page's settings, grouped: a titled panel of SettingRows, each ruled off from
5
7
  * the next. Cards stack with room between them. */
6
- function SettingsCard({ title, description, action, actionAlign = "beside", overflowVisible = false, className, children }) {
7
- return /* @__PURE__ */ jsxs("section", {
8
- className: cx("mt-10 first:mt-0", className),
9
- children: [(title || action) && /* @__PURE__ */ jsxs("div", {
10
- className: "mb-3 px-0.5",
11
- children: [/* @__PURE__ */ jsxs("div", {
12
- className: cx("flex items-center gap-1.5", actionAlign === "end" && "justify-between"),
13
- children: [title && /* @__PURE__ */ jsx("h2", {
14
- className: "text-[15px] leading-none font-semibold theme-text",
15
- children: title
16
- }), action]
17
- }), description && /* @__PURE__ */ jsx("p", {
18
- className: "mt-1.5 text-xs leading-snug theme-muted-text",
19
- children: description
8
+ function SettingsCard({ title, description, action, actionAlign = "beside", headingLevel = 2, overflowVisible = false, className, children }) {
9
+ const Heading = `h${headingLevel}`;
10
+ return /* @__PURE__ */ jsx(HeadingLevel, {
11
+ value: headingLevel + 1,
12
+ children: /* @__PURE__ */ jsxs("section", {
13
+ className: cx("mt-10 first:mt-0", className),
14
+ children: [(title || action) && /* @__PURE__ */ jsxs("div", {
15
+ className: "mb-3 px-0.5",
16
+ children: [/* @__PURE__ */ jsxs("div", {
17
+ className: cx("flex items-center gap-1.5", actionAlign === "end" && "justify-between"),
18
+ children: [title && /* @__PURE__ */ jsx(Heading, {
19
+ className: "text-[15px] leading-none font-semibold theme-text",
20
+ children: title
21
+ }), action]
22
+ }), description && /* @__PURE__ */ jsx("p", {
23
+ className: "mt-1.5 text-xs leading-snug theme-muted-text",
24
+ children: description
25
+ })]
26
+ }), /* @__PURE__ */ jsx("div", {
27
+ className: cx("panel divide-y divide-(--theme-border)", overflowVisible ? "overflow-visible" : "overflow-hidden"),
28
+ children
20
29
  })]
21
- }), /* @__PURE__ */ jsx("div", {
22
- className: cx("panel divide-y divide-(--theme-border)", overflowVisible ? "overflow-visible" : "overflow-hidden"),
23
- children
24
- })]
30
+ })
25
31
  });
26
32
  }
27
- /** A heading between groups of rows inside a SettingsCard. */
33
+ /** A heading between groups of rows inside a SettingsCard, a level below the card's title. */
28
34
  function SettingsHeading({ children }) {
29
- return /* @__PURE__ */ jsx("h3", {
35
+ const Heading = `h${useContext(HeadingLevel)}`;
36
+ return /* @__PURE__ */ jsx(Heading, {
30
37
  className: "px-5 py-3 text-sm font-semibold tracking-wider uppercase theme-muted-panel theme-muted-text",
31
38
  children
32
39
  });
@@ -20,7 +20,7 @@ function Slider$1({ value, onValueChange, min, max, step = 1, disabled = false,
20
20
  className: "h-1 w-full rounded-full bg-(--theme-border)",
21
21
  children: [/* @__PURE__ */ jsx(Slider.Indicator, { className: "rounded-full bg-(--theme-accent)" }), /* @__PURE__ */ jsx(Slider.Thumb, {
22
22
  "aria-label": ariaLabel,
23
- className: "size-4 rounded-full border-2 border-(--theme-accent) bg-(--theme-panel-bg) shadow-sm outline-none has-[:focus-visible]:ring-2 has-[:focus-visible]:ring-(--theme-focus-ring)"
23
+ className: "size-4 rounded-full border-2 border-(--theme-accent) bg-(--theme-panel-bg) shadow-sm has-[:focus-visible]:outline-2 has-[:focus-visible]:outline-offset-2 has-[:focus-visible]:outline-(--theme-focus)"
24
24
  })]
25
25
  })
26
26
  })
@@ -13,7 +13,7 @@ function StatusBadge({ children, variant = "default", pulse = false, dot = false
13
13
  children: [
14
14
  pulse && /* @__PURE__ */ jsxs("span", {
15
15
  className: "relative flex h-2 w-2",
16
- children: [/* @__PURE__ */ jsx("span", { className: cx("absolute inline-flex h-full w-full animate-ping rounded-full opacity-75", toneFill[variant]) }), /* @__PURE__ */ jsx("span", { className: cx("relative inline-flex h-2 w-2 rounded-full", toneFill[variant]) })]
16
+ children: [/* @__PURE__ */ jsx("span", { className: cx("absolute inline-flex h-full w-full animate-ping rounded-full opacity-75 motion-reduce:hidden", toneFill[variant]) }), /* @__PURE__ */ jsx("span", { className: cx("relative inline-flex h-2 w-2 rounded-full", toneFill[variant]) })]
17
17
  }),
18
18
  dot && !pulse && /* @__PURE__ */ jsx("span", { className: cx("inline-flex h-1.5 w-1.5 rounded-full", toneFill[variant]) }),
19
19
  children
@@ -27,7 +27,7 @@ function StatusDot({ variant = "default", pulse = false, size = 8, className })
27
27
  width: size,
28
28
  height: size
29
29
  },
30
- children: [pulse && /* @__PURE__ */ jsx("span", { className: cx("absolute inline-flex h-full w-full animate-ping rounded-full opacity-75", toneFill[variant]) }), /* @__PURE__ */ jsx("span", {
30
+ children: [pulse && /* @__PURE__ */ jsx("span", { className: cx("absolute inline-flex h-full w-full animate-ping rounded-full opacity-75 motion-reduce:hidden", toneFill[variant]) }), /* @__PURE__ */ jsx("span", {
31
31
  className: cx("relative inline-flex rounded-full", toneFill[variant]),
32
32
  style: {
33
33
  width: size,
@@ -1,15 +1,16 @@
1
1
  import { cx } from "../cx.js";
2
+ import { focusOutline } from "./fieldBox.js";
2
3
  import { jsx, jsxs } from "react/jsx-runtime";
3
4
  import { Switch } from "@base-ui/react/switch";
4
5
  //#region src/components/Switch.tsx
5
6
  var sizes = {
6
7
  sm: {
7
8
  root: "h-5 w-9",
8
- thumb: "size-4 data-checked:translate-x-4"
9
+ thumb: "size-4 data-checked:translate-x-4 rtl:data-checked:-translate-x-4"
9
10
  },
10
11
  md: {
11
12
  root: "h-6 w-11",
12
- thumb: "size-5 data-checked:translate-x-5"
13
+ thumb: "size-5 data-checked:translate-x-5 rtl:data-checked:-translate-x-5"
13
14
  }
14
15
  };
15
16
  /**
@@ -20,8 +21,8 @@ var sizes = {
20
21
  function Switch$1({ size = "md", className, onLabel, offLabel, ...props }) {
21
22
  const control = /* @__PURE__ */ jsx(Switch.Root, {
22
23
  ...props,
23
- className: cx("peer inline-flex shrink-0 items-center rounded-full p-0.5 bg-(--theme-border) transition-colors duration-200 cursor-pointer outline-none", "data-checked:bg-(--theme-accent)", "focus-visible:ring-2 focus-visible:ring-(--theme-focus-ring) aria-invalid:ring-2 aria-invalid:ring-(--theme-error)", "data-disabled:cursor-not-allowed data-disabled:opacity-50", sizes[size].root, className),
24
- children: /* @__PURE__ */ jsx(Switch.Thumb, { className: cx("rounded-full bg-white shadow-sm transition-transform duration-200", sizes[size].thumb) })
24
+ className: cx("peer inline-flex shrink-0 items-center rounded-full p-0.5 bg-(--theme-border-strong) transition-colors duration-200 cursor-pointer motion-reduce:transition-none", "data-checked:bg-(--theme-accent)", focusOutline, "aria-invalid:ring-2 aria-invalid:ring-(--theme-error)", "data-disabled:cursor-not-allowed data-disabled:opacity-50", sizes[size].root, className),
25
+ children: /* @__PURE__ */ jsx(Switch.Thumb, { className: cx("rounded-full bg-white shadow-sm transition-transform duration-200 motion-reduce:transition-none", sizes[size].thumb) })
25
26
  });
26
27
  if (onLabel === void 0 && offLabel === void 0) return control;
27
28
  return /* @__PURE__ */ jsxs("span", {
@@ -1,24 +1,30 @@
1
1
  import React from 'react';
2
- import type { TDirection } from './Sort.js';
3
- interface IItemProps extends React.TdHTMLAttributes<HTMLTableCellElement> {
2
+ /** Which way a column sorts, as `aria-sort` names it. */
3
+ export type SortDirection = 'ascending' | 'descending' | 'none';
4
+ /** `comfortable` gives each row room; `compact` fits a short key and value list. */
5
+ export type TableDensity = 'comfortable' | 'compact';
6
+ interface ItemProps extends React.TdHTMLAttributes<HTMLTableCellElement> {
7
+ /** Lets the text wrap; by default a cell keeps to one line. */
4
8
  wrap?: boolean;
5
- colspan?: number;
6
9
  }
7
- declare function Item({ wrap, children, className, colspan, ...tdProps }: IItemProps): React.JSX.Element;
8
- declare function CompactItem({ wrap, children, className, colspan, ...tdProps }: IItemProps): React.JSX.Element;
9
- interface ITableHeaderProps {
10
+ declare function Item({ wrap, children, className, ...tdProps }: ItemProps): React.JSX.Element;
11
+ interface HeaderProps {
10
12
  children?: React.ReactNode;
11
- className?: string;
13
+ className?: string | undefined;
12
14
  style?: React.CSSProperties | undefined;
13
- colspan?: number;
14
- onClick?: (() => void) | undefined;
15
- sort?: TDirection | 'none';
16
- /** When false, drops uppercase + tracking-wider for a sentence-case header. */
17
- caps?: boolean;
15
+ colSpan?: number | undefined;
16
+ /** Which way the column sorts now. With `onSort`, the header is a button
17
+ * that shows it; `none` for a sortable column that isn't the sorted one. */
18
+ sort?: SortDirection | undefined;
19
+ /** Sorts by this column, or flips its direction. */
20
+ onSort?: (() => void) | undefined;
21
+ /** False sets the title in sentence case instead of small capitals. */
22
+ caps?: boolean | undefined;
18
23
  }
19
- declare function Header({ children, className, style, colspan, onClick, sort, caps, }: ITableHeaderProps): React.JSX.Element;
20
- interface ITableProps {
24
+ declare function Header({ children, className, style, colSpan, sort, onSort, caps }: HeaderProps): React.JSX.Element;
25
+ interface TableProps {
21
26
  children?: React.ReactNode;
27
+ density?: TableDensity | undefined;
22
28
  borderless?: boolean;
23
29
  /** When false, drops the theme-panel background. */
24
30
  panel?: boolean;
@@ -30,6 +36,13 @@ interface ITableProps {
30
36
  rounded?: boolean;
31
37
  roundedBottom?: boolean;
32
38
  isLoading?: boolean;
39
+ /** The header row stays in view while the rows scroll under it. It sticks
40
+ * to the nearest scrolling ancestor, `--table-header-top` below its top
41
+ * edge (0 unless an ancestor sets it), so the table no longer scrolls or
42
+ * clips on its own: a box that scrolls itself is all a sticky header can
43
+ * stick to. Its ancestor scrolls it sideways as well as down. Rows pass
44
+ * under the header, so a `theadClassName` of your own needs a background. */
45
+ stickyHeader?: boolean | undefined;
33
46
  /** Forwarded to the `<table>`, for attributes that must sit on the element owning
34
47
  * the rows — `role='grid'`, aria-activedescendant, aria-rowcount. `className` is
35
48
  * excluded because it is spread after the table's own classes; use the
@@ -39,14 +52,11 @@ interface ITableProps {
39
52
  'aria-rowcount'?: number;
40
53
  };
41
54
  }
42
- export declare function Table({ borderless, panel, className, wrapperClassName, tbodyClassName, theadClassName, children, roundedTop, rounded, roundedBottom, isLoading, tableProps, }: ITableProps): React.JSX.Element;
55
+ /** Rows of values under a row of column titles. Put `Table.Header`s first among
56
+ * the children, then `<tr>`s of `Table.Item`s. */
57
+ export declare function Table({ density, borderless, panel, className, wrapperClassName, tbodyClassName, theadClassName, children, roundedTop, rounded, roundedBottom, isLoading, stickyHeader, tableProps, }: TableProps): React.JSX.Element;
43
58
  export declare namespace Table {
44
59
  export { Header };
45
60
  export { Item };
46
61
  }
47
- export declare function CompactTable({ wrapperClassName, className, tbodyClassName, children, roundedTop, rounded, roundedBottom, }: Pick<ITableProps, 'wrapperClassName' | 'className' | 'tbodyClassName' | 'children' | 'roundedTop' | 'rounded' | 'roundedBottom'>): React.JSX.Element;
48
- export declare namespace CompactTable {
49
- export { Header };
50
- export { CompactItem as Item };
51
- }
52
62
  export {};
@@ -1,41 +1,41 @@
1
1
  import { cx } from "../cx.js";
2
+ import { SortDownIcon, SortUnsortedIcon, SortUpIcon } from "../icons.js";
2
3
  import { Loader } from "./Loader.js";
3
4
  import { jsx, jsxs } from "react/jsx-runtime";
4
- import React from "react";
5
+ import React, { createContext, useContext } from "react";
5
6
  //#region src/components/Table.tsx
6
- function Item({ wrap = false, children, className, colspan = 1, ...tdProps }) {
7
- const yPadding = className?.includes("py-") ? "" : "py-4";
8
- const xPadding = className?.includes("px-") ? "" : "px-2";
7
+ var DensityContext = createContext("comfortable");
8
+ var cellX = "px-3";
9
+ function Item({ wrap = false, children, className, ...tdProps }) {
10
+ const density = useContext(DensityContext);
9
11
  return /* @__PURE__ */ jsx("td", {
10
12
  ...tdProps,
11
- colSpan: colspan,
12
- className: cx(yPadding, xPadding, wrap ? "" : "whitespace-nowrap", className),
13
+ className: cx(cellX, density === "compact" ? "py-1.5 text-sm" : "py-4", !wrap && "whitespace-nowrap", className),
13
14
  children
14
15
  });
15
16
  }
16
- function CompactItem({ wrap = false, children, className, colspan = 1, ...tdProps }) {
17
- return /* @__PURE__ */ jsx("td", {
18
- ...tdProps,
19
- colSpan: colspan,
20
- className: cx("px-2 text-sm font-medium", !wrap && "whitespace-nowrap", className),
21
- children
22
- });
23
- }
24
- function Header({ children, className, style, colspan = 1, onClick, sort, caps = true }) {
25
- const yPadding = className?.includes("py-") ? "" : "py-3";
26
- const xPadding = className?.includes("px-") ? "" : "px-3";
27
- const textAlign = className?.includes("text-") ? "" : "text-left";
17
+ var sortIcons = {
18
+ ascending: SortUpIcon,
19
+ descending: SortDownIcon,
20
+ none: SortUnsortedIcon
21
+ };
22
+ function Header({ children, className, style, colSpan, sort, onSort, caps = true }) {
23
+ const density = useContext(DensityContext);
24
+ const Icon = sortIcons[sort ?? "none"];
28
25
  return /* @__PURE__ */ jsx("th", {
29
26
  scope: "col",
30
- colSpan: colspan,
27
+ colSpan,
31
28
  style,
32
- "aria-sort": sort === "unsorted" ? "none" : sort,
33
- className: cx(className, yPadding, xPadding, textAlign, "text-xs font-medium", caps ? "uppercase tracking-wider" : ""),
34
- children: onClick ? /* @__PURE__ */ jsx("button", {
29
+ "aria-sort": onSort ? sort ?? "none" : void 0,
30
+ className: cx(cellX, density === "compact" ? "py-2" : "py-3", "text-left text-xs font-medium", caps && "uppercase tracking-wider", className),
31
+ children: onSort ? /* @__PURE__ */ jsxs("button", {
35
32
  type: "button",
36
- onClick,
37
- className: "w-full cursor-pointer text-inherit [text-align:inherit] hover:opacity-80 transition-opacity",
38
- children
33
+ onClick: onSort,
34
+ className: "group/sort -mx-1 -my-1 inline-flex cursor-pointer py-1 align-middle items-center gap-1 rounded px-1 text-inherit [text-transform:inherit] hover:text-(--theme-app) focus-visible:outline-2 focus-visible:outline-(--theme-link) in-[.text-right]:flex-row-reverse",
35
+ children: [children, /* @__PURE__ */ jsx(Icon, {
36
+ "aria-hidden": "true",
37
+ className: cx("size-3.5 shrink-0", (sort ?? "none") === "none" && "opacity-0 group-hover/sort:opacity-40 group-focus-visible/sort:opacity-40 pointer-coarse:opacity-40")
38
+ })]
39
39
  }) : children
40
40
  });
41
41
  }
@@ -43,60 +43,37 @@ var isHeaderChild = (child) => {
43
43
  if (!React.isValidElement(child)) return false;
44
44
  return child.type === Header || typeof child.type === "function" && child.type.isTableHeader === true;
45
45
  };
46
- var getHeaders = (children) => children.filter(isHeaderChild);
47
- function Table({ borderless = false, panel = true, className = "", wrapperClassName = "", tbodyClassName = "divide-y", theadClassName = "theme-muted-panel", children, roundedTop = false, rounded = false, roundedBottom = false, isLoading = false, tableProps }) {
48
- const ChildrenArr = React.Children.toArray(children);
49
- const Headers = getHeaders(ChildrenArr);
50
- const hasOverflow = wrapperClassName.split(" ").some((cls) => cls.startsWith("overflow-"));
51
- return /* @__PURE__ */ jsx("div", {
52
- "aria-busy": isLoading,
53
- className: cx("flex flex-col w-full", !hasOverflow && "overflow-hidden", wrapperClassName),
54
- children: isLoading ? /* @__PURE__ */ jsx("div", {
55
- className: "flex justify-center items-center h-32",
56
- children: /* @__PURE__ */ jsx(Loader, {})
57
- }) : /* @__PURE__ */ jsx("div", {
58
- className: cx("align-middle inline-block min-w-full overflow-x-auto", panel && "theme-panel", !borderless && "border theme-border", rounded && "rounded-2xl", roundedBottom && "rounded-b-2xl", roundedTop && "rounded-t-2xl"),
59
- children: /* @__PURE__ */ jsxs("table", {
60
- className: cx(className, "min-w-full divide-y theme-border"),
61
- ...tableProps,
62
- children: [/* @__PURE__ */ jsx("thead", {
63
- className: theadClassName,
64
- children: /* @__PURE__ */ jsx("tr", { children: Headers })
65
- }), /* @__PURE__ */ jsx("tbody", {
66
- className: tbodyClassName,
67
- children: ChildrenArr.filter((c) => !isHeaderChild(c))
68
- })]
69
- })
70
- })
71
- });
72
- }
73
- function CompactTable({ wrapperClassName = "", className = "", tbodyClassName = "divide-y", children, roundedTop = false, rounded = false, roundedBottom = false }) {
74
- const ChildrenArr = React.Children.toArray(children);
75
- const Headers = getHeaders(ChildrenArr);
46
+ /** Rows of values under a row of column titles. Put `Table.Header`s first among
47
+ * the children, then `<tr>`s of `Table.Item`s. */
48
+ function Table({ density = "comfortable", borderless = false, panel = true, className, wrapperClassName = "", tbodyClassName = "divide-y", theadClassName = "theme-muted-panel", children, roundedTop = false, rounded = false, roundedBottom = false, isLoading = false, stickyHeader = false, tableProps }) {
49
+ const childList = React.Children.toArray(children);
76
50
  const hasOverflow = wrapperClassName.split(" ").some((cls) => cls.startsWith("overflow-"));
77
- return /* @__PURE__ */ jsx("div", {
78
- className: cx("flex flex-col w-full", !hasOverflow && "overflow-hidden", wrapperClassName),
51
+ return /* @__PURE__ */ jsx(DensityContext, {
52
+ value: density,
79
53
  children: /* @__PURE__ */ jsx("div", {
80
- className: cx("theme-panel inline-block min-w-full align-middle overflow-x-auto", rounded && "rounded-2xl", roundedBottom && "rounded-b-2xl pb-1", roundedTop && "rounded-t-2xl"),
81
- children: /* @__PURE__ */ jsxs("table", {
82
- className: cx("min-w-full divide-y theme-border", className),
83
- children: [/* @__PURE__ */ jsx("thead", {
84
- className: "theme-muted-panel",
85
- children: /* @__PURE__ */ jsx("tr", {
86
- className: "divide-x",
87
- children: Headers
88
- })
89
- }), /* @__PURE__ */ jsx("tbody", {
90
- className: tbodyClassName,
91
- children: ChildrenArr.filter((c) => !isHeaderChild(c))
92
- })]
54
+ "aria-busy": isLoading,
55
+ className: cx("flex w-full flex-col", !hasOverflow && !stickyHeader && "overflow-hidden", wrapperClassName),
56
+ children: isLoading ? /* @__PURE__ */ jsx("div", {
57
+ className: "flex h-32 items-center justify-center",
58
+ children: /* @__PURE__ */ jsx(Loader, {})
59
+ }) : /* @__PURE__ */ jsx("div", {
60
+ className: cx("inline-block min-w-full align-middle", !stickyHeader && "overflow-x-auto", panel && "theme-panel", !borderless && "border theme-border", rounded && "rounded-2xl", roundedBottom && "rounded-b-2xl", roundedTop && "rounded-t-2xl"),
61
+ children: /* @__PURE__ */ jsxs("table", {
62
+ className: cx("min-w-full divide-y theme-border", className),
63
+ ...tableProps,
64
+ children: [/* @__PURE__ */ jsx("thead", {
65
+ className: cx(stickyHeader && "sticky top-(--table-header-top,0px) z-(--layer-sticky) border-b-0 shadow-[inset_0_-1px_0_var(--theme-border)]", theadClassName),
66
+ children: /* @__PURE__ */ jsx("tr", { children: childList.filter(isHeaderChild) })
67
+ }), /* @__PURE__ */ jsx("tbody", {
68
+ className: tbodyClassName,
69
+ children: childList.filter((c) => !isHeaderChild(c))
70
+ })]
71
+ })
93
72
  })
94
73
  })
95
74
  });
96
75
  }
97
76
  Table.Header = Header;
98
77
  Table.Item = Item;
99
- CompactTable.Header = Header;
100
- CompactTable.Item = CompactItem;
101
78
  //#endregion
102
- export { CompactTable, Table };
79
+ export { Table };
@@ -11,10 +11,6 @@ export interface TabItem<Value extends string = string> {
11
11
  disabled?: boolean;
12
12
  testId?: string;
13
13
  }
14
- declare const stickyClasses: {
15
- underHeader: string;
16
- underToolbar: string;
17
- };
18
14
  export interface TabsProps<Value extends string> extends SegmentLayout {
19
15
  /** Names the set of tabs for assistive technology. */
20
16
  label: string;
@@ -29,8 +25,9 @@ export interface TabsProps<Value extends string> extends SegmentLayout {
29
25
  variant?: 'line' | 'segmented' | undefined;
30
26
  /** At the tab row's far end, such as a picker for what the tabs show. */
31
27
  end?: ReactNode;
32
- /** Pins the tab row as the page scrolls. */
33
- sticky?: keyof typeof stickyClasses | undefined;
28
+ /** Pins the tab row to the top of the page's scroller as it scrolls; give it a
29
+ * `top-*` in `className` to pin it under something else pinned there. */
30
+ sticky?: boolean | undefined;
34
31
  /** On the tab row. */
35
32
  className?: string | undefined;
36
33
  testId?: string | undefined;
@@ -49,4 +46,3 @@ export declare function TabPanel({ value, keepMounted, className, children, }: {
49
46
  className?: string | undefined;
50
47
  children: ReactNode;
51
48
  }): import("react").JSX.Element;
52
- export {};
@@ -1,20 +1,16 @@
1
1
  import { cx } from "../cx.js";
2
2
  import { Tooltip } from "./Tooltip.js";
3
- import { useLink } from "./Provider.js";
3
+ import { AppLink } from "./AppLink.js";
4
4
  import { SegmentContent, segmentClassName, segmentGroupClassName } from "./segmented.js";
5
5
  import { jsx, jsxs } from "react/jsx-runtime";
6
6
  import { useState } from "react";
7
7
  import { Tabs } from "@base-ui/react/tabs";
8
8
  //#region src/components/Tabs.tsx
9
- var stickyClasses = {
10
- underHeader: "sticky top-10 z-(--layer-sticky) bg-(--theme-app-bg)",
11
- underToolbar: "sticky top-22 z-(--layer-sticky) bg-(--theme-app-bg)"
12
- };
9
+ var stickyClassName = "sticky top-0 z-(--layer-sticky) bg-(--theme-app-bg)";
13
10
  /** Views of one thing, one shown at a time: panels below the tabs, or pages
14
11
  * the tabs link to. A lone tab would only repeat the page's title, so the row
15
12
  * hides unless there are two or more, or something at its end. */
16
13
  function Tabs$1({ label, items, value, defaultValue, onValueChange, variant = "line", fill = false, iconOnly = false, end, sticky, className, testId, children }) {
17
- const Link = useLink();
18
14
  const segmented = variant === "segmented";
19
15
  const layout = {
20
16
  fill,
@@ -30,9 +26,9 @@ function Tabs$1({ label, items, value, defaultValue, onValueChange, variant = "l
30
26
  "data-testid": item.testId,
31
27
  ...item.href ? {
32
28
  nativeButton: false,
33
- render: /* @__PURE__ */ jsx(Link, { href: item.href })
29
+ render: /* @__PURE__ */ jsx(AppLink, { href: item.href })
34
30
  } : {},
35
- className: segmented ? segmentClassName(item.value === current, layout) : "flex cursor-pointer select-none items-center gap-1.5 whitespace-nowrap px-2 py-2 text-sm font-semibold theme-muted-text outline-none transition-colors hover:theme-text focus-visible:rounded-sm focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-(--theme-link) data-active:text-(--theme-link) data-disabled:cursor-not-allowed data-disabled:opacity-50",
31
+ className: segmented ? segmentClassName(item.value === current, layout) : "flex cursor-pointer select-none items-center gap-1.5 whitespace-nowrap px-2 py-2 text-sm font-semibold theme-muted-text transition-colors hover:theme-text focus-visible:rounded-sm focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-(--theme-focus) data-active:text-(--theme-link) data-disabled:cursor-not-allowed data-disabled:opacity-50",
36
32
  children: /* @__PURE__ */ jsx(SegmentContent, {
37
33
  ...item,
38
34
  iconOnly: layout.iconOnly
@@ -54,7 +50,7 @@ function Tabs$1({ label, items, value, defaultValue, onValueChange, variant = "l
54
50
  "data-testid": testId,
55
51
  className: children ? void 0 : "contents",
56
52
  children: [showRow && /* @__PURE__ */ jsxs("div", {
57
- className: cx("flex items-center justify-between gap-2", !segmented && "border-b border-(--theme-border)", sticky && stickyClasses[sticky], className),
53
+ className: cx("flex items-center justify-between gap-2", !segmented && "border-b border-(--theme-border)", sticky && stickyClassName, className),
58
54
  children: [/* @__PURE__ */ jsxs(Tabs.List, {
59
55
  "aria-label": label,
60
56
  className: cx(segmented ? segmentGroupClassName(layout) : "relative flex min-w-0 overflow-x-auto"),
@@ -68,7 +64,7 @@ function TabPanel({ value, keepMounted, className, children }) {
68
64
  return /* @__PURE__ */ jsx(Tabs.Panel, {
69
65
  value,
70
66
  keepMounted,
71
- className: cx("outline-none", className),
67
+ className: cx("rounded-sm focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-(--theme-focus)", className),
72
68
  children
73
69
  });
74
70
  }
@@ -2,12 +2,12 @@ import { cx } from "../cx.js";
2
2
  import { useStrings } from "./Provider.js";
3
3
  import { useCopy } from "./useCopy.js";
4
4
  import { Button } from "./Button.js";
5
+ import { fieldBox } from "./fieldBox.js";
5
6
  import { parseColor, toHex } from "../theme/color.js";
6
7
  import { CODE_STYLES, DEFAULT_THEME, THEME_PRESETS, modeOf, parseTheme, schemeFor, serializeTheme } from "../theme/model.js";
7
8
  import { deriveTheme, generateTheme } from "../theme/derive.js";
8
9
  import { prefersWideGamut } from "../theme/index.js";
9
10
  import { Field } from "./Field.js";
10
- import { fieldBox } from "./fieldBox.js";
11
11
  import { Textarea } from "./Input.js";
12
12
  import { ColorInput } from "./ColorInput.js";
13
13
  import { Disclosure } from "./Disclosure.js";
@@ -32,7 +32,8 @@ function ThemeEditor({ value, onChange, mode, onModeChange, preference, onPrefer
32
32
  setOwnMode(next);
33
33
  onModeChange?.(next);
34
34
  };
35
- const scheme = schemeFor(value, editing);
35
+ const scheme = useMemo(() => schemeFor(value, editing), [value, editing]);
36
+ const serialized = useMemo(() => serializeTheme(value), [value]);
36
37
  const seed = scheme.interface;
37
38
  const update = (next) => onChange({
38
39
  ...value,
@@ -76,7 +77,7 @@ function ThemeEditor({ value, onChange, mode, onModeChange, preference, onPrefer
76
77
  children: THEME_PRESETS.map((preset) => {
77
78
  const native = preset.theme[editing] ? editing : preset.theme.light ? "light" : "dark";
78
79
  const own = schemeFor(preset.theme, native).interface;
79
- const current = serializeTheme(preset.theme) === serializeTheme(value);
80
+ const current = presetKey(preset.theme) === serialized;
80
81
  return /* @__PURE__ */ jsxs(Button, {
81
82
  size: "sm",
82
83
  variant: current ? "primary" : "secondary",
@@ -201,12 +202,21 @@ function ThemeEditor({ value, onChange, mode, onModeChange, preference, onPrefer
201
202
  })]
202
203
  });
203
204
  }
205
+ var presetKeys = /* @__PURE__ */ new WeakMap();
206
+ var presetKey = (theme) => {
207
+ let key = presetKeys.get(theme);
208
+ if (key === void 0) {
209
+ key = serializeTheme(theme);
210
+ presetKeys.set(theme, key);
211
+ }
212
+ return key;
213
+ };
204
214
  function Swatch({ colors }) {
205
215
  return /* @__PURE__ */ jsx("span", {
206
216
  "aria-hidden": "true",
207
217
  className: "flex -space-x-1",
208
218
  children: colors.map((c, i) => /* @__PURE__ */ jsx("span", {
209
- className: "size-3 rounded-full border border-black/10",
219
+ className: "size-3 rounded-full border border-(--theme-border-strong)",
210
220
  style: { backgroundColor: toHex(parseColor(c) ?? {
211
221
  l: 0,
212
222
  c: 0,
@@ -280,7 +290,7 @@ var CODE_SAMPLE = [
280
290
  /** The theme on a small page: a sidebar, a panel of text, a control, statuses and code. */
281
291
  function ThemePreview({ theme, mode }) {
282
292
  const { theme: t } = useStrings();
283
- const scheme = schemeFor(theme, mode);
293
+ const scheme = useMemo(() => schemeFor(theme, mode), [theme, mode]);
284
294
  const style = useMemo(() => {
285
295
  const generated = generateTheme(scheme, theme.code ? { code: theme.code } : {});
286
296
  return {
@@ -294,7 +304,7 @@ function ThemePreview({ theme, mode }) {
294
304
  "data-testid": "theme-preview",
295
305
  style,
296
306
  className: "flex min-h-80 overflow-hidden rounded-xl border border-(--theme-border) bg-(--theme-app-bg) text-sm text-(--theme-app) shadow-(--theme-shadow)",
297
- children: [/* @__PURE__ */ jsx("nav", {
307
+ children: [/* @__PURE__ */ jsx("div", {
298
308
  className: "flex w-32 shrink-0 flex-col gap-0.5 bg-(--theme-sidebar-bg) p-2",
299
309
  children: t.previewNav.map((item, i) => /* @__PURE__ */ jsx("span", {
300
310
  className: cx("rounded-md px-2 py-1.5", i === 1 ? "bg-(--theme-sidebar-active-bg) font-medium text-(--theme-sidebar-active-text)" : "text-(--theme-sidebar-text)"),
@@ -306,7 +316,7 @@ function ThemePreview({ theme, mode }) {
306
316
  /* @__PURE__ */ jsxs("div", {
307
317
  className: "flex flex-col gap-2 rounded-lg border border-(--theme-border) bg-(--theme-panel-bg) p-3 shadow-(--theme-shadow-sm)",
308
318
  children: [
309
- /* @__PURE__ */ jsx("h3", {
319
+ /* @__PURE__ */ jsx("p", {
310
320
  className: "font-semibold",
311
321
  children: t.previewHeading
312
322
  }),
@@ -337,7 +347,7 @@ function ThemePreview({ theme, mode }) {
337
347
  /* @__PURE__ */ jsxs("div", {
338
348
  className: "flex items-center gap-2",
339
349
  children: [/* @__PURE__ */ jsx("span", {
340
- className: cx(fieldBox({ size: "sm" }), "flex-1 cursor-default text-(--theme-placeholder) border-(--theme-border-strong)"),
350
+ className: cx(fieldBox({ size: "sm" }), "flex flex-1 cursor-default items-center text-(--theme-placeholder) border-(--theme-border-strong)"),
341
351
  children: t.previewSearch
342
352
  }), /* @__PURE__ */ jsx("span", {
343
353
  className: "rounded-md bg-(--theme-accent) px-3 py-1.5 text-xs font-medium text-(--theme-accent-text)",
@@ -1,10 +1,18 @@
1
1
  import { type ReactNode } from 'react';
2
+ import { type LinkTarget } from './AppLink.js';
2
3
  export type ToastTone = 'info' | 'success' | 'warning' | 'error';
3
- export interface ToastAction {
4
+ /** Runs `onClick`, or with `href` is a link, such as to what the toast reports
5
+ * on; either way the toast then closes. */
6
+ export type ToastAction = {
4
7
  label: ReactNode;
5
- /** Runs, then the toast closes. */
6
8
  onClick: () => void;
7
- }
9
+ href?: undefined;
10
+ } | ({
11
+ label: ReactNode;
12
+ onClick?: undefined;
13
+ } & LinkTarget & {
14
+ href: string;
15
+ });
8
16
  export interface ToastOptions {
9
17
  /** Shows the toast in place of an open one with this id, rather than stacking another. */
10
18
  id?: string | undefined;