@ciridae/ui 1.0.1 → 1.0.3
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.
- package/dist/app/auth.d.ts +10 -0
- package/dist/app/auth.js +60 -0
- package/dist/app/error-boundary.d.ts +18 -0
- package/dist/app/error-boundary.js +45 -0
- package/dist/app/feedback.d.ts +12 -0
- package/dist/app/feedback.js +128 -0
- package/dist/app/index.d.ts +8 -0
- package/dist/app/index.js +8 -0
- package/dist/app/request-errors.d.ts +63 -0
- package/dist/app/request-errors.js +172 -0
- package/dist/app/sentry.d.ts +18 -0
- package/dist/app/sentry.js +52 -0
- package/dist/app/telemetry.d.ts +7 -0
- package/dist/app/telemetry.js +28 -0
- package/dist/app/trail.d.ts +9 -0
- package/dist/app/trail.js +18 -0
- package/dist/chat/chat-query-keys.d.ts +3 -3
- package/dist/chat/contract.d.ts +15 -15
- package/dist/chat/conversation-items-query-options.d.ts +114 -114
- package/dist/chat/conversation-source.d.ts +75 -0
- package/dist/chat/conversation-source.js +1 -0
- package/dist/chat/message-text.d.ts +1 -1
- package/dist/chat/message-text.js +114 -46
- package/dist/chat/use-conversation-list.d.ts +6 -6
- package/dist/components/activity-feed.d.ts +2 -2
- package/dist/components/agent-work.d.ts +3 -3
- package/dist/components/app-frame.d.ts +79 -0
- package/dist/components/app-frame.js +92 -0
- package/dist/components/app-navigation.d.ts +3 -3
- package/dist/components/badge.d.ts +1 -1
- package/dist/components/brand-icons.d.ts +3 -3
- package/dist/components/bulk-action-bar.d.ts +1 -1
- package/dist/components/button.d.ts +4 -4
- package/dist/components/calendar.d.ts +1 -1
- package/dist/components/centered-page.d.ts +1 -1
- package/dist/components/chart.d.ts +22 -2
- package/dist/components/chart.js +239 -44
- package/dist/components/chat-client-source.d.ts +16 -0
- package/dist/components/chat-client-source.js +256 -0
- package/dist/components/chat-page.d.ts +9 -8
- package/dist/components/chat-page.js +7 -11
- package/dist/components/chat-sheet-controller.d.ts +10 -14
- package/dist/components/chat-sheet-controller.js +2 -3
- package/dist/components/chat-sheet.d.ts +10 -11
- package/dist/components/chat-sheet.js +135 -273
- package/dist/components/chat.d.ts +22 -8
- package/dist/components/chat.js +128 -33
- package/dist/components/checkbox-item.d.ts +1 -1
- package/dist/components/checkbox-list.d.ts +1 -1
- package/dist/components/chip.d.ts +1 -1
- package/dist/components/collapsible.d.ts +1 -1
- package/dist/components/color-theme.d.ts +1 -1
- package/dist/components/column-settings.d.ts +1 -1
- package/dist/components/command-menu.d.ts +1 -1
- package/dist/components/command-palette.d.ts +3 -3
- package/dist/components/command-palette.js +1 -2
- package/dist/components/copyable-id.d.ts +22 -5
- package/dist/components/copyable-id.js +46 -6
- package/dist/components/data-display.d.ts +4 -4
- package/dist/components/data-grid.d.ts +10 -10
- package/dist/components/date-range-picker.d.ts +1 -1
- package/dist/components/date-time.d.ts +1 -1
- package/dist/components/dialog-height-context.d.ts +1 -1
- package/dist/components/document-viewer.d.ts +2 -2
- package/dist/components/drawer.d.ts +6 -6
- package/dist/components/dropzone.d.ts +4 -4
- package/dist/components/editable-field.d.ts +2 -2
- package/dist/components/email-input.d.ts +1 -1
- package/dist/components/environment-frame.d.ts +1 -1
- package/dist/components/expandable-text.d.ts +1 -1
- package/dist/components/feedback-screenshot.d.ts +1 -1
- package/dist/components/feedback-sheet.d.ts +18 -3
- package/dist/components/feedback-sheet.js +216 -55
- package/dist/components/field-context.d.ts +1 -1
- package/dist/components/filter-bar.d.ts +3 -3
- package/dist/components/filter-bar.js +4 -1
- package/dist/components/form-controls.d.ts +4 -4
- package/dist/components/form-layout.d.ts +7 -7
- package/dist/components/hotkeys.d.ts +2 -2
- package/dist/components/icon.d.ts +2 -2
- package/dist/components/input.d.ts +4 -4
- package/dist/components/input.js +3 -2
- package/dist/components/keyboard-shortcuts.d.ts +2 -2
- package/dist/components/keycap.d.ts +2 -2
- package/dist/components/layout.d.ts +15 -15
- package/dist/components/lightbox.d.ts +9 -3
- package/dist/components/lightbox.js +11 -8
- package/dist/components/link.d.ts +1 -1
- package/dist/components/locale.d.ts +32 -2
- package/dist/components/locale.js +25 -1
- package/dist/components/log-list.d.ts +3 -3
- package/dist/components/mention-input.d.ts +2 -2
- package/dist/components/menu.d.ts +2 -2
- package/dist/components/meter.d.ts +1 -1
- package/dist/components/navigation.d.ts +2 -2
- package/dist/components/notification-tray.d.ts +1 -1
- package/dist/components/overlays.d.ts +4 -4
- package/dist/components/page-frame.d.ts +4 -4
- package/dist/components/panel.d.ts +4 -4
- package/dist/components/profile-header.d.ts +1 -1
- package/dist/components/progress.d.ts +1 -1
- package/dist/components/project-avatar.d.ts +1 -1
- package/dist/components/radio-card.d.ts +2 -2
- package/dist/components/record.d.ts +4 -4
- package/dist/components/resolved-file-url.d.ts +19 -0
- package/dist/components/resolved-file-url.js +49 -0
- package/dist/components/scroll-area.d.ts +1 -1
- package/dist/components/secret-dialog.d.ts +1 -1
- package/dist/components/segmented-bar.d.ts +1 -1
- package/dist/components/select.d.ts +4 -4
- package/dist/components/settings.d.ts +4 -4
- package/dist/components/shell-skeleton.d.ts +1 -1
- package/dist/components/shell.d.ts +19 -19
- package/dist/components/shell.js +3 -1
- package/dist/components/side-panel.d.ts +3 -3
- package/dist/components/sidebar.d.ts +6 -6
- package/dist/components/site-banner.d.ts +2 -2
- package/dist/components/skeleton.d.ts +1 -1
- package/dist/components/skeletons.d.ts +5 -5
- package/dist/components/stages.d.ts +5 -5
- package/dist/components/stat-card.d.ts +3 -3
- package/dist/components/status-banner.d.ts +1 -1
- package/dist/components/status.d.ts +2 -2
- package/dist/components/steps.d.ts +1 -1
- package/dist/components/switch.d.ts +1 -1
- package/dist/components/tabs.d.ts +8 -8
- package/dist/components/theme-customizer.d.ts +2 -2
- package/dist/components/toast.d.ts +1 -1
- package/dist/components/use-new-version-available.d.ts +6 -0
- package/dist/components/use-new-version-available.js +29 -0
- package/dist/components/user-chip.d.ts +3 -3
- package/dist/components/wizard.d.ts +2 -2
- package/dist/feedback/contract.d.ts +136 -136
- package/dist/feedback/feedback-controller.d.ts +6 -6
- package/dist/feedback/generated/zod.gen.d.ts +28 -28
- package/dist/feedback/operator-contract.d.ts +11 -11
- package/dist/feedback/operator-controller.d.ts +32 -13
- package/dist/feedback/operator-controller.js +44 -11
- package/dist/styled-system/styles.css +203 -59
- package/dist/theme/tokens.js +17 -8
- package/package.json +32 -3
package/dist/components/chat.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
-
import { ArrowClockwiseIcon, ArrowUpIcon } from "@phosphor-icons/react";
|
|
2
|
+
import { ArrowClockwiseIcon, ArrowDownIcon, ArrowUpIcon } from "@phosphor-icons/react";
|
|
3
3
|
import { isSameDay, isToday, isYesterday } from "date-fns";
|
|
4
4
|
import { Fragment, useEffect, useRef, useState, useSyncExternalStore, } from "react";
|
|
5
5
|
import { css, cva, cx } from "#primitives/css";
|
|
@@ -11,6 +11,8 @@ import { icon, Spinner } from "./icon.js";
|
|
|
11
11
|
import { Lightbox } from "./lightbox.js";
|
|
12
12
|
import { useCiridaeLocale } from "./locale.js";
|
|
13
13
|
import { MentionInput } from "./mention-input.js";
|
|
14
|
+
import { useResolvedFileUrl } from "./resolved-file-url.js";
|
|
15
|
+
export { MessageText, splitSources, } from "../chat/message-text.js";
|
|
14
16
|
/*
|
|
15
17
|
* Two composers share one behaviour: `page` is the wide card of a chat page, and `sheet` the
|
|
16
18
|
* composer at the foot of the agent sheet, its parts side by side as a messaging app's: the tools
|
|
@@ -192,6 +194,9 @@ const thread = css({
|
|
|
192
194
|
flexDirection: "column",
|
|
193
195
|
gap: "layout.tightGap",
|
|
194
196
|
padding: "panel.default",
|
|
197
|
+
// The thread follows its newest entry itself: the browser's scroll anchoring would hold the
|
|
198
|
+
// view on what was there as a reply lands and pull it off the foot.
|
|
199
|
+
overflowAnchor: "none",
|
|
195
200
|
"&[data-density=compact]": {
|
|
196
201
|
paddingBlock: "layout.controlGap",
|
|
197
202
|
"& > [data-group-position=single], & > [data-group-position=first]": {
|
|
@@ -199,6 +204,24 @@ const thread = css({
|
|
|
199
204
|
},
|
|
200
205
|
},
|
|
201
206
|
});
|
|
207
|
+
/*
|
|
208
|
+
* Under the thread, held at the foot of the scrolling area while the reader is away from the
|
|
209
|
+
* newest entry: the jump back to it. Takes no height, so showing it moves nothing.
|
|
210
|
+
*/
|
|
211
|
+
const latestSlot = css({
|
|
212
|
+
position: "sticky",
|
|
213
|
+
bottom: "layout.controlGap",
|
|
214
|
+
zIndex: "1",
|
|
215
|
+
display: "flex",
|
|
216
|
+
alignItems: "flex-end",
|
|
217
|
+
justifyContent: "center",
|
|
218
|
+
height: "0",
|
|
219
|
+
marginTop: "calc(token(spacing.layout.tightGap) * -1)",
|
|
220
|
+
pointerEvents: "none",
|
|
221
|
+
"& > *": { pointerEvents: "auto", boxShadow: "card" },
|
|
222
|
+
});
|
|
223
|
+
/** How close to the bottom the reader must be for new content to keep the thread at its foot. */
|
|
224
|
+
const followDistancePx = 96;
|
|
202
225
|
/* A reply's sources under its bubble: small links in a row. */
|
|
203
226
|
const sourceRow = css({
|
|
204
227
|
display: "flex",
|
|
@@ -338,7 +361,7 @@ const typingDots = css({
|
|
|
338
361
|
"& > span:nth-child(2)": { animationDelay: "0.2s" },
|
|
339
362
|
"& > span:nth-child(3)": { animationDelay: "0.4s" },
|
|
340
363
|
});
|
|
341
|
-
export function ChatComposer({ value, defaultValue = "", onValueChange, onSend, placeholder, ariaLabel: ownAriaLabel, tools, actions, submitLabel: ownSubmitLabel, sendDisabled = false, sendsWithoutText = false, attachments, variant = "page", autoFocus, mentions, mentionMark, mentionsLabel, inputProps, className, ...props }) {
|
|
364
|
+
export function ChatComposer({ value, defaultValue = "", onValueChange, onSend, placeholder, ariaLabel: ownAriaLabel, tools, actions, submitLabel: ownSubmitLabel, sendDisabled = false, sendsWithoutText = false, attachments, onPasteFiles, variant = "page", autoFocus, mentions, mentionMark, mentionsLabel, inputProps, className, ...props }) {
|
|
342
365
|
const { labels } = useCiridaeLocale();
|
|
343
366
|
const ariaLabel = ownAriaLabel ?? labels.chat.message;
|
|
344
367
|
const submitLabel = ownSubmitLabel ?? labels.chat.sendMessage;
|
|
@@ -357,14 +380,27 @@ export function ChatComposer({ value, defaultValue = "", onValueChange, onSend,
|
|
|
357
380
|
setValue("");
|
|
358
381
|
};
|
|
359
382
|
const sheet = variant !== "page";
|
|
383
|
+
// In the capture phase, ahead of the text field and of an enclosing `Dropzone`, which would
|
|
384
|
+
// take the same files again.
|
|
385
|
+
const pasteFiles = onPasteFiles
|
|
386
|
+
? (event) => {
|
|
387
|
+
const { files, types } = event.clipboardData;
|
|
388
|
+
// Rich text comes with a picture of itself, as office apps copy it: that stays text.
|
|
389
|
+
if (files.length === 0 || types.includes("text/html"))
|
|
390
|
+
return;
|
|
391
|
+
event.preventDefault();
|
|
392
|
+
event.stopPropagation();
|
|
393
|
+
onPasteFiles(Array.from(files));
|
|
394
|
+
}
|
|
395
|
+
: undefined;
|
|
360
396
|
const input = (_jsx(MentionInput, { ...inputProps, "aria-label": ariaLabel, autoFocus: autoFocus, className: cx(sheet ? sheetInput : pageInput, inputProps?.className), value: currentValue, onValueChange: setValue, triggers: mentions, mentionMark: mentionMark, listLabel: mentionsLabel, placeholder: placeholder, submitOn: variant === "feed" ? "mod+enter" : "enter", onSubmit: send }));
|
|
361
397
|
// The sheet's send is quiet until there is something to send.
|
|
362
398
|
const sendButton = (_jsx(IconButton, { "aria-label": submitLabel, disabled: !canSend, onClick: send, variant: sheet ? (canSend ? "primary" : "ghost") : "raised", children: _jsx(ArrowUpIcon, { className: icon({ size: "small" }), weight: "bold" }) }));
|
|
363
399
|
const waiting = attachments ? _jsx("div", { "data-attachments": "", children: attachments }) : null;
|
|
364
400
|
if (sheet) {
|
|
365
|
-
return (_jsxs("div", { ...props, className: cx(sheetComposer, className), "data-ciridae-ui": "", children: [tools && _jsx("div", { className: sheetSide, children: tools }), _jsxs("div", { className: sheetColumn, children: [waiting, _jsxs("div", { className: sheetBox, children: [input, actions && _jsx("div", { "data-actions": "", children: actions })] })] }), _jsx("div", { className: sheetSide, children: sendButton })] }));
|
|
401
|
+
return (_jsxs("div", { ...props, className: cx(sheetComposer, className), "data-ciridae-ui": "", onPasteCapture: pasteFiles, children: [tools && _jsx("div", { className: sheetSide, children: tools }), _jsxs("div", { className: sheetColumn, children: [waiting, _jsxs("div", { className: sheetBox, children: [input, actions && _jsx("div", { "data-actions": "", children: actions })] })] }), _jsx("div", { className: sheetSide, children: sendButton })] }));
|
|
366
402
|
}
|
|
367
|
-
return (_jsxs("div", { ...props, className: cx(pageComposer, className), "data-ciridae-ui": "", children: [waiting, input, _jsxs("div", { className: composerFooter, children: [_jsx("div", { className: actionGroup, children: tools }), _jsxs("div", { className: actionGroup, children: [actions, sendButton] })] })] }));
|
|
403
|
+
return (_jsxs("div", { ...props, className: cx(pageComposer, className), "data-ciridae-ui": "", onPasteCapture: pasteFiles, children: [waiting, input, _jsxs("div", { className: composerFooter, children: [_jsx("div", { className: actionGroup, children: tools }), _jsxs("div", { className: actionGroup, children: [actions, sendButton] })] })] }));
|
|
368
404
|
}
|
|
369
405
|
/** A message bubble in the agent sheet. */
|
|
370
406
|
export function ChatBubble({ side, groupPosition, className, ...props }) {
|
|
@@ -384,12 +420,13 @@ export function ChatAction({ className, ...props }) {
|
|
|
384
420
|
/*
|
|
385
421
|
* A conversation in time order. Close messages from one author read as a group: bubbles 4px
|
|
386
422
|
* apart, groups 8px apart, the author's avatar beside the group's last bubble on the assistant's
|
|
387
|
-
* side and the author and time once under it. The nearest scrolling ancestor
|
|
388
|
-
*
|
|
423
|
+
* side and the author and time once under it. The nearest scrolling ancestor follows the newest
|
|
424
|
+
* entry while the reader is at its foot; scrolled up, reading back, a jump to the newest shows
|
|
425
|
+
* instead. A message the user sends always brings the thread to its foot.
|
|
389
426
|
*/
|
|
390
|
-
export function ChatThread({ entries, assistant, renderCustom, formatTime, density = "comfortable", attachmentTiles = false, dayLabels = false, className, }) {
|
|
427
|
+
export function ChatThread({ entries, assistant, renderCustom, formatTime, density = "comfortable", attachmentTiles = false, dayLabels = false, resolveAttachmentUrl, className, }) {
|
|
391
428
|
const rootRef = useRef(null);
|
|
392
|
-
const { formatDateTime } = useCiridaeLocale();
|
|
429
|
+
const { formatDateTime, labels } = useCiridaeLocale();
|
|
393
430
|
const authorOf = (entry) => entry.kind === "line" || entrySide(entry) === "user"
|
|
394
431
|
? undefined
|
|
395
432
|
: ((entry.kind === "message" ? entry.author : undefined) ?? assistant);
|
|
@@ -398,20 +435,16 @@ export function ChatThread({ entries, assistant, renderCustom, formatTime, densi
|
|
|
398
435
|
at: entry.at,
|
|
399
436
|
author: authorOf(entry)?.name,
|
|
400
437
|
})));
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
const newDay = dayLabels && (!previous || !isSameDay(previous.at, entry.at));
|
|
412
|
-
const content = renderEntry(entry, index);
|
|
413
|
-
return newDay ? (_jsxs(Fragment, { children: [_jsx(DayLabel, { at: entry.at }), content] }, entry.id)) : (content);
|
|
414
|
-
}) }));
|
|
438
|
+
const newestUserMessage = [...entries]
|
|
439
|
+
.reverse()
|
|
440
|
+
.find((entry) => entry.kind === "message" && entry.side === "user");
|
|
441
|
+
const latest = useFollowLatest(rootRef, newestUserMessage?.id);
|
|
442
|
+
return (_jsxs("div", { ref: rootRef, className: cx(thread, className), "data-ciridae-ui": "", "data-density": density === "compact" ? "compact" : undefined, children: [entries.map((entry, index) => {
|
|
443
|
+
const previous = entries[index - 1];
|
|
444
|
+
const newDay = dayLabels && (!previous || !isSameDay(previous.at, entry.at));
|
|
445
|
+
const content = renderEntry(entry, index);
|
|
446
|
+
return newDay ? (_jsxs(Fragment, { children: [_jsx(DayLabel, { at: entry.at }), content] }, entry.id)) : (content);
|
|
447
|
+
}), _jsx("div", { className: latestSlot, children: latest.away && (_jsx(IconButton, { "aria-label": labels.chat.scrollToLatest, size: "compact", variant: "raised", onClick: latest.scrollToLatest, children: _jsx(ArrowDownIcon, { className: icon({ size: "small" }) }) })) })] }));
|
|
415
448
|
function renderEntry(entry, index) {
|
|
416
449
|
if (entry.kind === "line") {
|
|
417
450
|
return (_jsx(ChatSystemLine, { tone: entry.tone, children: entry.text }, entry.id));
|
|
@@ -424,7 +457,7 @@ export function ChatThread({ entries, assistant, renderCustom, formatTime, densi
|
|
|
424
457
|
const tiles = attachmentTiles && message?.attachments && message.attachments.length > 0
|
|
425
458
|
? message.attachments
|
|
426
459
|
: null;
|
|
427
|
-
return (_jsxs("div", { className: entryBlock, "data-side": side, "data-group-position": position, children: [tiles && _jsx(AttachmentTiles, { attachments: tiles }), !(tiles && message?.body === "") && (_jsxs("div", { className: entryRow, title: message ? formatDateTime(entry.at) : undefined, children: [side === "assistant" && (_jsx("span", { className: avatarSlot, children: closesGroup && author && (_jsx(Avatar, { kind: author.kind, src: author.src, label: author.name, size: "small", "aria-hidden": "true" })) })), _jsx(ThreadEntryContent, { entry: entry, side: side, groupPosition: position, renderCustom: renderCustom, attachmentTiles: attachmentTiles }), message?.actions && !message.sending && (_jsx("span", { "data-entry-actions": "", children: message.actions }))] })), message?.sources && message.sources.length > 0 && (_jsx("span", { className: sourceRow, children: message.sources.map((source) => source.href ? (_jsx("a", { href: source.href, children: source.label }, source.id)) : (_jsx("span", { children: source.label }, source.id))) })), closesGroup && entry.kind !== "typing" && (_jsx("span", { className: entryFooter, children: message?.sending ? (_jsxs(_Fragment, { children: [_jsx(Spinner, { "aria-hidden": "true", size: "compact" }),
|
|
460
|
+
return (_jsxs("div", { className: entryBlock, "data-side": side, "data-group-position": position, children: [tiles && _jsx(AttachmentTiles, { attachments: tiles, resolveUrl: resolveAttachmentUrl }), !(tiles && message?.body === "") && (_jsxs("div", { className: entryRow, title: message ? formatDateTime(entry.at) : undefined, children: [side === "assistant" && (_jsx("span", { className: avatarSlot, children: closesGroup && author && (_jsx(Avatar, { kind: author.kind, src: author.src, label: author.name, size: "small", "aria-hidden": "true" })) })), _jsx(ThreadEntryContent, { entry: entry, side: side, groupPosition: position, renderCustom: renderCustom, attachmentTiles: attachmentTiles }), message?.actions && !message.sending && (_jsx("span", { "data-entry-actions": "", children: message.actions }))] })), message?.sources && message.sources.length > 0 && (_jsx("span", { className: sourceRow, children: message.sources.map((source) => source.href ? (_jsx("a", { href: source.href, children: source.label }, source.id)) : (_jsx("span", { children: source.label }, source.id))) })), closesGroup && entry.kind !== "typing" && (_jsx("span", { className: entryFooter, children: message?.sending ? (_jsxs(_Fragment, { children: [_jsx(Spinner, { "aria-hidden": "true", size: "compact" }), labels.chat.sending] })) : (_jsxs("span", { children: [author && (_jsxs(_Fragment, { children: [author.label ?? author.name, " · "] })), _jsx(MessageTime, { at: entry.at, format: formatTime, dated: !dayLabels })] })) }))] }, entry.id));
|
|
428
461
|
}
|
|
429
462
|
}
|
|
430
463
|
/** A day's heading in a thread that runs over days: Today, Yesterday, or the date. */
|
|
@@ -440,17 +473,23 @@ function DayLabel({ at }) {
|
|
|
440
473
|
export function ChatSuggestions({ suggestions, onSelect, className }) {
|
|
441
474
|
return (_jsx("div", { className: cx(suggestionList, className), "data-ciridae-ui": "", children: suggestions.map((text) => (_jsx("button", { type: "button", className: suggestion, onClick: () => onSelect(text), children: text }, text))) }));
|
|
442
475
|
}
|
|
443
|
-
function AttachmentTiles({ attachments }) {
|
|
444
|
-
const { labels } = useCiridaeLocale();
|
|
476
|
+
function AttachmentTiles({ attachments, resolveUrl, }) {
|
|
445
477
|
const [open, setOpen] = useState(null);
|
|
446
|
-
// The files the lightbox can show, in the message's order: those
|
|
447
|
-
const viewable = attachments.
|
|
478
|
+
// The files the lightbox can show, in the message's order: those with a link or a way to one.
|
|
479
|
+
const viewable = attachments.filter((attachment) => attachment.url || resolveUrl);
|
|
448
480
|
return (_jsxs("span", { className: attachmentTiles, children: [attachments.map((attachment) => {
|
|
449
|
-
const
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
481
|
+
const index = viewable.indexOf(attachment);
|
|
482
|
+
return (_jsx(AttachmentTile, { attachment: attachment, resolveUrl: resolveUrl, onOpen: index >= 0 ? () => setOpen(index) : undefined }, attachment.id));
|
|
483
|
+
}), _jsx(Lightbox, { items: viewable, index: open, onIndexChange: setOpen, resolveUrl: resolveUrl })] }));
|
|
484
|
+
}
|
|
485
|
+
/** An image's thumbnail, loaded through `resolveUrl` when it has no link, or the file's icon and name. */
|
|
486
|
+
function AttachmentTile({ attachment, resolveUrl, onOpen, }) {
|
|
487
|
+
const { labels } = useCiridaeLocale();
|
|
488
|
+
const imageType = attachment.mediaType?.startsWith("image/") ?? false;
|
|
489
|
+
const { url } = useResolvedFileUrl(attachment, resolveUrl, imageType);
|
|
490
|
+
const image = imageType && url !== null;
|
|
491
|
+
const content = image ? (_jsx("img", { src: url, alt: attachment.name })) : (_jsxs(_Fragment, { children: [fileTypeIcon({ name: attachment.name, type: attachment.mediaType ?? "" }), _jsx("span", { children: attachment.name })] }));
|
|
492
|
+
return onOpen ? (_jsx("button", { type: "button", className: fileSquare, "data-image": image || undefined, "aria-label": labels.lightbox.preview(attachment.name), title: attachment.name, onClick: onOpen, children: content })) : (_jsx("span", { className: fileSquare, "data-image": image || undefined, title: attachment.name, children: content }));
|
|
454
493
|
}
|
|
455
494
|
function ThreadEntryContent({ entry, side, groupPosition, renderCustom, attachmentTiles: tiles, }) {
|
|
456
495
|
const { labels } = useCiridaeLocale();
|
|
@@ -460,7 +499,7 @@ function ThreadEntryContent({ entry, side, groupPosition, renderCustom, attachme
|
|
|
460
499
|
case "typing":
|
|
461
500
|
return (_jsxs(ChatBubble, { side: side, groupPosition: groupPosition, className: typingBubble, role: "status", "aria-label": labels.chat.typing, children: [entry.label, _jsx(ChatTypingDots, {})] }));
|
|
462
501
|
case "failure":
|
|
463
|
-
return (_jsxs(ChatBubble, { side: side, groupPosition: groupPosition, className: errorBubble, role: "alert", children: [entry.message, _jsx(Button, { variant: "ghost", icon: _jsx(ArrowClockwiseIcon, { className: icon({ size: "small" }) }), onClick: entry.onRetry, children:
|
|
502
|
+
return (_jsxs(ChatBubble, { side: side, groupPosition: groupPosition, className: errorBubble, role: "alert", children: [entry.message, _jsx(Button, { variant: "ghost", icon: _jsx(ArrowClockwiseIcon, { className: icon({ size: "small" }) }), onClick: entry.onRetry, children: labels.common.retry })] }));
|
|
464
503
|
case "custom":
|
|
465
504
|
return renderCustom?.(entry.data);
|
|
466
505
|
}
|
|
@@ -535,6 +574,62 @@ function MessageTime({ at, format: formatAt, dated, }) {
|
|
|
535
574
|
: formatTime(at);
|
|
536
575
|
return (_jsxs("time", { dateTime: new Date(at).toISOString(), className: messageTime, children: [_jsx("span", { "data-shown": "", children: text }), exact !== text && _jsx("span", { "data-exact": "", children: exact })] }));
|
|
537
576
|
}
|
|
577
|
+
/**
|
|
578
|
+
* Keeps the nearest scrolling ancestor of `rootRef` at its foot while the reader is there, as
|
|
579
|
+
* entries land or images in them load; `away` while they have scrolled up from it. A new
|
|
580
|
+
* `sentMessageId`, the user's own message, brings it to the foot from anywhere.
|
|
581
|
+
*/
|
|
582
|
+
function useFollowLatest(rootRef, sentMessageId) {
|
|
583
|
+
const [away, setAway] = useState(false);
|
|
584
|
+
const atFootRef = useRef(true);
|
|
585
|
+
const scrollerRef = useRef(null);
|
|
586
|
+
useEffect(() => {
|
|
587
|
+
const root = rootRef.current;
|
|
588
|
+
const scroller = root && findScrollContainer(root);
|
|
589
|
+
if (!root || !scroller)
|
|
590
|
+
return;
|
|
591
|
+
scrollerRef.current = scroller;
|
|
592
|
+
const toFoot = () => {
|
|
593
|
+
scroller.scrollTop = scroller.scrollHeight;
|
|
594
|
+
};
|
|
595
|
+
// Content that grew since the last look keeps a reader at the foot there, whichever of its
|
|
596
|
+
// resize or the scroll it caused is seen first; a reader's own scroll leaves the height.
|
|
597
|
+
let lastHeight = scroller.scrollHeight;
|
|
598
|
+
const follow = () => {
|
|
599
|
+
const grew = scroller.scrollHeight !== lastHeight;
|
|
600
|
+
lastHeight = scroller.scrollHeight;
|
|
601
|
+
if (grew && atFootRef.current)
|
|
602
|
+
return toFoot();
|
|
603
|
+
const distance = scroller.scrollHeight - scroller.scrollTop - scroller.clientHeight;
|
|
604
|
+
atFootRef.current = distance < followDistancePx;
|
|
605
|
+
setAway(!atFootRef.current);
|
|
606
|
+
};
|
|
607
|
+
toFoot();
|
|
608
|
+
const resizes = new ResizeObserver(follow);
|
|
609
|
+
resizes.observe(root);
|
|
610
|
+
resizes.observe(scroller);
|
|
611
|
+
scroller.addEventListener("scroll", follow, { passive: true });
|
|
612
|
+
return () => {
|
|
613
|
+
resizes.disconnect();
|
|
614
|
+
scroller.removeEventListener("scroll", follow);
|
|
615
|
+
};
|
|
616
|
+
}, [rootRef]);
|
|
617
|
+
useEffect(() => {
|
|
618
|
+
const scroller = scrollerRef.current;
|
|
619
|
+
if (!scroller || sentMessageId === undefined)
|
|
620
|
+
return;
|
|
621
|
+
atFootRef.current = true;
|
|
622
|
+
scroller.scrollTop = scroller.scrollHeight;
|
|
623
|
+
}, [sentMessageId]);
|
|
624
|
+
return {
|
|
625
|
+
away,
|
|
626
|
+
scrollToLatest: () => {
|
|
627
|
+
const scroller = scrollerRef.current;
|
|
628
|
+
atFootRef.current = true;
|
|
629
|
+
scroller?.scrollTo({ top: scroller.scrollHeight, behavior: "smooth" });
|
|
630
|
+
},
|
|
631
|
+
};
|
|
632
|
+
}
|
|
538
633
|
function findScrollContainer(element) {
|
|
539
634
|
for (let node = element; node; node = node.parentElement) {
|
|
540
635
|
const { overflowY } = getComputedStyle(node);
|
|
@@ -8,4 +8,4 @@ export type CheckboxItemProps = Omit<ComponentProps<typeof BaseCheckbox.Root>, "
|
|
|
8
8
|
grip?: boolean;
|
|
9
9
|
className?: string;
|
|
10
10
|
};
|
|
11
|
-
export declare function CheckboxItem({ children, meta, grip: showGrip, className, ...props }: CheckboxItemProps): import("
|
|
11
|
+
export declare function CheckboxItem({ children, meta, grip: showGrip, className, ...props }: CheckboxItemProps): import("react").JSX.Element;
|
|
@@ -48,4 +48,4 @@ export type CheckboxListProps = {
|
|
|
48
48
|
* group. A long list can take a search, and bulk actions that touch only the items it leaves shown,
|
|
49
49
|
* so nothing is ticked or cleared out of sight.
|
|
50
50
|
*/
|
|
51
|
-
export declare function CheckboxList(props: CheckboxListProps): import("
|
|
51
|
+
export declare function CheckboxList(props: CheckboxListProps): import("react").JSX.Element;
|
|
@@ -14,4 +14,4 @@ export type ChipProps = Omit<ComponentProps<"span">, "children"> & {
|
|
|
14
14
|
/** Compact recipients and inline tags; regular preserves the standalone chip. */
|
|
15
15
|
size?: "regular" | "compact";
|
|
16
16
|
};
|
|
17
|
-
export declare function Chip({ children, icon, tone, onRemove, removeLabel, disabled, invalid, size, className, ...props }: ChipProps): import("
|
|
17
|
+
export declare function Chip({ children, icon, tone, onRemove, removeLabel, disabled, invalid, size, className, ...props }: ChipProps): import("react").JSX.Element;
|
|
@@ -5,4 +5,4 @@ export type CollapsibleProps = Omit<ComponentProps<typeof BaseCollapsible.Root>,
|
|
|
5
5
|
label: ReactNode;
|
|
6
6
|
children: ReactNode;
|
|
7
7
|
};
|
|
8
|
-
export declare function Collapsible({ label, children, ...rootProps }: CollapsibleProps): import("
|
|
8
|
+
export declare function Collapsible({ label, children, ...rootProps }: CollapsibleProps): import("react").JSX.Element;
|
|
@@ -33,7 +33,7 @@ export type ThemeProviderProps = {
|
|
|
33
33
|
* `_light` values resolve through, so every component follows without
|
|
34
34
|
* threading a prop.
|
|
35
35
|
*/
|
|
36
|
-
export declare function ThemeProvider({ children, defaultColorTheme, storageKey, brand, palette, fonts, }: ThemeProviderProps): import("
|
|
36
|
+
export declare function ThemeProvider({ children, defaultColorTheme, storageKey, brand, palette, fonts, }: ThemeProviderProps): import("react").JSX.Element;
|
|
37
37
|
/** Throws outside a `ThemeProvider`, where there is no theme to report or change. */
|
|
38
38
|
export declare function useColorTheme(): ColorThemeContextValue;
|
|
39
39
|
/** Throws outside a `ThemeProvider` given a `brand`, where there is no name to show. */
|
|
@@ -40,4 +40,4 @@ export type CommandMenuProps = {
|
|
|
40
40
|
/** Shown when no row matches, above any `unfiltered` row; the locale's "No results" by default. */
|
|
41
41
|
empty?: ReactNode;
|
|
42
42
|
};
|
|
43
|
-
export declare function CommandMenu({ open, onOpenChange, query, onQueryChange, groups, title: ownTitle, placeholder: ownPlaceholder, empty: ownEmpty, }: CommandMenuProps): import("
|
|
43
|
+
export declare function CommandMenu({ open, onOpenChange, query, onQueryChange, groups, title: ownTitle, placeholder: ownPlaceholder, empty: ownEmpty, }: CommandMenuProps): import("react").JSX.Element;
|
|
@@ -24,13 +24,13 @@ export declare function useCommandPalette({ hotkey }?: {
|
|
|
24
24
|
hotkey?: HotkeyChord;
|
|
25
25
|
}): {
|
|
26
26
|
open: boolean;
|
|
27
|
-
setOpen: import("
|
|
27
|
+
setOpen: import("react").Dispatch<import("react").SetStateAction<boolean>>;
|
|
28
28
|
toggle: () => void;
|
|
29
29
|
};
|
|
30
|
-
export declare function CommandPalette({ open, onOpenChange, groups, onQueryChange, footerItem, title, placeholder, empty, }: CommandPaletteProps): import("
|
|
30
|
+
export declare function CommandPalette({ open, onOpenChange, groups, onQueryChange, footerItem, title, placeholder, empty, }: CommandPaletteProps): import("react").JSX.Element;
|
|
31
31
|
export type CommandPaletteTriggerProps = ComponentProps<"button"> & {
|
|
32
32
|
/** The hotkey `useCommandPalette` opens it with, shown at the end; Cmd/Ctrl+K by default. */
|
|
33
33
|
hotkey?: HotkeyChord;
|
|
34
34
|
};
|
|
35
35
|
/** A search field's face, as a button that opens the palette; reads "Search" unless given text. */
|
|
36
|
-
export declare function CommandPaletteTrigger({ hotkey, className, children, ...props }: CommandPaletteTriggerProps): import("
|
|
36
|
+
export declare function CommandPaletteTrigger({ hotkey, className, children, ...props }: CommandPaletteTriggerProps): import("react").JSX.Element;
|
|
@@ -54,8 +54,7 @@ const trigger = css({
|
|
|
54
54
|
alignItems: "center",
|
|
55
55
|
gap: "control.iconGap",
|
|
56
56
|
width: "100%",
|
|
57
|
-
|
|
58
|
-
height: "control.small",
|
|
57
|
+
height: "control.compact",
|
|
59
58
|
paddingInlineStart: "control.compactInline",
|
|
60
59
|
paddingInlineEnd: "control.iconGap",
|
|
61
60
|
border: "1px solid token(colors.border.control)",
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { type IconButtonProps } from "./button.js";
|
|
2
2
|
/**
|
|
3
3
|
* Copies `value` (or what it returns, read at the moment of copying) and reports `copied` for a
|
|
4
|
-
* moment afterwards, for a check-mark confirmation.
|
|
4
|
+
* moment afterwards, for a check-mark confirmation. A copy the browser refuses, such as a denied
|
|
5
|
+
* permission or an insecure origin with no clipboard, goes to `onError`, or without one raises the
|
|
6
|
+
* kit's error toast, so a reader never pastes a stale clipboard thinking it holds the value.
|
|
5
7
|
*/
|
|
6
|
-
export declare function useCopy(value: string | (() => string), onCopied?: () => void): {
|
|
8
|
+
export declare function useCopy(value: string | (() => string), onCopied?: () => void, onError?: (error: unknown) => void): {
|
|
7
9
|
copied: boolean;
|
|
8
10
|
copy: () => undefined;
|
|
9
11
|
};
|
|
@@ -16,10 +18,12 @@ export type CopyButtonProps = {
|
|
|
16
18
|
variant?: "raised" | "ghost" | "inline";
|
|
17
19
|
size?: IconButtonProps["size"];
|
|
18
20
|
onCopied?: () => void;
|
|
21
|
+
/** A refused copy; the kit's error toast without it. */
|
|
22
|
+
onError?: (error: unknown) => void;
|
|
19
23
|
className?: string;
|
|
20
24
|
};
|
|
21
25
|
/** A button that copies `value`, its icon turning into a check once copied. */
|
|
22
|
-
export declare function CopyButton({ value, label, variant, size, onCopied, className, }: CopyButtonProps): import("
|
|
26
|
+
export declare function CopyButton({ value, label, variant, size, onCopied, onError, className, }: CopyButtonProps): import("react").JSX.Element;
|
|
23
27
|
/**
|
|
24
28
|
* A long identifier, such as an error's trace ID, shown short and copied whole on click so a
|
|
25
29
|
* reader can hand it to support.
|
|
@@ -28,10 +32,23 @@ export declare function CopyableId({ value, label, className, }: {
|
|
|
28
32
|
value: string;
|
|
29
33
|
label?: string;
|
|
30
34
|
className?: string;
|
|
31
|
-
}): import("
|
|
35
|
+
}): import("react").JSX.Element;
|
|
32
36
|
/** Text shown in full with a copy control; `label` names what gets copied, such as a key's name. */
|
|
33
37
|
export declare function CopyableText({ text, label, className, }: {
|
|
34
38
|
text: string;
|
|
35
39
|
label: string;
|
|
36
40
|
className?: string;
|
|
37
|
-
}): import("
|
|
41
|
+
}): import("react").JSX.Element;
|
|
42
|
+
/**
|
|
43
|
+
* A value to paste elsewhere, such as a command or a connection code, as a labelled read-only
|
|
44
|
+
* field with a copy button: it selects on focus and reads like the field it is pasted into. The
|
|
45
|
+
* row stays while there is no value yet, showing `placeholder`. The value is masked from session
|
|
46
|
+
* recorders, since such values are often credentials.
|
|
47
|
+
*/
|
|
48
|
+
export declare function CopyField({ label, value, placeholder, className, }: {
|
|
49
|
+
label: string;
|
|
50
|
+
value: string | undefined;
|
|
51
|
+
/** What an absent value means, such as that it is not generated yet. */
|
|
52
|
+
placeholder?: string;
|
|
53
|
+
className?: string;
|
|
54
|
+
}): import("react").JSX.Element;
|
|
@@ -3,8 +3,11 @@ import { CheckIcon, CopyIcon } from "@phosphor-icons/react";
|
|
|
3
3
|
import { useEffect, useRef, useState } from "react";
|
|
4
4
|
import { css, cx } from "#primitives/css";
|
|
5
5
|
import { IconButton } from "./button.js";
|
|
6
|
+
import { Field, FieldLabel } from "./form-layout.js";
|
|
6
7
|
import { icon } from "./icon.js";
|
|
8
|
+
import { Input } from "./input.js";
|
|
7
9
|
import { useCiridaeLocale } from "./locale.js";
|
|
10
|
+
import { useToast } from "./toast.js";
|
|
8
11
|
const copyableId = css({
|
|
9
12
|
display: "inline-flex",
|
|
10
13
|
alignItems: "center",
|
|
@@ -23,20 +26,41 @@ const shownLength = 8;
|
|
|
23
26
|
const copiedFeedbackMs = 1500;
|
|
24
27
|
/**
|
|
25
28
|
* Copies `value` (or what it returns, read at the moment of copying) and reports `copied` for a
|
|
26
|
-
* moment afterwards, for a check-mark confirmation.
|
|
29
|
+
* moment afterwards, for a check-mark confirmation. A copy the browser refuses, such as a denied
|
|
30
|
+
* permission or an insecure origin with no clipboard, goes to `onError`, or without one raises the
|
|
31
|
+
* kit's error toast, so a reader never pastes a stale clipboard thinking it holds the value.
|
|
27
32
|
*/
|
|
28
|
-
export function useCopy(value, onCopied) {
|
|
33
|
+
export function useCopy(value, onCopied, onError) {
|
|
29
34
|
const [copied, setCopied] = useState(false);
|
|
35
|
+
const { labels } = useCiridaeLocale();
|
|
36
|
+
const toast = useToast();
|
|
30
37
|
useEffect(() => {
|
|
31
38
|
if (!copied)
|
|
32
39
|
return;
|
|
33
40
|
const timer = setTimeout(() => setCopied(false), copiedFeedbackMs);
|
|
34
41
|
return () => clearTimeout(timer);
|
|
35
42
|
}, [copied]);
|
|
36
|
-
|
|
43
|
+
// `await` rather than `.catch`: an insecure origin has no `navigator.clipboard` at all and
|
|
44
|
+
// throws before a promise exists.
|
|
45
|
+
const writeValue = async () => {
|
|
46
|
+
try {
|
|
47
|
+
await navigator.clipboard.writeText(typeof value === "function" ? value() : value);
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
if (onError)
|
|
51
|
+
onError(error);
|
|
52
|
+
else
|
|
53
|
+
toast.add({
|
|
54
|
+
variant: "error",
|
|
55
|
+
title: labels.clipboard.copyFailed,
|
|
56
|
+
description: labels.clipboard.copyByHand,
|
|
57
|
+
});
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
37
60
|
setCopied(true);
|
|
38
61
|
onCopied?.();
|
|
39
|
-
}
|
|
62
|
+
};
|
|
63
|
+
const copy = () => void writeValue();
|
|
40
64
|
return { copied, copy };
|
|
41
65
|
}
|
|
42
66
|
const inlineCopy = css({
|
|
@@ -51,8 +75,8 @@ const inlineCopy = css({
|
|
|
51
75
|
_focusVisible: { focusRing: "outer", borderRadius: "control" },
|
|
52
76
|
});
|
|
53
77
|
/** A button that copies `value`, its icon turning into a check once copied. */
|
|
54
|
-
export function CopyButton({ value, label, variant = "raised", size, onCopied, className, }) {
|
|
55
|
-
const { copied, copy } = useCopy(value, onCopied);
|
|
78
|
+
export function CopyButton({ value, label, variant = "raised", size, onCopied, onError, className, }) {
|
|
79
|
+
const { copied, copy } = useCopy(value, onCopied, onError);
|
|
56
80
|
const { labels } = useCiridaeLocale();
|
|
57
81
|
const name = copied
|
|
58
82
|
? labels.common.copied
|
|
@@ -134,3 +158,19 @@ export function CopyableText({ text, label, className, }) {
|
|
|
134
158
|
};
|
|
135
159
|
return (_jsxs("span", { className: copyableText, "data-ciridae-ui": "", onMouseEnter: measureOverflow, children: [_jsx("span", { ref: box, className: cx(marqueeBox, className), title: text, children: _jsx("span", { children: text }) }), _jsx("button", { type: "button", className: copyTextButton, "aria-label": labels.common.copy(label), "data-copied": copied || undefined, onClick: copy, children: copied ? (_jsx(CheckIcon, { className: icon({ size: "small" }) })) : (_jsx(CopyIcon, { className: icon({ size: "small" }) })) })] }));
|
|
136
160
|
}
|
|
161
|
+
const copyFieldRow = css({
|
|
162
|
+
display: "grid",
|
|
163
|
+
gridTemplateColumns: "minmax(0, 1fr) auto",
|
|
164
|
+
alignItems: "end",
|
|
165
|
+
gap: "layout.tightGap",
|
|
166
|
+
});
|
|
167
|
+
const copyFieldValue = css({ fontFamily: "mono", fontSize: "code" });
|
|
168
|
+
/**
|
|
169
|
+
* A value to paste elsewhere, such as a command or a connection code, as a labelled read-only
|
|
170
|
+
* field with a copy button: it selects on focus and reads like the field it is pasted into. The
|
|
171
|
+
* row stays while there is no value yet, showing `placeholder`. The value is masked from session
|
|
172
|
+
* recorders, since such values are often credentials.
|
|
173
|
+
*/
|
|
174
|
+
export function CopyField({ label, value, placeholder, className, }) {
|
|
175
|
+
return (_jsxs("div", { className: cx(copyFieldRow, className), "data-ciridae-ui": "", children: [_jsxs(Field, { children: [_jsx(FieldLabel, { children: label }), _jsx(Input, { className: cx("ph-no-capture", copyFieldValue), "data-sentry-mask": true, onFocus: (event) => event.target.select(), placeholder: placeholder, readOnly: true, value: value ?? "" })] }), value !== undefined && _jsx(CopyButton, { label: label, value: value, variant: "ghost" })] }));
|
|
176
|
+
}
|
|
@@ -19,12 +19,12 @@ export declare function Avatar({ label, src, size, kind, icon, badge, color, cla
|
|
|
19
19
|
icon?: ReactNode;
|
|
20
20
|
badge?: ReactNode;
|
|
21
21
|
color?: AvatarColor;
|
|
22
|
-
}): import("
|
|
22
|
+
}): import("react").JSX.Element;
|
|
23
23
|
export declare function Divider({ inset, className, ...props }: Omit<ComponentProps<typeof BaseSeparator>, "className"> & {
|
|
24
24
|
className?: string;
|
|
25
25
|
/** `menu` insets it to a menu's or a popover's rows. */
|
|
26
26
|
inset?: "none" | "menu";
|
|
27
|
-
}): import("
|
|
27
|
+
}): import("react").JSX.Element;
|
|
28
28
|
export type DescriptionRow = [label: string, value: ReactNode];
|
|
29
29
|
/**
|
|
30
30
|
* Label-value pairs in two columns. Rows whose value is `null` or `undefined` are left out, so
|
|
@@ -36,7 +36,7 @@ export declare function DescriptionList({ rows, density, loading, className, ...
|
|
|
36
36
|
rows: DescriptionRow[];
|
|
37
37
|
density?: "default" | "compact";
|
|
38
38
|
loading?: boolean;
|
|
39
|
-
}): import("
|
|
39
|
+
}): import("react").JSX.Element;
|
|
40
40
|
/**
|
|
41
41
|
* Scrollable block of literal text, such as a command or a generated file. `copy` adds a copy
|
|
42
42
|
* button with that text, which can differ from what is shown (e.g. masked secrets).
|
|
@@ -44,4 +44,4 @@ export declare function DescriptionList({ rows, density, loading, className, ...
|
|
|
44
44
|
export declare function CodeBlock({ className, copy, copyLabel, ...props }: ComponentProps<"pre"> & {
|
|
45
45
|
copy?: string;
|
|
46
46
|
copyLabel?: string;
|
|
47
|
-
}): import("
|
|
47
|
+
}): import("react").JSX.Element;
|
|
@@ -38,10 +38,10 @@ export type TableColumnMeta = {
|
|
|
38
38
|
hideOnNarrow?: boolean;
|
|
39
39
|
};
|
|
40
40
|
declare const tableFeatureSet: {
|
|
41
|
-
rowSortingFeature: import("@tanstack/react-table
|
|
42
|
-
columnVisibilityFeature: import("@tanstack/react-table
|
|
43
|
-
columnOrderingFeature: import("@tanstack/react-table
|
|
44
|
-
sortedRowModel: (table: import("@tanstack/react-table
|
|
41
|
+
rowSortingFeature: import("@tanstack/react-table").TableFeature;
|
|
42
|
+
columnVisibilityFeature: import("@tanstack/react-table").TableFeature;
|
|
43
|
+
columnOrderingFeature: import("@tanstack/react-table").TableFeature;
|
|
44
|
+
sortedRowModel: (table: import("@tanstack/react-table").Table<any, any>) => () => import("@tanstack/react-table").RowModel<any, any>;
|
|
45
45
|
columnMeta: TableColumnMeta;
|
|
46
46
|
};
|
|
47
47
|
export type TableFeatureSet = typeof tableFeatureSet;
|
|
@@ -52,10 +52,10 @@ export type TableColumns<Row extends RowData> = ReturnType<ColumnHelper<TableFea
|
|
|
52
52
|
* columns render without one. See `TableColumnMeta` for the per-column options.
|
|
53
53
|
*/
|
|
54
54
|
export declare function createTableColumns<Row extends RowData>(): ColumnHelper<{
|
|
55
|
-
rowSortingFeature: import("@tanstack/react-table
|
|
56
|
-
columnVisibilityFeature: import("@tanstack/react-table
|
|
57
|
-
columnOrderingFeature: import("@tanstack/react-table
|
|
58
|
-
sortedRowModel: (table: import("@tanstack/react-table
|
|
55
|
+
rowSortingFeature: import("@tanstack/react-table").TableFeature;
|
|
56
|
+
columnVisibilityFeature: import("@tanstack/react-table").TableFeature;
|
|
57
|
+
columnOrderingFeature: import("@tanstack/react-table").TableFeature;
|
|
58
|
+
sortedRowModel: (table: import("@tanstack/react-table").Table<any, any>) => () => import("@tanstack/react-table").RowModel<any, any>;
|
|
59
59
|
columnMeta: TableColumnMeta;
|
|
60
60
|
}, Row>;
|
|
61
61
|
/** A column's id and name as column settings list them. */
|
|
@@ -156,7 +156,7 @@ export type DataGridProps<Row extends RowData> = Omit<ComponentProps<"div">, "ch
|
|
|
156
156
|
* hover-revealed row actions, groups, loading, empty and no-results states. `role="table"`; Enter
|
|
157
157
|
* on a pressable row opens it.
|
|
158
158
|
*/
|
|
159
|
-
export declare function DataGrid<Row extends RowData>({ data, columns, getRowId, variant, density, sorting: sortingProp, defaultSorting, onSortingChange, manualSorting, enableRowSelection, rowSelection: rowSelectionProp, defaultRowSelection, onRowSelectionChange, stickySelectColumn, columnVisibility: columnVisibilityProp, defaultColumnVisibility, onColumnVisibilityChange, columnOrder: columnOrderProp, defaultColumnOrder, onColumnOrderChange, headerMenu, filters, onFiltersChange, getRowHref, renderRowLink, onRowClick, activeRowId, keyboardNavigation, virtualize, rowActions, renderRowDetail, groupBy, renderGroupRow, loading, empty, noResults, filtered, hideHeader, fill, narrowScreenLayout, footer, labels: ownLabels, className, frameClassName, style, ...props }: DataGridProps<Row>): import("
|
|
159
|
+
export declare function DataGrid<Row extends RowData>({ data, columns, getRowId, variant, density, sorting: sortingProp, defaultSorting, onSortingChange, manualSorting, enableRowSelection, rowSelection: rowSelectionProp, defaultRowSelection, onRowSelectionChange, stickySelectColumn, columnVisibility: columnVisibilityProp, defaultColumnVisibility, onColumnVisibilityChange, columnOrder: columnOrderProp, defaultColumnOrder, onColumnOrderChange, headerMenu, filters, onFiltersChange, getRowHref, renderRowLink, onRowClick, activeRowId, keyboardNavigation, virtualize, rowActions, renderRowDetail, groupBy, renderGroupRow, loading, empty, noResults, filtered, hideHeader, fill, narrowScreenLayout, footer, labels: ownLabels, className, frameClassName, style, ...props }: DataGridProps<Row>): import("react").JSX.Element;
|
|
160
160
|
export type TableProps<Row extends RowData> = Omit<DataGridProps<Row>, "defaultSorting" | "empty"> & {
|
|
161
161
|
/** The sort the table starts with; `defaultSorting` on `DataGrid`. */
|
|
162
162
|
initialSorting?: SortingState;
|
|
@@ -167,4 +167,4 @@ export type TableProps<Row extends RowData> = Omit<DataGridProps<Row>, "defaultS
|
|
|
167
167
|
* `DataGrid` with the plain look: flush with its section, heads in caps, rows that light on hover
|
|
168
168
|
* when they lead somewhere.
|
|
169
169
|
*/
|
|
170
|
-
export declare function Table<Row extends RowData>({ variant, initialSorting, emptyMessage, ...props }: TableProps<Row>): import("
|
|
170
|
+
export declare function Table<Row extends RowData>({ variant, initialSorting, emptyMessage, ...props }: TableProps<Row>): import("react").JSX.Element;
|
|
@@ -8,4 +8,4 @@ import { type DateInput } from "./locale.js";
|
|
|
8
8
|
export declare function DateTime({ value, mode, }: {
|
|
9
9
|
value: DateInput | null;
|
|
10
10
|
mode?: "auto" | "date" | "dateTime" | "relative";
|
|
11
|
-
}): import("
|
|
11
|
+
}): import("react").JSX.Element | null;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/** A Wizard starts a new height scope on each step; filtering within that step keeps its height. */
|
|
2
|
-
export declare const DialogHeightResetContext: import("
|
|
2
|
+
export declare const DialogHeightResetContext: import("react").Context<(() => void) | null>;
|
|
@@ -49,7 +49,7 @@ export type DocumentViewerProps = Omit<ComponentProps<"div">, "children"> & {
|
|
|
49
49
|
actions?: ReactNode;
|
|
50
50
|
labels?: Partial<CiridaeLabels["documentViewer"]>;
|
|
51
51
|
};
|
|
52
|
-
export declare function DocumentViewer({ pages, regions, activeRegionId: ownActiveRegionId, defaultActiveRegionId, onActiveRegionChange, pageId: ownPageId, defaultPageId, onPageChange, zoom: ownZoom, defaultZoom, onZoomChange, aside, actions, labels: ownLabels, className, ...props }: DocumentViewerProps): import("
|
|
52
|
+
export declare function DocumentViewer({ pages, regions, activeRegionId: ownActiveRegionId, defaultActiveRegionId, onActiveRegionChange, pageId: ownPageId, defaultPageId, onPageChange, zoom: ownZoom, defaultZoom, onZoomChange, aside, actions, labels: ownLabels, className, ...props }: DocumentViewerProps): import("react").JSX.Element;
|
|
53
53
|
export type DocumentFieldProps = useRender.ComponentProps<"button"> & {
|
|
54
54
|
/** The region this field was read from; selecting either marks the other. */
|
|
55
55
|
regionId: string;
|
|
@@ -59,4 +59,4 @@ export type DocumentFieldProps = useRender.ComponentProps<"button"> & {
|
|
|
59
59
|
* selected, marked while its region is hovered, and scrolled into view when its region is
|
|
60
60
|
* selected on the page.
|
|
61
61
|
*/
|
|
62
|
-
export declare function DocumentField({ regionId, render, className, onClick, onMouseEnter, onMouseLeave, ...props }: DocumentFieldProps): import("
|
|
62
|
+
export declare function DocumentField({ regionId, render, className, onClick, onMouseEnter, onMouseLeave, ...props }: DocumentFieldProps): import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
|