@indxsearch/systm 2.7.0 → 2.10.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/CHANGELOG.md CHANGED
@@ -5,6 +5,41 @@ All notable changes to @indxsearch/systm will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [2.10.0] - 2026-09-15
9
+
10
+ ### Added
11
+
12
+ - Chat family, promoted from the components-gallery mockup: `ChatPanel` (header /
13
+ scrolling thread / composer / hints frame, with `Kbd` and `defaultChatHints`),
14
+ `UserMessage` and `AssistantMessage`, `Composer` (Enter sends, Shift+Enter breaks
15
+ the line, grows to `maxLines`, Send becomes Stop while `streaming`), `CitationRef`
16
+ (inline numbered mark) and `CitationList` (numbered chips with a source-type icon),
17
+ `StreamStatus`, `Suggestions` and `AnswerActions` (Copy + Ask a follow-up). First
18
+ used by the docs assistant in indx-docs. Not yet in Blazor.
19
+
20
+ ## [2.9.0] - 2026-09-12
21
+
22
+ ### Added
23
+
24
+ - `Alert`, `AlertTitle`, `AlertDescription`: an in-page callout with variants
25
+ `default` / `info` / `success` / `warning` / `destructive`, a default icon per
26
+ variant (`icon` overrides, `null` suppresses), and `role="alert"` for
27
+ warning/destructive. No shadow; the variant colours the icon, title and a 2px
28
+ start edge. Ported to Blazor.
29
+ - Tokens `--CLightBlue` and `--CWarning` in globals.css, matching the Blazor side.
30
+
31
+ ## [2.8.0] - 2026-09-11
32
+
33
+ ### Added
34
+
35
+ - `Breadcrumbs`: page trail where each step is a link and may carry an
36
+ independent context switcher (`switcher`: current value, options, and an
37
+ optional `action` entry such as "New team…" that runs instead of selecting).
38
+ Sizes `micro` and `default`; step icons render at 14px. Ported to Blazor.
39
+ - `NavigationMenu`: Radix navigation menu with Systm styling (`NavigationMenu`,
40
+ `NavigationMenuList`, `NavigationMenuItem`, `NavigationMenuTrigger`,
41
+ `NavigationMenuContent`, `NavigationMenuLink`). Not yet in Blazor.
42
+
8
43
  ## [2.7.0] - 2026-09-08
9
44
 
10
45
  ### Added
package/README.md CHANGED
@@ -109,8 +109,48 @@ import '@indxsearch/systm/patterns.css'; // Or import patterns standalone
109
109
  }
