@ciridae/ui 1.0.4 → 1.0.9

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 (147) hide show
  1. package/README.md +3 -2
  2. package/dist/chat/conversation-source.d.ts +1 -3
  3. package/dist/chat/message-text.js +6 -6
  4. package/dist/chat/use-chat-conversation.d.ts +7 -2
  5. package/dist/chat/use-chat-conversation.js +2 -1
  6. package/dist/components/activity-feed.d.ts +0 -1
  7. package/dist/components/activity-feed.js +6 -7
  8. package/dist/components/agent-work.d.ts +5 -1
  9. package/dist/components/agent-work.js +27 -13
  10. package/dist/components/app-frame.d.ts +3 -17
  11. package/dist/components/app-frame.js +11 -30
  12. package/dist/components/app-navigation.d.ts +5 -6
  13. package/dist/components/app-navigation.js +70 -40
  14. package/dist/components/badge.d.ts +0 -4
  15. package/dist/components/badge.js +17 -27
  16. package/dist/components/bulk-action-bar.js +2 -2
  17. package/dist/components/button.js +41 -50
  18. package/dist/components/calendar.js +5 -8
  19. package/dist/components/centered-page.js +4 -4
  20. package/dist/components/chart.js +3 -4
  21. package/dist/components/chat-client-source.js +55 -34
  22. package/dist/components/chat-page.js +1 -1
  23. package/dist/components/chat-sheet.d.ts +30 -20
  24. package/dist/components/chat-sheet.js +112 -54
  25. package/dist/components/chat.d.ts +27 -56
  26. package/dist/components/chat.js +153 -132
  27. package/dist/components/checkbox-item.js +4 -4
  28. package/dist/components/checkbox-list.js +6 -6
  29. package/dist/components/chip.js +2 -2
  30. package/dist/components/collapsible.js +3 -3
  31. package/dist/components/color-theme.d.ts +3 -6
  32. package/dist/components/color-theme.js +10 -11
  33. package/dist/components/column-settings.js +3 -3
  34. package/dist/components/command-menu.d.ts +1 -2
  35. package/dist/components/command-menu.js +56 -77
  36. package/dist/components/command-palette.js +5 -2
  37. package/dist/components/copyable-id.js +5 -5
  38. package/dist/components/data-display.d.ts +1 -7
  39. package/dist/components/data-display.js +32 -55
  40. package/dist/components/data-grid.d.ts +4 -7
  41. package/dist/components/data-grid.js +106 -90
  42. package/dist/components/date-range-picker.js +4 -5
  43. package/dist/components/document-viewer.js +23 -23
  44. package/dist/components/drawer.d.ts +2 -1
  45. package/dist/components/drawer.js +45 -20
  46. package/dist/components/dropzone.js +13 -13
  47. package/dist/components/editable-field.d.ts +2 -7
  48. package/dist/components/editable-field.js +14 -27
  49. package/dist/components/email-input.js +2 -3
  50. package/dist/components/environment-frame.js +7 -7
  51. package/dist/components/expandable-text.js +2 -2
  52. package/dist/components/feedback-screenshot.js +7 -7
  53. package/dist/components/feedback-sheet.js +8 -8
  54. package/dist/components/filter-bar.js +41 -27
  55. package/dist/components/form-controls.d.ts +3 -6
  56. package/dist/components/form-controls.js +15 -22
  57. package/dist/components/form-layout.d.ts +6 -6
  58. package/dist/components/form-layout.js +10 -16
  59. package/dist/components/glass-menu.d.ts +2 -0
  60. package/dist/components/glass-menu.js +14 -18
  61. package/dist/components/gradient-edge.d.ts +0 -1
  62. package/dist/components/gradient-edge.js +8 -9
  63. package/dist/components/icon.js +1 -1
  64. package/dist/components/input.js +18 -17
  65. package/dist/components/keycap.d.ts +2 -6
  66. package/dist/components/keycap.js +4 -12
  67. package/dist/components/layout.js +11 -10
  68. package/dist/components/lightbox.js +8 -8
  69. package/dist/components/link.js +1 -1
  70. package/dist/components/locale.d.ts +23 -7
  71. package/dist/components/locale.js +19 -7
  72. package/dist/components/log-entry.d.ts +2 -14
  73. package/dist/components/log-entry.js +11 -22
  74. package/dist/components/log-list.js +1 -1
  75. package/dist/components/mention-input.js +13 -14
  76. package/dist/components/menu.d.ts +7 -4
  77. package/dist/components/menu.js +23 -10
  78. package/dist/components/meter.d.ts +2 -3
  79. package/dist/components/meter.js +12 -16
  80. package/dist/components/navigation.d.ts +0 -7
  81. package/dist/components/navigation.js +3 -12
  82. package/dist/components/notification-tray.js +7 -7
  83. package/dist/components/overlays.d.ts +5 -2
  84. package/dist/components/overlays.js +24 -24
  85. package/dist/components/panel.js +3 -3
  86. package/dist/components/progress.js +2 -2
  87. package/dist/components/radio-card.d.ts +1 -1
  88. package/dist/components/radio-card.js +9 -9
  89. package/dist/components/record.d.ts +2 -4
  90. package/dist/components/record.js +19 -32
  91. package/dist/components/scroll-area.js +10 -10
  92. package/dist/components/segmented-bar.js +9 -9
  93. package/dist/components/select.d.ts +3 -5
  94. package/dist/components/select.js +26 -44
  95. package/dist/components/settings.js +1 -1
  96. package/dist/components/shell-skeleton.js +1 -1
  97. package/dist/components/shell.d.ts +1 -1
  98. package/dist/components/shell.js +69 -24
  99. package/dist/components/side-panel.js +3 -3
  100. package/dist/components/sidebar.d.ts +0 -5
  101. package/dist/components/sidebar.js +25 -33
  102. package/dist/components/single-line-text.js +3 -4
  103. package/dist/components/site-banner.js +4 -4
  104. package/dist/components/skeleton.js +19 -22
  105. package/dist/components/skeletons.d.ts +0 -3
  106. package/dist/components/skeletons.js +5 -10
  107. package/dist/components/stages.d.ts +6 -3
  108. package/dist/components/stages.js +77 -105
  109. package/dist/components/stat-card.d.ts +2 -5
  110. package/dist/components/stat-card.js +23 -31
  111. package/dist/components/status-banner.js +6 -6
  112. package/dist/components/status.js +3 -3
  113. package/dist/components/steps.js +2 -2
  114. package/dist/components/switch.js +1 -1
  115. package/dist/components/tabs.js +15 -18
  116. package/dist/components/theme-customizer.d.ts +5 -8
  117. package/dist/components/theme-customizer.js +9 -41
  118. package/dist/components/theme-toggle.d.ts +0 -1
  119. package/dist/components/theme-toggle.js +6 -11
  120. package/dist/components/toast.d.ts +1 -7
  121. package/dist/components/toast.js +19 -22
  122. package/dist/components/user-chip.js +8 -8
  123. package/dist/components/wizard.js +6 -4
  124. package/dist/preset.d.ts +1 -2
  125. package/dist/preset.js +41 -89
  126. package/dist/styled-system/css/conditions.mjs +1 -1
  127. package/dist/styled-system/css/css.mjs +1 -1
  128. package/dist/styled-system/styles.css +820 -1297
  129. package/dist/styled-system/tokens/index.mjs +78 -1926
  130. package/dist/styled-system/tokens/tokens.d.ts +18 -33
  131. package/dist/styled-system/types/conditions.d.ts +0 -74
  132. package/dist/styled-system/types/prop-type.d.ts +15 -40
  133. package/dist/styled-system/types/style-props.d.ts +705 -705
  134. package/dist/theme/color.d.ts +0 -1
  135. package/dist/theme/color.js +0 -16
  136. package/dist/theme/derive.d.ts +3 -3
  137. package/dist/theme/derive.js +9 -32
  138. package/dist/theme/index.d.ts +1 -2
  139. package/dist/theme/index.js +3 -5
  140. package/dist/theme/options.d.ts +2 -4
  141. package/dist/theme/options.js +0 -1
  142. package/dist/theme/{palettes.d.ts → palette.d.ts} +12 -23
  143. package/dist/theme/palette.js +127 -0
  144. package/dist/theme/tokens.d.ts +8 -13
  145. package/dist/theme/tokens.js +39 -92
  146. package/package.json +1 -1
  147. package/dist/theme/palettes.js +0 -254
