@av-pi-studio/ui-library 0.0.0-stage → 0.0.115

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/README.md +137 -2
  3. package/dist/brand/config.d.ts +125 -0
  4. package/dist/brand/index.d.ts +3 -0
  5. package/dist/brand/index.js +6 -0
  6. package/dist/brand/theme-injection.d.ts +9 -0
  7. package/dist/breakpoints.d.ts +34 -0
  8. package/dist/breakpoints.js +32 -0
  9. package/dist/chunks/theme-injection-BHAAhBYz.js +103 -0
  10. package/dist/chunks/token-guard-B85Ysv3w.js +813 -0
  11. package/dist/index.d.ts +13 -0
  12. package/dist/index.js +1049 -0
  13. package/dist/kv-store.d.ts +3 -0
  14. package/dist/primitives/Announcer.d.ts +13 -0
  15. package/dist/primitives/Avatar.d.ts +15 -0
  16. package/dist/primitives/Button.d.ts +18 -0
  17. package/dist/primitives/Checkbox.d.ts +11 -0
  18. package/dist/primitives/Dialog.d.ts +58 -0
  19. package/dist/primitives/Divider.d.ts +10 -0
  20. package/dist/primitives/EmptyState.d.ts +11 -0
  21. package/dist/primitives/Icon.d.ts +20 -0
  22. package/dist/primitives/IconButton.d.ts +25 -0
  23. package/dist/primitives/Menu.d.ts +50 -0
  24. package/dist/primitives/Panel.d.ts +9 -0
  25. package/dist/primitives/Popover.d.ts +25 -0
  26. package/dist/primitives/ResizeHandle.d.ts +20 -0
  27. package/dist/primitives/ScreenTitle.d.ts +15 -0
  28. package/dist/primitives/ScrollArea.d.ts +11 -0
  29. package/dist/primitives/Select.d.ts +25 -0
  30. package/dist/primitives/Shortcut.d.ts +15 -0
  31. package/dist/primitives/Spinner.d.ts +14 -0
  32. package/dist/primitives/StatusBadge.d.ts +13 -0
  33. package/dist/primitives/StatusDot.d.ts +17 -0
  34. package/dist/primitives/Surface.d.ts +13 -0
  35. package/dist/primitives/Switch.d.ts +14 -0
  36. package/dist/primitives/TextInput.d.ts +14 -0
  37. package/dist/primitives/ToastViewport.d.ts +17 -0
  38. package/dist/primitives/helpers.d.ts +47 -0
  39. package/dist/primitives/index.d.ts +24 -0
  40. package/dist/primitives/useHover.d.ts +16 -0
  41. package/dist/reset.css +43 -0
  42. package/dist/stores/announcer-store.d.ts +37 -0
  43. package/dist/stores/toast-store.d.ts +37 -0
  44. package/dist/styles.css +1 -0
  45. package/dist/theme/ThemeBoundary.d.ts +38 -0
  46. package/dist/theme/appearance-store.d.ts +37 -0
  47. package/dist/theme/color-utils.d.ts +13 -0
  48. package/dist/theme/colors.d.ts +111 -0
  49. package/dist/theme/css-bridge.d.ts +21 -0
  50. package/dist/theme/dev-warnings.d.ts +23 -0
  51. package/dist/theme/index.d.ts +10 -0
  52. package/dist/theme/index.js +39 -0
  53. package/dist/theme/palette.d.ts +19 -0
  54. package/dist/theme/theme.d.ts +47 -0
  55. package/dist/theme/token-guard.d.ts +20 -0
  56. package/dist/theme/tokens.d.ts +105 -0
  57. package/dist/theme/variants.d.ts +12 -0
  58. package/dist/ui/avatar.d.ts +11 -0
  59. package/dist/ui/button.d.ts +34 -0
  60. package/dist/ui/combobox.d.ts +55 -0
  61. package/dist/ui/index.d.ts +10 -0
  62. package/dist/ui/index.js +406 -0
  63. package/dist/ui/option-groups.d.ts +36 -0
  64. package/dist/ui/screen-header.d.ts +23 -0
  65. package/dist/ui/shortcut.d.ts +13 -0
  66. package/dist/ui/status-badge.d.ts +15 -0
  67. package/dist/ui/status-dot.d.ts +20 -0
  68. package/dist/ui/toast.d.ts +60 -0
  69. package/package.json +68 -4
