@parallelworks/ui 0.77.0 → 0.78.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (262) hide show
  1. package/README.md +30 -5
  2. package/dist/access/AccessDrawer.d.ts +28 -7
  3. package/dist/access/AccessDrawer.js +216 -35
  4. package/dist/access/AccessList.d.ts +19 -1
  5. package/dist/access/AccessList.js +220 -9
  6. package/dist/access/GrantView.d.ts +3 -1
  7. package/dist/access/GrantView.js +17 -4
  8. package/dist/access/PrincipalPicker.js +5 -5
  9. package/dist/access/focus.js +1 -1
  10. package/dist/access/index.d.ts +2 -2
  11. package/dist/access/index.js +2 -2
  12. package/dist/access/strings.d.ts +18 -0
  13. package/dist/access/strings.js +20 -2
  14. package/dist/access/types.d.ts +26 -0
  15. package/dist/ai/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 +2 -2
  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 +26 -2
  60. package/dist/components/ConfirmModal.js +81 -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 +16 -4
  66. package/dist/components/CreateModal.js +27 -16
  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 +38 -2
  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 +13 -2
  113. package/dist/components/Popover.js +20 -21
  114. package/dist/components/Provider.d.ts +140 -3
  115. package/dist/components/Provider.js +142 -12
  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 +7 -7
  214. package/dist/graph/MatrixGroup.js +2 -2
  215. package/dist/graph/ProblemsButton.js +3 -3
  216. package/dist/graph/Reveal.js +1 -1
  217. package/dist/graph/RunWarningsList.js +1 -1
  218. package/dist/graph/ShortcutsButton.js +25 -8
  219. package/dist/graph/StepSummaries.js +1 -1
  220. package/dist/graph/TreeView.js +2 -2
  221. package/dist/graph/WorkflowSettingsDialog.js +3 -3
  222. package/dist/graph/editorFields.js +3 -3
  223. package/dist/graph/editorPrimitives.js +1 -1
  224. package/dist/graph/editorRows.js +5 -5
  225. package/dist/graph/fieldProblems.js +2 -2
  226. package/dist/graph/inputRefs.js +7 -6
  227. package/dist/graph/stepWith.js +2 -2
  228. package/dist/index.d.ts +30 -21
  229. package/dist/index.js +20 -12
  230. package/dist/list/ActionToolbar.d.ts +4 -0
  231. package/dist/list/ActionToolbar.js +35 -12
  232. package/dist/list/ListFilterBar.d.ts +42 -0
  233. package/dist/list/ListFilterBar.js +789 -0
  234. package/dist/list/ListPage.d.ts +42 -4
  235. package/dist/list/ListPage.js +56 -22
  236. package/dist/list/ListTable.d.ts +27 -3
  237. package/dist/list/ListTable.js +48 -23
  238. package/dist/list/ListToolbar.d.ts +31 -0
  239. package/dist/list/ListToolbar.js +43 -0
  240. package/dist/list/ListViewControls.d.ts +8 -4
  241. package/dist/list/ListViewControls.js +22 -14
  242. package/dist/list/UserHoverCard.d.ts +8 -2
  243. package/dist/list/UserHoverCard.js +26 -13
  244. package/dist/list/filterModel.d.ts +122 -0
  245. package/dist/list/filterModel.js +308 -0
  246. package/dist/list/index.d.ts +6 -2
  247. package/dist/list/index.js +6 -2
  248. package/dist/list/listSearch.d.ts +1 -1
  249. package/dist/list/listSearch.js +8 -4
  250. package/dist/list/listView.d.ts +24 -2
  251. package/dist/list/listView.js +47 -45
  252. package/dist/list/rowMenu.d.ts +10 -5
  253. package/dist/list/rowMenu.js +17 -7
  254. package/dist/list/useListFilters.d.ts +68 -0
  255. package/dist/list/useListFilters.js +252 -0
  256. package/dist/logviewer/LogViewer.js +4 -4
  257. package/dist/styles/theme.css +94 -0
  258. package/dist/styles.css +1 -1
  259. package/package.json +11 -11
  260. package/dist/assets/yaml.worker-k9AdOqzf.js +0 -1441
  261. package/dist/components/fullscreen.d.ts +0 -4
  262. package/dist/components/fullscreen.js +0 -18
