@parallelworks/ui 0.51.0 → 0.52.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 (227) hide show
  1. package/README.md +155 -14
  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 +12 -0
  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 +81 -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 +21 -9
  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 +15 -5
  67. package/dist/components/Field.js +40 -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 +4 -1
  71. package/dist/components/InfoTip.js +2 -1
  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/MenuEntries.d.ts +4 -0
  76. package/dist/components/MenuEntries.js +11 -12
  77. package/dist/components/Meter.js +5 -4
  78. package/dist/components/Modal.d.ts +28 -4
  79. package/dist/components/Modal.js +37 -14
  80. package/dist/components/Overview.d.ts +20 -12
  81. package/dist/components/Overview.js +14 -9
  82. package/dist/components/PageHeader.d.ts +47 -65
  83. package/dist/components/PageHeader.js +275 -153
  84. package/dist/components/PageHeaderAction.d.ts +67 -0
  85. package/dist/components/PageHeaderAction.js +107 -0
  86. package/dist/components/Pagination.js +6 -16
  87. package/dist/components/Popover.js +3 -2
  88. package/dist/components/Provider.d.ts +77 -19
  89. package/dist/components/Provider.js +139 -130
  90. package/dist/components/Radio.js +2 -1
  91. package/dist/components/RefreshButton.js +7 -8
  92. package/dist/components/RequiredMark.js +1 -1
  93. package/dist/components/Section.js +1 -1
  94. package/dist/components/Select.d.ts +4 -9
  95. package/dist/components/Select.js +24 -11
  96. package/dist/components/SettingModeOption.d.ts +1 -1
  97. package/dist/components/SettingModeOption.js +7 -1
  98. package/dist/components/SettingsCard.d.ts +5 -3
  99. package/dist/components/SettingsCard.js +27 -20
  100. package/dist/components/Slider.js +1 -1
  101. package/dist/components/StatusBadge.js +2 -2
  102. package/dist/components/Switch.js +5 -4
  103. package/dist/components/Table.d.ts +30 -20
  104. package/dist/components/Table.js +50 -73
  105. package/dist/components/Tabs.d.ts +3 -7
  106. package/dist/components/Tabs.js +6 -10
  107. package/dist/components/ThemeEditor.js +18 -8
  108. package/dist/components/Toast.d.ts +11 -3
  109. package/dist/components/Toast.js +45 -20
  110. package/dist/components/buttonClasses.js +1 -1
  111. package/dist/components/comboboxItems.d.ts +4 -0
  112. package/dist/components/comboboxItems.js +6 -1
  113. package/dist/components/dismiss.d.ts +12 -0
  114. package/dist/components/dismiss.js +19 -0
  115. package/dist/components/fieldBox.d.ts +4 -0
  116. package/dist/components/fieldBox.js +7 -3
  117. package/dist/components/floating.d.ts +3 -3
  118. package/dist/components/floating.js +1 -1
  119. package/dist/components/markdownCodeBreaks.js +3 -4
  120. package/dist/components/pageHeaderStore.d.ts +41 -0
  121. package/dist/components/pageHeaderStore.js +67 -0
  122. package/dist/components/pathBreaks.d.ts +8 -0
  123. package/dist/components/pathBreaks.js +28 -0
  124. package/dist/components/segmented.js +1 -1
  125. package/dist/components/shortcutKey.d.ts +2 -1
  126. package/dist/components/shortcutKey.js +19 -2
  127. package/dist/components/splitter.js +1 -1
  128. package/dist/components/useCssIsDark.js +40 -18
  129. package/dist/components/useTheme.js +9 -10
  130. package/dist/dev.d.ts +9 -0
  131. package/dist/dev.js +14 -0
  132. package/dist/editor/Editor.d.ts +3 -2
  133. package/dist/editor/Editor.js +11 -2
  134. package/dist/editor/EditorField.d.ts +2 -1
  135. package/dist/editor/EditorField.js +11 -29
  136. package/dist/editor/FormCodePanel.d.ts +7 -3
  137. package/dist/editor/FormCodePanel.js +14 -7
  138. package/dist/editor/Monaco.d.ts +14 -5
  139. package/dist/editor/Monaco.js +163 -112
  140. package/dist/editor/index.d.ts +5 -5
  141. package/dist/editor/index.js +3 -3
  142. package/dist/editor/themes.d.ts +8 -5
  143. package/dist/editor/themes.js +58 -30
  144. package/dist/editor/yaml.d.ts +6 -2
  145. package/dist/editor/yaml.js +11 -2
  146. package/dist/file-explorer/FileExplorer.js +143 -124
  147. package/dist/file-explorer/FileExplorerContext.js +1 -1
  148. package/dist/file-explorer/FilePreview/StreamedBadge.js +3 -1
  149. package/dist/file-explorer/FilePreview/Viewer.js +2 -2
  150. package/dist/file-explorer/FilePreview/index.js +4 -4
  151. package/dist/file-explorer/FileRow.js +1 -1
  152. package/dist/file-explorer/FileRowsWindow.js +34 -3
  153. package/dist/file-explorer/FileTable.js +3 -1
  154. package/dist/file-explorer/TreeView.js +37 -14
  155. package/dist/file-explorer/helpers.d.ts +2 -1
  156. package/dist/file-explorer/helpers.js +21 -20
  157. package/dist/file-explorer/toasts.js +27 -19
  158. package/dist/file-explorer/treeRows.d.ts +6 -0
  159. package/dist/file-explorer/treeRows.js +19 -1
  160. package/dist/file-explorer/useNearEnd.js +3 -6
  161. package/dist/form/Fields/CheckboxGroupField.js +12 -5
  162. package/dist/form/Fields/DurationField.js +1 -1
  163. package/dist/form/Fields/LabelField.js +1 -1
  164. package/dist/form/Fields/ObjectField.d.ts +1 -1
  165. package/dist/form/Fields/ObjectField.js +3 -2
  166. package/dist/form/Fields/StringField.js +16 -29
  167. package/dist/form/Fields/TextAreaField.js +3 -4
  168. package/dist/form/Form.js +3 -8
  169. package/dist/form/Wizard/WizardNavigation.js +0 -3
  170. package/dist/form/Wizard/utils.js +1 -1
  171. package/dist/form/fieldFrame.d.ts +1 -1
  172. package/dist/form/fieldFrame.js +2 -2
  173. package/dist/form/types/fieldComponentTypes.d.ts +2 -1
  174. package/dist/graph/AnnotationBanner.d.ts +1 -2
  175. package/dist/graph/AnnotationBanner.js +30 -32
  176. package/dist/graph/Connectors.js +4 -1
  177. package/dist/graph/DependencyGraph.js +2 -2
  178. package/dist/graph/GraphEditor.js +11 -9
  179. package/dist/graph/GraphEditorDialogs.js +1 -1
  180. package/dist/graph/GraphNode.js +7 -4
  181. package/dist/graph/InputDialog.js +1 -1
  182. package/dist/graph/InputsEditor.js +14 -11
  183. package/dist/graph/MatrixGroup.js +9 -3
  184. package/dist/graph/Reveal.js +18 -10
  185. package/dist/graph/ShortcutsButton.d.ts +11 -2
  186. package/dist/graph/ShortcutsButton.js +14 -3
  187. package/dist/graph/TreeView.js +35 -18
  188. package/dist/graph/WorkflowSettingsDialog.js +1 -1
  189. package/dist/graph/editorFields.js +1 -1
  190. package/dist/graph/editorRows.js +16 -10
  191. package/dist/graph/editorStrings.d.ts +7 -0
  192. package/dist/graph/editorStrings.js +8 -1
  193. package/dist/graph/inputRefs.js +1 -1
  194. package/dist/graph/settingsViews.js +11 -18
  195. package/dist/graph/stepWith.js +1 -1
  196. package/dist/icons.d.ts +2 -0
  197. package/dist/icons.js +4 -2
  198. package/dist/index.d.ts +12 -12
  199. package/dist/index.js +16 -16
  200. package/dist/list/ActionToolbar.d.ts +42 -6
  201. package/dist/list/ActionToolbar.js +297 -101
  202. package/dist/list/ListPage.d.ts +15 -23
  203. package/dist/list/ListPage.js +42 -43
  204. package/dist/list/ListTable.d.ts +32 -7
  205. package/dist/list/ListTable.js +48 -12
  206. package/dist/list/ListViewControls.js +1 -1
  207. package/dist/list/UserHoverCard.js +7 -15
  208. package/dist/list/index.d.ts +2 -2
  209. package/dist/list/index.js +2 -2
  210. package/dist/list/listSearch.js +12 -10
  211. package/dist/list/listView.d.ts +10 -1
  212. package/dist/list/listView.js +15 -1
  213. package/dist/logviewer/LogViewer.d.ts +4 -2
  214. package/dist/logviewer/LogViewer.js +87 -69
  215. package/dist/logviewer/logviewer.css +3 -2
  216. package/dist/reducedMotion.d.ts +5 -0
  217. package/dist/reducedMotion.js +20 -0
  218. package/dist/safeUrl.d.ts +1 -1
  219. package/dist/safeUrl.js +4 -2
  220. package/dist/styles.css +1 -1
  221. package/package.json +1 -1
  222. package/dist/components/Breadcrumbs.d.ts +0 -37
  223. package/dist/components/Breadcrumbs.js +0 -90
  224. package/dist/components/CopyToClipboard.d.ts +0 -17
  225. package/dist/components/CopyToClipboard.js +0 -66
  226. package/dist/components/Sort.d.ts +0 -9
  227. package/dist/components/Sort.js +0 -42