@@ -0,0 +1,3 @@
1
+ import { type KeyValueStore } from "./theme/appearance-store.js";
2
+ export declare const localStorageKvStore: KeyValueStore;
3
+ //# sourceMappingURL=kv-store.d.ts.map
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Announcer — the app's one off-screen `aria-live` region for `features/agent-ui/announce.ts`'s
3
+ * § 08 pending-question transitions and § 11 `notify`/`set_editor_text` copy (sprint-069/task-008).
4
+ * Mount exactly once, at the app-shell level — `WorkspacePage.tsx`, alongside `ToastViewport`.
5
+ *
6
+ * Two separate always-mounted regions, one `role="status"` (`aria-live="polite"`) and one
7
+ * `role="alert"` (implicit `aria-live="assertive"`) — toggling a single element's `aria-live`
8
+ * value at runtime is not reliably picked up by assistive tech, so `announcer-store.ts`'s
9
+ * `politeness` instead selects which of these two ever receives text; the other is left empty,
10
+ * which is itself silent (removing/never-setting content is not announced).
11
+ */
12
+ export declare function Announcer(): import("react").JSX.Element;
13
+ //# sourceMappingURL=Announcer.d.ts.map
@@ -0,0 +1,15 @@
1
+ /**
2
+ * ProjectAvatar — shows a data-URI image or a deterministic colored initial fallback.
3
+ * ui-components.md § Surfaces / badges / chips / avatars
4
+ */
5
+ export interface AvatarProps {
6
+ /** Project/entity key used to derive color + initial when no image. */
7
+ projectKey: string;
8
+ /** Optional data URI (or any image URL) to show instead of the fallback. */
9
+ src?: string;
10
+ /** Size in pixels (both width and height). */
11
+ size?: number;
12
+ className?: string;
13
+ }
14
+ export declare function Avatar({ projectKey, src, size, className }: AvatarProps): import("react").JSX.Element;
15
+ //# sourceMappingURL=Avatar.d.ts.map
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Button — pressable with variant/size/state, styled from --pi-* CSS variables.
3
+ * ui-components.md § Pressables
4
+ */
5
+ import { type ReactNode, type Ref, type ButtonHTMLAttributes } from "react";
6
+ import { type ButtonVariant, type ButtonSize } from "../ui/button.js";
7
+ export interface ButtonProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, "children"> {
8
+ variant?: ButtonVariant;
9
+ size?: ButtonSize;
10
+ loading?: boolean;
11
+ leftIcon?: ReactNode;
12
+ trailing?: ReactNode;
13
+ iconOnly?: boolean;
14
+ children?: ReactNode;
15
+ ref?: Ref<HTMLButtonElement>;
16
+ }
17
+ export declare function Button({ variant, size, loading, disabled, leftIcon, trailing, iconOnly, children, style, className, ref, ...rest }: ButtonProps): import("react").JSX.Element;
18
+ //# sourceMappingURL=Button.d.ts.map
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Checkbox — accessible checkbox control.
3
+ * ui-components.md § Inputs & form controls
4
+ */
5
+ import { type InputHTMLAttributes, type ReactNode } from "react";
6
+ export interface CheckboxProps extends Omit<InputHTMLAttributes<HTMLInputElement>, "type"> {
7
+ label?: ReactNode;
8
+ checked?: boolean;
9
+ }
10
+ export declare const Checkbox: import("react").ForwardRefExoticComponent<CheckboxProps & import("react").RefAttributes<HTMLInputElement>>;
11
+ //# sourceMappingURL=Checkbox.d.ts.map
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Dialog — generic centered modal chrome (overlay + card + header/title/close + optional footer),
3
+ * wrapping Radix `Dialog` (design-system.md § Overlays: `@radix-ui/react-dialog` for
4
+ * dialogs/menus/tooltips/popovers). Every feature-specific modal (workspace picker today; rename/
5
+ * confirm dialogs later) SHOULD build on this instead of hand-rolling `Dialog.Root/Portal/Overlay/
6
+ * Content` again — only the body content and footer actions vary per use.
7
+ */
8
+ import { type ComponentPropsWithoutRef, type ReactNode } from "react";
9
+ import * as RadixDialog from "@radix-ui/react-dialog";
10
+ export interface DialogProps {
11
+ open: boolean;
12
+ onOpenChange: (open: boolean) => void;
13
+ title: string;
14
+ /** Body content between the header and the optional footer. */
15
+ children?: ReactNode;
16
+ /** Sticky action row rendered under the body (e.g. Cancel/Confirm buttons). */
17
+ footer?: ReactNode;
18
+ /** Content card width; defaults to 500px (design-system.md § Overlays desktop dialog sizing). */
19
+ width?: number | string;
20
+ /** Extra class applied to the content card, for callers that need to tweak body sizing. */
21
+ className?: string;
22
+ /**
23
+ * Omit the header bar's reserved height and float the close button over the body instead.
24
+ * Use for content (e.g. an image lightbox) that should sit dead-center in the viewport rather
25
+ * than be pushed down by an asymmetric top-only header. `title` remains as an accessible
26
+ * (visually hidden) label for the dialog.
27
+ */
28
+ bare?: boolean;
29
+ /**
30
+ * Forwarded to Radix `Dialog.Content`. Call `preventDefault()` to keep this dialog open —
31
+ * REQUIRED when a second dialog is stacked on top of this one: the two contents are DOM
32
+ * siblings (each portals to `body`), so a pointerdown inside the upper dialog reads as an
33
+ * outside-interaction on this one and would otherwise dismiss both at once.
34
+ */
35
+ onInteractOutside?: ComponentPropsWithoutRef<typeof RadixDialog.Content>["onInteractOutside"];
36
+ onEscapeKeyDown?: ComponentPropsWithoutRef<typeof RadixDialog.Content>["onEscapeKeyDown"];
37
+ /**
38
+ * Forwarded to Radix `Dialog.Content`. Radix's own default restores focus to whatever had it
39
+ * before the dialog opened; call `preventDefault()` and focus a specific element instead when
40
+ * that default is wrong for this dialog's own state (e.g. after closing back to a caller-chosen
41
+ * fallback rather than nothing).
42
+ */
43
+ onCloseAutoFocus?: ComponentPropsWithoutRef<typeof RadixDialog.Content>["onCloseAutoFocus"];
44
+ /**
45
+ * Forwarded to Radix `Dialog.Content`. Radix's own default on open focuses the first focusable
46
+ * descendant in DOM order — which is always this primitive's own header Close button, since it
47
+ * is rendered before `children`, regardless of any `autoFocus` a caller places on a body/footer
48
+ * element (React's native `autofocus` commit does not reliably win a race against Radix's own
49
+ * `FocusScope` mount effect). Call `preventDefault()` and focus the desired element explicitly
50
+ * whenever the default Close-button focus is wrong for this dialog's content.
51
+ */
52
+ onOpenAutoFocus?: ComponentPropsWithoutRef<typeof RadixDialog.Content>["onOpenAutoFocus"];
53
+ }
54
+ /** Re-exported so callers can wrap a footer button in `<Dialog.Close asChild>` to auto-dismiss
55
+ * without threading `onOpenChange(false)` through their own click handler. */
56
+ export declare const DialogClose: import("react").ForwardRefExoticComponent<RadixDialog.DialogCloseProps & import("react").RefAttributes<HTMLButtonElement>>;
57
+ export declare function Dialog({ open, onOpenChange, title, children, footer, width, className, bare, onInteractOutside, onEscapeKeyDown, onCloseAutoFocus, onOpenAutoFocus, }: DialogProps): import("react").JSX.Element;
58
+ //# sourceMappingURL=Dialog.d.ts.map
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Divider — a 1px separator line.
3
+ * ui-components.md § Scroll & dividers
4
+ */
5
+ export interface DividerProps {
6
+ orientation?: "horizontal" | "vertical";
7
+ className?: string;
8
+ }
9
+ export declare function Divider({ orientation, className }: DividerProps): import("react").JSX.Element;
10
+ //# sourceMappingURL=Divider.d.ts.map
@@ -0,0 +1,11 @@
1
+ /**
2
+ * EmptyState — centered, muted placeholder text (loading/error/no-results states) — the shared
3
+ * shape behind FileExplorer/ChangesPanel/OpenWorkspaceDialog/SessionList's plain-text variant and
4
+ * FilePanel/MoleculeViewer's `<Spinner/> Loading…` variant (both are a centered flex row; a
5
+ * lone text child renders identically to the plain-text sites' old `text-align: center`).
6
+ * ui-components.md § Feedback
7
+ */
8
+ import { type HTMLAttributes } from "react";
9
+ export type EmptyStateProps = HTMLAttributes<HTMLDivElement>;
10
+ export declare function EmptyState({ className, ...rest }: EmptyStateProps): import("react").JSX.Element;
11
+ //# sourceMappingURL=EmptyState.d.ts.map
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Icon — lucide-react wrapper honouring iconSize tokens.
3
+ * ui-components.md § Icons
4
+ */
5
+ import { type LucideIcon } from "lucide-react";
6
+ /** Token name → pixel size (matches design-system.md § iconSize). */
7
+ export type IconSizeToken = "xs" | "sm" | "md" | "lg";
8
+ declare const ICON_SIZE_PX: Record<IconSizeToken, number>;
9
+ export interface IconProps {
10
+ icon: LucideIcon;
11
+ size?: IconSizeToken | number;
12
+ /** CSS color value OR a --pi-color-* CSS variable reference. */
13
+ color?: string;
14
+ className?: string;
15
+ "aria-hidden"?: boolean;
16
+ "aria-label"?: string;
17
+ }
18
+ export declare function Icon({ icon: LucideComponent, size, color, className, ...ariaProps }: IconProps): import("react").JSX.Element;
19
+ export { ICON_SIZE_PX };
20
+ //# sourceMappingURL=Icon.d.ts.map
@@ -0,0 +1,25 @@
1
+ /**
2
+ * IconButton — compact, chromeless icon affordance for row actions and menu triggers (file-row
3
+ * "⋮", session-row "⋮", workspace-header chevron/"⋮", Dialog's inline close, TabStrip's "+").
4
+ * Distinct from `Button`'s `iconOnly` mode: `Button` sizes from 28px up (a labeled-CTA minimum
5
+ * tap target) and hovers to a fixed `surface1` — too large and the wrong hover color for a tiny
6
+ * hover-reveal affordance sitting inside an already-compact row (20px tall, in flow, reserved
7
+ * box + opacity-on-row-hover, sprint-062) against a variety of ambient backgrounds
8
+ * (`surfaceSidebar`/`surface2`/page `background`/`surface1`, matching each row's own container —
9
+ * see `--icon-btn-hover-base` below). ui-components.md § Pressables
10
+ */
11
+ import { type ButtonHTMLAttributes } from "react";
12
+ export type IconButtonSize = "xs" | "sm";
13
+ export interface IconButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
14
+ /** `xs` (20px) — row actions and menu triggers, the common case. `sm` (28px) — a standalone
15
+ * button not embedded in a compact row, e.g. Dialog's inline header close. */
16
+ size?: IconButtonSize;
17
+ /** Overrides the hover background's base color (mixed 85/15 with `foreground`, matching
18
+ * `theme/color-utils.ts`'s app-wide hover-lift recipe) — defaults to `--pi-color-surface1`,
19
+ * the right base for a button sitting directly on a panel surface. A button sitting on a
20
+ * different ambient background (the sidebar, page background, a workspace header) passes the
21
+ * matching token, e.g. `hoverBase="var(--pi-color-surfaceSidebar)"`. */
22
+ hoverBase?: string;
23
+ }
24
+ export declare function IconButton({ size, hoverBase, className, style, type, ...rest }: IconButtonProps): import("react").JSX.Element;
25
+ //# sourceMappingURL=IconButton.d.ts.map
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Menu — shared chrome for every Radix `DropdownMenu` popup in the app (file/session/workspace
3
+ * right-click context menus, TabStrip's "+" menu, ModelMenu's picker). `DropdownMenu.Root` and
4
+ * `.Trigger` need no shared styling and stay imported directly from `@radix-ui/react-dropdown-menu`
5
+ * at each call site; this only wraps the pieces that were previously four (or more) byte-identical
6
+ * CSS Modules: the invisible cursor-anchored trigger button used by every right-click menu, the
7
+ * popover surface, the row, the separator, and the labelled section header for grouped pickers
8
+ * (`MenuGroup`, whose data half is `ui/option-groups.ts`).
9
+ * ui-components.md § Menus & popovers
10
+ */
11
+ import { type ComponentPropsWithoutRef } from "react";
12
+ import * as DropdownMenu from "@radix-ui/react-dropdown-menu";
13
+ export interface MenuCursorTriggerProps {
14
+ /** Viewport coordinates (from the triggering `contextmenu`/click event) to anchor the popup at. */
15
+ x: number;
16
+ y: number;
17
+ }
18
+ /** Invisible 1x1 trigger positioned at cursor coordinates — the shared shape behind every
19
+ * right-click context menu: `DropdownMenu.Trigger asChild` wraps this so Radix anchors its
20
+ * popover at the click point instead of at a visible element. */
21
+ export declare const MenuCursorTrigger: import("react").ForwardRefExoticComponent<MenuCursorTriggerProps & import("react").RefAttributes<HTMLButtonElement>>;
22
+ export interface MenuContentProps extends ComponentPropsWithoutRef<typeof DropdownMenu.Content> {
23
+ /** Popover min-width — right-click menus default to a narrow 140-160px; wider pickers (e.g.
24
+ * ModelMenu) override. */
25
+ minWidth?: number;
26
+ }
27
+ /** Popover surface (background/border/radius/shadow) + Radix portal, `align="start"` and a
28
+ * `sideOffset` of 2 to match the tight right-click-menu default; callers with a visible,
29
+ * button-style trigger (TabStrip's "+" menu, ModelMenu) pass a larger `sideOffset`. */
30
+ export declare function MenuContent({ className, minWidth, style, sideOffset, ...rest }: MenuContentProps): import("react").JSX.Element;
31
+ export interface MenuGroupProps extends ComponentPropsWithoutRef<typeof DropdownMenu.Group> {
32
+ /** Section header text. Omit for an unlabelled section (the ungrouped bucket
33
+ * `ui/option-groups.ts`'s `groupOptions` puts last) — the group still nests its items, it just
34
+ * renders no header row. */
35
+ label?: string;
36
+ }
37
+ /** Labelled section of menu items — the render half of the grouped-picker mechanic whose data
38
+ * half is `ui/option-groups.ts`. The header is a Radix `DropdownMenu.Label`, which is
39
+ * deliberately NOT focusable, so roving focus and typeahead skip headers with no extra work at
40
+ * the call site. It sticks to the top of whatever scroll container the group sits in (see
41
+ * `.groupLabel`), so the provider/section a row belongs to stays visible while scrolling a long
42
+ * list — the whole point of grouping a picker that outgrew one flat list. */
43
+ export declare function MenuGroup({ label, className, children, ...rest }: MenuGroupProps): import("react").JSX.Element;
44
+ export interface MenuItemProps extends ComponentPropsWithoutRef<typeof DropdownMenu.Item> {
45
+ /** Destructive action styling (delete/archive/remove — red text). */
46
+ danger?: boolean;
47
+ }
48
+ export declare function MenuItem({ className, danger, ...rest }: MenuItemProps): import("react").JSX.Element;
49
+ export declare function MenuSeparator(props: ComponentPropsWithoutRef<typeof DropdownMenu.Separator>): import("react").JSX.Element;
50
+ //# sourceMappingURL=Menu.d.ts.map
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Panel — full-height flex-column container, the shell every tab/sidebar panel starts from
3
+ * (ChatPanel, FilePanel, MoleculeViewerPanel, RightSidebar, TextViewer, SessionList — all were
4
+ * byte-identical local `.panel`/`.wrap` CSS classes). ui-components.md § Surfaces
5
+ */
6
+ import { type HTMLAttributes } from "react";
7
+ export type PanelProps = HTMLAttributes<HTMLDivElement>;
8
+ export declare function Panel({ className, ...rest }: PanelProps): import("react").JSX.Element;
9
+ //# sourceMappingURL=Panel.d.ts.map
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Popover — shared chrome for Radix `Popover` surfaces: anchored, non-modal panels that host
3
+ * interactive content such as a text field. A `DropdownMenu` is the wrong primitive for those (its
4
+ * typeahead and roving focus fight text input), so `Menu.tsx`'s sibling here wraps
5
+ * `@radix-ui/react-popover` the same way: `Root`/`Trigger` need no shared styling and are plain
6
+ * passthroughs; only the portal + surface is wrapped, with the `Menu` surface tokens.
7
+ * ui-components.md § Overlays
8
+ */
9
+ import type { ComponentPropsWithoutRef } from "react";
10
+ import * as RadixPopover from "@radix-ui/react-popover";
11
+ export declare const Popover: {
12
+ Root: import("react").FC<RadixPopover.PopoverProps>;
13
+ Trigger: import("react").ForwardRefExoticComponent<RadixPopover.PopoverTriggerProps & import("react").RefAttributes<HTMLButtonElement>>;
14
+ Anchor: import("react").ForwardRefExoticComponent<RadixPopover.PopoverAnchorProps & import("react").RefAttributes<HTMLDivElement>>;
15
+ Close: import("react").ForwardRefExoticComponent<RadixPopover.PopoverCloseProps & import("react").RefAttributes<HTMLButtonElement>>;
16
+ };
17
+ export interface PopoverContentProps extends ComponentPropsWithoutRef<typeof RadixPopover.Content> {
18
+ /** Surface width in px; the panel is otherwise sized by its content. */
19
+ width?: number;
20
+ }
21
+ /** Portaled popover surface. Defaults: below the trigger, `align="start"`, 6px offset, and an
22
+ * 8px collision padding so it never touches the viewport edge. Radix returns focus to the trigger
23
+ * on close and dismisses on Escape/outside press by default. */
24
+ export declare function PopoverContent({ className, width, style, side, align, sideOffset, collisionPadding, ...rest }: PopoverContentProps): import("react").JSX.Element;
25
+ //# sourceMappingURL=Popover.d.ts.map
@@ -0,0 +1,20 @@
1
+ /**
2
+ * ResizeHandle — thin draggable strip for resizing an adjacent sidebar (`WorkspacePage`'s
3
+ * `sidebarLeft`/`sidebarRight`). Pointer-driven: `pointerdown` starts a drag, `pointermove`
4
+ * reports the raw pixel delta since the last move, `pointerup` ends it. Width clamping and
5
+ * persistence live in the caller (`ui-store.ts`'s `setLeftSidebarWidth`/`setRightSidebarWidth`) —
6
+ * this component only ever reports deltas, never owns or reads the width itself.
7
+ *
8
+ * The drag explicitly captures its pointer to the handle so it survives the cursor crossing a
9
+ * cross-document child (`HtmlViewer`'s preview iframe) — see `handlePointerDown`.
10
+ */
11
+ export interface ResizeHandleProps {
12
+ /** Which sidebar this handle resizes. Left sidebar grows when dragged right (positive delta);
13
+ * right sidebar shrinks when dragged right (its left edge moves right into the panel) — `side`
14
+ * picks the correct sign so the caller only ever adds the raw delta to its current width. */
15
+ side: "left" | "right";
16
+ onResize(deltaX: number): void;
17
+ className?: string;
18
+ }
19
+ export declare function ResizeHandle({ side, onResize, className }: ResizeHandleProps): import("react").JSX.Element;
20
+ //# sourceMappingURL=ResizeHandle.d.ts.map
@@ -0,0 +1,15 @@
1
+ /**
2
+ * ScreenTitle — canonical top-of-screen title. Mirrors Paseo's
3
+ * `components/headers/screen-title.tsx`: fontSize base, weight 400 on compact /
4
+ * 300 on desktop, `foreground` color. Leading icons/badges are siblings, never
5
+ * nested inside this component.
6
+ *
7
+ * swe docs/design.md §3 (hierarchy via weight+color, not size).
8
+ */
9
+ import type { ReactNode } from "react";
10
+ export interface ScreenTitleProps {
11
+ children: ReactNode;
12
+ className?: string;
13
+ }
14
+ export declare function ScreenTitle({ children, className }: ScreenTitleProps): import("react").JSX.Element;
15
+ //# sourceMappingURL=ScreenTitle.d.ts.map
@@ -0,0 +1,11 @@
1
+ /**
2
+ * ScrollArea — a themed scrollable container.
3
+ * ui-components.md § Scroll & dividers
4
+ */
5
+ import { type ReactNode, type HTMLAttributes } from "react";
6
+ export interface ScrollAreaProps extends HTMLAttributes<HTMLDivElement> {
7
+ axis?: "both" | "x" | "y";
8
+ children?: ReactNode;
9
+ }
10
+ export declare function ScrollArea({ axis, className, children, ...rest }: ScrollAreaProps): import("react").JSX.Element;
11
+ //# sourceMappingURL=ScrollArea.d.ts.map
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Select + Combobox — form selection controls.
3
+ * Select = native <select> styled for theme consistency.
4
+ * Combobox = filterable text input + dropdown list, consuming sprint-012 combobox model.
5
+ * ui-components.md § Inputs & form controls
6
+ */
7
+ import { type SelectHTMLAttributes } from "react";
8
+ import { type ComboboxOption } from "../ui/combobox.js";
9
+ export interface SelectProps extends SelectHTMLAttributes<HTMLSelectElement> {
10
+ options: {
11
+ value: string;
12
+ label: string;
13
+ }[];
14
+ placeholder?: string;
15
+ }
16
+ export declare const Select: import("react").ForwardRefExoticComponent<SelectProps & import("react").RefAttributes<HTMLSelectElement>>;
17
+ export interface ComboboxProps {
18
+ options: ComboboxOption<string>[];
19
+ value?: string;
20
+ onSelect?: (value: string) => void;
21
+ placeholder?: string;
22
+ className?: string;
23
+ }
24
+ export declare function Combobox({ options, value, onSelect, placeholder, className, }: ComboboxProps): import("react").JSX.Element;
25
+ //# sourceMappingURL=Select.d.ts.map
@@ -0,0 +1,15 @@
1
+ /**
2
+ * ShortcutHint — displays keyboard shortcut chip(s).
3
+ * ui-components.md § Shortcut
4
+ */
5
+ import { type OsFamily } from "../ui/shortcut.js";
6
+ export interface ShortcutProps {
7
+ /** A single combo string e.g. "cmd+k". */
8
+ combo?: string;
9
+ /** A sequence of combos e.g. ["cmd+k", "cmd+s"]. */
10
+ chord?: string[];
11
+ os?: OsFamily;
12
+ className?: string;
13
+ }
14
+ export declare function ShortcutHint({ combo, chord, os, className }: ShortcutProps): import("react").JSX.Element | null;
15
+ //# sourceMappingURL=Shortcut.d.ts.map
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Spinner — a thin activity-indicator circle.
3
+ * ui-components.md § Feedback
4
+ */
5
+ export type SpinnerSize = "xs" | "sm" | "md" | "lg";
6
+ export interface SpinnerProps {
7
+ size?: SpinnerSize | number;
8
+ /** CSS color string; defaults to currentColor. */
9
+ color?: string;
10
+ className?: string;
11
+ "aria-label"?: string;
12
+ }
13
+ export declare function Spinner({ size, color, className, "aria-label": ariaLabel, }: SpinnerProps): import("react").JSX.Element;
14
+ //# sourceMappingURL=Spinner.d.ts.map
@@ -0,0 +1,13 @@
1
+ /**
2
+ * StatusBadge — small rounded pill with variant coloring.
3
+ * ui-components.md § Surfaces / badges / chips / avatars
4
+ */
5
+ import { type ReactNode } from "react";
6
+ import { type StatusBadgeVariant } from "../ui/status-badge.js";
7
+ export interface StatusBadgeProps {
8
+ label: ReactNode;
9
+ variant: StatusBadgeVariant;
10
+ className?: string;
11
+ }
12
+ export declare function StatusBadge({ label, variant, className }: StatusBadgeProps): import("react").JSX.Element;
13
+ //# sourceMappingURL=StatusBadge.d.ts.map
@@ -0,0 +1,17 @@
1
+ /**
2
+ * AgentStatusDot — 8×8 circle whose color reflects agent status.
3
+ * ui-components.md § Status dots & avatars
4
+ */
5
+ import { type StatusDotInput } from "../ui/status-dot.js";
6
+ export type StatusDotProps = StatusDotInput & {
7
+ className?: string;
8
+ /** Opt-in box-shadow ring, local to the needs-input state (sprint-069/task-002) — never part of
9
+ * `StatusDot`'s default rendering, so every other status/caller is unaffected. Defaults off. */
10
+ pulse?: boolean;
11
+ /** When set, the dot becomes an accessible element carrying this name instead of the default
12
+ * `role="presentation"` (§ 08: "no dot is ever colour-only") — sprint-069/task-003. Omitted ⇒
13
+ * today's decorative default, unchanged for every existing caller. */
14
+ "aria-label"?: string;
15
+ };
16
+ export declare function StatusDot({ className, pulse, "aria-label": ariaLabel, ...input }: StatusDotProps): import("react").JSX.Element | null;
17
+ //# sourceMappingURL=StatusDot.d.ts.map
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Surface / Card — an elevated container reading surface tokens.
3
+ * ui-components.md § Surfaces / badges / chips / avatars
4
+ */
5
+ import { type ReactNode, type HTMLAttributes } from "react";
6
+ import { type SurfaceElevation } from "./helpers.js";
7
+ export interface SurfaceProps extends HTMLAttributes<HTMLDivElement> {
8
+ elevation?: SurfaceElevation;
9
+ noBorder?: boolean;
10
+ children?: ReactNode;
11
+ }
12
+ export declare function Surface({ elevation, noBorder, className, children, ...rest }: SurfaceProps): import("react").JSX.Element;
13
+ //# sourceMappingURL=Surface.d.ts.map
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Switch — animated toggle control.
3
+ * ui-components.md § Inputs & form controls (Switch)
4
+ */
5
+ export interface SwitchProps {
6
+ checked: boolean;
7
+ onCheckedChange: (checked: boolean) => void;
8
+ disabled?: boolean;
9
+ id?: string;
10
+ "aria-label"?: string;
11
+ className?: string;
12
+ }
13
+ export declare function Switch({ checked, onCheckedChange, disabled, id, "aria-label": ariaLabel, className, }: SwitchProps): import("react").JSX.Element;
14
+ //# sourceMappingURL=Switch.d.ts.map
@@ -0,0 +1,14 @@
1
+ /**
2
+ * TextInput / TextArea — form input controls.
3
+ * ui-components.md § Inputs & form controls (AdaptiveTextInput)
4
+ */
5
+ import { type InputHTMLAttributes, type TextareaHTMLAttributes } from "react";
6
+ export interface TextInputProps extends InputHTMLAttributes<HTMLInputElement> {
7
+ className?: string;
8
+ }
9
+ export declare const TextInput: import("react").ForwardRefExoticComponent<TextInputProps & import("react").RefAttributes<HTMLInputElement>>;
10
+ export interface TextAreaProps extends TextareaHTMLAttributes<HTMLTextAreaElement> {
11
+ className?: string;
12
+ }
13
+ export declare const TextArea: import("react").ForwardRefExoticComponent<TextAreaProps & import("react").RefAttributes<HTMLTextAreaElement>>;
14
+ //# sourceMappingURL=TextInput.d.ts.map
@@ -0,0 +1,17 @@
1
+ /**
2
+ * ToastViewport — single top-anchored toast stack, portalled to `document.body` (`Dialog.tsx`'s
3
+ * `Portal` precedent; this app has no dedicated named overlay-root element, so `document.body`
4
+ * matches what Radix's own `Portal` already defaults to for every other overlay). Mount exactly
5
+ * once, at the app-shell level — `WorkspacePage.tsx`. ui-components.md § Feedback; visual spec §
6
+ * 01 (`surface1` + per-variant rail), § 11 (stacking), § 13 (reduced motion).
7
+ *
8
+ * Exit animation is owned here, not in `toast-store.ts`: the store's `dismiss` is an immediate,
9
+ * synchronous array removal — kept deliberately simple and Node-testable (task-005's own test
10
+ * plan). This component instead keeps a small local cache of every toast it has rendered, and — on
11
+ * noticing an id leave the store's array, from *either* auto-dismiss or a manual close click, both
12
+ * of which only ever mutate the store — renders it a little longer with an `.exiting` class so its
13
+ * opacity/slide transition can play, before dropping it from local state. Reduced motion skips the
14
+ * lingering entirely: the exiting id is dropped in the same tick it leaves the store (§ 13).
15
+ */
16
+ export declare function ToastViewport(): import("react").ReactPortal | null;
17
+ //# sourceMappingURL=ToastViewport.d.ts.map
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Pure helper functions for the DOM primitive components.
3
+ * Kept in a .ts file (no CSS imports) so they are testable in the node environment.
4
+ * design-system.md § Hover-to-show, ui-components.md § Pressables
5
+ */
6
+ import { type ButtonVariant, type ButtonSize, BUTTON_MIN_HEIGHT, BUTTON_PADDING_H, BUTTON_FONT_SIZE, BUTTON_ICON_SIZE, resolveButtonState, buttonIconColorToken, ghostHoverIconToken } from "../ui/button.js";
7
+ import { statusDotColor, type StatusDotInput } from "../ui/status-dot.js";
8
+ export { BUTTON_MIN_HEIGHT, BUTTON_PADDING_H, BUTTON_FONT_SIZE, BUTTON_ICON_SIZE, resolveButtonState, buttonIconColorToken, ghostHoverIconToken, type ButtonVariant, type ButtonSize, };
9
+ /**
10
+ * Returns true when a hover-revealed control should be visible.
11
+ * visible = isHovered || isNative || isCompact
12
+ * On Pi-Studio (web-only), isNative is always false.
13
+ */
14
+ export declare function hoverVisible(isHovered: boolean, isNative: boolean, isCompact: boolean): boolean;
15
+ export type ButtonAriaAttrs = {
16
+ disabled: boolean;
17
+ "aria-disabled": boolean | undefined;
18
+ "aria-busy": boolean | undefined;
19
+ tabIndex: number;
20
+ };
21
+ /**
22
+ * Derive accessible DOM attributes for a button from its logical state.
23
+ */
24
+ export declare function buttonAriaAttrs(opts: {
25
+ disabled: boolean;
26
+ loading: boolean;
27
+ }): ButtonAriaAttrs;
28
+ export type ButtonInlineStyle = {
29
+ minHeight: number;
30
+ paddingLeft: number;
31
+ paddingRight: number;
32
+ fontSize: string;
33
+ opacity: number;
34
+ };
35
+ export declare function buttonInlineStyle(opts: {
36
+ size: ButtonSize;
37
+ variant: ButtonVariant;
38
+ pressed: boolean;
39
+ disabled: boolean;
40
+ loading: boolean;
41
+ }): ButtonInlineStyle;
42
+ export declare function buttonIconPx(size: ButtonSize): number;
43
+ export type SurfaceElevation = 0 | 1 | 2 | 3 | 4;
44
+ export declare function surfaceBgVar(elevation: SurfaceElevation): string;
45
+ export { statusDotColor, type StatusDotInput };
46
+ export declare function statusDotVisible(input: StatusDotInput): boolean;
47
+ //# sourceMappingURL=helpers.d.ts.map
@@ -0,0 +1,24 @@
1
+ export { Button, type ButtonProps } from "./Button.js";
2
+ export { IconButton, type IconButtonProps, type IconButtonSize } from "./IconButton.js";
3
+ export { Icon, type IconProps, type IconSizeToken, ICON_SIZE_PX } from "./Icon.js";
4
+ export { StatusDot, type StatusDotProps } from "./StatusDot.js";
5
+ export { StatusBadge, type StatusBadgeProps } from "./StatusBadge.js";
6
+ export { Avatar, type AvatarProps } from "./Avatar.js";
7
+ export { ShortcutHint, type ShortcutProps } from "./Shortcut.js";
8
+ export { Spinner, type SpinnerProps, type SpinnerSize } from "./Spinner.js";
9
+ export { Divider, type DividerProps } from "./Divider.js";
10
+ export { Switch, type SwitchProps } from "./Switch.js";
11
+ export { Surface, type SurfaceProps } from "./Surface.js";
12
+ export { Panel, type PanelProps } from "./Panel.js";
13
+ export { EmptyState, type EmptyStateProps } from "./EmptyState.js";
14
+ export { TextInput, TextArea, type TextInputProps, type TextAreaProps } from "./TextInput.js";
15
+ export { ScrollArea, type ScrollAreaProps } from "./ScrollArea.js";
16
+ export { Checkbox, type CheckboxProps } from "./Checkbox.js";
17
+ export { Select, Combobox, type SelectProps, type ComboboxProps } from "./Select.js";
18
+ export { Dialog, DialogClose, type DialogProps } from "./Dialog.js";
19
+ export { ResizeHandle, type ResizeHandleProps } from "./ResizeHandle.js";
20
+ export { MenuCursorTrigger, MenuContent, MenuGroup, MenuItem, MenuSeparator, type MenuCursorTriggerProps, type MenuContentProps, type MenuGroupProps, type MenuItemProps, } from "./Menu.js";
21
+ export { Popover, PopoverContent, type PopoverContentProps } from "./Popover.js";
22
+ export { useHover, type UseHoverReturn } from "./useHover.js";
23
+ export { hoverVisible, buttonAriaAttrs, buttonInlineStyle, buttonIconPx, surfaceBgVar, statusDotVisible, type SurfaceElevation, type ButtonAriaAttrs, type ButtonInlineStyle, } from "./helpers.js";
24
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,16 @@
1
+ /**
2
+ * useHover — pointer-enter/leave hover tracking for web.
3
+ * design-system.md § Hover-to-show
4
+ * Raw pointer events only used inside this hook (web-safe; never a layout signal).
5
+ */
6
+ export interface UseHoverReturn {
7
+ isHovered: boolean;
8
+ hoverProps: {
9
+ onPointerEnter: () => void;
10
+ onPointerLeave: () => void;
11
+ };
12
+ /** True when the control should be visible per hover-to-show rule. */
13
+ isVisible: (isCompact?: boolean) => boolean;
14
+ }
15
+ export declare function useHover(): UseHoverReturn;
16
+ //# sourceMappingURL=useHover.d.ts.map
package/dist/reset.css ADDED
@@ -0,0 +1,43 @@
1
+ /* Global reset — zero the browser default body margin, paint the themed page background, and
2
+ theme the scrollbars. Color/type tokens are injected as `--pi-*` CSS variables at runtime by
3
+ the theme system (see src/theme/css-bridge.ts, applied via ThemeBoundary).
4
+ Opt-in: an app embedding the library into a host page can skip this file. App-specific layout
5
+ (e.g. `#root` sizing) belongs in the app's own stylesheet, not here. */
6
+ /* Root font-size is left at the browser default (100% / 16px) so `rem` tracks the user's own
7
+ zoom / accessibility text-size setting untouched — no app-level multiplier layered on top.
8
+ No CSS module hardcodes a font-size: every one is `var(--pi-font-size-<rung>)`, emitted as rem
9
+ by theme/css-bridge.ts's `pxToRem` from theme/tokens.ts's `baseFontSize`. That table is the one
10
+ lever for the app's text size; there is no root-percentage override to keep in sync with it,
11
+ and the font-scale guard test fails the build if a literal or a dangling rung creeps back in. */
12
+ html,
13
+ body {
14
+ margin: 0;
15
+ padding: 0;
16
+ }
17
+
18
+ body {
19
+ min-height: 100vh;
20
+ overflow: hidden;
21
+ background: var(--pi-color-background);
22
+ color: var(--pi-color-foreground);
23
+ font-family: var(--pi-font-ui);
24
+ }
25
+
26
+ *,
27
+ *::before,
28
+ *::after {
29
+ box-sizing: border-box;
30
+ }
31
+
32
+ /* Scrollbar theming */
33
+ ::-webkit-scrollbar {
34
+ width: 6px;
35
+ height: 6px;
36
+ }
37
+ ::-webkit-scrollbar-track {
38
+ background: transparent;
39
+ }
40
+ ::-webkit-scrollbar-thumb {
41
+ background: var(--pi-color-border);
42
+ border-radius: var(--pi-radius-base);
43
+ }