@@ -1,14 +1,43 @@
1
- import type { ReactNode } from 'react';
2
- import { type MenuEntry, type MenuSearch } from './MenuEntries.js';
3
- /** A trigger that opens a menu, such as a header's "New" or "…" button. */
4
- export declare function ActionMenu({ items, label, search, align, triggerClassName, children, }: {
1
+ import { type ReactElement, type ReactNode } from 'react';
2
+ import { type MenuPopupProps, type MenuSize } from './Menu.js';
3
+ import { type MenuAction, type MenuEntry, type MenuSearch } from './MenuEntries.js';
4
+ export interface ActionMenuProps {
5
5
  items: MenuEntry[];
6
- /** Names the trigger, which usually shows only an icon, and labels its tooltip. */
6
+ /** Names the trigger, which usually shows only an icon, and labels its tooltip. With
7
+ * `trigger`, it names the menu instead. */
7
8
  label: string;
8
9
  search?: MenuSearch | undefined;
9
10
  align?: 'start' | 'center' | 'end';
10
- /** Styles the trigger; without it the trigger is a ghost icon button. */
11
+ /** Where the menu opens from the trigger, such as `top` for one near the window's bottom. */
12
+ side?: MenuPopupProps['side'];
13
+ /** Styles the built-in trigger; without it the trigger is a ghost icon button. */
11
14
  triggerClassName?: string | undefined;
12
- /** The trigger's content. */
13
- children: ReactNode;
14
- }): import("react").JSX.Element;
15
+ /** The built-in trigger's content. */
16
+ children?: ReactNode;
17
+ /** The whole trigger in place of the built-in one, such as a button with visible text and
18
+ * a chevron, or an avatar and name. It receives the trigger's props and ref, so it must
19
+ * pass them to its element. */
20
+ trigger?: ReactElement | undefined;
21
+ /** Shows `label` on hover. On by default for the built-in trigger, which shows only an
22
+ * icon, and off with `trigger`, whose text would repeat it. Hidden while the menu is open. */
23
+ tooltip?: boolean | undefined;
24
+ /** The trigger can't open the menu, such as while there is nothing to act on. */
25
+ disabled?: boolean | undefined;
26
+ /** On the popup, such as a wider floor: `min-w-64`. */
27
+ popupClassName?: string | undefined;
28
+ /** At least as wide as the trigger, as a switcher under a wide button is. */
29
+ matchTriggerWidth?: boolean | undefined;
30
+ /** Lines above the rows that aren't choices, such as who is signed in. */
31
+ header?: ReactNode;
32
+ /** One action pinned under the rows, ruled off and always in view, such as "See all". */
33
+ footer?: MenuAction | undefined;
34
+ /** Shown in place of the rows when there are none, such as "No connected resources". */
35
+ empty?: string | undefined;
36
+ /** `sm` rows for a compact toolbar whose own text is 12px. */
37
+ size?: MenuSize | undefined;
38
+ /** As `MenuPopup`'s: classes on the menu and its submenus, such as token overrides. */
39
+ themeClassName?: string | undefined;
40
+ onOpenChange?: ((open: boolean) => void) | undefined;
41
+ }
42
+ /** A trigger that opens a menu, such as a header's "New" or "…" button. */
43
+ export declare function ActionMenu({ items, label, search, align, side, triggerClassName, children, trigger, tooltip, disabled, popupClassName, matchTriggerWidth, header, footer, empty, size, themeClassName, onOpenChange, }: ActionMenuProps): import("react").JSX.Element;
@@ -1,34 +1,60 @@
1
+ import { cx } from "../cx.js";
1
2
  import { buttonClasses } from "./buttonClasses.js";
3
+ import { EmptyState } from "./EmptyState.js";
2
4
  import { MenuPopup } from "./Menu.js";
3
5
  import { Tooltip } from "./Tooltip.js";
4
- import { MenuEntries, MenuFilter } from "./MenuEntries.js";
6
+ import { ActionRow, MenuEntries, MenuFilter } from "./MenuEntries.js";
5
7
  import { Menu } from "@base-ui/react/menu";
8
+ import { useState } from "react";
6
9
  import { jsx, jsxs } from "react/jsx-runtime";
7
10
  //#region src/components/ActionMenu.tsx
8
11
  /** A trigger that opens a menu, such as a header's "New" or "…" button. */
