@streamsai/ui 0.0.0-stage → 0.1.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.
- package/LICENSE +21 -0
- package/README.md +57 -2
- package/dist/components/ui/agent-avatar.d.ts +50 -0
- package/dist/components/ui/agent-avatar.js +38 -0
- package/dist/components/ui/alert-dialog.d.ts +12 -0
- package/dist/components/ui/alert-dialog.js +37 -0
- package/dist/components/ui/alert.d.ts +10 -0
- package/dist/components/ui/alert.js +28 -0
- package/dist/components/ui/assets/loader.json.js +1 -0
- package/dist/components/ui/avatar-frame.d.ts +11 -0
- package/dist/components/ui/avatar-frame.js +20 -0
- package/dist/components/ui/avatar.d.ts +23 -0
- package/dist/components/ui/avatar.js +54 -0
- package/dist/components/ui/badge.d.ts +7 -0
- package/dist/components/ui/badge.js +36 -0
- package/dist/components/ui/bar-list.d.ts +40 -0
- package/dist/components/ui/bar-list.js +37 -0
- package/dist/components/ui/breadcrumb.d.ts +8 -0
- package/dist/components/ui/breadcrumb.js +21 -0
- package/dist/components/ui/button-group.d.ts +10 -0
- package/dist/components/ui/button-group.js +41 -0
- package/dist/components/ui/button.d.ts +9 -0
- package/dist/components/ui/button.js +39 -0
- package/dist/components/ui/card.d.ts +9 -0
- package/dist/components/ui/card.js +25 -0
- package/dist/components/ui/checkbox.d.ts +3 -0
- package/dist/components/ui/checkbox.js +16 -0
- package/dist/components/ui/chip.d.ts +13 -0
- package/dist/components/ui/chip.js +22 -0
- package/dist/components/ui/clickable.d.ts +27 -0
- package/dist/components/ui/clickable.js +54 -0
- package/dist/components/ui/code-block.d.ts +68 -0
- package/dist/components/ui/code-block.js +112 -0
- package/dist/components/ui/code-view.d.ts +21 -0
- package/dist/components/ui/code-view.js +20 -0
- package/dist/components/ui/collapsible.d.ts +6 -0
- package/dist/components/ui/collapsible.js +18 -0
- package/dist/components/ui/combobox.d.ts +14 -0
- package/dist/components/ui/combobox.js +37 -0
- package/dist/components/ui/command.d.ts +15 -0
- package/dist/components/ui/command.js +34 -0
- package/dist/components/ui/context-menu.d.ts +21 -0
- package/dist/components/ui/context-menu.js +60 -0
- package/dist/components/ui/counter.d.ts +11 -0
- package/dist/components/ui/counter.js +20 -0
- package/dist/components/ui/dialog.d.ts +17 -0
- package/dist/components/ui/dialog.js +41 -0
- package/dist/components/ui/disabled-reason.d.ts +22 -0
- package/dist/components/ui/disabled-reason.js +16 -0
- package/dist/components/ui/dropdown-menu.d.ts +33 -0
- package/dist/components/ui/dropdown-menu.js +58 -0
- package/dist/components/ui/editable-text.d.ts +95 -0
- package/dist/components/ui/editable-text.js +191 -0
- package/dist/components/ui/heading.d.ts +24 -0
- package/dist/components/ui/heading.js +92 -0
- package/dist/components/ui/hover-card.d.ts +9 -0
- package/dist/components/ui/hover-card.js +16 -0
- package/dist/components/ui/icon-button.d.ts +23 -0
- package/dist/components/ui/icon-button.js +32 -0
- package/dist/components/ui/input.d.ts +3 -0
- package/dist/components/ui/input.js +8 -0
- package/dist/components/ui/kbd.d.ts +12 -0
- package/dist/components/ui/kbd.js +12 -0
- package/dist/components/ui/label.d.ts +3 -0
- package/dist/components/ui/label.js +7 -0
- package/dist/components/ui/loader.d.ts +19 -0
- package/dist/components/ui/loader.js +157 -0
- package/dist/components/ui/message-toolbar.d.ts +20 -0
- package/dist/components/ui/message-toolbar.js +17 -0
- package/dist/components/ui/modal.d.ts +30 -0
- package/dist/components/ui/modal.js +41 -0
- package/dist/components/ui/nav-item.d.ts +25 -0
- package/dist/components/ui/nav-item.js +66 -0
- package/dist/components/ui/panel-section.d.ts +22 -0
- package/dist/components/ui/panel-section.js +26 -0
- package/dist/components/ui/popover.d.ts +14 -0
- package/dist/components/ui/popover.js +30 -0
- package/dist/components/ui/progress.d.ts +5 -0
- package/dist/components/ui/progress.js +16 -0
- package/dist/components/ui/provider-badge.d.ts +22 -0
- package/dist/components/ui/provider-badge.js +38 -0
- package/dist/components/ui/radio-group.d.ts +5 -0
- package/dist/components/ui/radio-group.js +21 -0
- package/dist/components/ui/reply-summary.d.ts +16 -0
- package/dist/components/ui/reply-summary.js +8 -0
- package/dist/components/ui/resizable.d.ts +8 -0
- package/dist/components/ui/resizable.js +15 -0
- package/dist/components/ui/rich-text-editor.d.ts +447 -0
- package/dist/components/ui/rich-text-editor.js +2419 -0
- package/dist/components/ui/running-indicator.d.ts +17 -0
- package/dist/components/ui/running-indicator.js +34 -0
- package/dist/components/ui/sandboxed-frame.d.ts +29 -0
- package/dist/components/ui/sandboxed-frame.js +77 -0
- package/dist/components/ui/scroll-area.d.ts +14 -0
- package/dist/components/ui/scroll-area.js +17 -0
- package/dist/components/ui/section-header.d.ts +12 -0
- package/dist/components/ui/section-header.js +12 -0
- package/dist/components/ui/select.d.ts +15 -0
- package/dist/components/ui/select.js +40 -0
- package/dist/components/ui/separator.d.ts +3 -0
- package/dist/components/ui/separator.js +13 -0
- package/dist/components/ui/sheet.d.ts +23 -0
- package/dist/components/ui/sheet.js +48 -0
- package/dist/components/ui/shimmer-text.d.ts +26 -0
- package/dist/components/ui/shimmer-text.js +32 -0
- package/dist/components/ui/sidebar.d.ts +63 -0
- package/dist/components/ui/sidebar.js +283 -0
- package/dist/components/ui/skeleton.d.ts +14 -0
- package/dist/components/ui/skeleton.js +12 -0
- package/dist/components/ui/sonner.d.ts +4 -0
- package/dist/components/ui/sonner.js +14 -0
- package/dist/components/ui/spark-bars.d.ts +29 -0
- package/dist/components/ui/spark-bars.js +24 -0
- package/dist/components/ui/spinner.d.ts +16 -0
- package/dist/components/ui/spinner.js +26 -0
- package/dist/components/ui/stacked-bar.d.ts +37 -0
- package/dist/components/ui/stacked-bar.js +56 -0
- package/dist/components/ui/status-dot.d.ts +16 -0
- package/dist/components/ui/status-dot.js +32 -0
- package/dist/components/ui/switch.d.ts +5 -0
- package/dist/components/ui/switch.js +13 -0
- package/dist/components/ui/tabs.d.ts +14 -0
- package/dist/components/ui/tabs.js +55 -0
- package/dist/components/ui/text.d.ts +27 -0
- package/dist/components/ui/text.js +100 -0
- package/dist/components/ui/textarea.d.ts +3 -0
- package/dist/components/ui/textarea.js +7 -0
- package/dist/components/ui/theme-toggle.d.ts +21 -0
- package/dist/components/ui/theme-toggle.js +17 -0
- package/dist/components/ui/toggle-group.d.ts +6 -0
- package/dist/components/ui/toggle-group.js +12 -0
- package/dist/components/ui/tooltip.d.ts +11 -0
- package/dist/components/ui/tooltip.js +21 -0
- package/dist/components/ui/trace.d.ts +24 -0
- package/dist/components/ui/trace.js +57 -0
- package/dist/components/ui/trend-line.d.ts +93 -0
- package/dist/components/ui/trend-line.js +215 -0
- package/dist/components/ui/truncate.d.ts +30 -0
- package/dist/components/ui/truncate.js +54 -0
- package/dist/components/ui/viewer-shell.d.ts +55 -0
- package/dist/components/ui/viewer-shell.js +15 -0
- package/dist/components/ui/virtual-list.d.ts +91 -0
- package/dist/components/ui/virtual-list.js +406 -0
- package/dist/components/ui/visually-hidden.d.ts +15 -0
- package/dist/components/ui/visually-hidden.js +19 -0
- package/dist/direction/index.d.ts +19 -0
- package/dist/direction/index.js +32 -0
- package/dist/hooks/use-code-highlighting.d.ts +22 -0
- package/dist/hooks/use-code-highlighting.js +47 -0
- package/dist/hooks/use-is-truncated.d.ts +7 -0
- package/dist/hooks/use-is-truncated.js +23 -0
- package/dist/hooks/use-mobile.d.ts +2 -0
- package/dist/hooks/use-mobile.js +15 -0
- package/dist/icons/custom.d.ts +29 -0
- package/dist/icons/custom.js +48 -0
- package/dist/icons/index.d.ts +49 -0
- package/dist/icons/index.js +50 -0
- package/dist/icons/provider-logos.d.ts +17 -0
- package/dist/icons/provider-logos.js +28 -0
- package/dist/icons/providers.d.ts +9 -0
- package/dist/icons/providers.js +51 -0
- package/dist/index.d.ts +102 -0
- package/dist/index.js +124 -0
- package/dist/lib/code-highlighter.d.ts +9 -0
- package/dist/lib/code-highlighter.js +65 -0
- package/dist/lib/code-language.d.ts +13 -0
- package/dist/lib/code-language.js +103 -0
- package/dist/lib/code-tokens.d.ts +9 -0
- package/dist/lib/code-tokens.js +27 -0
- package/dist/lib/copy-text.d.ts +6 -0
- package/dist/lib/copy-text.js +46 -0
- package/dist/lib/home-tile.d.ts +12 -0
- package/dist/lib/home-tile.js +45 -0
- package/dist/lib/reveal-mask.d.ts +9 -0
- package/dist/lib/reveal-mask.js +16 -0
- package/dist/lib/text-direction.d.ts +28 -0
- package/dist/lib/text-direction.js +119 -0
- package/dist/lib/utils.d.ts +11 -0
- package/dist/lib/utils.js +30 -0
- package/dist/motion/components.d.ts +184 -0
- package/dist/motion/components.js +211 -0
- package/dist/motion/config.d.ts +849 -0
- package/dist/motion/config.js +429 -0
- package/dist/motion/index.d.ts +8 -0
- package/dist/motion/index.js +8 -0
- package/dist/motion/modal-presence.d.ts +5 -0
- package/dist/motion/modal-presence.js +27 -0
- package/dist/motion/popup.d.ts +77 -0
- package/dist/motion/popup.js +103 -0
- package/dist/platform/index.d.ts +29 -0
- package/dist/platform/index.js +63 -0
- package/dist/styles/base.css +319 -0
- package/dist/styles/fonts/Figtree-Variable.woff2 +0 -0
- package/dist/styles/fonts/OFL.txt +93 -0
- package/dist/styles/fonts/Poppins-Medium.woff2 +0 -0
- package/dist/styles/fonts/Poppins-Regular.woff2 +0 -0
- package/dist/styles/fonts/Poppins-SemiBold.woff2 +0 -0
- package/dist/styles/fonts.css +28 -0
- package/dist/styles/globals.css +8 -0
- package/dist/styles/mcp-host.css +76 -0
- package/dist/styles/tokens.css +387 -0
- package/dist/styles/tokens.d.mts +57 -0
- package/dist/styles/tokens.mjs +59 -0
- package/dist/theme/index.d.ts +28 -0
- package/dist/theme/index.js +65 -0
- package/package.json +136 -3
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { cn } from '../../lib/utils.js';
|
|
3
|
+
import { IconButton } from './icon-button.js';
|
|
4
|
+
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from './tooltip.js';
|
|
5
|
+
/**
|
|
6
|
+
* The hover-action strip on a message row (Figma "right actions group"): white background,
|
|
7
|
+
* ui-background hairline, Vibe medium 8px radius, Shadow/XS, and 8px padding and gaps around
|
|
8
|
+
* 24px icon buttons, so the strip is 42px tall.
|
|
9
|
+
*/
|
|
10
|
+
function MessageToolbar({ children, className, ...props }) {
|
|
11
|
+
return (_jsx(TooltipProvider, { children: _jsx("div", { role: "toolbar", "data-slot": "message-toolbar", className: cn('flex items-center gap-2 rounded-lg border border-secondary bg-background p-2 shadow-xs', className), ...props, children: children }) }));
|
|
12
|
+
}
|
|
13
|
+
function MessageToolbarButton({ icon, label, tooltip, onClick, active, }) {
|
|
14
|
+
const name = tooltip ?? label;
|
|
15
|
+
return (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { closeOnClick: false, render: _jsx(IconButton, { "aria-label": name, "aria-pressed": active, size: "icon-xs", variant: active ? 'secondary' : 'ghost', className: "rounded-[4px] text-icon hover:text-icon [&_svg:not([class*='size-'])]:size-4", onClick: onClick }), children: icon }), _jsx(TooltipContent, { side: "top", children: name })] }));
|
|
16
|
+
}
|
|
17
|
+
export { MessageToolbar, MessageToolbarButton };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { Dialog as DialogPrimitive } from '@base-ui/react/dialog';
|
|
3
|
+
/**
|
|
4
|
+
* Vibe's Modal: a 480px card with a 24px title, a 16px description, a close button in the
|
|
5
|
+
* corner and a footer of one primary and one optional secondary (tertiary) action.
|
|
6
|
+
* `Dialog` stays the general-purpose shadcn shape; reach for `Modal` where the design asks
|
|
7
|
+
* for the Vibe one.
|
|
8
|
+
*/
|
|
9
|
+
declare function Modal({ actionsRef, onOpenChange, ...props }: DialogPrimitive.Root.Props): React.JSX.Element;
|
|
10
|
+
declare function ModalContent({ className, children, closeLabel, closeDisabled, ...props }: DialogPrimitive.Popup.Props & {
|
|
11
|
+
/** Accessible name of the corner close button. */
|
|
12
|
+
closeLabel?: string;
|
|
13
|
+
closeDisabled?: boolean;
|
|
14
|
+
}): React.JSX.Element;
|
|
15
|
+
declare function ModalHeader({ className, ...props }: React.ComponentProps<'div'>): React.JSX.Element;
|
|
16
|
+
declare function ModalTitle({ className, ...props }: DialogPrimitive.Title.Props): React.JSX.Element;
|
|
17
|
+
declare function ModalDescription({ className, ...props }: DialogPrimitive.Description.Props): React.JSX.Element;
|
|
18
|
+
/** Free-form body between the header and the footer. */
|
|
19
|
+
declare function ModalBody({ className, ...props }: React.ComponentProps<'div'>): React.JSX.Element;
|
|
20
|
+
interface ModalAction {
|
|
21
|
+
label: React.ReactNode;
|
|
22
|
+
onClick?: () => void;
|
|
23
|
+
disabled?: boolean;
|
|
24
|
+
loading?: boolean;
|
|
25
|
+
}
|
|
26
|
+
declare function ModalFooter({ className, primaryButton, secondaryButton, ...props }: Omit<React.ComponentProps<'div'>, 'children'> & {
|
|
27
|
+
primaryButton: ModalAction;
|
|
28
|
+
secondaryButton?: ModalAction;
|
|
29
|
+
}): React.JSX.Element;
|
|
30
|
+
export { Modal, ModalContent, ModalHeader, ModalTitle, ModalDescription, ModalBody, ModalFooter, type ModalAction, };
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
import { Dialog as DialogPrimitive } from '@base-ui/react/dialog';
|
|
4
|
+
import { cn } from '../../lib/utils.js';
|
|
5
|
+
import { PopupExitContext, renderBackdrop, useModalRender, usePopupExit } from '../../motion/popup.js';
|
|
6
|
+
import { presets } from '../../motion/config.js';
|
|
7
|
+
import { X as XIcon } from '../../icons/index.js';
|
|
8
|
+
import { Button } from './button.js';
|
|
9
|
+
import { Spinner } from './spinner.js';
|
|
10
|
+
/**
|
|
11
|
+
* Vibe's Modal: a 480px card with a 24px title, a 16px description, a close button in the
|
|
12
|
+
* corner and a footer of one primary and one optional secondary (tertiary) action.
|
|
13
|
+
* `Dialog` stays the general-purpose shadcn shape; reach for `Modal` where the design asks
|
|
14
|
+
* for the Vibe one.
|
|
15
|
+
*/
|
|
16
|
+
function Modal({ actionsRef, onOpenChange, ...props }) {
|
|
17
|
+
const exit = usePopupExit(actionsRef, onOpenChange);
|
|
18
|
+
return (_jsx(PopupExitContext, { value: exit.unmount, children: _jsx(DialogPrimitive.Root, { "data-slot": "modal", ...props, actionsRef: exit.actionsRef, onOpenChange: exit.onOpenChange }) }));
|
|
19
|
+
}
|
|
20
|
+
function ModalContent({ className, children, closeLabel = 'Close', closeDisabled, ...props }) {
|
|
21
|
+
const renderPopup = useModalRender(presets.dialog);
|
|
22
|
+
return (_jsxs(DialogPrimitive.Portal, { children: [_jsx(DialogPrimitive.Backdrop, { render: renderBackdrop, "data-slot": "modal-overlay", className: "fixed inset-y-0 left-[var(--overlay-inset-left,0px)] right-[var(--overlay-inset-right,0px)] isolate z-(--z-modal) bg-black/30" }), _jsxs(DialogPrimitive.Popup, { render: renderPopup, "data-slot": "modal-content", className: cn('fixed top-1/2 left-[var(--overlay-inset-left,0px)] right-[var(--overlay-inset-right,0px)] mx-auto z-(--z-modal) flex w-[calc(100%-var(--overlay-inset-left,0px)-var(--overlay-inset-right,0px)-var(--modal-gutter,2rem))]! -translate-y-1/2 flex-col rounded-2xl bg-popover text-popover-foreground shadow-lg outline-none sm:max-w-120', className), ...props, children: [children, _jsxs(DialogPrimitive.Close, { "data-slot": "modal-close", disabled: closeDisabled, render: _jsx(Button, { variant: "ghost", size: "icon", className: "absolute top-5 right-5" }), children: [_jsx(XIcon, { className: "size-5" }), _jsx("span", { className: "sr-only", children: closeLabel })] })] })] }));
|
|
23
|
+
}
|
|
24
|
+
function ModalHeader({ className, ...props }) {
|
|
25
|
+
return (_jsx("div", { "data-slot": "modal-header", className: cn('flex flex-col gap-2 px-8 pt-8 pe-16', className), ...props }));
|
|
26
|
+
}
|
|
27
|
+
function ModalTitle({ className, ...props }) {
|
|
28
|
+
return (_jsx(DialogPrimitive.Title, { "data-slot": "modal-title", className: cn('font-heading text-2xl font-medium text-foreground', className), ...props }));
|
|
29
|
+
}
|
|
30
|
+
function ModalDescription({ className, ...props }) {
|
|
31
|
+
return (_jsx(DialogPrimitive.Description, { "data-slot": "modal-description", className: cn('text-base text-muted-foreground', className), ...props }));
|
|
32
|
+
}
|
|
33
|
+
/** Free-form body between the header and the footer. */
|
|
34
|
+
function ModalBody({ className, ...props }) {
|
|
35
|
+
return _jsx("div", { "data-slot": "modal-body", className: cn('px-8 pt-4', className), ...props });
|
|
36
|
+
}
|
|
37
|
+
const MODAL_BUTTON = 'h-10 px-4 text-base';
|
|
38
|
+
function ModalFooter({ className, primaryButton, secondaryButton, ...props }) {
|
|
39
|
+
return (_jsxs("div", { "data-slot": "modal-footer", className: cn('flex justify-end gap-2 px-8 pt-8 pb-8', className), ...props, children: [secondaryButton ? (_jsx(Button, { type: "button", variant: "ghost", className: MODAL_BUTTON, disabled: secondaryButton.disabled, onClick: secondaryButton.onClick, children: secondaryButton.label })) : null, _jsxs(Button, { type: "button", className: MODAL_BUTTON, disabled: primaryButton.disabled || primaryButton.loading, onClick: primaryButton.onClick, children: [primaryButton.loading ? _jsx(Spinner, { className: "size-4", "aria-hidden": true }) : null, primaryButton.label] })] }));
|
|
40
|
+
}
|
|
41
|
+
export { Modal, ModalContent, ModalHeader, ModalTitle, ModalDescription, ModalBody, ModalFooter, };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { type ComponentProps, type ReactNode } from 'react';
|
|
2
|
+
import { type StatusDotProps } from './status-dot.js';
|
|
3
|
+
interface NavItemProps extends Omit<ComponentProps<'button'>, 'children'> {
|
|
4
|
+
icon?: ReactNode;
|
|
5
|
+
/** One line. When it does not fit it fades out at the edge and slides into view on hover. */
|
|
6
|
+
label: ReactNode;
|
|
7
|
+
/** Extra classes for the label span (e.g. `font-medium` for unread). */
|
|
8
|
+
labelClassName?: string;
|
|
9
|
+
active?: boolean;
|
|
10
|
+
depth?: 0 | 1;
|
|
11
|
+
status?: StatusDotProps['status'];
|
|
12
|
+
statusLabel?: string;
|
|
13
|
+
/** `home` is the mobile Home dot (yellow Running pulse with a halo); everything else keeps the default. */
|
|
14
|
+
statusAppearance?: StatusDotProps['appearance'];
|
|
15
|
+
/** Always-visible trailing mark (e.g. unread dot). Does not hide on row hover. */
|
|
16
|
+
indicator?: ReactNode;
|
|
17
|
+
trailing?: ReactNode;
|
|
18
|
+
hoverActions?: ReactNode;
|
|
19
|
+
/** Show `hoverActions` without hover or focus (e.g. on the active row). */
|
|
20
|
+
actionsVisible?: boolean;
|
|
21
|
+
/** Keep `indicator` next to the actions instead of swapping it out while they show. */
|
|
22
|
+
keepIndicator?: boolean;
|
|
23
|
+
}
|
|
24
|
+
declare function NavItem({ icon, label, labelClassName, active, depth, status, statusLabel, statusAppearance, indicator, trailing, hoverActions, actionsVisible, keepIndicator, className, ...props }: NavItemProps): import("react").JSX.Element;
|
|
25
|
+
export { NavItem, type NavItemProps };
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useLayoutEffect, useRef, useState, } from 'react';
|
|
3
|
+
import { useTextDirection } from '../../direction/index.js';
|
|
4
|
+
import { AnimatePresence, Swap, motion, useMotionValue, useTransform } from '../../motion/index.js';
|
|
5
|
+
import { presets, scrollReveal } from '../../motion/config.js';
|
|
6
|
+
import { revealMask } from '../../lib/reveal-mask.js';
|
|
7
|
+
import { cn } from '../../lib/utils.js';
|
|
8
|
+
import { StatusDot } from './status-dot.js';
|
|
9
|
+
/**
|
|
10
|
+
* One-line label that fades out where it is clipped and, while `revealing`, slides the rest of
|
|
11
|
+
* itself into view at a reading pace (ChatGPT's sidebar titles). The fade follows the slide: the
|
|
12
|
+
* leading edge fades in as text leaves it, the trailing fade melts away as the last letters land.
|
|
13
|
+
*/
|
|
14
|
+
function RevealLabel({ revealing, className, children, }) {
|
|
15
|
+
const clipRef = useRef(null);
|
|
16
|
+
const textRef = useRef(null);
|
|
17
|
+
const rtl = useTextDirection() === 'rtl';
|
|
18
|
+
const [overflow, setOverflow] = useState(0);
|
|
19
|
+
const x = useMotionValue(0);
|
|
20
|
+
const overflowPx = useMotionValue(0);
|
|
21
|
+
const maskImage = useTransform([x, overflowPx], ([offset = 0, hidden = 0]) => revealMask(offset, hidden, rtl));
|
|
22
|
+
// The clip narrows on hover (actions take the trailing slot), so this re-measures then too.
|
|
23
|
+
useLayoutEffect(() => {
|
|
24
|
+
const clip = clipRef.current;
|
|
25
|
+
const text = textRef.current;
|
|
26
|
+
if (!clip || !text)
|
|
27
|
+
return;
|
|
28
|
+
const measure = () => {
|
|
29
|
+
const hidden = Math.max(0, text.scrollWidth - clip.clientWidth);
|
|
30
|
+
overflowPx.set(hidden);
|
|
31
|
+
setOverflow(hidden);
|
|
32
|
+
};
|
|
33
|
+
measure();
|
|
34
|
+
const observer = new ResizeObserver(measure);
|
|
35
|
+
observer.observe(clip);
|
|
36
|
+
observer.observe(text);
|
|
37
|
+
return () => observer.disconnect();
|
|
38
|
+
}, [overflowPx]);
|
|
39
|
+
const target = revealing ? overflow : 0;
|
|
40
|
+
return (_jsx(motion.span, { ref: clipRef, "data-slot": "nav-item-label",
|
|
41
|
+
// The row button may carry a native shortcut title; an empty title here keeps it off the
|
|
42
|
+
// label, which shows its own full text on hover.
|
|
43
|
+
title: "", className: cn('flex min-w-0 flex-1 items-center overflow-hidden', className), style: { maskImage, WebkitMaskImage: maskImage }, children: _jsx(motion.span, { ref: textRef, className: "flex shrink-0 items-center whitespace-nowrap", style: { x }, animate: { x: rtl ? target : -target }, transition: target > 0 ? scrollReveal.to(target) : scrollReveal.back, children: children }) }));
|
|
44
|
+
}
|
|
45
|
+
function NavItem({ icon, label, labelClassName, active = false, depth = 0, status, statusLabel = '', statusAppearance, indicator, trailing, hoverActions, actionsVisible = false, keepIndicator = false, className, ...props }) {
|
|
46
|
+
// Hover or keyboard focus reveals a clipped label. Touch has no hover, so a tap must not
|
|
47
|
+
// start it moving just as the row navigates away.
|
|
48
|
+
const [hovered, setHovered] = useState(false);
|
|
49
|
+
const [focused, setFocused] = useState(false);
|
|
50
|
+
const onPointerEnter = (event) => setHovered(event.pointerType !== 'touch');
|
|
51
|
+
const onFocus = (event) => setFocused(event.target.matches(':focus-visible'));
|
|
52
|
+
// Row is a div so hoverActions (which hold buttons) sit beside the button, not inside it.
|
|
53
|
+
// Motion: the active and hover washes fade (`transition-colors`), a status change crossfades
|
|
54
|
+
// in the leading slot, and an indicator (unread dot, badge) pops in and out.
|
|
55
|
+
return (_jsxs("div", { onPointerEnter: onPointerEnter, onPointerLeave: () => setHovered(false), onFocus: onFocus, onBlur: () => setFocused(false), className: cn('group/navitem flex h-8 w-full min-w-0 items-center gap-2 rounded-sm px-2 text-body-2 text-sidebar-foreground transition-colors', 'hover:bg-sidebar-accent has-[[data-slot=nav-item]:focus-visible]:ring-2 has-[[data-slot=nav-item]:focus-visible]:ring-ring', active && 'bg-selected text-selected-foreground hover:bg-selected', depth === 1 && 'pl-7', className), children: [_jsxs("button", { type: "button", "data-slot": "nav-item", "aria-current": active ? 'page' : undefined, className: "relative flex h-full min-w-0 flex-1 items-center gap-2 text-left outline-none", ...props, children: [status || icon ? (_jsx(Swap, { inline: true, swapKey: status ?? 'icon', "data-slot": "nav-item-leading", className: "flex size-4 shrink-0 items-center justify-center text-icon [&>svg]:size-4", children: status ? (_jsx(StatusDot, { status: status, label: statusLabel, size: "sm", appearance: statusAppearance })) : (icon) })) : null, _jsx(RevealLabel, { revealing: hovered || focused, className: labelClassName, children: label }), _jsx(AnimatePresence, { initial: false, children: indicator ? (_jsx(motion.span, { ...presets.pop, "data-slot": "nav-item-indicator",
|
|
56
|
+
// 24px slot, same as the hover action button: the dot and the "more" button
|
|
57
|
+
// share one centre line. The button takes its place while the row is hovered.
|
|
58
|
+
className: cn('flex size-6 shrink-0 items-center justify-center', hoverActions &&
|
|
59
|
+
!keepIndicator &&
|
|
60
|
+
'group-hover/navitem:hidden group-focus-within/navitem:hidden group-has-[[data-popup-open]]/navitem:hidden'), children: indicator }, "indicator")) : null }), trailing ? (_jsx("span", { className: "shrink-0 text-body-3 text-muted-foreground group-hover/navitem:hidden group-focus-within/navitem:hidden group-has-[[data-popup-open]]/navitem:hidden", children: trailing })) : null] }), hoverActions ? (
|
|
61
|
+
// Keep the trigger mounted while its portaled menu is open. `hidden` would
|
|
62
|
+
// collapse the anchor (focus leaves the row for the portal; pointer often
|
|
63
|
+
// does too) and Base UI's Positioner falls back to the top-left of the viewport.
|
|
64
|
+
_jsx("span", { className: cn('shrink-0 items-center gap-0.5 group-hover/navitem:flex group-focus-within/navitem:flex has-[[data-popup-open]]:flex', actionsVisible ? 'flex' : 'hidden'), children: hoverActions })) : null] }));
|
|
65
|
+
}
|
|
66
|
+
export { NavItem };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
interface PanelSectionProps {
|
|
3
|
+
title: string;
|
|
4
|
+
children: ReactNode;
|
|
5
|
+
/** Right-aligned controls on the title row (icon buttons, a small link). */
|
|
6
|
+
action?: ReactNode;
|
|
7
|
+
isEmpty?: boolean;
|
|
8
|
+
empty?: ReactNode;
|
|
9
|
+
defaultOpen?: boolean;
|
|
10
|
+
/** Controls the open state from outside; `defaultOpen` is then ignored. */
|
|
11
|
+
open?: boolean;
|
|
12
|
+
onOpenChange?: (open: boolean) => void;
|
|
13
|
+
className?: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* One block of the details pane: a collapsible title row (12px semibold primary text, an xs
|
|
17
|
+
* icon-button chevron in the icon colour after the title) and its secondary-text content. A
|
|
18
|
+
* layout-border hairline separates it from the next block, inset to 8px past the title on each
|
|
19
|
+
* side rather than running edge to edge. The pane stacks these; nothing else draws section chrome.
|
|
20
|
+
*/
|
|
21
|
+
declare function PanelSection({ title, children, action, isEmpty, empty, defaultOpen, open: openProp, onOpenChange, className, }: PanelSectionProps): import("react").JSX.Element;
|
|
22
|
+
export { PanelSection, type PanelSectionProps };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useState } from 'react';
|
|
4
|
+
import { motion } from '../../motion/index.js';
|
|
5
|
+
import { transitions } from '../../motion/config.js';
|
|
6
|
+
import { cn } from '../../lib/utils.js';
|
|
7
|
+
import { ChevronDown } from '../../icons/index.js';
|
|
8
|
+
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from './collapsible.js';
|
|
9
|
+
import { Heading } from './heading.js';
|
|
10
|
+
/**
|
|
11
|
+
* One block of the details pane: a collapsible title row (12px semibold primary text, an xs
|
|
12
|
+
* icon-button chevron in the icon colour after the title) and its secondary-text content. A
|
|
13
|
+
* layout-border hairline separates it from the next block, inset to 8px past the title on each
|
|
14
|
+
* side rather than running edge to edge. The pane stacks these; nothing else draws section chrome.
|
|
15
|
+
*/
|
|
16
|
+
function PanelSection({ title, children, action, isEmpty, empty, defaultOpen = true, open: openProp, onOpenChange, className, }) {
|
|
17
|
+
const [innerOpen, setInnerOpen] = useState(defaultOpen);
|
|
18
|
+
const open = openProp ?? innerOpen;
|
|
19
|
+
const setOpen = (next) => {
|
|
20
|
+
if (openProp === undefined)
|
|
21
|
+
setInnerOpen(next);
|
|
22
|
+
onOpenChange?.(next);
|
|
23
|
+
};
|
|
24
|
+
return (_jsxs(Collapsible, { open: open, onOpenChange: setOpen, render: _jsx("section", { "data-slot": "panel-section", className: cn('relative flex flex-col gap-2 px-5 py-3', 'after:absolute after:inset-x-3 after:bottom-0 after:h-px after:bg-border last:after:hidden', className) }), children: [_jsxs("div", { className: "flex min-h-6 items-center justify-between gap-2", children: [_jsx(Heading, { level: 3, size: "6", className: "min-w-0 text-body-3 leading-4 font-semibold text-foreground", children: _jsxs(CollapsibleTrigger, { className: "group/panel-section w-auto gap-1 rounded-sm outline-none focus-visible:ring-2 focus-visible:ring-ring", children: [_jsx("span", { className: "truncate", children: title }), _jsx("span", { "data-slot": "panel-section-chevron", className: "flex size-6 shrink-0 items-center justify-center rounded-[min(var(--radius-md),10px)] text-icon transition-colors group-hover/panel-section:bg-accent", "aria-hidden": "true", children: _jsx(motion.span, { animate: { rotate: open ? 0 : -90 }, transition: transitions.base, className: "flex size-3 items-center justify-center", children: _jsx(ChevronDown, { className: "size-3" }) }) })] }) }), action ? (_jsx("span", { className: "flex shrink-0 items-center gap-0.5 text-foreground", children: action })) : null] }), _jsx(CollapsibleContent, { className: "text-muted-foreground", children: isEmpty ? empty : children })] }));
|
|
25
|
+
}
|
|
26
|
+
export { PanelSection };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { Popover as PopoverPrimitive } from '@base-ui/react/popover';
|
|
3
|
+
import { type PopupVariant } from '../../motion/popup.js';
|
|
4
|
+
declare function Popover({ actionsRef, onOpenChange, ...props }: PopoverPrimitive.Root.Props): React.JSX.Element;
|
|
5
|
+
declare function PopoverTrigger({ ...props }: PopoverPrimitive.Trigger.Props): React.JSX.Element;
|
|
6
|
+
declare function PopoverClose({ ...props }: PopoverPrimitive.Close.Props): React.JSX.Element;
|
|
7
|
+
declare function PopoverContent({ className, align, alignOffset, side, sideOffset, anchor, collisionAvoidance, collisionPadding, positionMethod, motion, ...props }: PopoverPrimitive.Popup.Props & {
|
|
8
|
+
/** `drift` fades and rises without the scale, for a list that belongs to a dense form. */
|
|
9
|
+
motion?: Exclude<PopupVariant, 'drift-tip'>;
|
|
10
|
+
} & Pick<PopoverPrimitive.Positioner.Props, 'align' | 'alignOffset' | 'side' | 'sideOffset' | 'anchor' | 'collisionAvoidance' | 'collisionPadding' | 'positionMethod'>): React.JSX.Element;
|
|
11
|
+
declare function PopoverHeader({ className, ...props }: React.ComponentProps<'div'>): React.JSX.Element;
|
|
12
|
+
declare function PopoverTitle({ className, ...props }: PopoverPrimitive.Title.Props): React.JSX.Element;
|
|
13
|
+
declare function PopoverDescription({ className, ...props }: PopoverPrimitive.Description.Props): React.JSX.Element;
|
|
14
|
+
export { Popover, PopoverClose, PopoverContent, PopoverDescription, PopoverHeader, PopoverTitle, PopoverTrigger, };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { Popover as PopoverPrimitive } from '@base-ui/react/popover';
|
|
5
|
+
import { cn } from '../../lib/utils.js';
|
|
6
|
+
import { PopupExitContext, usePopupExit, usePopupRender } from '../../motion/popup.js';
|
|
7
|
+
function Popover({ actionsRef, onOpenChange, ...props }) {
|
|
8
|
+
const exit = usePopupExit(actionsRef, onOpenChange);
|
|
9
|
+
return (_jsx(PopupExitContext, { value: exit.unmount, children: _jsx(PopoverPrimitive.Root, { "data-slot": "popover", ...props, actionsRef: exit.actionsRef, onOpenChange: exit.onOpenChange }) }));
|
|
10
|
+
}
|
|
11
|
+
function PopoverTrigger({ ...props }) {
|
|
12
|
+
return _jsx(PopoverPrimitive.Trigger, { "data-slot": "popover-trigger", ...props });
|
|
13
|
+
}
|
|
14
|
+
function PopoverClose({ ...props }) {
|
|
15
|
+
return _jsx(PopoverPrimitive.Close, { "data-slot": "popover-close", ...props });
|
|
16
|
+
}
|
|
17
|
+
function PopoverContent({ className, align = 'center', alignOffset = 0, side = 'bottom', sideOffset = 4, anchor, collisionAvoidance, collisionPadding, positionMethod, motion = 'scale', ...props }) {
|
|
18
|
+
const renderPopup = usePopupRender(motion);
|
|
19
|
+
return (_jsx(PopoverPrimitive.Portal, { children: _jsx(PopoverPrimitive.Positioner, { align: align, alignOffset: alignOffset, side: side, sideOffset: sideOffset, anchor: anchor, collisionAvoidance: collisionAvoidance, collisionPadding: collisionPadding, positionMethod: positionMethod, className: "isolate z-(--z-dropdown)", children: _jsx(PopoverPrimitive.Popup, { render: renderPopup, "data-slot": "popover-content", className: cn('z-(--z-dropdown) flex w-72 origin-(--transform-origin) flex-col gap-2.5 rounded-lg bg-popover p-2.5 text-sm text-popover-foreground shadow-md ring-1 ring-foreground/10 outline-hidden', className), ...props }) }) }));
|
|
20
|
+
}
|
|
21
|
+
function PopoverHeader({ className, ...props }) {
|
|
22
|
+
return (_jsx("div", { "data-slot": "popover-header", className: cn('flex flex-col gap-0.5 text-sm', className), ...props }));
|
|
23
|
+
}
|
|
24
|
+
function PopoverTitle({ className, ...props }) {
|
|
25
|
+
return (_jsx(PopoverPrimitive.Title, { "data-slot": "popover-title", className: cn('font-medium', className), ...props }));
|
|
26
|
+
}
|
|
27
|
+
function PopoverDescription({ className, ...props }) {
|
|
28
|
+
return (_jsx(PopoverPrimitive.Description, { "data-slot": "popover-description", className: cn('text-muted-foreground', className), ...props }));
|
|
29
|
+
}
|
|
30
|
+
export { Popover, PopoverClose, PopoverContent, PopoverDescription, PopoverHeader, PopoverTitle, PopoverTrigger, };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useCallback } from 'react';
|
|
3
|
+
import { Progress as ProgressPrimitive } from '@base-ui/react/progress';
|
|
4
|
+
import { motion } from '../../motion/index.js';
|
|
5
|
+
import { transitions } from '../../motion/config.js';
|
|
6
|
+
import { cn } from '../../lib/utils.js';
|
|
7
|
+
function Progress({ className, value, ...props }) {
|
|
8
|
+
const renderIndicator = useCallback((indicatorProps) => {
|
|
9
|
+
const { style, ...rest } = indicatorProps;
|
|
10
|
+
// Base UI also sizes the indicator to `value`%; the translation below already carries the fill,
|
|
11
|
+
// so keep it full width or the bar shows `value`% of `value`%.
|
|
12
|
+
return (_jsx(motion.div, { ...rest, style: { ...style, width: '100%' }, animate: { x: `${-(100 - (value ?? 0))}%` }, transition: transitions.slow }));
|
|
13
|
+
}, [value]);
|
|
14
|
+
return (_jsx(ProgressPrimitive.Root, { "data-slot": "progress", value: value, "aria-valuenow": value ?? undefined, className: cn('relative h-2 w-full overflow-hidden rounded-full bg-secondary', className), ...props, children: _jsx(ProgressPrimitive.Track, { className: "h-full w-full", children: _jsx(ProgressPrimitive.Indicator, { render: renderIndicator, "data-slot": "progress-indicator", className: "h-full w-full bg-primary" }) }) }));
|
|
15
|
+
}
|
|
16
|
+
export { Progress };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { type ProviderMarkType } from '../../icons/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* THE one place that decides which provider gets a badge on an agent's picture and with what
|
|
4
|
+
* artwork. A provider that is not listed (custom webhook, custom token-only, the Streams
|
|
5
|
+
* platform agent, anything newer than this map) shows no badge. The artwork is the provider's
|
|
6
|
+
* full-colour `ProviderMark` logo (white for the logos drawn black, in dark mode).
|
|
7
|
+
*/
|
|
8
|
+
export declare const PROVIDER_BADGE_MARKS: Readonly<Record<string, ProviderMarkType>>;
|
|
9
|
+
/** The badge artwork for a provider type, or `null` when that provider shows none. */
|
|
10
|
+
export declare const providerBadgeMarkOf: (type: string | null | undefined) => ProviderMarkType | null;
|
|
11
|
+
/**
|
|
12
|
+
* The provider's logo on a plate that overhangs an agent picture's bottom-right corner. Render it
|
|
13
|
+
* as a sibling of the (clipped) picture inside a `relative` frame. Purely presentational: the
|
|
14
|
+
* caller decides whether to show it. Pass `label` to announce the provider, or omit it when an
|
|
15
|
+
* adjacent label already names it (the badge is then hidden from assistive tech).
|
|
16
|
+
*/
|
|
17
|
+
declare function ProviderBadge({ type, label, className, }: {
|
|
18
|
+
type: ProviderMarkType;
|
|
19
|
+
label?: string;
|
|
20
|
+
className?: string;
|
|
21
|
+
}): import("react").JSX.Element;
|
|
22
|
+
export { ProviderBadge };
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { ProviderMark } from '../../icons/index.js';
|
|
3
|
+
import { cn } from '../../lib/utils.js';
|
|
4
|
+
/**
|
|
5
|
+
* THE one place that decides which provider gets a badge on an agent's picture and with what
|
|
6
|
+
* artwork. A provider that is not listed (custom webhook, custom token-only, the Streams
|
|
7
|
+
* platform agent, anything newer than this map) shows no badge. The artwork is the provider's
|
|
8
|
+
* full-colour `ProviderMark` logo (white for the logos drawn black, in dark mode).
|
|
9
|
+
*/
|
|
10
|
+
export const PROVIDER_BADGE_MARKS = {
|
|
11
|
+
claude: 'claude',
|
|
12
|
+
mistral: 'mistral',
|
|
13
|
+
elevenlabs: 'elevenlabs',
|
|
14
|
+
copilot_studio: 'copilot_studio',
|
|
15
|
+
cursor: 'cursor',
|
|
16
|
+
monday: 'monday',
|
|
17
|
+
sphera: 'sphera',
|
|
18
|
+
devin: 'devin',
|
|
19
|
+
};
|
|
20
|
+
/** The badge artwork for a provider type, or `null` when that provider shows none. */
|
|
21
|
+
export const providerBadgeMarkOf = (type) => type ? (PROVIDER_BADGE_MARKS[type] ?? null) : null;
|
|
22
|
+
/**
|
|
23
|
+
* Handoff geometry, as percentages of the agent frame so it scales with whatever size the call
|
|
24
|
+
* site gives the avatar: a 56px frame carries a 22px badge hanging 6px past its bottom-right
|
|
25
|
+
* corner (22/56 and 6/56). A 28px frame gets 11px and 3px.
|
|
26
|
+
*/
|
|
27
|
+
const BADGE_SIZE = '39.2857%';
|
|
28
|
+
const BADGE_OFFSET = '-10.7143%';
|
|
29
|
+
/**
|
|
30
|
+
* The provider's logo on a plate that overhangs an agent picture's bottom-right corner. Render it
|
|
31
|
+
* as a sibling of the (clipped) picture inside a `relative` frame. Purely presentational: the
|
|
32
|
+
* caller decides whether to show it. Pass `label` to announce the provider, or omit it when an
|
|
33
|
+
* adjacent label already names it (the badge is then hidden from assistive tech).
|
|
34
|
+
*/
|
|
35
|
+
function ProviderBadge({ type, label, className, }) {
|
|
36
|
+
return (_jsx("span", { "data-slot": "provider-badge", "data-provider": type, role: label ? 'img' : undefined, "aria-label": label, "aria-hidden": label ? undefined : true, className: cn('pointer-events-none absolute z-10 flex aspect-square items-center justify-center rounded-[27%] bg-background text-foreground shadow-sm ring-1 ring-border', className), style: { width: BADGE_SIZE, right: BADGE_OFFSET, bottom: BADGE_OFFSET }, children: _jsx(ProviderMark, { type: type, className: "size-[64%]" }) }));
|
|
37
|
+
}
|
|
38
|
+
export { ProviderBadge };
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { RadioGroup as RadioGroupPrimitive } from '@base-ui/react/radio-group';
|
|
2
|
+
import { Radio } from '@base-ui/react/radio';
|
|
3
|
+
declare function RadioGroup({ className, ...props }: RadioGroupPrimitive.Props): import("react").JSX.Element;
|
|
4
|
+
declare function RadioGroupItem({ className, ...props }: Radio.Root.Props): import("react").JSX.Element;
|
|
5
|
+
export { RadioGroup, RadioGroupItem };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { RadioGroup as RadioGroupPrimitive } from '@base-ui/react/radio-group';
|
|
3
|
+
import { Radio } from '@base-ui/react/radio';
|
|
4
|
+
import { motion } from '../../motion/index.js';
|
|
5
|
+
import { scale, transitions } from '../../motion/config.js';
|
|
6
|
+
import { cn } from '../../lib/utils.js';
|
|
7
|
+
/** Indicator dot pops in with a spring scale when the radio is selected. */
|
|
8
|
+
function renderRadioIndicator(props, state) {
|
|
9
|
+
return (_jsx(motion.span, { ...props, initial: false, animate: { opacity: state.checked ? 1 : 0, scale: state.checked ? 1 : scale.pop }, transition: transitions.pop }));
|
|
10
|
+
}
|
|
11
|
+
function RadioGroup({ className, ...props }) {
|
|
12
|
+
return (_jsx(RadioGroupPrimitive, { "data-slot": "radio-group", className: cn('grid gap-2', className), ...props }));
|
|
13
|
+
}
|
|
14
|
+
function RadioGroupItem({ className, ...props }) {
|
|
15
|
+
return (_jsx(Radio.Root, { "data-slot": "radio-group-item", className: cn(
|
|
16
|
+
// Match Checkbox: flex + shrink-0 so size-4 holds on the Base UI <span>
|
|
17
|
+
// and the indicator dot stays centered (without flex it sits off-kilter
|
|
18
|
+
// and card rows with items-start look vertically broken).
|
|
19
|
+
'relative flex aspect-square size-4 shrink-0 items-center justify-center rounded-full border border-primary text-primary shadow transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 data-checked:bg-primary', className), ...props, children: _jsx(Radio.Indicator, { "data-slot": "radio-group-indicator", render: renderRadioIndicator, keepMounted: true, className: "flex items-center justify-center", children: _jsx("span", { className: "block size-2 rounded-full bg-background" }) }) }));
|
|
20
|
+
}
|
|
21
|
+
export { RadioGroup, RadioGroupItem };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { ComponentProps, ReactNode } from 'react';
|
|
2
|
+
interface ReplySummaryProps extends Omit<ComponentProps<'button'>, 'children'> {
|
|
3
|
+
avatars: ReactNode;
|
|
4
|
+
/** The reply count, or its full label ("3 Replies"). */
|
|
5
|
+
count: ReactNode;
|
|
6
|
+
lastReplyAt: ReactNode;
|
|
7
|
+
label: string;
|
|
8
|
+
status?: ReactNode;
|
|
9
|
+
/**
|
|
10
|
+
* The counts have not arrived yet. Same box as the loaded chip, but inert: pass skeletons for the
|
|
11
|
+
* slots that are still unknown and keep the rest, so the chip only fills in when the data lands.
|
|
12
|
+
*/
|
|
13
|
+
pending?: boolean;
|
|
14
|
+
}
|
|
15
|
+
declare function ReplySummary({ avatars, count, lastReplyAt, label, status, pending, disabled, className, ...props }: ReplySummaryProps): import("react").JSX.Element;
|
|
16
|
+
export { ReplySummary, type ReplySummaryProps };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { cn } from '../../lib/utils.js';
|
|
3
|
+
function ReplySummary({ avatars, count, lastReplyAt, label, status, pending = false, disabled, className, ...props }) {
|
|
4
|
+
return (_jsxs("button", { type: "button", "aria-label": label, "aria-busy": pending || undefined, disabled: pending || disabled, "data-pending": pending ? '' : undefined, "data-slot": "reply-summary",
|
|
5
|
+
// 8px padding inside a border that only takes colour on hover.
|
|
6
|
+
className: cn('flex w-full min-w-0 cursor-pointer items-center gap-2 rounded-[8px] border border-transparent p-2 text-start text-body-2 outline-none transition-[background-color,border-color,box-shadow]', '[@media(hover:hover)]:hover:border-border [@media(hover:hover)]:hover:bg-background [@media(hover:hover)]:hover:shadow-xs focus-visible:ring-2 focus-visible:ring-ring', pending && 'pointer-events-none', className), ...props, children: [avatars, _jsx("span", { className: "shrink-0 whitespace-nowrap text-primary tabular-nums", children: count }), _jsx("span", { "data-slot": "reply-summary-last", className: "min-w-0 truncate whitespace-nowrap text-muted-foreground", children: lastReplyAt }), status] }));
|
|
7
|
+
}
|
|
8
|
+
export { ReplySummary };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { Group, Panel, Separator } from 'react-resizable-panels';
|
|
3
|
+
declare function ResizablePanelGroup({ className, ...props }: React.ComponentProps<typeof Group>): React.JSX.Element;
|
|
4
|
+
declare function ResizablePanel({ ...props }: React.ComponentProps<typeof Panel>): React.JSX.Element;
|
|
5
|
+
declare function ResizableHandle({ withHandle, className, ...props }: React.ComponentProps<typeof Separator> & {
|
|
6
|
+
withHandle?: boolean;
|
|
7
|
+
}): React.JSX.Element;
|
|
8
|
+
export { ResizablePanelGroup, ResizablePanel, ResizableHandle };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
import { Group, Panel, Separator } from 'react-resizable-panels';
|
|
4
|
+
import { cn } from '../../lib/utils.js';
|
|
5
|
+
import { GripVertical as GripVerticalIcon } from '../../icons/index.js';
|
|
6
|
+
function ResizablePanelGroup({ className, ...props }) {
|
|
7
|
+
return (_jsx(Group, { "data-slot": "resizable-panel-group", className: cn('flex h-full w-full data-[orientation=vertical]:flex-col', className), ...props }));
|
|
8
|
+
}
|
|
9
|
+
function ResizablePanel({ ...props }) {
|
|
10
|
+
return _jsx(Panel, { "data-slot": "resizable-panel", ...props });
|
|
11
|
+
}
|
|
12
|
+
function ResizableHandle({ withHandle, className, ...props }) {
|
|
13
|
+
return (_jsx(Separator, { "data-slot": "resizable-handle", className: cn('relative flex w-px items-center justify-center bg-border after:absolute after:inset-y-0 after:left-1/2 after:w-1 after:-translate-x-1/2 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-1 data-[orientation=vertical]:h-px data-[orientation=vertical]:w-full data-[orientation=vertical]:after:left-0 data-[orientation=vertical]:after:h-1 data-[orientation=vertical]:after:w-full data-[orientation=vertical]:after:-translate-y-1/2 data-[orientation=vertical]:after:translate-x-0', className), ...props, children: withHandle && (_jsx("div", { className: "z-10 flex h-4 w-3 items-center justify-center rounded-sm border bg-border", children: _jsx(GripVerticalIcon, { className: "size-2.5" }) })) }));
|
|
14
|
+
}
|
|
15
|
+
export { ResizablePanelGroup, ResizablePanel, ResizableHandle };
|