110
110
  ```
111
111
 
112
+ ## NavigationMenu
113
+
114
+ Composable site navigation with direct links and dropdown panels, powered by
115
+ Radix and styled with Systm colors, sharp corners, and Pixl dropdown icons.
116
+ Use `micro` (30px, `--text-xs`) or `default` (40px, `--text-sm`). Leading trigger
117
+ icons use 14px, with Button-matched gaps of 7px and 10px respectively.
118
+
119
+ ```tsx
120
+ import {
121
+ NavigationMenu, NavigationMenuList, NavigationMenuItem,
122
+ NavigationMenuTrigger, NavigationMenuContent, NavigationMenuLink,
123
+ } from '@indxsearch/systm';
124
+
125
+ <NavigationMenu size="default" aria-label="Site navigation">
126
+ <NavigationMenuList>
127
+ <NavigationMenuItem>
128
+ <NavigationMenuTrigger>Explore</NavigationMenuTrigger>
129
+ <NavigationMenuContent>
130
+ <NavigationMenuLink href="/datasets">Datasets</NavigationMenuLink>
131
+ <NavigationMenuLink href="/teams">Teams</NavigationMenuLink>
132
+ </NavigationMenuContent>
133
+ </NavigationMenuItem>
134
+ <NavigationMenuItem>
135
+ <NavigationMenuLink variant="navigation" href="/" active>
136
+ Overview
137
+ </NavigationMenuLink>
138
+ </NavigationMenuItem>
139
+ </NavigationMenuList>
140
+ </NavigationMenu>
141
+ ```
142
+
143
+ Use `asChild` on links to wrap a router Link. Triggers accept an `icon` element
144
+ and `disabled`; links accept `active` for the current page. Panels support custom
145
+ layouts such as grids and descriptions. The shared dropdown viewport is included
146
+ by the root and fits its width up to 560px. Radix root props such as `value`,
147
+ `onValueChange`, and `delayDuration` are forwarded. See `/navigation-menu` in the
148
+ component viewer for interactive examples.
149
+
112
150
  ## Dependencies
113
151
 
152
+ - `@radix-ui/react-navigation-menu` - Site navigation primitives
153
+
114
154
  - `@indxsearch/pixl` - Icon library
115
155
  - `@radix-ui/react-dialog` - Modal/dialog primitives
116
156
  - `@radix-ui/react-popover` - Popover component primitives
@@ -0,0 +1,24 @@
1
+ import { default as React } from 'react';
2
+ export type AlertVariant = 'default' | 'info' | 'success' | 'warning' | 'destructive';
3
+ export interface AlertProps {
4
+ /** Tone. `destructive` for errors and irreversible outcomes, `warning` for things that need
5
+ * attention, `success` for a completed action, `info` for neutral notices. */
6
+ variant?: AlertVariant;
7
+ /** Leading icon; defaults per variant (none for `default` and `info`). Pass `null` to suppress. */
8
+ icon?: React.ReactNode;
9
+ className?: string;
10
+ /** Use `AlertTitle` and `AlertDescription` for the standard layout; any content works. */
11
+ children: React.ReactNode;
12
+ role?: 'alert' | 'status';
13
+ }
14
+ /** A callout that stays in the flow of the page — for outcomes and conditions the reader must
15
+ * not miss, not for transient toasts. Title and description are optional; an alert can be one line. */
16
+ export declare const Alert: React.FC<AlertProps>;
17
+ export declare const AlertTitle: React.FC<{
18
+ children: React.ReactNode;
19
+ className?: string;
20
+ }>;
21
+ export declare const AlertDescription: React.FC<{
22
+ children: React.ReactNode;
23
+ className?: string;
24
+ }>;
@@ -0,0 +1,34 @@
1
+ import { default as React } from 'react';
2
+ import { SelectOption } from '../Select/Select';
3
+ export interface BreadcrumbItem {
4
+ id: string;
5
+ label: string;
6
+ href?: string;
7
+ onClick?: React.MouseEventHandler<HTMLAnchorElement>;
8
+ /** Leading icon; icon components receive Button-compatible size and color props. */
9
+ icon?: React.ReactNode;
10
+ /** Supply a switcher to show an independent dropdown beside the page link. */
11
+ switcher?: {
12
+ label: string;
13
+ value: string;
14
+ options: SelectOption[];
15
+ onValueChange: (value: string) => void;
16
+ disabled?: boolean;
17
+ /** Optional entry below the options — typically "New …" — that runs instead of selecting. */
18
+ action?: {
19
+ label: string;
20
+ onSelect: () => void;
21
+ };
22
+ };
23
+ }
24
+ export interface BreadcrumbsProps {
25
+ items: BreadcrumbItem[];
26
+ size?: 'micro' | 'default';
27
+ className?: string;
28
+ separator?: React.ReactNode;
29
+ /** Return a router link, forwarding these anchor props to preserve styling and accessibility. */
30
+ renderLink?: (item: BreadcrumbItem, props: React.ComponentPropsWithoutRef<'a'>) => React.ReactNode;
31
+ 'aria-label'?: string;
32
+ }
33
+ /** Page navigation with independently controlled context switchers. */
34
+ export declare const Breadcrumbs: React.FC<BreadcrumbsProps>;
@@ -7,6 +7,10 @@ type ButtonBaseProps = {
7
7
  size?: 'micro' | 'default' | 'large';
8
8
  variant?: 'primary' | 'secondary' | 'ghost';
9
9
  disabled?: boolean;
10
+ /** The action behind this button is in progress: a Spinner takes the left-icon slot and the
11
+ * button is disabled until it clears. Set it on every button that starts work the user has
12
+ * to wait for, so a slow operation never reads as a dead click. */
13
+ loading?: boolean;
10
14
  iconLeft?: React.ReactElement<IconProps>;
11
15
  iconRight?: React.ReactElement<IconProps>;
12
16
  className?: string;
@@ -0,0 +1,10 @@
1
+ export interface AnswerActionsProps {
2
+ onCopy?: () => void;
3
+ /** Flip briefly after `onCopy` to acknowledge the copy. */
4
+ copied?: boolean;
5
+ onFollowUp?: () => void;
6
+ followUpLabel?: string;
7
+ className?: string;
8
+ }
9
+ /** The row under a finished answer: Copy on the left, the follow-up prompt on the right. */
10
+ export declare function AnswerActions({ onCopy, copied, onFollowUp, followUpLabel, className }: AnswerActionsProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,24 @@
1
+ import { default as React } from 'react';
2
+ export interface ChatPanelProps {
3
+ /** Rendered above the thread — typically a mode `Tabs`. */
4
+ header?: React.ReactNode;
5
+ /** The conversation: messages, status lines, suggestions. Scrolls independently. */
6
+ children: React.ReactNode;
7
+ /** Rendered below the thread — typically a `Composer`. */
8
+ composer?: React.ReactNode;
9
+ /** Keyboard hints under the composer; `false` hides the row. */
10
+ hints?: React.ReactNode | false;
11
+ className?: string;
12
+ /** Ref to the scrolling thread, so a caller can keep the newest message in view. */
13
+ threadRef?: React.Ref<HTMLDivElement>;
14
+ 'aria-label'?: string;
15
+ }
16
+ /** Keyboard hint pill for the hints row. */
17
+ export declare function Kbd({ children }: {
18
+ children: React.ReactNode;
19
+ }): import("react/jsx-runtime").JSX.Element;
20
+ /** Default hints: Enter sends, Shift+Enter breaks a line, Escape closes. */
21
+ export declare const defaultChatHints: import("react/jsx-runtime").JSX.Element;
22
+ /** The frame of a conversation: optional header, a scrolling thread, the composer and a hints row.
23
+ * Sized by its container — give it a height (or let a modal/dialog do so) and the thread scrolls. */
24
+ export declare function ChatPanel({ header, children, composer, hints, className, threadRef, 'aria-label': ariaLabel }: ChatPanelProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,33 @@
1
+ import { default as React } from 'react';
2
+ interface IconProps {
3
+ size?: string | number;
4
+ color?: string;
5
+ }
6
+ export interface CitationRefProps {
7
+ /** The number the source list shows for this citation. */
8
+ n: number;
9
+ /** Where the source lives; rendered as a link when given. */
10
+ href?: string;
11
+ onClick?: (e: React.MouseEvent) => void;
12
+ title?: string;
13
+ className?: string;
14
+ }
15
+ /** Numbered inline mark that sits in the running text and points at an entry in `CitationList`. */
16
+ export declare function CitationRef({ n, href, onClick, title, className }: CitationRefProps): import("react/jsx-runtime").JSX.Element;
17
+ export interface CitationItem {
18
+ n: number;
19
+ title: string;
20
+ href?: string;
21
+ /** Icon of the source type — a pixl icon element. */
22
+ icon?: React.ReactElement<IconProps>;
23
+ onClick?: (e: React.MouseEvent) => void;
24
+ }
25
+ export interface CitationListProps {
26
+ items: CitationItem[];
27
+ /** Heading over the list. */
28
+ label?: string;
29
+ className?: string;
30
+ }
31
+ /** The sources an answer drew on, as a row of numbered chips. */
32
+ export declare function CitationList({ items, label, className }: CitationListProps): import("react/jsx-runtime").JSX.Element | null;
33
+ export {};
@@ -0,0 +1,26 @@
1
+ import { default as React } from 'react';
2
+ export interface ComposerProps {
3
+ value: string;
4
+ onChange: (value: string) => void;
5
+ /** Called with the trimmed text on Enter or the send button. Not called while `streaming`. */
6
+ onSend: (text: string) => void;
7
+ /** Called by the Stop button, which replaces Send while `streaming`. */
8
+ onStop?: () => void;
9
+ /** An answer is in flight: the send button becomes Stop and Enter does nothing. */
10
+ streaming?: boolean;
11
+ placeholder?: string;
12
+ disabled?: boolean;
13
+ autoFocus?: boolean;
14
+ /** Leading icon; defaults to the pixl AI agent. `null` hides it. */
15
+ icon?: React.ReactNode;
16
+ /** Tallest the field grows before it scrolls, in lines. */
17
+ maxLines?: number;
18
+ className?: string;
19
+ 'aria-label'?: string;
20
+ }
21
+ export interface ComposerHandle {
22
+ focus: () => void;
23
+ }
24
+ /** The message field. Enter sends, Shift+Enter breaks the line; the field grows with its text up
25
+ * to `maxLines`. Send becomes Stop while an answer streams. */
26
+ export declare const Composer: React.ForwardRefExoticComponent<ComposerProps & React.RefAttributes<ComposerHandle>>;
@@ -0,0 +1,18 @@
1
+ import { default as React } from 'react';
2
+ export interface UserMessageProps {
3
+ children: React.ReactNode;
4
+ className?: string;
5
+ }
6
+ /** What the person typed: right-aligned, on a raised tone. Line breaks are kept. */
7
+ export declare function UserMessage({ children, className }: UserMessageProps): import("react/jsx-runtime").JSX.Element;
8
+ export interface AssistantMessageProps {
9
+ /** Name shown above the answer. */
10
+ label?: string;
11
+ /** Icon before the name; defaults to the pixl AI agent. */
12
+ icon?: React.ReactNode;
13
+ /** The answer and anything under it — `StreamStatus`, `CitationList`, `AnswerActions`. */
14
+ children: React.ReactNode;
15
+ className?: string;
16
+ }
17
+ /** The assistant's turn: a small labelled head, then whatever the answer is made of. */
18
+ export declare function AssistantMessage({ label, icon, children, className }: AssistantMessageProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,7 @@
1
+ import { default as React } from 'react';
2
+ export interface StreamStatusProps {
3
+ children: React.ReactNode;
4
+ className?: string;
5
+ }
6
+ /** One quiet line saying what the assistant is doing right now — "Searching the docs…", "Writing…". */
7
+ export declare function StreamStatus({ children, className }: StreamStatusProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,9 @@
1
+ export interface SuggestionsProps {
2
+ items: string[];
3
+ onPick: (text: string) => void;
4
+ /** Heading over the row. */
5
+ label?: string;
6
+ className?: string;
7
+ }
8
+ /** Questions to start from, shown while the thread is empty. */
9
+ export declare function Suggestions({ items, onPick, label, className }: SuggestionsProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,7 @@
1
+ export { ChatPanel, Kbd, defaultChatHints, type ChatPanelProps } from './ChatPanel';
2
+ export { UserMessage, AssistantMessage, type UserMessageProps, type AssistantMessageProps } from './Message';
3
+ export { Composer, type ComposerProps, type ComposerHandle } from './Composer';
4
+ export { CitationRef, CitationList, type CitationRefProps, type CitationItem, type CitationListProps } from './Citation';
5
+ export { StreamStatus, type StreamStatusProps } from './StreamStatus';
6
+ export { Suggestions, type SuggestionsProps } from './Suggestions';
7
+ export { AnswerActions, type AnswerActionsProps } from './AnswerActions';
@@ -0,0 +1,25 @@
1
+ import { default as React } from 'react';
2
+ import * as Primitive from '@radix-ui/react-navigation-menu';
3
+ export interface NavigationMenuProps extends React.ComponentPropsWithoutRef<typeof Primitive.Root> {
4
+ size?: 'micro' | 'default';
5
+ }
6
+ /** Compose with List, Item, Trigger, Content and Link. The shared panel is included. */
7
+ export declare const NavigationMenu: React.ForwardRefExoticComponent<NavigationMenuProps & React.RefAttributes<HTMLElement>>;
8
+ export declare const NavigationMenuList: React.ForwardRefExoticComponent<Omit<Primitive.NavigationMenuListProps & React.RefAttributes<HTMLUListElement>, "ref"> & React.RefAttributes<HTMLUListElement>>;
9
+ export declare const NavigationMenuItem: React.ForwardRefExoticComponent<Primitive.NavigationMenuItemProps & React.RefAttributes<HTMLLIElement>>;
10
+ type Icon = React.ReactElement<{
11
+ size?: string | number;
12
+ color?: string;
13
+ }>;
14
+ export interface NavigationMenuTriggerProps extends Omit<React.ComponentPropsWithoutRef<typeof Primitive.Trigger>, 'asChild'> {
15
+ icon?: Icon;
16
+ }
17
+ export declare const NavigationMenuTrigger: React.ForwardRefExoticComponent<NavigationMenuTriggerProps & React.RefAttributes<HTMLButtonElement>>;
18
+ export declare const NavigationMenuContent: React.ForwardRefExoticComponent<Omit<Primitive.NavigationMenuContentProps & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
19
+ export interface NavigationMenuLinkProps extends React.ComponentPropsWithoutRef<typeof Primitive.Link> {
20
+ /** Use navigation for a direct link in the top-level list. */
21
+ variant?: 'navigation' | 'panel';
22
+ }
23
+ /** Supports asChild for React Router and other link components. */
24
+ export declare const NavigationMenuLink: React.ForwardRefExoticComponent<NavigationMenuLinkProps & React.RefAttributes<HTMLAnchorElement>>;
25
+ export {};