9
- function ActionMenu({ items, label, search, align, triggerClassName, children }) {
12
+ function ActionMenu({ items, label, search, align, side, triggerClassName, children, trigger, tooltip = trigger === void 0, disabled = false, popupClassName, matchTriggerWidth = false, header, footer, empty, size, themeClassName, onOpenChange }) {
13
+ const [open, setOpen] = useState(false);
14
+ const button = trigger ? /* @__PURE__ */ jsx(Menu.Trigger, {
15
+ render: trigger,
16
+ disabled
17
+ }) : /* @__PURE__ */ jsx(Menu.Trigger, {
18
+ "aria-label": label,
19
+ disabled,
20
+ className: triggerClassName ?? buttonClasses({
21
+ variant: "ghost",
22
+ size: "sm",
23
+ iconOnly: true
24
+ }),
25
+ children
26
+ });
10
27
  return /* @__PURE__ */ jsx(MenuFilter, {
11
28
  search,
12
- children: (query) => /* @__PURE__ */ jsxs(Menu.Root, { children: [/* @__PURE__ */ jsx(Tooltip, {
13
- content: label,
14
- children: /* @__PURE__ */ jsx(Menu.Trigger, {
15
- "aria-label": label,
16
- className: triggerClassName ?? buttonClasses({
17
- variant: "ghost",
18
- size: "sm",
19
- iconOnly: true
20
- }),
21
- children
22
- })
23
- }), /* @__PURE__ */ jsx(MenuPopup, {
24
- align,
25
- className: "min-w-52",
26
- children: /* @__PURE__ */ jsx(MenuEntries, {
27
- entries: items,
28
- search,
29
- query
30
- })
31
- })] })
29
+ children: (query) => /* @__PURE__ */ jsxs(Menu.Root, {
30
+ onOpenChange: (next) => {
31
+ setOpen(next);
32
+ onOpenChange?.(next);
33
+ },
34
+ children: [tooltip ? /* @__PURE__ */ jsx(Tooltip, {
35
+ content: label,
36
+ disabled: open,
37
+ children: button
38
+ }) : button, /* @__PURE__ */ jsx(MenuPopup, {
39
+ align,
40
+ side,
41
+ size,
42
+ themeClassName,
43
+ matchAnchorWidth: matchTriggerWidth,
44
+ label: trigger ? label : void 0,
45
+ header,
46
+ footer: footer && /* @__PURE__ */ jsx(ActionRow, { action: footer }),
47
+ className: cx("min-w-52", popupClassName),
48
+ children: items.length === 0 && empty ? /* @__PURE__ */ jsx(EmptyState, {
49
+ variant: "bare",
50
+ title: empty
51
+ }) : /* @__PURE__ */ jsx(MenuEntries, {
52
+ entries: items,
53
+ search,
54
+ query
55
+ })
56
+ })]
57
+ })
32
58
  });
33
59
  }
34
60
  //#endregion
@@ -1,20 +1,80 @@
1
+ import { type ReactNode } from 'react';
1
2
  export type AvatarSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl';
2
3
  export type AvatarStatus = 'online' | 'offline' | 'busy' | 'away';
4
+ /** Who an avatar stands for. An agent's avatar is a rounded square, so its shape, and not only
5
+ * its color, tells it from a person's. */
6
+ export type AvatarKind = 'person' | 'agent';
7
+ export type AvatarShape = 'circle' | 'square';
3
8
  export interface AvatarProps {
4
9
  /** Image URL. Until it loads, or when it fails, the initials of `name` show. */
5
10
  src?: string | null | undefined;
6
11
  name?: string | undefined;
12
+ /** A person (a circle, the default) or an agent (a rounded square). Under UIProvider's
13
+ * `avatarColoring="kind"` it also picks the fill: `--avatar-person` or `--avatar-agent`. */
14
+ kind?: AvatarKind | undefined;
15
+ /** Overrides the shape `kind` gives, such as a square for an organization. */
16
+ shape?: AvatarShape | undefined;
7
17
  /** Picks the fallback's color from the theme's categorical palette, so the same key gets the
8
18
  * same color everywhere. Defaults to `name`; pass a stable id when names can repeat or
9
- * change, or `null` for the accent fill whatever the name. Without either, the accent fills it. */
19
+ * change, or `null` for the accent fill whatever the name. Without either, the accent fills it.
20
+ * Ignored under `avatarColoring="kind"`. */
10
21
  colorKey?: string | null | undefined;
22
+ /** Classes for the initials' fill and text in place of the palette's or the kind's, such as a
23
+ * neutral fill for something that is neither a person nor an agent. */
24
+ colorClassName?: string | undefined;
25
+ /** Defaults to the group's size inside an `AvatarGroup`, else `md`. */
11
26
  size?: AvatarSize | undefined;
12
27
  status?: AvatarStatus | undefined;
28
+ /** Hides it from assistive technology, for an avatar beside the name it shows, which a
29
+ * screen reader would otherwise read twice. */
30
+ decorative?: boolean | undefined;
31
+ /** Names it on hover: `true` shows the name, with the presence when it has a status dot, and
32
+ * anything else shows that instead, such as what the person is doing. */
33
+ tooltip?: boolean | ReactNode;
34
+ /** On the avatar's shape, rounded as it is, so a ring or a shadow follows the circle or the
35
+ * square: its margin, ring or hover effect. */
13
36
  className?: string | undefined;
14
37
  }
38
+ export interface AvatarInitialsOptions {
39
+ /** Two letters for a one-word name ("maya" reads "MA"), splitting a handle on `_` and `-`
40
+ * too and leaving out an email's domain. Default false: one letter, "M". */
41
+ twoLetters?: boolean | undefined;
42
+ }
15
43
  /** Up to two initials: the first and last word of a name split on spaces and dots. */
16
- export declare function avatarInitials(name: string | undefined): string;
17
- /** A person's picture, or their initials while it loads or when it fails. It is
18
- * one image to assistive technology, named for the person, whichever shows,
19
- * and their presence when it has a status dot. */
20
- export declare function Avatar({ src, name, colorKey, size, status, className }: AvatarProps): import("react").JSX.Element;
44
+ export declare function avatarInitials(name: string | undefined, { twoLetters }?: AvatarInitialsOptions): string;
45
+ /** A person's or an agent's picture, or their initials while it loads or when it fails. It is
46
+ * one image to assistive technology, named for them, whichever shows, and their presence when
47
+ * it has a status dot, unless it is `decorative`.
48
+ *
49
+ * Without a picture the fill follows UIProvider's `avatarColoring`: by name from the
50
+ * categorical palette (the default), or by kind, where people share `--avatar-person` (with
51
+ * `--avatar-person-text`) and agents `--avatar-agent` (with `--avatar-agent-text`, and the
52
+ * edge `--avatar-agent-ring`). */
53
+ export declare function Avatar({ src, name, kind, shape, colorKey, colorClassName, size: sizeProp, status, decorative, tooltip, className, }: AvatarProps): import("react").JSX.Element;
54
+ export interface AvatarGroupProps {
55
+ /** Avatars, each possibly wrapped, such as in a hover card. Each child counts as one. */
56
+ children: ReactNode;
57
+ /** Shows at most this many; the rest become a "+N" chip. */
58
+ max?: number | undefined;
59
+ /** How many there are in all, when the children are already a slice of them: the chip counts
60
+ * the rest. Defaults to the number of children. */
61
+ total?: number | undefined;
62
+ /** Shows the "+N" chip for those left out. Default true; false for a stack whose count is
63
+ * printed beside it. */
64
+ showOverflow?: boolean | undefined;
65
+ /** Every avatar's size, and the chip's. Default `sm`. */
66
+ size?: AvatarSize | undefined;
67
+ /** Rings each avatar in the color behind the stack, so overlapping faces read apart. Default
68
+ * true. */
69
+ ring?: boolean | undefined;
70
+ /** The ring's color, a CSS color: the surface the stack sits on. Defaults to the panel's. One
71
+ * avatar can set its own, such as a highlight, by setting `--avatar-ring` in its `className`. */
72
+ ringColor?: string | undefined;
73
+ /** The group's accessible name, such as "3 people here". */
74
+ label?: string | undefined;
75
+ className?: string | undefined;
76
+ }
77
+ /** Overlapping avatars, such as a task's assignees or who is here, with a "+N" chip for the
78
+ * rest. Each avatar inside takes the group's size and a ring in the color behind it, which
79
+ * follows its shape, round or square. */
80
+ export declare function AvatarGroup({ children, max, total, showOverflow, size, ring, ringColor, label, className, }: AvatarGroupProps): import("react").JSX.Element;
@@ -1,6 +1,8 @@
1
1
  import { cx } from "../cx.js";
2
- import { useStrings } from "./Provider.js";
2
+ import { Tooltip } from "./Tooltip.js";
3
+ import { useAvatarColoring, useLocale, useStrings } from "./Provider.js";
3
4
  import { categoryClasses } from "./category.js";
5
+ import { Children, createContext, use, useMemo } from "react";
4
6
  import { jsx, jsxs } from "react/jsx-runtime";
5
7
  import { Avatar } from "@base-ui/react/avatar";
6
8
  //#region src/components/Avatar.tsx
@@ -12,6 +14,23 @@ var SIZE_CLASSES = {
12
14
  xl: "size-12 text-lg",
13
15
  "2xl": "size-16 text-xl"
14
16
  };
17
+ var KIND_TEXT_CLASSES = {
18
+ xs: "text-[8px]",
19
+ md: "text-[11px]"
20
+ };
21
+ var SQUARE_CLASSES = {
22
+ xs: "rounded-[5px]",
23
+ sm: "rounded-[5px]",
24
+ md: "rounded-[5px]",
25
+ lg: "rounded-lg",
26
+ xl: "rounded-[10px]",
27
+ "2xl": "rounded-xl"
28
+ };
29
+ var KIND_CLASSES = {
30
+ person: "bg-(--avatar-person,color-mix(in_oklab,var(--theme-info)_12%,var(--theme-panel-bg))) text-(--avatar-person-text,var(--theme-info-text))",
31
+ agent: "bg-(--avatar-agent,var(--theme-category-2)) text-(--avatar-agent-text,var(--theme-category-2-text))"
32
+ };
33
+ var AGENT_EDGE = "after:pointer-events-none after:absolute after:inset-0 after:rounded-[inherit] after:content-[''] after:inset-ring after:inset-ring-(--avatar-agent-ring,color-mix(in_oklab,var(--avatar-agent-text,var(--theme-category-2-text))_40%,transparent))";
15
34
  var STATUS_CLASSES = {
16
35
  online: "bg-(--theme-success)",
17
36
  offline: "bg-(--theme-muted-text-color)",
@@ -19,44 +38,71 @@ var STATUS_CLASSES = {
19
38
  away: "bg-(--theme-warning)"
20
39
  };
21
40
  var graphemes = typeof Intl !== "undefined" && "Segmenter" in Intl ? new Intl.Segmenter(void 0, { granularity: "grapheme" }) : void 0;
41
+ function leadingCharacters(text, count) {
42
+ if (!text) return "";
43
+ const out = [];
44
+ for (const part of graphemes ? Array.from(graphemes.segment(text), (s) => s.segment) : text) {
45
+ if (out.length === count) break;
46
+ out.push(part);
47
+ }
48
+ return out.join("");
49
+ }
22
50
  function firstCharacter(text) {
23
- if (!text) return;
24
- if (graphemes) return graphemes.segment(text)[Symbol.iterator]().next().value?.segment;
25
- return Array.from(text)[0];
51
+ return leadingCharacters(text, 1) || void 0;
26
52
  }
27
53
  /** Up to two initials: the first and last word of a name split on spaces and dots. */
28
- function avatarInitials(name) {
29
- const parts = (name ?? "").split(/[\s.]+/).filter(Boolean);
54
+ function avatarInitials(name, { twoLetters = false } = {}) {
55
+ let text = (name ?? "").trim();
56
+ if (twoLetters && /^[^\s@]+@\S+$/.test(text)) text = text.slice(0, text.indexOf("@"));
57
+ const parts = text.split(twoLetters ? /[\s.@_-]+/ : /[\s.]+/).filter(Boolean);
30
58
  const first = firstCharacter(parts[0]);
31
59
  const last = firstCharacter(parts.at(-1));
32
60
  if (parts.length >= 2 && first && last) return (first + last).toUpperCase();
61
+ if (twoLetters && parts.length === 1) return leadingCharacters(parts[0], 2).toUpperCase();
33
62
  return first?.toUpperCase() || "?";
34
63
  }
35
- /** A person's picture, or their initials while it loads or when it fails. It is
36
- * one image to assistive technology, named for the person, whichever shows,
37
- * and their presence when it has a status dot. */
38
- function Avatar$1({ src, name, colorKey, size = "md", status, className }) {
64
+ var AvatarGroupContext = createContext(null);
65
+ /** A person's or an agent's picture, or their initials while it loads or when it fails. It is
66
+ * one image to assistive technology, named for them, whichever shows, and their presence when
67
+ * it has a status dot, unless it is `decorative`.
68
+ *
69
+ * Without a picture the fill follows UIProvider's `avatarColoring`: by name from the
70
+ * categorical palette (the default), or by kind, where people share `--avatar-person` (with
71
+ * `--avatar-person-text`) and agents `--avatar-agent` (with `--avatar-agent-text`, and the
72
+ * edge `--avatar-agent-ring`). */
73
+ function Avatar$1({ src, name, kind = "person", shape = kind === "agent" ? "square" : "circle", colorKey, colorClassName, size: sizeProp, status, decorative = false, tooltip = false, className }) {
39
74
  const { common } = useStrings();
75
+ const byKind = useAvatarColoring() === "kind";
76
+ const group = use(AvatarGroupContext);
77
+ const size = sizeProp ?? group?.size ?? "md";
40
78
  const who = name || common.userAvatar;
79
+ const named = status ? common.withPresence(who, common.presence[status]) : who;
41
80
  const colorBy = colorKey === void 0 ? name?.trim() : colorKey;
42
- return /* @__PURE__ */ jsxs("span", {
43
- role: "img",
44
- "aria-label": status ? common.withPresence(who, common.presence[status]) : who,
45
- className: cx("relative inline-flex shrink-0", className),
81
+ const initials = avatarInitials(name, { twoLetters: byKind });
82
+ const radius = shape === "square" ? SQUARE_CLASSES[size] : "rounded-full";
83
+ const fill = colorClassName ?? (byKind ? KIND_CLASSES[kind] : colorBy ? categoryClasses(colorBy) : "bg-gradient-to-br from-[var(--gradient-start,var(--theme-accent))] to-[var(--gradient-mid,var(--theme-link))] text-(--theme-accent-text)");
84
+ const avatar = /* @__PURE__ */ jsxs("span", {
85
+ ...decorative ? { "aria-hidden": true } : {
86
+ role: "img",
87
+ "aria-label": named
88
+ },
89
+ "data-shape": shape,
90
+ className: cx("relative inline-flex shrink-0", radius, group?.ring && "ring-2 ring-(--avatar-ring)", className),
46
91
  children: [/* @__PURE__ */ jsxs(Avatar.Root, {
47
- className: cx("relative inline-flex items-center justify-center overflow-hidden rounded-full font-medium select-none", SIZE_CLASSES[size]),
92
+ className: cx("relative inline-flex items-center justify-center overflow-hidden select-none", byKind ? "font-semibold" : "font-medium", radius, SIZE_CLASSES[size], byKind && KIND_TEXT_CLASSES[size], byKind && kind === "agent" && !colorClassName && AGENT_EDGE),
48
93
  children: [src && /* @__PURE__ */ jsx(Avatar.Image, {
49
94
  src,
50
95
  alt: "",
51
96
  loading: "lazy",
97
+ decoding: "async",
52
98
  keepMounted: true,
53
99
  className: "absolute inset-0 size-full object-cover data-error:hidden data-loading:invisible"
54
100
  }, src), /* @__PURE__ */ jsx(Avatar.Fallback, {
55
101
  "aria-hidden": "true",
56
- className: cx("flex size-full items-center justify-center", colorBy ? categoryClasses(colorBy) : "bg-gradient-to-br from-[var(--gradient-start,var(--theme-accent))] to-[var(--gradient-mid,var(--theme-link))] text-(--theme-accent-text)"),
102
+ className: cx("flex size-full items-center justify-center", fill),
57
103
  children: /* @__PURE__ */ jsx("span", {
58
104
  className: "leading-none [text-box:trim-both_cap_alphabetic]",
59
- children: size === "xs" ? firstCharacter(avatarInitials(name)) : avatarInitials(name)
105
+ children: size === "xs" && !byKind ? firstCharacter(initials) : initials
60
106
  })
61
107
  })]
62
108
  }), status && /* @__PURE__ */ jsx("span", {
@@ -64,6 +110,72 @@ function Avatar$1({ src, name, colorKey, size = "md", status, className }) {
64
110
  className: cx("absolute right-0 bottom-0 block rounded-full ring-2 ring-(--theme-app-bg)", STATUS_CLASSES[status], size === "xs" || size === "sm" ? "size-1.5" : size === "md" ? "size-2" : "size-2.5")
65
111
  })]
66
112
  });
113
+ if (tooltip === false || tooltip === null || tooltip === void 0) return avatar;
114
+ return /* @__PURE__ */ jsx(Tooltip, {
115
+ content: tooltip === true ? named : tooltip,
116
+ children: avatar
117
+ });
118
+ }
119
+ var OVERLAP_CLASSES = {
120
+ xs: "-space-x-px",
121
+ sm: "-space-x-0.5",
122
+ md: "-space-x-1",
123
+ lg: "-space-x-1.5",
124
+ xl: "-space-x-1.5",
125
+ "2xl": "-space-x-1.5"
126
+ };
127
+ var CHIP_SIZE_CLASSES = {
128
+ xs: "h-4 min-w-4 px-0.5 text-[8px]",
129
+ sm: "h-5 min-w-5 px-1 text-[9px]",
130
+ md: "h-7 min-w-7 px-1 text-[11px]",
131
+ lg: "h-10 min-w-10 px-1.5 text-sm",
132
+ xl: "h-12 min-w-12 px-2 text-base",
133
+ "2xl": "h-16 min-w-16 px-2 text-lg"
134
+ };
135
+ var numberFormats = /* @__PURE__ */ new Map();
136
+ function formatNumber(n, locale) {
137
+ let format = numberFormats.get(locale);
138
+ if (!format) {
139
+ format = new Intl.NumberFormat(locale);
140
+ numberFormats.set(locale, format);
141
+ }
142
+ return format.format(n);
143
+ }
144
+ /** Overlapping avatars, such as a task's assignees or who is here, with a "+N" chip for the
145
+ * rest. Each avatar inside takes the group's size and a ring in the color behind it, which
146
+ * follows its shape, round or square. */
147
+ function AvatarGroup({ children, max, total, showOverflow = true, size = "sm", ring = true, ringColor, label, className }) {
148
+ const { common } = useStrings();
149
+ const locale = useLocale();
150
+ const items = Children.toArray(children);
151
+ const shown = max === void 0 ? items : items.slice(0, Math.max(0, max));
152
+ const rest = Math.max(0, (total ?? items.length) - shown.length);
153
+ const context = useMemo(() => ({
154
+ size,
155
+ ring
156
+ }), [size, ring]);
157
+ return /* @__PURE__ */ jsx(AvatarGroupContext, {
158
+ value: context,
159
+ children: /* @__PURE__ */ jsxs("span", {
160
+ ...label ? {
161
+ role: "group",
162
+ "aria-label": label
163
+ } : {},
164
+ style: { "--avatar-ring": ringColor ?? "var(--theme-panel-bg)" },
165
+ className: cx("inline-flex shrink-0 items-center", OVERLAP_CLASSES[size], className),
166
+ children: [shown, showOverflow && rest > 0 && /* @__PURE__ */ jsxs("span", {
167
+ className: cx("relative inline-flex shrink-0 items-center justify-center rounded-full bg-(--theme-muted-panel-bg) font-medium text-(--theme-muted-text-color) tabular-nums select-none", CHIP_SIZE_CLASSES[size], ring && "ring-2 ring-(--avatar-ring)"),
168
+ children: [/* @__PURE__ */ jsxs("span", {
169
+ "aria-hidden": "true",
170
+ className: "leading-none [text-box:trim-both_cap_alphabetic]",
171
+ children: ["+", formatNumber(rest, locale)]
172
+ }), /* @__PURE__ */ jsx("span", {
173
+ className: "sr-only",
174
+ children: common.moreCount(rest)
175
+ })]
176
+ })]
177
+ })
178
+ });
67
179
  }
68
180
  //#endregion
69
- export { Avatar$1 as Avatar, avatarInitials };
181
+ export { Avatar$1 as Avatar, AvatarGroup, avatarInitials };
@@ -1,8 +1,12 @@
1
+ import { type ReactNode } from 'react';
1
2
  /** One step of the trail to the current page. */
2
3
  export interface Breadcrumb {
3
4
  /** Empty while the name is still loading: the trail shows a placeholder. */
4
5
  label: string;
5
6
  href?: string | undefined;
7
+ /** Before the label, such as the section a page belongs to; also beside
8
+ * the crumb's row once it folds into the "…" menu. */
9
+ icon?: ReactNode;
6
10
  }
7
11
  export interface BreadcrumbsProps {
8
12
  /** The trail, ending with where the reader is. A crumb with an empty label,
@@ -1,14 +1,14 @@
1
1
  import { cx } from "../cx.js";
2
2
  import { buttonClasses } from "./buttonClasses.js";
3
3
  import { ChevronRightIcon, MoreIcon } from "../icons.js";
4
- import { keyedByContent } from "./keys.js";
5
4
  import { Tooltip } from "./Tooltip.js";
6
5
  import { useStrings } from "./Provider.js";
7
6
  import { AppLink } from "./AppLink.js";
7
+ import { keyedByContent } from "./keys.js";
8
8
  import { ActionMenu } from "./ActionMenu.js";
9
9
  import { Skeleton } from "./Skeleton.js";
10
- import { jsx, jsxs } from "react/jsx-runtime";
11
10
  import { useLayoutEffect, useState } from "react";
11
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
12
12
  //#region src/components/Breadcrumbs.tsx
13
13
  /**
14
14
  * The trail to where the reader is, as a list in a `nav` landmark. A trail too
@@ -29,16 +29,20 @@ function Breadcrumbs({ crumbs, onSelect, current = "page", heading = false, labe
29
29
  const Last = heading ? "h1" : "span";
30
30
  const menuItem = (crumb, index) => {
31
31
  const name = crumb.label || common.loading;
32
+ const icon = crumb.icon;
32
33
  if (crumb.href) return {
33
34
  label: name,
35
+ icon,
34
36
  href: crumb.href
35
37
  };
36
38
  if (onSelect) return {
37
39
  label: name,
40
+ icon,
38
41
  onClick: () => onSelect(crumb, index)
39
42
  };
40
43
  return {
41
44
  label: name,
45
+ icon,
42
46
  disabled: true,
43
47
  onClick: () => {}
44
48
  };
@@ -73,16 +77,16 @@ function Breadcrumbs({ crumbs, onSelect, current = "page", heading = false, labe
73
77
  overflowOnly: true,
74
78
  children: crumb.href ? /* @__PURE__ */ jsx(AppLink, {
75
79
  href: crumb.href,
76
- className: cx(crumbText, crumbLink, "max-w-48"),
77
- children: crumb.label
80
+ className: cx(crumbText, crumbLink, crumb.icon && withIcon, "max-w-48"),
81
+ children: /* @__PURE__ */ jsx(CrumbLabel, { crumb })
78
82
  }) : onSelect ? /* @__PURE__ */ jsx("button", {
79
83
  type: "button",
80
84
  onClick: () => onSelect(crumb, index),
81
- className: cx(crumbText, crumbLink, "max-w-48 cursor-pointer text-start"),
82
- children: crumb.label
85
+ className: cx(crumbText, crumbLink, crumb.icon && withIcon, "max-w-48 cursor-pointer text-start"),
86
+ children: /* @__PURE__ */ jsx(CrumbLabel, { crumb })
83
87
  }) : /* @__PURE__ */ jsx("span", {
84
- className: cx(crumbText, "max-w-48"),
85
- children: crumb.label
88
+ className: cx(crumbText, crumb.icon && withIcon, "max-w-48"),
89
+ children: /* @__PURE__ */ jsx(CrumbLabel, { crumb })
86
90
  })
87
91
  }), /* @__PURE__ */ jsx(Separator, {})]
88
92
  }, key);
@@ -98,8 +102,8 @@ function Breadcrumbs({ crumbs, onSelect, current = "page", heading = false, labe
98
102
  overflowOnly: true,
99
103
  children: /* @__PURE__ */ jsx(Last, {
100
104
  "aria-current": current,
101
- className: "m-0 block truncate text-[13px] font-medium leading-none text-(--theme-app)",
102
- children: last.label
105
+ className: cx("m-0 block truncate text-[13px] font-medium leading-none text-(--theme-app)", last.icon && withIcon),
106
+ children: /* @__PURE__ */ jsx(CrumbLabel, { crumb: last })
103
107
  })
104
108
  })
105
109
  })
@@ -122,6 +126,18 @@ function Breadcrumbs({ crumbs, onSelect, current = "page", heading = false, labe
122
126
  });
123
127
  }