package/README.md CHANGED
@@ -11,7 +11,8 @@ npm install @ciridae/ui
11
11
  Use the published package for new and updated consumers.
12
12
 
13
13
  Panda generates the component styles in your app. Add the preset, scan the package output, and
14
- recognise its `css` import alias:
14
+ recognise its `css` import alias. The components use only this preset's tokens; add
15
+ `"@pandacss/preset-panda"` before it only if your own styles use Panda's stock tokens:
15
16
 
16
17
  ```ts
17
18
  // panda.config.ts
@@ -19,7 +20,7 @@ import { ciridaePreset } from "@ciridae/ui/preset";
19
20
  import { defineConfig } from "@pandacss/dev";
20
21
 
21
22
  export default defineConfig({
22
- presets: ["@pandacss/preset-panda", ciridaePreset],
23
+ presets: [ciridaePreset],
23
24
  importMap: { css: ["#primitives/css", "styled-system/css"] },
24
25
  include: ["./src/**/*.{ts,tsx}", "./node_modules/@ciridae/ui/dist/**/*.js"],
25
26
  });
@@ -27,11 +27,9 @@ export type ChatConversationItem = {
27
27
  message?: string;
28
28
  retry: () => void;
29
29
  };
30
- /** Sources the reply cites beyond its Markdown's, such as the values it read, as cards. */
30
+ /** Beyond its Markdown's, such as the values it read, as cards. */
31
31
  sources?: readonly ChatSource[];
32
- /** Buttons under the reply for what it suggests doing on the page. */
33
32
  suggestedActions?: ReactNode;
34
- /** A closing line under the reply, such as what it read. */
35
33
  footnote?: ReactNode;
36
34
  }
37
35
  /**
@@ -14,7 +14,7 @@ const text = css({
14
14
  overflowWrap: "anywhere",
15
15
  "& :is(p, ul, ol, pre, table, blockquote, h1, h2, h3, h4, h5, h6, hr)": { margin: "none" },
16
16
  "& p": { whiteSpace: "pre-line" },
17
- "& :is(h1, h2, h3, h4, h5, h6)": { fontSize: "inherit", fontWeight: "semibold" },
17
+ "& :is(h1, h2, h3, h4, h5, h6)": { fontSize: "[inherit]", fontWeight: "semibold" },
18
18
  "& :is(ul, ol)": { paddingInlineStart: "layout.clusterGap" },
19
19
  "& li > :is(ul, ol)": { marginBlockStart: "control.trackInset" },
20
20
  "& li + li": { marginBlockStart: "control.trackInset" },
@@ -38,7 +38,7 @@ const text = css({
38
38
  "& hr": { border: "0", borderTop: "1px solid token(colors.border.control)" },
39
39
  "& table": {
40
40
  display: "block",
41
- maxWidth: "100%",
41
+ maxWidth: "full",
42
42
  overflowX: "auto",
43
43
  borderCollapse: "collapse",
44
44
  fontVariantNumeric: "tabular-nums",
@@ -52,12 +52,12 @@ const text = css({
52
52
  overflowWrap: "normal",
53
53
  },
54
54
  "& th": { fontWeight: "medium" },
55
- "& a:not([data-mention])": { color: "inherit", textDecoration: "underline" },
55
+ "& a:not([data-mention])": { color: "[inherit]", textDecoration: "underline" },
56
56
  });
57
57
  const mention = css({
58
58
  display: "inline-flex",
59
59
  alignItems: "center",
60
- maxWidth: "100%",
60
+ maxWidth: "full",
61
61
  paddingInline: "control.iconGap",
62
62
  border: "1px solid token(colors.border.control)",
63
63
  borderRadius: "keycap",
@@ -101,8 +101,8 @@ const plainText = css({
101
101
  paddingInline: "none",
102
102
  border: "0",
103
103
  background: "transparent",
104
- color: "inherit",
105
- fontSize: "inherit",
104
+ color: "[inherit]",
105
+ fontSize: "[inherit]",
106
106
  fontWeight: "semibold",
107
107
  _hover: { background: "transparent", textDecoration: "underline" },
108
108
  },
@@ -10,9 +10,14 @@ export type PendingMessage = {
10
10
  attachments: readonly Attachment[];
11
11
  /** When the user sent it, as epoch milliseconds, so it groups with the messages around it. */
12
12
  sentAt: number;
13
+ } & ({
13
14
  /** `posted` once the service accepted it, until the conversation's items include it. */
14
- state: "sending" | "posted" | "failed";
15
- };
15
+ state: "sending" | "posted";
16
+ } | {
17
+ state: "failed";
18
+ /** Why this message did not send, from the error its send threw. */
19
+ failureMessage: string;
20
+ });
16
21
  export type ChatConversationState = {
17
22
  conversation: Conversation | undefined;
18
23
  items: readonly Item[];
@@ -106,7 +106,8 @@ export function useChatConversation({ client, conversationId, onConversationCrea
106
106
  setPendingMessages((existing) => existing.filter((message) => message.localId !== localId));
107
107
  }
108
108
  catch (error) {
109
- setPendingMessages((existing) => existing.map((message) => message.localId === localId ? { ...message, state: "failed" } : message));
109
+ const failureMessage = error instanceof Error ? error.message : String(error);
110
+ setPendingMessages((existing) => existing.map((message) => message.localId === localId ? { ...message, state: "failed", failureMessage } : message));
110
111
  throw error;
111
112
  }
112
113
  }, [client, conversationId, onConversationCreated, queryClient]);
@@ -1,7 +1,6 @@
1
1
  import { type ReactNode, type RefObject } from "react";
2
2
  import { type CiridaeLabels } from "./locale.js";
3
3
  import { type UserChipProps } from "./user-chip.js";
4
- export { LogActor, LogEntry, LogGroupHeader, type LogActorProps, type LogEntryProps, type LogGroupHeaderProps, } from "./log-entry.js";
5
4
  export type ActivityFeedActor = Pick<UserChipProps, "name" | "kind" | "src" | "icon" | "profile">;
6
5
  export type ActivityFeedUpdate = {
7
6
  kind: "update";
@@ -14,7 +14,6 @@ import { Toolbar } from "./layout.js";
14
14
  import { useCiridaeLocale } from "./locale.js";
15
15
  import { MentionChip, openMentionPicker, readMentions, } from "./mention-input.js";
16
16
  import { UserName } from "./user-chip.js";
17
- export { LogActor, LogEntry, LogGroupHeader, } from "./log-entry.js";
18
17
  const FILTERS = [
19
18
  { value: "all", label: "all", empty: "noActivity" },
20
19
  { value: "comments", label: "comments", empty: "noComments" },
@@ -78,14 +77,14 @@ const updateRun = css({
78
77
  gridTemplateColumns: "minmax(0, 1fr)",
79
78
  justifyItems: "center",
80
79
  gap: "layout.tightGap",
81
- maxWidth: "100%",
80
+ maxWidth: "full",
82
81
  });
83
82
  // The actors give way to an ellipsis before the count does.
84
83
  const runToggle = css({
85
84
  display: "inline-flex",
86
85
  alignItems: "center",
87
86
  gap: "layout.tightGap",
88
- maxWidth: "100%",
87
+ maxWidth: "full",
89
88
  padding: "none",
90
89
  border: "0",
91
90
  background: "transparent",
@@ -94,8 +93,8 @@ const runToggle = css({
94
93
  cursor: "pointer",
95
94
  _hover: { color: "fg.primary" },
96
95
  _focusVisible: { focusRing: "outer" },
97
- "& > svg": { transition: "rotate 120ms ease" },
98
- "&[aria-expanded=true] > svg": { rotate: "90deg", _rtl: { rotate: "-90deg" } },
96
+ "& > svg": { transitionProperty: "[rotate]", transitionDuration: "fast" },
97
+ "&[aria-expanded=true] > svg": { rotate: "[90deg]", _rtl: { rotate: "[-90deg]" } },
99
98
  "& > [data-actors]": { overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" },
100
99
  "& > [data-count]": { flexShrink: "0", whiteSpace: "nowrap" },
101
100
  });
@@ -114,7 +113,7 @@ const chip = css({
114
113
  display: "inline-flex",
115
114
  alignItems: "center",
116
115
  gap: "layout.tightGap",
117
- maxWidth: "100%",
116
+ maxWidth: "full",
118
117
  minWidth: "0",
119
118
  paddingBlock: "control.trackInset",
120
119
  paddingInline: "control.iconGap",
@@ -151,7 +150,7 @@ const thumbnail = css({
151
150
  _focusVisible: { focusRing: "outer" },
152
151
  "& img": {
153
152
  display: "block",
154
- maxWidth: "100%",
153
+ maxWidth: "full",
155
154
  width: "auto",
156
155
  height: "skeleton.medium",
157
156
  objectFit: "cover",
@@ -70,7 +70,11 @@ export type AgentWorkButtonProps = {
70
70
  export declare function AgentWorkButton({ tasks, title, className }: AgentWorkButtonProps): import("react").JSX.Element | null;
71
71
  export type AgentTaskCardProps = {
72
72
  task: AgentTask;
73
- onReply?: (task: AgentTask, reply: AgentTaskReply) => void;
73
+ /**
74
+ * Sends the user's approval or answer. The card's buttons wait while it runs, and if it rejects
75
+ * the card shows its error and takes another reply; the card goes once the task moves on.
76
+ */
77
+ onReply: (task: AgentTask, reply: AgentTaskReply) => Promise<void>;
74
78
  };
75
79
  /** The agent asking: a waiting task's question, its details, and Deny / Approve or the answers. */
76
80
  export declare function AgentTaskCard({ task, onReply }: AgentTaskCardProps): import("react").JSX.Element | null;
@@ -60,7 +60,7 @@ const nowLine = css({
60
60
  });
61
61
  const waitingRow = css({
62
62
  display: "block",
63
- width: "100%",
63
+ width: "full",
64
64
  paddingBlock: "control.compactBlock",
65
65
  paddingInline: "menu.itemInline",
66
66
  border: "0",
@@ -82,7 +82,7 @@ const summaryBar = css({
82
82
  display: "flex",
83
83
  alignItems: "center",
84
84
  gap: "control.iconGap",
85
- width: "100%",
85
+ width: "full",
86
86
  minHeight: "control.small",
87
87
  paddingBlock: "layout.tightGap",
88
88
  paddingInline: "panel.comfortable",
@@ -103,11 +103,11 @@ const summaryBar = css({
103
103
  textOverflow: "ellipsis",
104
104
  whiteSpace: "nowrap",
105
105
  },
106
- "& > svg:last-child": { transition: "rotate 120ms ease" },
107
- "&[aria-expanded=true] > svg:last-child": { rotate: "180deg" },
106
+ "& > svg:last-child": { transitionProperty: "[rotate]", transitionDuration: "fast" },
107
+ "&[aria-expanded=true] > svg:last-child": { rotate: "[180deg]" },
108
108
  });
109
109
  const summaryLists = css({
110
- maxHeight: "50vh",
110
+ maxHeight: "[50vh]",
111
111
  overflowY: "auto",
112
112
  borderBottom: "1px solid token(colors.border.control)",
113
113
  });
@@ -167,7 +167,7 @@ export function AgentWorkButton({ tasks, title, className }) {
167
167
  const askCard = css({
168
168
  display: "grid",
169
169
  gap: "control.iconGap",
170
- width: "100%",
170
+ width: "full",
171
171
  maxWidth: "chat.bubble",
172
172
  paddingBlock: "control.block",
173
173
  paddingInline: "control.compactInline",
@@ -176,9 +176,9 @@ const askCard = css({
176
176
  background: "bg.card",
177
177
  fontSize: "caption",
178
178
  lineHeight: "log",
179
- outline: "none",
179
+ outline: "0",
180
180
  scrollMarginBlock: "panel.default",
181
- transitionProperty: "border-color, box-shadow",
181
+ transitionProperty: "[border-color, box-shadow]",
182
182
  transitionDuration: "fast",
183
183
  "&[data-highlighted]": { borderColor: "border.focus", boxShadow: "focus" },
184
184
  });
@@ -192,13 +192,14 @@ const detailList = css({
192
192
  "& > dt": { color: "fg.muted", whiteSpace: "nowrap" },
193
193
  "& > dd": { margin: "none", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" },
194
194
  });
195
+ const replyError = css({ color: "accent.red", fontSize: "code", lineHeight: "compact" });
195
196
  const cardActions = css({ display: "flex", justifyContent: "flex-end", gap: "layout.controlGap" });
196
197
  const optionList = css({
197
- marginInline: "calc(token(spacing.control.compactInline) * -1)",
198
- marginBlockEnd: "calc(token(spacing.control.block) * -1)",
198
+ marginInline: "[calc(token(spacing.control.compactInline) * -1)]",
199
+ marginBlockEnd: "[calc(token(spacing.control.block) * -1)]",
199
200
  "& > button": {
200
201
  display: "block",
201
- width: "100%",
202
+ width: "full",
202
203
  paddingBlock: "control.compactBlock",
203
204
  paddingInline: "control.compactInline",
204
205
  border: "0",
@@ -208,8 +209,9 @@ const optionList = css({
208
209
  font: "inherit",
209
210
  textAlign: "start",
210
211
  cursor: "pointer",
211
- _hover: { background: "bg.hover" },
212
+ "&:enabled:hover": { background: "bg.hover" },
212
213
  _focusVisible: { focusRing: "inset" },
214
+ _disabled: { opacity: "disabled", cursor: "not-allowed" },
213
215
  "&:last-child": { borderBottomLeftRadius: "field", borderBottomRightRadius: "field" },
214
216
  "& > span": { display: "block", color: "fg.muted", fontSize: "code" },
215
217
  },
@@ -217,8 +219,20 @@ const optionList = css({
217
219
  /** The agent asking: a waiting task's question, its details, and Deny / Approve or the answers. */
218
220
  export function AgentTaskCard({ task, onReply }) {
219
221
  const { labels } = useCiridaeLocale();
222
+ const [replyState, setReplyState] = useState({ kind: "unanswered" });
220
223
  const { ask } = task;
221
224
  if (!ask)
222
225
  return null;
223
- return (_jsxs("div", { id: agentTaskAnchorId(task.id), className: askCard, tabIndex: -1, "data-ciridae-ui": "", children: [_jsx("span", { children: ask.text }), ask.kind === "approval" && ask.details && ask.details.length > 0 && (_jsx("dl", { className: detailList, children: ask.details.map((detail) => (_jsxs(Fragment, { children: [_jsx("dt", { children: detail.label }), _jsx("dd", { children: detail.value })] }, detail.label))) })), ask.kind === "approval" ? (_jsxs("div", { className: cardActions, children: [_jsx(Button, { variant: "secondary", onClick: () => onReply?.(task, { kind: "decision", decision: "deny" }), children: labels.chat.deny }), _jsx(Button, { onClick: () => onReply?.(task, { kind: "decision", decision: "allow" }), children: labels.chat.approve })] })) : (_jsx("div", { className: optionList, children: ask.options.map((option) => (_jsxs("button", { type: "button", onClick: () => onReply?.(task, { kind: "answer", answer: option.label }), children: [option.label, option.description && _jsx("span", { children: option.description })] }, option.label))) }))] }));
226
+ const sendReply = (reply) => {
227
+ setReplyState({ kind: "sending", reply });
228
+ onReply(task, reply).catch((error) => setReplyState({
229
+ kind: "failed",
230
+ message: error instanceof Error ? error.message : String(error),
231
+ }));
232
+ };
233
+ const sending = replyState.kind === "sending";
234
+ const sendingDecision = (decision) => replyState.kind === "sending" &&
235
+ replyState.reply.kind === "decision" &&
236
+ replyState.reply.decision === decision;
237
+ return (_jsxs("div", { id: agentTaskAnchorId(task.id), className: askCard, tabIndex: -1, "data-ciridae-ui": "", children: [_jsx("span", { children: ask.text }), ask.kind === "approval" && ask.details && ask.details.length > 0 && (_jsx("dl", { className: detailList, children: ask.details.map((detail) => (_jsxs(Fragment, { children: [_jsx("dt", { children: detail.label }), _jsx("dd", { children: detail.value })] }, detail.label))) })), replyState.kind === "failed" && (_jsx("span", { className: replyError, role: "alert", children: replyState.message })), ask.kind === "approval" ? (_jsxs("div", { className: cardActions, children: [_jsx(Button, { variant: "secondary", disabled: sending, loading: sendingDecision("deny"), onClick: () => sendReply({ kind: "decision", decision: "deny" }), children: labels.chat.deny }), _jsx(Button, { disabled: sending, loading: sendingDecision("allow"), onClick: () => sendReply({ kind: "decision", decision: "allow" }), children: labels.chat.approve })] })) : (_jsx("div", { className: optionList, children: ask.options.map((option) => (_jsxs("button", { type: "button", disabled: sending, onClick: () => sendReply({ kind: "answer", answer: option.label }), children: [option.label, option.description && _jsx("span", { children: option.description })] }, option.label))) }))] }));
224
238
  }
@@ -1,26 +1,15 @@
1
- import { type PaletteName } from "../theme/index.js";
2
1
  import { type AppNavigationProps } from "./app-navigation.js";
3
2
  import { type HotkeyChord } from "./hotkeys.js";
4
3
  import { type MenuItem } from "./menu.js";
5
4
  import type { ComponentProps, ReactNode } from "react";
6
- /** The palette the reader shows, which the host keeps, such as in storage, for `ThemeProvider`. */
7
- export type PaletteChoice = {
8
- /** `undefined` is the stylesheet's own palette, `ciridae`. */
9
- value: PaletteName | undefined;
10
- onValueChange: (palette: PaletteName) => void;
11
- };
12
5
  /** The color theme submenu: system, light or dark. */
13
6
  export declare function useColorThemeMenuItem(): MenuItem;
14
- /** The palette submenu over the kit's palettes. */
15
- export declare function usePaletteMenuItem(choice: PaletteChoice): MenuItem;
16
7
  export type AccountMenuProps = {
17
8
  avatar: ReactNode;
18
9
  name: string;
19
10
  detail?: ReactNode;
20
11
  /** The app's own entries, such as Edit profile, above the color theme. */
21
12
  items?: readonly MenuItem[];
22
- /** Adds a palette submenu after the color theme. */
23
- palette?: PaletteChoice;
24
13
  /** The last entry, in the danger color. */
25
14
  signOut?: {
26
15
  onSelect: () => void;
@@ -30,18 +19,15 @@ export type AccountMenuProps = {
30
19
  /** The avatar alone, for the rail and the phone header. */
31
20
  compact?: boolean;
32
21
  };
33
- /** The signed-in account's menu: the app's entries, the color theme and palette, then sign out. */
34
- export declare function AccountMenu({ avatar, name, detail, items, palette, signOut, compact, }: AccountMenuProps): import("react").JSX.Element;
22
+ export declare function AccountMenu({ avatar, name, detail, items, signOut, compact, }: AccountMenuProps): import("react").JSX.Element;
35
23
  export type AssistantLauncherProps = Omit<ComponentProps<"button">, "children"> & {
36
- /** Such as "Ask Ciridae"; the rail's button is named by it. */
24
+ /** The rail's button is named by it. */
37
25
  label: string;
38
26
  icon: ReactNode;
39
- /** The hotkey that opens the assistant, shown at the end; the host binds it. */
27
+ /** The host binds it. */
40
28
  hotkey?: HotkeyChord;
41
- /** The icon alone, round, for the rail. */
42
29
  compact?: boolean;
43
30
  };
44
- /** Opens the app's assistant from the sidebar's foot: a raised pill, or a round icon in the rail. */
45
31
  export declare function AssistantLauncher({ label, icon: launcherIcon, hotkey, compact, className, ...props }: AssistantLauncherProps): import("react").JSX.Element;
46
32
  /** A footer control drawn for every width: a sidebar row, a rail icon and a phone-header icon. */
47
33
  export type AppFrameItem = {
@@ -3,12 +3,11 @@ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-run
3
3
  * The app's frame, composed from the shell's pieces: the sidebar that folds to a rail and then
4
4
  * into the phone menu, its footer rows and account menu drawn for each width, and, given a
5
5
  * `title`, the main panel's header too. `AccountMenu` is the signed-in account's menu: the app's
6
- * own entries, the color theme and palette, and sign out. Auth stays with the host, which passes
6
+ * own entries, the color theme, and sign out. Auth stays with the host, which passes
7
7
  * sign-out as an action. `AssistantLauncher` opens the app's assistant from the sidebar's foot.
8
8
  */
9
- import { ArrowClockwiseIcon, CaretUpIcon, CircleHalfIcon, PaletteIcon, PulseIcon, SignOutIcon, } from "@phosphor-icons/react";
9
+ import { ArrowClockwiseIcon, CaretUpIcon, CircleHalfIcon, PulseIcon, SignOutIcon, } from "@phosphor-icons/react";
10
10
  import { css, cx } from "#primitives/css";
11
- import { PALETTE_NAMES } from "../theme/index.js";
12
11
  import { AppNavigation } from "./app-navigation.js";
13
12
  import { Button, IconButton } from "./button.js";
14
13
  import { useColorTheme } from "./color-theme.js";
@@ -18,6 +17,7 @@ import { ShortcutHint } from "./keycap.js";
18
17
  import { Link } from "./link.js";
19
18
  import { useCiridaeLocale } from "./locale.js";
20
19
  import { Menu } from "./menu.js";
20
+ import { Tooltip } from "./overlays.js";
21
21
  import { AppAccountButton, AppBreadcrumbs, AppContent, AppHeader, AppHeaderActions, AppHeaderCompact, AppMain, AppShell, AppSidebar, AppSidebarFooter, AppSidebarFootnote, AppSidebarGroup, AppSidebarNav, AppSidebarOnly, AppSidebarRail, } from "./shell.js";
22
22
  import { SidebarItem } from "./sidebar.js";
23
23
  import { useNewVersionAvailable } from "./use-new-version-available.js";
@@ -40,24 +40,7 @@ export function useColorThemeMenuItem() {
40
40
  })),
41
41
  };
42
42
  }
43
- /** The palette submenu over the kit's palettes. */
44
- export function usePaletteMenuItem(choice) {
45
- return paletteMenuItem(choice, useCiridaeLocale().labels);
46
- }
47
- function paletteMenuItem({ value, onValueChange }, labels) {
48
- const selected = value ?? "ciridae";
49
- return {
50
- label: labels.themeCustomizer.palette,
51
- icon: _jsx(PaletteIcon, { className: icon({ size: "small" }) }),
52
- items: PALETTE_NAMES.map((name) => ({
53
- label: labels.themeCustomizer.paletteName(name),
54
- checked: selected === name,
55
- onSelect: () => onValueChange(name),
56
- })),
57
- };
58
- }
59
- /** The signed-in account's menu: the app's entries, the color theme and palette, then sign out. */
60
- export function AccountMenu({ avatar, name, detail, items = [], palette, signOut, compact = false, }) {
43
+ export function AccountMenu({ avatar, name, detail, items = [], signOut, compact = false, }) {
61
44
  const { labels } = useCiridaeLocale();
62
45
  const colorThemeItem = useColorThemeMenuItem();
63
46
  return (_jsx(Menu
@@ -66,10 +49,9 @@ export function AccountMenu({ avatar, name, detail, items = [], palette, signOut
66
49
  , {
67
50
  // In the sidebar the menu is as wide as the account row it opens from, as the design draws
68
51
  // it, so it covers whatever sits above that row; the avatar alone opens a menu of its own width.
69
- matchTriggerWidth: !compact, trigger: _jsx(AppAccountButton, { "aria-label": labels.accountMenu.menu, avatar: avatar, compact: compact, detail: detail, name: name, trailing: _jsx(CaretUpIcon, { className: icon({ size: "small" }) }) }), items: [
52
+ matchTriggerWidth: !compact, triggerTooltip: compact ? labels.accountMenu.menu : undefined, trigger: _jsx(AppAccountButton, { "aria-label": labels.accountMenu.menu, avatar: avatar, compact: compact, detail: detail, name: name, trailing: _jsx(CaretUpIcon, { className: icon({ size: "small" }) }) }), items: [
70
53
  ...items,
71
54
  colorThemeItem,
72
- ...(palette ? [paletteMenuItem(palette, labels)] : []),
73
55
  ...(signOut
74
56
  ? [
75
57
  { separator: true },
@@ -83,18 +65,17 @@ export function AccountMenu({ avatar, name, detail, items = [], palette, signOut
83
65
  : []),
84
66
  ] }));
85
67
  }
86
- // A raised pill on the canvas; in the rail, a round button with the same face.
87
68
  const assistantLauncher = css({
88
69
  display: "flex",
89
70
  alignItems: "center",
90
71
  gap: "control.iconGap",
91
- width: "100%",
72
+ width: "full",
92
73
  height: "control.default",
93
74
  paddingInlineStart: "control.compactInline",
94
75
  paddingInlineEnd: "control.launcherInlineEnd",
95
76
  border: "1px solid token(colors.border.canvas)",
96
77
  borderRadius: "shell",
97
- background: "token(gradients.raised)",
78
+ background: "[token(gradients.raised)]",
98
79
  color: "fg.primary",
99
80
  font: "inherit",
100
81
  fontWeight: "medium",
@@ -113,15 +94,15 @@ const assistantLauncher = css({
113
94
  borderRadius: "round",
114
95
  },
115
96
  });
116
- /** Opens the app's assistant from the sidebar's foot: a raised pill, or a round icon in the rail. */
117
97
  export function AssistantLauncher({ label, icon: launcherIcon, hotkey, compact = false, className, ...props }) {
118
- return (_jsxs("button", { type: "button", "aria-label": compact ? label : undefined, ...props, className: cx(assistantLauncher, className), "data-ciridae-ui": "", "data-compact": compact || undefined, children: [launcherIcon, !compact && (_jsxs(_Fragment, { children: [_jsx("span", { "data-label": "", children: label }), hotkey && _jsx(ShortcutHint, { boxed: true, hotkey: hotkey })] }))] }));
98
+ const launcher = (_jsxs("button", { type: "button", "aria-label": compact ? label : undefined, ...props, className: cx(assistantLauncher, className), "data-ciridae-ui": "", "data-compact": compact || undefined, children: [launcherIcon, !compact && (_jsxs(_Fragment, { children: [_jsx("span", { "data-label": "", children: label }), hotkey && _jsx(ShortcutHint, { boxed: true, hotkey: hotkey })] }))] }));
99
+ return compact ? (_jsx(Tooltip, { content: label, side: "inline-end", children: launcher })) : (launcher);
119
100
  }
120
101
  /** The app's frame: the sidebar for every width, its footer and account, and the page. */
121
102
  export function AppFrame({ title, actions, sidebarTop, sidebarRail, navigation, sidebar, sidebarFooter, items = [], footnote, buildSha = null, statusUrl, railActions, compactActions, account, overlays, children, }) {
122
103
  const { labels } = useCiridaeLocale();
123
- const statusLink = statusUrl && (_jsx(IconButton, { "aria-label": labels.appFrame.status, nativeButton: false, render: _jsx("a", { href: statusUrl, target: "_blank", rel: "noreferrer" }), children: _jsx(PulseIcon, { className: icon() }) }));
124
- const sidebarFoot = (_jsxs(_Fragment, { children: [(sidebarFooter || buildSha !== null || items.length > 0) && (_jsxs(AppSidebarOnly, { children: [sidebarFooter, buildSha !== null && _jsx(BuildUpdateButton, { buildSha: buildSha }), items.map((item) => (_jsx(SidebarItem, { "aria-pressed": item.pressed, icon: item.icon, onClick: item.onClick, children: item.label }, item.id)))] })), _jsxs(AppSidebarFootnote, { children: [footnote, statusUrl && (_jsxs(_Fragment, { children: [_jsx(Link, { external: true, tone: "muted", href: statusUrl, children: labels.appFrame.status }), _jsx("span", { "aria-hidden": "true", children: "\u00B7" })] })), _jsx("code", { title: buildSha ?? undefined, children: buildSha ? buildSha.slice(0, 7) : labels.appFrame.localBuild })] }), (railActions || statusLink || items.length > 0) && (_jsxs(AppSidebarOnly, { rail: true, children: [items.map((item) => (_jsx(SidebarItem, { "aria-label": item.label, "aria-pressed": item.pressed, icon: item.icon, onClick: item.onClick }, item.id))), railActions, statusLink] })), account && (_jsxs(_Fragment, { children: [_jsx(AppSidebarOnly, { children: _jsx(AccountMenu, { ...account }) }), _jsx(AppSidebarOnly, { rail: true, children: _jsx(AccountMenu, { ...account, compact: true }) })] }))] }));
104
+ const statusLink = statusUrl ? (_jsx(IconButton, { "aria-label": labels.appFrame.status, nativeButton: false, render: _jsx("a", { href: statusUrl, target: "_blank", rel: "noreferrer" }), children: _jsx(PulseIcon, { className: icon() }) })) : undefined;
105
+ const sidebarFoot = (_jsxs(_Fragment, { children: [(sidebarFooter || buildSha !== null || items.length > 0) && (_jsxs(AppSidebarOnly, { children: [sidebarFooter, buildSha !== null && _jsx(BuildUpdateButton, { buildSha: buildSha }), items.map((item) => (_jsx(SidebarItem, { "aria-pressed": item.pressed, icon: item.icon, onClick: item.onClick, children: item.label }, item.id)))] })), _jsxs(AppSidebarFootnote, { children: [footnote, statusUrl && (_jsxs(_Fragment, { children: [_jsx(Link, { external: true, tone: "muted", href: statusUrl, children: labels.appFrame.status }), _jsx("span", { "aria-hidden": "true", children: "\u00B7" })] })), _jsx("code", { title: buildSha ?? undefined, children: buildSha ? buildSha.slice(0, 7) : labels.appFrame.localBuild })] }), (railActions || statusLink || items.length > 0) && (_jsxs(AppSidebarOnly, { rail: true, children: [items.map((item) => (_jsx(Tooltip, { content: item.label, side: "inline-end", children: _jsx(SidebarItem, { "aria-label": item.label, "aria-pressed": item.pressed, icon: item.icon, onClick: item.onClick }) }, item.id))), railActions, statusLink && (_jsx(Tooltip, { content: labels.appFrame.status, side: "inline-end", children: statusLink }))] })), account && (_jsxs(_Fragment, { children: [_jsx(AppSidebarOnly, { children: _jsx(AccountMenu, { ...account }) }), _jsx(AppSidebarOnly, { rail: true, children: _jsx(AccountMenu, { ...account, compact: true }) })] }))] }));
125
106
  return (_jsxs(AppShell, { children: [_jsx(KeyboardShortcuts, {}), navigation ? (_jsx(AppNavigation, { ...navigation, header: sidebarTop, railHeader: sidebarRail, footer: sidebarFoot })) : (_jsxs(AppSidebar, { children: [_jsx(AppSidebarGroup, { children: sidebarTop }), _jsx(AppSidebarRail, { children: sidebarRail }), sidebar && _jsx(AppSidebarNav, { children: sidebar }), _jsx(AppSidebarFooter, { children: sidebarFoot })] })), title === undefined ? (children) : (_jsxs(AppMain, { children: [_jsx(AppHeader, { actions: _jsxs(AppHeaderActions, { children: [actions, _jsxs(AppHeaderCompact, { children: [compactActions, statusLink, items.map((item) => (_jsx(IconButton, { "aria-label": item.label, "aria-pressed": item.pressed, onClick: item.onClick, children: item.icon }, item.id))), account && _jsx(AccountMenu, { ...account, compact: true })] })] }), children: _jsx(AppBreadcrumbs, { children: title }) }), _jsx(AppContent, { children: children })] })), overlays] }));
126
107
  }
127
108
  /** Only mounted for a named build, so local previews do not need a query provider. */
@@ -58,11 +58,12 @@ export type AppNavigationProps = Omit<ComponentProps<"aside">, "children"> & {
58
58
  }>;
59
59
  };
60
60
  /**
61
- * Whether the sidebar has room to list `foldedRows` more rows: the free space between its
62
- * navigation and its footer covers them. Once it has, it loses it only when the navigation runs
63
- * out of room, so it does not flicker at the threshold.
61
+ * Whether the sidebar has room to unfold every section: the free space between its navigation and
62
+ * its footer covers the `hiddenRows` its folds hide, less the More rows unfolding removes. Once it
63
+ * has, it loses it only when the navigation runs out of room, so it does not flicker at the
64
+ * threshold.
64
65
  */
65
- export declare function useSidebarRoom(foldedRows: number): {
66
+ export declare function useSidebarRoom(hiddenRows: number): {
66
67
  navRef: import("react").RefObject<HTMLDivElement | null>;
67
68
  footerRef: import("react").RefObject<HTMLDivElement | null>;
68
69
  roomy: boolean;
@@ -80,7 +81,6 @@ export type WorkspaceMarkProps = {
80
81
  size?: "regular" | "small";
81
82
  className?: string;
82
83
  };
83
- /** A workspace's mark: its name's first letter on a square tile. */
84
84
  export declare function WorkspaceMark({ name, current, size, className, }: WorkspaceMarkProps): import("react").JSX.Element;
85
85
  export type WorkspaceSwitcherProps = {
86
86
  workspaces: readonly Workspace[];
@@ -89,5 +89,4 @@ export type WorkspaceSwitcherProps = {
89
89
  /** The mark alone, for the rail. */
90
90
  compact?: boolean;
91
91
  };
92
- /** The current workspace, opening a menu of every workspace the reader belongs to, current checked. */
93
92
  export declare function WorkspaceSwitcher({ workspaces, currentId, onSelect, compact, }: WorkspaceSwitcherProps): import("react").JSX.Element;