@@ -1,15 +1,14 @@
1
- import { defaultToolStrings } from "./agent/toolStrings.js";
1
+ import { countOf, defaultToolStrings } from "./agent/toolStrings.js";
2
2
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
- //#region src/ai/strings.tsx
4
3
  var defaultChatStrings = {
5
4
  shareConversation: {
6
- title: "Share Conversation",
5
+ title: "Share conversation",
7
6
  loadError: "Failed to load sharing settings",
8
7
  saveSuccess: "Sharing settings saved",
9
- orgAccess: "Organization Access",
8
+ orgAccess: "Organization access",
10
9
  orgCanView: "Anyone in the organization can view",
11
10
  allowCollaboration: "Allow collaboration (edit messages)",
12
- groupAccess: "Group Access",
11
+ groupAccess: "Group access",
13
12
  noGroups: "No groups have access yet",
14
13
  viewOnly: "View only",
15
14
  canCollaborate: "Can collaborate",
@@ -24,7 +23,7 @@ var defaultChatStrings = {
24
23
  shareButton: "Share conversation"
25
24
  },
26
25
  blockedGroup: {
27
- title: "Billing group \"{group}\" is over its allocation",
26
+ title: (group) => `Billing group \u201c${group}\u201d is over its allocation`,
28
27
  message: "It has reached its allocation limit. Messages to this provider are paused until your administrator increases the allocation."
29
28
  },
30
29
  queue: {
@@ -61,7 +60,49 @@ var defaultChatStrings = {
61
60
  },
62
61
  activity: {
63
62
  tokens: (input, output) => `↑${input} ↓${output} tokens`,
64
- stop: "Stop"
63
+ stop: "Stop",
64
+ words: [
65
+ "Thinking",
66
+ "Cogitating",
67
+ "Pondering",
68
+ "Percolating",
69
+ "Ruminating",
70
+ "Noodling",
71
+ "Conjuring",
72
+ "Simmering",
73
+ "Marinating",
74
+ "Tinkering",
75
+ "Scheming",
76
+ "Brewing",
77
+ "Wrangling",
78
+ "Finagling",
79
+ "Spelunking",
80
+ "Puttering",
81
+ "Composing",
82
+ "Synthesizing",
83
+ "Deliberating",
84
+ "Mulling",
85
+ "Contemplating",
86
+ "Vibing",
87
+ "Whittling",
88
+ "Concocting",
89
+ "Formulating",
90
+ "Hatching",
91
+ "Herding",
92
+ "Ideating",
93
+ "Manifesting",
94
+ "Moseying",
95
+ "Musing",
96
+ "Percussing",
97
+ "Reticulating",
98
+ "Schlepping",
99
+ "Stewing",
100
+ "Transmuting",
101
+ "Wibbling",
102
+ "Crunching",
103
+ "Forging",
104
+ "Cooking"
105
+ ]
65
106
  },
66
107
  emptyState: {
67
108
  greeting: null,
@@ -78,33 +119,36 @@ var defaultChatStrings = {
78
119
  },
79
120
  input: {
80
121
  placeholder: "Ask anything",
81
- placeholderLoading: "Loading models...",
122
+ placeholderLoading: "Loading models…",
82
123
  placeholderNoProviders: "Add an AI provider to start chatting",
83
124
  attachFiles: "Attach files",
84
125
  stopGenerating: "Stop generating (Escape)",
85
126
  sendMessage: "Send message (Enter)",
86
- filesAttached: (count) => count === 1 ? "1 file attached" : `${count.toLocaleString()} files attached`
127
+ filesAttached: (count) => `${countOf(count, "file", "files")} attached`
87
128
  },
88
129
  paste: {
89
130
  title: "Pasted text",
90
- lines: (count) => count === 1 ? "1 line" : `${count.toLocaleString()} lines`,
131
+ lines: (count) => countOf(count, "line", "lines"),
91
132
  saving: "Saving…",
92
133
  remove: "Remove paste"
93
134
  },
94
135
  thinking: {
95
136
  label: "Thinking",
96
- ellipsis: "Thinking...",
137
+ ellipsis: "Thinking…",
97
138
  thoughtFor: (duration) => `Thought for ${duration}`,
98
139
  thoughtProcess: "Thought process",
99
140
  activity: "Activity",
100
- ranToolCalls: (count) => count === 1 ? "Ran 1 tool call" : `Ran ${count.toLocaleString()} tool calls`
141
+ ranToolCalls: (count) => `Ran ${countOf(count, "tool call", "tool calls")}`
142
+ },
143
+ thread: {
144
+ viewOnly: "You have view only access",
145
+ label: "Conversation"
101
146
  },
102
- thread: { viewOnly: "You have view only access" },
103
147
  sidebar: {
104
148
  groupToday: "Today",
105
149
  groupYesterday: "Yesterday",
106
- groupThisWeek: "This Week",
107
- groupThisMonth: "This Month",
150
+ groupThisWeek: "This week",
151
+ groupThisMonth: "This month",
108
152
  groupOlder: "Older",
109
153
  untitled: "Untitled",
110
154
  sharedWithYou: "Shared with you",
@@ -115,18 +159,18 @@ var defaultChatStrings = {
115
159
  resizeHint: "Drag to resize; double-click to reset",
116
160
  newChat: "New chat",
117
161
  attachments: "Attachments",
118
- connectTools: "Connect Tools",
119
- manageProviders: "Manage Providers",
162
+ connectTools: "Connect tools",
163
+ manageProviders: "Manage providers",
120
164
  noConversations: "No conversations yet",
121
- deleteTitle: "Delete Conversation",
165
+ deleteTitle: "Delete conversation",
122
166
  deleteBody: "Are you sure you want to delete this conversation? This action cannot be undone.",
123
- renameTitle: "Rename Conversation",
167
+ renameTitle: "Rename conversation",
124
168
  renameLabel: "Conversation title",
125
169
  renamePlaceholder: "Enter a new title"
126
170
  },
127
171
  attachmentUpload: {
128
172
  fileTooLarge: (maxSize) => `File too large. Maximum size is ${maxSize}`,
129
- maxFilesAllowed: (max) => `Maximum ${max} files allowed`,
173
+ maxFilesAllowed: (max) => `Maximum ${countOf(max, "file", "files")} allowed`,
130
174
  dropFilesHere: "Drop files here",
131
175
  releaseToUpload: "Release to upload",
132
176
  addFiles: "Add files (drag or click)",
@@ -135,7 +179,12 @@ var defaultChatStrings = {
135
179
  },
136
180
  attachmentManager: {
137
181
  title: "Attachments",
138
- empty: "No attachments yet"
182
+ empty: "No attachments yet",
183
+ unnamedImage: "Image attachment",
184
+ unnamedFile: "File",
185
+ open: (name) => `Open ${name}`,
186
+ download: (name) => `Download ${name}`,
187
+ remove: (name) => `Delete ${name}`
139
188
  },
140
189
  branch: {
141
190
  previous: "Previous branch",
@@ -151,12 +200,12 @@ var defaultChatStrings = {
151
200
  },
152
201
  messageMeta: {
153
202
  stopped: "Stopped",
154
- tokens: (total) => `${total.toLocaleString()} tokens`,
203
+ tokens: (total) => countOf(total, "token", "tokens"),
155
204
  tokensBreakdown: (prompt, completion) => `${prompt.toLocaleString()} in · ${completion.toLocaleString()} out`,
156
- copy: "Copy message",
205
+ copyLabel: "message",
157
206
  edit: "Edit message",
158
207
  regenerate: "Regenerate response",
159
- editPlaceholder: "Edit your message..."
208
+ editPlaceholder: "Edit your message…"
160
209
  },
161
210
  permissions: {
162
211
  choose: "Choose what the agent may do",
@@ -178,7 +227,7 @@ var defaultChatStrings = {
178
227
  interrupted: "Interrupted",
179
228
  noOutput: "(no output)",
180
229
  diffTruncated: "Diff truncated",
181
- moreLines: "+{count} more lines",
230
+ moreLines: (count) => `+${countOf(count, "more line", "more lines")}`,
182
231
  allowOnce: "Yes, allow this command",
183
232
  allowDirectory: "Yes, and allow this directory for the session",
184
233
  deny: "No, deny this command",
@@ -196,7 +245,13 @@ var defaultChatStrings = {
196
245
  tasks: "Tasks",
197
246
  planPending: "Plan awaiting approval in the terminal",
198
247
  approvalPending: "Waiting for an answer in the terminal",
199
- approvalOptions: "Offered choices"
248
+ approvalOptions: "Offered choices",
249
+ approvalLabel: "Waiting for your answer",
250
+ feedbackLabel: "Feedback for the agent",
251
+ ownAnswerLabel: "Your answer",
252
+ todoPending: "To do",
253
+ todoInProgress: "In progress",
254
+ todoCompleted: "Done"
200
255
  },
201
256
  tools: defaultToolStrings
202
257
  };
@@ -243,6 +243,10 @@ export interface ShareGroup {
243
243
  export type ChatLinkTarget = {
244
244
  kind: 'conversation';
245
245
  id: string;
246
+ }
247
+ /** Where `ChatNavigation.toNewChat` goes, for the sidebar's new chat link. */
248
+ | {
249
+ kind: 'newChat';
246
250
  } | {
247
251
  kind: 'attachments';
248
252
  } | {
@@ -20,10 +20,10 @@ export declare function OutputCard({ title, text, onDismiss, dismissLabel, testI
20
20
  }): import("react").JSX.Element;
21
21
  /** An inline notice next to the composer. One with no dismiss states a fact
22
22
  * that is still true; one with a dismiss is a message the reader can put away. */
23
- export declare function NoticeCard({ tone, children, onDismiss, dismissLabel, testId, }: {
23
+ export declare function NoticeCard({ tone, children, onDismiss, testId, }: {
24
24
  tone?: NoticeTone;
25
25
  children: ReactNode;
26
+ /** Adds a close button, named by the provider's `dismiss` string. */
26
27
  onDismiss?: () => void;
27
- dismissLabel?: string;
28
28
  testId?: string;
29
29
  }): import("react").JSX.Element;
@@ -1,57 +1,31 @@
1
1
  import { cx } from "../../cx.js";
2
- import { CloseIcon, ErrorIcon, InfoIcon } from "../../icons.js";
2
+ import { CloseIcon } from "../../icons.js";
3
+ import { Button } from "../../components/Button.js";
4
+ import { Callout } from "../../components/Callout.js";
3
5
  import { jsx, jsxs } from "react/jsx-runtime";
4
6
  //#region src/ai/ui/Notice.tsx
5
- var barTone = {
6
- neutral: "theme-border theme-muted-panel",
7
- info: "border-blue-500/30 bg-blue-500/10",
8
- warning: "border-amber-500/40 bg-amber-500/10",
9
- danger: "border-red-500/30 bg-red-500/10"
10
- };
11
- var iconTone = {
12
- neutral: "theme-muted-text",
13
- info: "text-blue-600 dark:text-blue-400",
14
- warning: "text-amber-600 dark:text-amber-400",
15
- danger: "text-red-600 dark:text-red-400"
16
- };
17
- var titleTone = {
18
- neutral: "theme-text",
19
- info: "text-blue-700 dark:text-blue-300",
20
- warning: "text-amber-700 dark:text-amber-300",
21
- danger: "text-red-700 dark:text-red-300"
22
- };
23
- var cardTone = {
24
- neutral: "theme-border theme-muted-panel theme-muted-text",
25
- info: "border-blue-500/40 bg-blue-500/10 text-blue-800 dark:text-blue-200",
26
- warning: "border-amber-500/40 bg-amber-500/10 text-amber-800 dark:text-amber-200",
27
- danger: "border-red-500/40 bg-red-500/10 text-red-700 dark:text-red-300"
7
+ var calloutTone = {
8
+ neutral: "default",
9
+ info: "info",
10
+ warning: "warning",
11
+ danger: "error"
28
12
  };
29
13
  /** A standing condition on the surface: a full-width bar under the header
30
14
  * with a title, an explanation, and the one thing the reader can do about it. */
31
15
  function NoticeBar({ tone, title, children, action, onAction, testId }) {
32
- const Icon = tone === "danger" || tone === "warning" ? ErrorIcon : InfoIcon;
33
- return /* @__PURE__ */ jsxs("div", {
34
- "data-testid": testId,
35
- className: cx("flex shrink-0 items-start gap-3 border-b px-6 py-3", barTone[tone]),
36
- children: [
37
- /* @__PURE__ */ jsx(Icon, { className: cx("mt-0.5 h-4 w-4 shrink-0", iconTone[tone]) }),
38
- /* @__PURE__ */ jsxs("div", {
39
- className: "min-w-0 flex-1",
40
- children: [/* @__PURE__ */ jsx("p", {
41
- className: cx("text-sm font-medium", titleTone[tone]),
42
- children: title
43
- }), children && /* @__PURE__ */ jsx("p", {
44
- className: "mt-0.5 text-xs theme-muted-text",
45
- children
46
- })]
47
- }),
48
- action && onAction && /* @__PURE__ */ jsx("button", {
49
- type: "button",
50
- onClick: onAction,
51
- className: "shrink-0 rounded-lg border theme-border bg-(--theme-panel-bg) px-3 py-1.5 text-xs theme-text hover:theme-hover",
52
- children: action
53
- })
54
- ]
16
+ return /* @__PURE__ */ jsx(Callout, {
17
+ tone: calloutTone[tone],
18
+ variant: "bar",
19
+ title,
20
+ testId,
21
+ className: "shrink-0 px-6",
22
+ ...action && onAction ? { action: /* @__PURE__ */ jsx(Button, {
23
+ size: "sm",
24
+ variant: "outline",
25
+ onClick: onAction,
26
+ children: action
27
+ }) } : {},
28
+ children
55
29
  });
56
30
  }
57
31
  /** What a command printed, kept verbatim under the command that printed it. */
@@ -82,21 +56,14 @@ function OutputCard({ title, text, onDismiss, dismissLabel, testId }) {
82
56
  }
83
57
  /** An inline notice next to the composer. One with no dismiss states a fact
84
58
  * that is still true; one with a dismiss is a message the reader can put away. */
85
- function NoticeCard({ tone = "neutral", children, onDismiss, dismissLabel, testId }) {
86
- return /* @__PURE__ */ jsxs("div", {
87
- "data-testid": testId,
88
- className: cx("flex items-start gap-2 rounded-lg border px-3 py-2 text-xs", cardTone[tone]),
89
- children: [/* @__PURE__ */ jsx("span", {
90
- className: "flex-1",
91
- children
92
- }), onDismiss && /* @__PURE__ */ jsx("button", {
93
- type: "button",
94
- onClick: onDismiss,
95
- "aria-label": dismissLabel,
96
- title: dismissLabel,
97
- className: "shrink-0 rounded p-0.5 hover:theme-hover",
98
- children: /* @__PURE__ */ jsx(CloseIcon, { className: "h-3 w-3" })
99
- })]
59
+ function NoticeCard({ tone = "neutral", children, onDismiss, testId }) {
60
+ return /* @__PURE__ */ jsx(Callout, {
61
+ tone: calloutTone[tone],
62
+ size: "sm",
63
+ icon: false,
64
+ onDismiss,
65
+ testId,
66
+ children
100
67
  });
101
68
  }
102
69
  //#endregion
@@ -44,12 +44,14 @@ export declare function SidebarRow({ selected, menuItems, openMenu, className, c
44
44
  children: ReactNode;
45
45
  }): import("react").JSX.Element;
46
46
  /** One entry in the collapsed rail: a square the size of the toggle, with the
47
- * same highlight as a row, holding whatever stands in for the item. */
48
- export declare function SidebarRailItem({ selected, label, onSelect, testId, children, }: {
47
+ * same highlight as a row, holding whatever stands in for the item. With
48
+ * `href` it is a link to the item, and `onSelect` runs only for a plain click. */
49
+ export declare function SidebarRailItem({ selected, label, href, onSelect, testId, children, }: {
49
50
  selected: boolean;
50
51
  /** Names the icon-only button, and shows beside it on hover. */
51
52
  label: string;
52
- onSelect: () => void;
53
+ href?: string | undefined;
54
+ onSelect?: (() => void) | undefined;
53
55
  testId?: string;
54
56
  children: ReactNode;
55
57
  }): import("react").JSX.Element;
@@ -1,9 +1,10 @@
1
1
  import { cx } from "../../cx.js";
2
2
  import { SidebarIcon } from "../../icons.js";
3
3
  import { Tooltip } from "../../components/Tooltip.js";
4
+ import { AppLink, isPlainClick } from "../../components/AppLink.js";
5
+ import { IconButton } from "../../components/IconButton.js";
4
6
  import { fieldBox } from "../../components/fieldBox.js";
5
7
  import { ConfirmModal } from "../../components/ConfirmModal.js";
6
- import { IconButton } from "../../components/IconButton.js";
7
8
  import { MoreButton, rowContextMenuProps, useRowMenuActive } from "../../list/rowMenu.js";
8
9
  import { focusOnMount } from "../../components/focus.js";
9
10
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
@@ -37,7 +38,7 @@ function SidebarToggle({ collapsed, onToggle, openLabel, closeLabel, className }
37
38
  function SidebarGroupHeading({ children, tone = "default", testId }) {
38
39
  return /* @__PURE__ */ jsx("h4", {
39
40
  "data-testid": testId,
40
- className: cx("mt-5 mb-1 whitespace-nowrap px-2 text-xs font-medium", tone === "attention" ? "text-amber-700 dark:text-amber-300" : "theme-muted-text"),
41
+ className: cx("mt-5 mb-1 whitespace-nowrap px-2 text-xs font-medium", tone === "attention" ? "text-(--theme-warning-text)" : "theme-muted-text"),
41
42
  children
42
43
  });
43
44
  }
@@ -69,18 +70,29 @@ function SidebarRow({ selected, menuItems, openMenu, className, children }) {
69
70
  });
70
71
  }
71
72
  /** One entry in the collapsed rail: a square the size of the toggle, with the
72
- * same highlight as a row, holding whatever stands in for the item. */
73
- function SidebarRailItem({ selected, label, onSelect, testId, children }) {
73
+ * same highlight as a row, holding whatever stands in for the item. With
74
+ * `href` it is a link to the item, and `onSelect` runs only for a plain click. */
75
+ function SidebarRailItem({ selected, label, href, onSelect, testId, children }) {
76
+ const props = {
77
+ "data-testid": testId,
78
+ "aria-label": label,
79
+ "aria-current": selected ? "page" : void 0,
80
+ className: cx("flex h-7 w-7 items-center justify-center rounded-md transition-colors", HIGHLIGHT_HOVER, selected && HIGHLIGHT_SELECTED)
81
+ };
74
82
  return /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(Tooltip, {
75
83
  content: label,
76
84
  side: "right",
77
- children: /* @__PURE__ */ jsx("button", {
85
+ children: href ? /* @__PURE__ */ jsx(AppLink, {
86
+ href,
87
+ onClick: (e) => {
88
+ if (isPlainClick(e)) onSelect?.();
89
+ },
90
+ ...props,
91
+ children
92
+ }) : /* @__PURE__ */ jsx("button", {
78
93
  type: "button",
79
- "data-testid": testId,
80
- "aria-label": label,
81
- "aria-current": selected ? "page" : void 0,
82
94
  onClick: onSelect,
83
- className: cx("flex h-7 w-7 items-center justify-center rounded-md transition-colors", HIGHLIGHT_HOVER, selected && HIGHLIGHT_SELECTED),
95
+ ...props,
84
96
  children
85
97
  })
86
98
  }) });
@@ -7,6 +7,7 @@ export declare function ActionMenu({ items, label, search, align, triggerClassNa
7
7
  label: string;
8
8
  search?: MenuSearch | undefined;
9
9
  align?: 'start' | 'center' | 'end';
10
+ /** Styles the trigger; without it the trigger is a ghost icon button. */
10
11
  triggerClassName?: string | undefined;
11
12
  /** The trigger's content. */
12
13
  children: ReactNode;
@@ -1,3 +1,4 @@
1
+ import { buttonClasses } from "./buttonClasses.js";
1
2
  import { MenuPopup } from "./Menu.js";
2
3
  import { Tooltip } from "./Tooltip.js";
3
4
  import { MenuEntries, MenuFilter } from "./MenuEntries.js";
@@ -12,7 +13,11 @@ function ActionMenu({ items, label, search, align, triggerClassName, children })
12
13
  content: label,
13
14
  children: /* @__PURE__ */ jsx(Menu.Trigger, {
14
15
  "aria-label": label,
15
- className: triggerClassName,
16
+ className: triggerClassName ?? buttonClasses({
17
+ variant: "ghost",
18
+ size: "sm",
19
+ iconOnly: true
20
+ }),
16
21
  children
17
22
  })
18
23
  }), /* @__PURE__ */ jsx(MenuPopup, {
@@ -0,0 +1,26 @@
1
+ import type { ComponentPropsWithRef, MouseEvent } from 'react';
2
+ /** Where a control navigates, for any component that can be a link instead of a button. */
3
+ export interface LinkTarget {
4
+ /** Navigates there: a plain click goes through the host's router, and a
5
+ * modified or middle click opens it as any link would. */
6
+ href?: string | undefined;
7
+ /** Loads the page instead of routing, for paths the host's router doesn't serve. */
8
+ reloadDocument?: boolean | undefined;
9
+ /** Such as `_blank`, which also cuts the opened page's hold on this one. */
10
+ target?: string | undefined;
11
+ }
12
+ export type AppLinkProps = Omit<ComponentPropsWithRef<'a'>, 'href' | 'target'> & LinkTarget & {
13
+ /** Keeps it a link that goes nowhere: no href, `aria-disabled`, still
14
+ * focusable so a tooltip saying why stays reachable. */
15
+ disabled?: boolean | undefined;
16
+ };
17
+ /** True for a click the browser would open in place: the primary button with
18
+ * no modifier. A link's own onClick work, such as closing a drawer or clearing
19
+ * state, belongs to that click only; the others open a new tab or window and
20
+ * leave this page as it is. */
21
+ export declare function isPlainClick(event: MouseEvent<Element>): boolean;
22
+ /** A link through the host's router (`useLink`): the one way a component
23
+ * renders an `href`. In-app paths route client-side; `reloadDocument` and
24
+ * URLs that leave the app get a plain anchor. Every href passes `safeUrl`,
25
+ * and one that doesn't, or a disabled link, renders without an href. */
26
+ export declare function AppLink({ href, reloadDocument, target, disabled, rel, onClick, children, ...props }: AppLinkProps): import("react").JSX.Element;
@@ -0,0 +1,51 @@
1
+ import { safeUrl } from "../safeUrl.js";
2
+ import { useLink, useStrings } from "./Provider.js";
3
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
4
+ //#region src/components/AppLink.tsx
5
+ function leavesApp(url) {
6
+ if (!/^([a-z][a-z\d+.-]*:|\/\/)/i.test(url)) return false;
7
+ if (typeof window === "undefined") return true;
8
+ return new URL(url, window.location.href).origin !== window.location.origin;
9
+ }
10
+ /** True for a click the browser would open in place: the primary button with
11
+ * no modifier. A link's own onClick work, such as closing a drawer or clearing
12
+ * state, belongs to that click only; the others open a new tab or window and
13
+ * leave this page as it is. */
14
+ function isPlainClick(event) {
15
+ return event.button === 0 && !event.metaKey && !event.ctrlKey && !event.shiftKey && !event.altKey && event.currentTarget.getAttribute("target") !== "_blank";
16
+ }
17
+ /** A link through the host's router (`useLink`): the one way a component
18
+ * renders an `href`. In-app paths route client-side; `reloadDocument` and
19
+ * URLs that leave the app get a plain anchor. Every href passes `safeUrl`,
20
+ * and one that doesn't, or a disabled link, renders without an href. */
21
+ function AppLink({ href, reloadDocument = false, target, disabled = false, rel, onClick, children, ...props }) {
22
+ const Link = useLink();
23
+ const { common } = useStrings();
24
+ const url = disabled ? void 0 : safeUrl(href);
25
+ if (!url) return /* @__PURE__ */ jsx("a", {
26
+ ...props,
27
+ role: "link",
28
+ "aria-disabled": "true",
29
+ tabIndex: props.tabIndex ?? 0,
30
+ children
31
+ });
32
+ const linkProps = {
33
+ ...props,
34
+ target,
35
+ rel: rel ?? (target === "_blank" ? "noopener noreferrer" : void 0),
36
+ onClick,
37
+ children: target === "_blank" ? /* @__PURE__ */ jsxs(Fragment, { children: [children, /* @__PURE__ */ jsxs("span", {
38
+ className: "sr-only",
39
+ children: [" ", common.opensInNewTab]
40
+ })] }) : children
41
+ };
42
+ return reloadDocument || leavesApp(url) ? /* @__PURE__ */ jsx("a", {
43
+ ...linkProps,
44
+ href: url
45
+ }) : /* @__PURE__ */ jsx(Link, {
46
+ ...linkProps,
47
+ href: url
48
+ });
49
+ }
50
+ //#endregion
51
+ export { AppLink, isPlainClick };
@@ -11,5 +11,6 @@ export interface AvatarProps {
11
11
  /** Up to two initials: the first and last word of a name split on spaces and dots. */
12
12
  export declare function avatarInitials(name: string | undefined): string;
13
13
  /** A person's picture, or their initials while it loads or when it fails. It is
14
- * one image to assistive technology, named for the person, whichever shows. */
14
+ * one image to assistive technology, named for the person, whichever shows,
15
+ * and their presence when it has a status dot. */
15
16
  export declare function Avatar({ src, name, size, status, className }: AvatarProps): import("react").JSX.Element;
@@ -26,12 +26,14 @@ function avatarInitials(name) {
26
26
  return first?.toUpperCase() || "?";
27
27
  }
28
28
  /** A person's picture, or their initials while it loads or when it fails. It is
29
- * one image to assistive technology, named for the person, whichever shows. */
29
+ * one image to assistive technology, named for the person, whichever shows,
30
+ * and their presence when it has a status dot. */
30
31
  function Avatar$1({ src, name, size = "md", status, className }) {
31
32
  const { common } = useStrings();
33
+ const who = name || common.userAvatar;
32
34
  return /* @__PURE__ */ jsxs("span", {
33
35
  role: "img",
34
- "aria-label": name || common.userAvatar,
36
+ "aria-label": status ? common.withPresence(who, common.presence[status]) : who,
35
37
  className: cx("relative inline-flex shrink-0", className),
36
38
  children: [/* @__PURE__ */ jsxs(Avatar.Root, {
37
39
  className: cx("relative inline-flex items-center justify-center overflow-hidden rounded-full font-medium select-none", SIZE_CLASSES[size]),
@@ -1,7 +1,8 @@
1
1
  import { Button as BaseButton } from '@base-ui/react/button';
2
2
  import type { ButtonHTMLAttributes, ReactNode } from 'react';
3
+ import { type AppLinkProps, type LinkTarget } from './AppLink.js';
3
4
  import { type ButtonStyle } from './buttonClasses.js';
4
- export interface ButtonProps extends Omit<BaseButton.Props, 'className'>, ButtonStyle {
5
+ interface ButtonOwnProps extends ButtonStyle {
5
6
  className?: string | undefined;
6
7
  /** Before the label. */
7
8
  icon?: ReactNode;
@@ -9,16 +10,25 @@ export interface ButtonProps extends Omit<BaseButton.Props, 'className'>, Button
9
10
  * be pressed again until done. */
10
11
  loading?: boolean | undefined;
11
12
  }
13
+ /** A button, or with `href` a link that looks like one: navigation stays a
14
+ * link, so it opens in a new tab and shows its URL like any other. */
15
+ export type ButtonProps = ButtonOwnProps & ((Omit<BaseButton.Props, 'className'> & {
16
+ href?: undefined;
17
+ }) | (Omit<AppLinkProps, 'className'> & LinkTarget & {
18
+ href: string;
19
+ }));
12
20
  /** A button in the package's one look (see `buttonClasses`).
13
- * `focusableWhenDisabled` keeps a disabled button's tooltip reachable. A link
14
- * that looks like a button stays a link: give it `buttonClasses()`. */
15
- export declare function Button({ variant, size, iconOnly, icon, loading, disabled, className, children, ...props }: ButtonProps): import("react").JSX.Element;
16
- interface MethodButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
21
+ * `focusableWhenDisabled` keeps a disabled button's tooltip reachable; a
22
+ * disabled link stays focusable on its own. */
23
+ export declare function Button({ variant, size, iconOnly, icon, loading, className, children, ...props }: ButtonProps): import("react").JSX.Element;
24
+ interface MethodButtonProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'children'> {
17
25
  icon?: ReactNode;
18
26
  label: string;
19
27
  description?: string;
20
28
  href?: string;
21
29
  loading?: boolean;
22
30
  }
31
+ /** One way to go on, such as a sign-in method: a large row with an icon, a
32
+ * label and a line under it. A list of them is spaced by its container. */
23
33
  export declare function MethodButton({ icon, label, description, href, loading, disabled, className, ...props }: MethodButtonProps): import("react").JSX.Element;
24
34
  export {};