124
128
  var crumbText = "block truncate text-(--theme-muted-text-color)";
129
+ var withIcon = "flex items-center gap-1";
130
+ function CrumbLabel({ crumb }) {
131
+ if (!crumb.icon) return crumb.label;
132
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("span", {
133
+ "aria-hidden": "true",
134
+ className: "inline-flex shrink-0 [&_svg]:size-3.5",
135
+ children: crumb.icon
136
+ }), /* @__PURE__ */ jsx("span", {
137
+ className: "min-w-0 truncate",
138
+ children: crumb.label
139
+ })] });
140
+ }
125
141
  var crumbLink = "rounded-sm transition-colors hover:text-(--theme-app) focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-(--theme-link)";
126
142
  function Separator() {
127
143
  return /* @__PURE__ */ jsx(ChevronRightIcon, { className: "size-3 shrink-0 text-(--theme-muted-text-color) opacity-60 rtl:rotate-180" });
@@ -6,8 +6,9 @@ interface ButtonOwnProps extends ButtonStyle {
6
6
  className?: string | undefined;
7
7
  /** Before the label. */
8
8
  icon?: ReactNode;
9
- /** Busy with what it started: a spinner takes the icon's place, and it can't
10
- * be pressed again until done. */
9
+ /** Busy with what it started: a spinner takes the icon's place, or without an
10
+ * icon sits over the label, so the button keeps its width. It can't be
11
+ * pressed again until done. */
11
12
  loading?: boolean | undefined;
12
13
  }
13
14
  /** A button, or with `href` a link that looks like one: navigation stays a
@@ -15,7 +15,17 @@ function Button$1({ variant, size = "md", iconOnly, icon, loading = false, class
15
15
  size,
16
16
  iconOnly
17
17
  }), className);
18
- const content = /* @__PURE__ */ jsxs(Fragment, { children: [loading ? /* @__PURE__ */ jsx(Loader, {
18
+ const content = loading && !icon ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("span", {
19
+ className: "inline-flex items-center gap-1.5 opacity-0",
20
+ children
21
+ }), /* @__PURE__ */ jsx("span", {
22
+ className: "absolute inset-0 flex items-center justify-center",
23
+ children: /* @__PURE__ */ jsx(Loader, {
24
+ inline: true,
25
+ decorative: true,
26
+ size: "1em"
27
+ })
28
+ })] }) : /* @__PURE__ */ jsxs(Fragment, { children: [loading ? /* @__PURE__ */ jsx(Loader, {
19
29
  inline: true,
20
30
  decorative: true,
21
31
  size: "1em"
@@ -1,7 +1,8 @@
1
1
  import type { ReactNode } from 'react';
2
2
  import { type Tone } from './tone.js';
3
- /** A callout's tone: `default` for a plain note, or a status. */
4
- export type CalloutTone = Extract<Tone, 'default' | 'info' | 'success' | 'warning' | 'error'>;
3
+ /** A callout's tone: `default` for a plain note, a status, or `muted` for a quiet
4
+ * note that something is read-only, such as a page only admins can change. */
5
+ export type CalloutTone = Extract<Tone, 'default' | 'info' | 'success' | 'warning' | 'error' | 'muted'>;
5
6
  export interface CalloutProps {
6
7
  tone?: CalloutTone | undefined;
7
8
  /** A bold first line that says what happened; the children explain it. */
@@ -1,5 +1,5 @@
1
1
  import { cx } from "../cx.js";
2
- import { CloseIcon, ErrorIcon, InfoIcon, SuccessIcon, WarningIcon } from "../icons.js";
2
+ import { CloseIcon, ErrorIcon, InfoIcon, LockIcon, SuccessIcon, WarningIcon } from "../icons.js";
3
3
  import { toneIcon, toneSurface } from "./tone.js";
4
4
  import { useStrings } from "./Provider.js";
5
5
  import { IconButton } from "./IconButton.js";
@@ -10,7 +10,8 @@ var toneIcons = {
10
10
  info: InfoIcon,
11
11
  success: SuccessIcon,
12
12
  warning: WarningIcon,
13
- error: ErrorIcon
13
+ error: ErrorIcon,
14
+ muted: LockIcon
14
15
  };
15
16
  /** A message set into the page in a status's tone: guidance, a warning, an error
16
17
  * or a success, and what to do about it. For a passing notice that floats over