@photon-ai/pho-ui 2.13.0 → 2.15.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.
Files changed (70) hide show
  1. package/dist/chunks/IconChevronRight-CzoJnYNI.js +11 -0
  2. package/dist/chunks/IconChevronRight-CzoJnYNI.js.map +1 -0
  3. package/dist/chunks/{basic-page-CJwG4I83.js → basic-page-CVZT_zaH.js} +619 -614
  4. package/dist/chunks/basic-page-CVZT_zaH.js.map +1 -0
  5. package/dist/chunks/code-block-CdozzaHM.js +139 -0
  6. package/dist/chunks/code-block-CdozzaHM.js.map +1 -0
  7. package/dist/chunks/combobox-D4LiGJB2.js +136 -0
  8. package/dist/chunks/combobox-D4LiGJB2.js.map +1 -0
  9. package/dist/chunks/command-Ck8IAgV7.js +192 -0
  10. package/dist/chunks/command-Ck8IAgV7.js.map +1 -0
  11. package/dist/chunks/copy-button-B_B15mEi.js +56 -0
  12. package/dist/chunks/copy-button-B_B15mEi.js.map +1 -0
  13. package/dist/chunks/description-list-C-mwe4ki.js +59 -0
  14. package/dist/chunks/description-list-C-mwe4ki.js.map +1 -0
  15. package/dist/chunks/filter-bar-Cjjq38xo.js +259 -0
  16. package/dist/chunks/filter-bar-Cjjq38xo.js.map +1 -0
  17. package/dist/chunks/log-list-0AXnjFrk.js +244 -0
  18. package/dist/chunks/log-list-0AXnjFrk.js.map +1 -0
  19. package/dist/chunks/toggle-o84tawXy.js +33 -0
  20. package/dist/chunks/toggle-o84tawXy.js.map +1 -0
  21. package/dist/chunks/tooltip-BTF7GChl.js +32 -0
  22. package/dist/chunks/tooltip-BTF7GChl.js.map +1 -0
  23. package/dist/chunks/trace-CbH0IohX.js +314 -0
  24. package/dist/chunks/trace-CbH0IohX.js.map +1 -0
  25. package/dist/chunks/use-copy-D6JwKUll.js +25 -0
  26. package/dist/chunks/use-copy-D6JwKUll.js.map +1 -0
  27. package/dist/components/code-block.js +6 -0
  28. package/dist/components/combobox.js +1 -1
  29. package/dist/components/command.js +3 -189
  30. package/dist/components/copy-button.js +6 -0
  31. package/dist/components/description-list.js +5 -0
  32. package/dist/components/filter-bar.js +8 -0
  33. package/dist/components/log-list.js +8 -0
  34. package/dist/components/phone-input.js +1 -1
  35. package/dist/components/toggle.js +3 -30
  36. package/dist/components/tooltip.js +2 -29
  37. package/dist/components/trace.js +9 -0
  38. package/dist/index.js +122 -96
  39. package/dist/primitives.js +2 -2
  40. package/dist/sections/basic-page.js +17 -17
  41. package/dist/src/components/accordion/index.d.ts +1 -1
  42. package/dist/src/components/code-block/code-block.d.ts +43 -0
  43. package/dist/src/components/code-block/index.d.ts +2 -0
  44. package/dist/src/components/code-block/tokenize-json.d.ts +12 -0
  45. package/dist/src/components/combobox/combobox.d.ts +30 -4
  46. package/dist/src/components/combobox/index.d.ts +1 -1
  47. package/dist/src/components/copy-button/copy-button.d.ts +49 -0
  48. package/dist/src/components/copy-button/index.d.ts +1 -0
  49. package/dist/src/components/description-list/description-list.d.ts +60 -0
  50. package/dist/src/components/description-list/index.d.ts +1 -0
  51. package/dist/src/components/filter-bar/filter-bar.d.ts +101 -0
  52. package/dist/src/components/filter-bar/index.d.ts +1 -0
  53. package/dist/src/components/log-list/index.d.ts +1 -0
  54. package/dist/src/components/log-list/log-list.d.ts +136 -0
  55. package/dist/src/components/trace/index.d.ts +2 -0
  56. package/dist/src/components/trace/layout.d.ts +48 -0
  57. package/dist/src/components/trace/trace.d.ts +53 -0
  58. package/dist/src/index.d.ts +6 -0
  59. package/dist/src/sections/basic-page/basic-page.d.ts +34 -24
  60. package/dist/src/utils/index.d.ts +1 -0
  61. package/dist/src/utils/use-copy.d.ts +14 -0
  62. package/dist/utils.js +6 -3
  63. package/package.json +25 -1
  64. package/src/styles/theme.css +30 -0
  65. package/dist/chunks/basic-page-CJwG4I83.js.map +0 -1
  66. package/dist/chunks/combobox-Dj5m_dDd.js +0 -117
  67. package/dist/chunks/combobox-Dj5m_dDd.js.map +0 -1
  68. package/dist/components/command.js.map +0 -1
  69. package/dist/components/toggle.js.map +0 -1
  70. package/dist/components/tooltip.js.map +0 -1
@@ -0,0 +1,43 @@
1
+ import { ComponentProps, ReactNode, Ref } from 'react';
2
+ /**
3
+ * Code Block — a read-only panel for a request body, a response, an
4
+ * event's JSON. Mono text on the code surface, a title row with a wrap
5
+ * toggle and a copy control, and past `maxLines` a fold that shows the
6
+ * first lines with a button for the rest.
7
+ *
8
+ * Design notes:
9
+ * - Wide lines scroll sideways inside the panel; the page never does.
10
+ * Wrapping is a toggle (`wrap` / `defaultWrap`), off by default so a
11
+ * body reads the way it was sent.
12
+ * - `language="json"` colors keys, strings, numbers, and keywords with a
13
+ * built-in tokenizer — no highlighter library at runtime — on the
14
+ * `--color-pho-code-*` tokens, which carry light and dark.
15
+ * - A body that isn't a string (an object) is pretty-printed as JSON.
16
+ */
17
+ export type CodeBlockLanguage = "json" | "text";
18
+ export interface CodeBlockProps extends Omit<ComponentProps<"div">, "title" | "children"> {
19
+ /** The text. An object is pretty-printed as JSON (two-space indent). */
20
+ code?: string | object | null;
21
+ /** `json` colors the text; `text` leaves it plain. @default "text" */
22
+ language?: CodeBlockLanguage;
23
+ /** The title row's words — "Request body", "Response". */
24
+ title?: ReactNode;
25
+ /** Past this many lines the panel folds. @default 30 */
26
+ maxLines?: number;
27
+ /** Wrap long lines (controlled). */
28
+ wrap?: boolean;
29
+ /** Wrap long lines at first (uncontrolled). @default false */
30
+ defaultWrap?: boolean;
31
+ onWrapChange?: (wrap: boolean) => void;
32
+ /** The copy control in the title row. @default true */
33
+ copy?: boolean;
34
+ /** What the panel says with no code. @default "Nothing to show." */
35
+ empty?: ReactNode;
36
+ /** More controls in the title row, before the built-in ones. */
37
+ actions?: ReactNode;
38
+ ref?: Ref<HTMLDivElement>;
39
+ }
40
+ export declare function CodeBlock({ code, language, title, maxLines, wrap: wrapProp, defaultWrap, onWrapChange, copy, empty, actions, className, ...props }: CodeBlockProps): import("react").JSX.Element;
41
+ export declare namespace CodeBlock {
42
+ var displayName: string;
43
+ }
@@ -0,0 +1,2 @@
1
+ export { CodeBlock, type CodeBlockProps, type CodeBlockLanguage, } from './code-block';
2
+ export { tokenizeJson, type JsonToken, type JsonTokenType, } from './tokenize-json';
@@ -0,0 +1,12 @@
1
+ /**
2
+ * A tokenizer for JSON, and nothing else: keys, strings, numbers, the
3
+ * three keywords, and punctuation. Runs one line at a time (a JSON
4
+ * string never spans lines) so a panel can show its first N lines and
5
+ * stop. Text that isn't JSON comes back as it is, in plain tokens.
6
+ */
7
+ export type JsonTokenType = "key" | "string" | "number" | "keyword" | "punctuation" | "plain";
8
+ export interface JsonToken {
9
+ type: JsonTokenType;
10
+ text: string;
11
+ }
12
+ export declare function tokenizeJson(line: string): JsonToken[];
@@ -5,9 +5,31 @@ type StyledProps<T extends ElementType> = Omit<ComponentProps<T>, "className"> &
5
5
  className?: string;
6
6
  };
7
7
  declare function InputGroup({ className, ...props }: StyledProps<typeof BaseCombobox.InputGroup>): import("react").JSX.Element;
8
- declare function Input({ className, ...props }: StyledProps<typeof BaseCombobox.Input>): import("react").JSX.Element;
8
+ export type ComboboxInputVariant = "field" | "popup";
9
+ declare function Input({ className, variant, ...props }: StyledProps<typeof BaseCombobox.Input> & {
10
+ /**
11
+ * `field` (default) is the boxed control a list filters under. `popup`
12
+ * is the search line at the top of the popup when a field `Trigger`
13
+ * stands in for the input: borderless, a hairline below, spanning the
14
+ * popup's width.
15
+ * @default "field"
16
+ */
17
+ variant?: ComboboxInputVariant;
18
+ }): import("react").JSX.Element;
9
19
  declare function Clear({ className, ...props }: StyledProps<typeof BaseCombobox.Clear>): import("react").JSX.Element;
10
- declare function Trigger({ className, ...props }: StyledProps<typeof BaseCombobox.Trigger>): import("react").JSX.Element;
20
+ export type ComboboxTriggerVariant = "icon" | "field";
21
+ declare function Trigger({ className, variant, disabled, ...props }: StyledProps<typeof BaseCombobox.Trigger> & {
22
+ /**
23
+ * `icon` (default) is the small button beside the input in an
24
+ * `InputGroup`. `field` is the whole control: `Select`'s trigger chrome
25
+ * around a `Combobox.Value` and a `Combobox.Icon`, for a searchable
26
+ * select whose `Input` then lives inside the popup (`variant="popup"`).
27
+ * @default "icon"
28
+ */
29
+ variant?: ComboboxTriggerVariant;
30
+ }): import("react").JSX.Element;
31
+ /** The glyph at a field trigger's end, `IconSelector` as on `Select`. */
32
+ declare function Icon({ className, ...props }: StyledProps<typeof BaseCombobox.Icon>): import("react").JSX.Element;
11
33
  declare function Positioner({ className, sideOffset, ...props }: StyledProps<typeof BaseCombobox.Positioner>): import("react").JSX.Element;
12
34
  declare function Popup({ className, ...props }: StyledProps<typeof BaseCombobox.Popup>): import("react").JSX.Element;
13
35
  declare function List({ className, ...props }: StyledProps<typeof BaseCombobox.List>): import("react").JSX.Element;
@@ -22,8 +44,11 @@ declare function ChipRemove({ className, ...props }: StyledProps<typeof BaseComb
22
44
  * Combobox built on Base UI `Combobox` — a text input that filters a list as
23
45
  * you type and commits to a value from it. Pass `items` to `Combobox.Root`;
24
46
  * `Combobox.List` takes a render function mapping each (filtered) item to a
25
- * `Combobox.Item`. Add `Combobox.Chips` for multi-select. For free-form text
26
- * with suggestions, use `Autocomplete`; for a small fixed set, use `Select`.
47
+ * `Combobox.Item`. Add `Combobox.Chips` for multi-select. For a searchable
48
+ * select, `Combobox.Trigger variant="field"` holds the `Value` and an
49
+ * `Icon`, and the `Input` (`variant="popup"`) moves inside the popup. For
50
+ * free-form text with suggestions, use `Autocomplete`; for a small fixed
51
+ * set, use `Select`.
27
52
  */
28
53
  export declare const Combobox: {
29
54
  Root: typeof BaseCombobox.Root;
@@ -31,6 +56,7 @@ export declare const Combobox: {
31
56
  InputGroup: typeof InputGroup;
32
57
  Input: typeof Input;
33
58
  Trigger: typeof Trigger;
59
+ Icon: typeof Icon;
34
60
  Clear: typeof Clear;
35
61
  Portal: import('react').ForwardRefExoticComponent<Omit<import('@base-ui/react').AutocompletePortalProps, "ref"> & import('react').RefAttributes<HTMLDivElement>>;
36
62
  Positioner: typeof Positioner;
@@ -1 +1 @@
1
- export { Combobox } from './combobox';
1
+ export { Combobox, type ComboboxInputVariant, type ComboboxTriggerVariant, } from './combobox';
@@ -0,0 +1,49 @@
1
+ import { ButtonHTMLAttributes, Ref } from 'react';
2
+ /**
3
+ * Size axis — a square ghost control that sits inside a row or a panel
4
+ * header. `sm` is the default: a 28px target beside 13px mono text.
5
+ */
6
+ export declare const COPY_BUTTON_SIZES: {
7
+ xs: {
8
+ classes: string;
9
+ description: string;
10
+ };
11
+ sm: {
12
+ classes: string;
13
+ description: string;
14
+ };
15
+ md: {
16
+ classes: string;
17
+ description: string;
18
+ };
19
+ };
20
+ export type CopyButtonSize = keyof typeof COPY_BUTTON_SIZES;
21
+ interface CopyButtonBaseProps {
22
+ /** The text that goes to the clipboard. */
23
+ value: string;
24
+ /**
25
+ * What is being copied, for the accessible name — "request id",
26
+ * "API key". Read as `Copy {label}`, then `{label} copied`.
27
+ * @default "to clipboard"
28
+ */
29
+ label?: string;
30
+ /** Size variant. @default "sm" */
31
+ size?: CopyButtonSize;
32
+ /** Called after the clipboard write lands. */
33
+ onCopied?: (value: string) => void;
34
+ ref?: Ref<HTMLButtonElement>;
35
+ }
36
+ export interface CopyButtonProps extends CopyButtonBaseProps, Omit<ButtonHTMLAttributes<HTMLButtonElement>, keyof CopyButtonBaseProps | "children"> {
37
+ }
38
+ /**
39
+ * Copy Button — the one copy affordance: a quiet icon button that writes
40
+ * `value` to the clipboard, swaps its glyph to a check for a moment, and
41
+ * says "Copied" to assistive tech through a polite live region. Ghost at
42
+ * rest so a mono value stays the loudest thing on its line; the wash and
43
+ * the ink lift on hover. Put it after the value it copies.
44
+ */
45
+ export declare function CopyButton({ value, label, size, onCopied, className, onClick, ...props }: CopyButtonProps): import("react").JSX.Element;
46
+ export declare namespace CopyButton {
47
+ var displayName: string;
48
+ }
49
+ export {};
@@ -0,0 +1 @@
1
+ export { CopyButton, COPY_BUTTON_SIZES, type CopyButtonProps, type CopyButtonSize, } from './copy-button';
@@ -0,0 +1,60 @@
1
+ import { ComponentProps, ReactNode, Ref } from 'react';
2
+ /**
3
+ * Description List — the facts about one record, label beside value:
4
+ * the status, the request id, the time, the ip, the api version, the
5
+ * idempotency key, the api key. A `<dl>` under the hood.
6
+ *
7
+ * Where `BasicPage.Row` is a 68px row built for a control on its right,
8
+ * these are dense lines of text: `inline` puts the label in a column
9
+ * beside the value, every label the same width (a subgrid), one line per
10
+ * fact; `stacked` puts the label above the value and flows the pairs
11
+ * into `columns`. A `mono` value wears the mono face with a copy
12
+ * control after it; a value that is not there says so in muted ink.
13
+ */
14
+ export type DescriptionListLayout = "inline" | "stacked";
15
+ export interface DescriptionListRootProps extends ComponentProps<"dl"> {
16
+ /**
17
+ * `inline` (default): label column beside the value column, one line
18
+ * per item. `stacked`: label above value, pairs flowing into `columns`.
19
+ */
20
+ layout?: DescriptionListLayout;
21
+ /** For `stacked`: pairs per row from `sm` up. @default 1 */
22
+ columns?: 1 | 2 | 3;
23
+ ref?: Ref<HTMLDListElement>;
24
+ }
25
+ declare function Root({ layout, columns, className, ...props }: DescriptionListRootProps): import("react").JSX.Element;
26
+ export interface DescriptionListItemProps extends Omit<ComponentProps<"div">, "children" | "title"> {
27
+ /** The fact's name — "Request ID", "Idempotency key". */
28
+ label: ReactNode;
29
+ /** The fact. A string wears the item's type; a node is yours to style. */
30
+ value?: ReactNode;
31
+ /** Composed content instead of `value` — a `Badge`, a link. */
32
+ children?: ReactNode;
33
+ /** The value in the mono face — ids, keys, addresses. */
34
+ mono?: boolean;
35
+ /**
36
+ * A copy control after the value. `true` copies a string `value`;
37
+ * pass the text to copy when the value is composed.
38
+ */
39
+ copy?: boolean | string;
40
+ /** Marks the label `(Optional)` — a fact that may not be there. */
41
+ optional?: boolean;
42
+ /** What an absent value says. @default "Not set" */
43
+ empty?: ReactNode;
44
+ ref?: Ref<HTMLDivElement>;
45
+ }
46
+ declare function Item({ label, value, children, mono, copy, optional, empty, className, ...props }: DescriptionListItemProps): import("react").JSX.Element;
47
+ /**
48
+ * ```tsx
49
+ * <DescriptionList.Root>
50
+ * <DescriptionList.Item label="Status"><Badge …/></DescriptionList.Item>
51
+ * <DescriptionList.Item label="Request ID" value="pho_req_…" mono copy />
52
+ * <DescriptionList.Item label="Idempotency key" optional mono copy />
53
+ * </DescriptionList.Root>
54
+ * ```
55
+ */
56
+ export declare const DescriptionList: {
57
+ Root: typeof Root;
58
+ Item: typeof Item;
59
+ };
60
+ export {};
@@ -0,0 +1 @@
1
+ export { DescriptionList, type DescriptionListLayout, type DescriptionListRootProps, type DescriptionListItemProps, } from './description-list';
@@ -0,0 +1,101 @@
1
+ import { ComponentProps, ReactNode, Ref } from 'react';
2
+ /**
3
+ * Filter Bar — the row that pins above a log list: a search field for an
4
+ * id, then one chip per filter. A chip with nothing chosen reads
5
+ * `+ Status`; with a value it reads `Status: Failed` and carries its own
6
+ * clear. Each chip opens a small popover: a keyboard-first list of
7
+ * options (with a search field past eight of them), or presets and a
8
+ * from / to pair for a date range.
9
+ *
10
+ * Design notes:
11
+ * - Fully controlled. The page owns `filters` and `search` and hands
12
+ * them back changed; the bar keeps no state but which popover is open.
13
+ * That keeps the query in one place (the URL, a store) and lets the
14
+ * list refetch from it.
15
+ * - Chips are real buttons (the trigger, and the clear beside it), so
16
+ * the bar is one tab stop per control and Escape closes a popover
17
+ * back onto its chip.
18
+ * - No scroll container of its own: chips wrap. `sticky` pins it to the
19
+ * top of the nearest scroll pane on the surface it sits on.
20
+ */
21
+ export interface FilterOption {
22
+ value: string;
23
+ label: string;
24
+ }
25
+ interface FilterDefinitionBase {
26
+ /** The key in `filters` this chip reads and writes. */
27
+ key: string;
28
+ /** The chip's word — "Status", "Event type". Sentence case. */
29
+ label: string;
30
+ }
31
+ export interface SelectFilterDefinition extends FilterDefinitionBase {
32
+ type?: "select";
33
+ options: readonly FilterOption[];
34
+ /** Several values at once (`string[]`); one at a time by default. */
35
+ multiple?: boolean;
36
+ /**
37
+ * A search field above the options. On by default past eight options,
38
+ * off below; say so to override.
39
+ */
40
+ searchable?: boolean;
41
+ /** The search field's placeholder. @default "Search" */
42
+ searchPlaceholder?: string;
43
+ }
44
+ /** A relative preset for a date-range filter — "Last 7 days" is 168 hours. */
45
+ export interface DateRangePreset {
46
+ label: string;
47
+ hours: number;
48
+ }
49
+ export interface DateRangeFilterDefinition extends FilterDefinitionBase {
50
+ type: "date-range";
51
+ /** The relative presets listed above the from / to pair. */
52
+ presets?: readonly DateRangePreset[];
53
+ }
54
+ export type FilterDefinition = SelectFilterDefinition | DateRangeFilterDefinition;
55
+ /**
56
+ * A date-range value. A preset stores an absolute ISO timestamp in `from`
57
+ * (computed when chosen) and its label in `preset`; the from / to pair
58
+ * stores plain `YYYY-MM-DD` dates. Either side may be open (`null`).
59
+ */
60
+ export interface DateRangeValue {
61
+ from: string | null;
62
+ to: string | null;
63
+ preset?: string;
64
+ }
65
+ export type FilterValue = string | string[] | DateRangeValue;
66
+ /** The page's filter state — one entry per definition key that is set. */
67
+ export type FilterValues = Record<string, FilterValue | undefined>;
68
+ /** The relative presets a date-range chip lists when given none. */
69
+ export declare const FILTER_DATE_PRESETS: readonly DateRangePreset[];
70
+ /** Whether a filter value counts as set — an empty string or list does not. */
71
+ export declare function isFilterSet(value: FilterValue | undefined): boolean;
72
+ /** The words a set chip shows after its label. */
73
+ export declare function formatFilterValue(definition: FilterDefinition, value: FilterValue | undefined): string;
74
+ export interface FilterBarProps extends Omit<ComponentProps<"div">, "children"> {
75
+ /** One chip per definition, in this order. */
76
+ definitions: readonly FilterDefinition[];
77
+ /** The values, keyed by definition key. Absent or empty means unset. */
78
+ filters: FilterValues;
79
+ /** The whole map, changed — set, cleared, or cleared all. */
80
+ onFiltersChange: (next: FilterValues) => void;
81
+ /** The search field's text. The field renders only with `onSearchChange`. */
82
+ search?: string;
83
+ onSearchChange?: (value: string) => void;
84
+ /** A teaching phrase — "Find an event by id". @default "Search" */
85
+ searchPlaceholder?: string;
86
+ /** The field's accessible name when the placeholder is too short to be one. */
87
+ searchLabel?: string;
88
+ /**
89
+ * Pin the bar to the top of the nearest scroll pane. It paints the
90
+ * surface it sits on (`--pho-surface`) so rows scroll under it.
91
+ */
92
+ sticky?: boolean;
93
+ /** Controls after the chips — a range picker, an export button. */
94
+ children?: ReactNode;
95
+ ref?: Ref<HTMLDivElement>;
96
+ }
97
+ export declare function FilterBar({ definitions, filters, onFiltersChange, search, onSearchChange, searchPlaceholder, searchLabel, sticky, className, children, ...props }: FilterBarProps): import("react").JSX.Element;
98
+ export declare namespace FilterBar {
99
+ var displayName: string;
100
+ }
101
+ export {};
@@ -0,0 +1 @@
1
+ export { FilterBar, FILTER_DATE_PRESETS, isFilterSet, formatFilterValue, type FilterBarProps, type FilterDefinition, type SelectFilterDefinition, type DateRangeFilterDefinition, type DateRangePreset, type DateRangeValue, type FilterOption, type FilterValue, type FilterValues, } from './filter-bar';
@@ -0,0 +1 @@
1
+ export { LogList, logStatusColor, logStatusLabel, truncateMiddle, type LogListRootProps, type LogListRowProps, type LogListEmptyProps, type LogListLoadMoreProps, type LogStatusProps, } from './log-list';
@@ -0,0 +1,136 @@
1
+ import { ComponentProps, MouseEvent, ReactNode, Ref } from 'react';
2
+ import { useRender } from '@base-ui/react/use-render';
3
+ import { BadgeColor, BadgeSize } from '../badge';
4
+ /**
5
+ * Keep the start and the end of an id and fold the middle into an
6
+ * ellipsis — `pho_req_01m04axjqrfzxv4xjet40a84gb` reads
7
+ * `pho_req_01m0…a84gb`. Ids that fit are returned whole.
8
+ */
9
+ export declare function truncateMiddle(value: string, head?: number, tail?: number): string;
10
+ /**
11
+ * The `Badge` color for a log status: an HTTP status code (2xx success,
12
+ * 3xx gray, 4xx warning, 5xx error) or a word (`delivered` / `failed` /
13
+ * `pending`). Anything else is gray.
14
+ */
15
+ export declare function logStatusColor(status: number | string): BadgeColor;
16
+ /** A status word as a label: `timed_out` reads `Timed out`. */
17
+ export declare function logStatusLabel(status: number | string): string;
18
+ export interface LogStatusProps extends Omit<ComponentProps<"span">, "children" | "color"> {
19
+ /** An HTTP status code or a status word. */
20
+ value: number | string;
21
+ /** Override the derived word. */
22
+ label?: ReactNode;
23
+ /** Badge size. @default "sm" */
24
+ size?: BadgeSize;
25
+ }
26
+ /** The status slot — a low-contrast `Badge` colored by `logStatusColor`. */
27
+ declare function Status({ value, label, size, className, ...props }: LogStatusProps): import("react").JSX.Element;
28
+ /** The method slot — `POST`, `GET` as a quiet mono chip. */
29
+ declare function Method({ className, ...props }: ComponentProps<"span"> & {
30
+ ref?: Ref<HTMLSpanElement>;
31
+ }): import("react").JSX.Element;
32
+ export interface LogListRowProps extends Omit<ComponentProps<"div">, "children" | "title" | "onClick" | "id"> {
33
+ /** The record's id — mono, middle-truncated, copied on click. */
34
+ id?: string;
35
+ /** The status slot — usually `LogList.Status`. */
36
+ status?: ReactNode;
37
+ /** The method — `POST`, `GET`; rendered in `LogList.Method`. */
38
+ method?: string;
39
+ /** What happened — the route, the event type, the message. */
40
+ label: ReactNode;
41
+ /** The label in mono — for a route or an event type. */
42
+ code?: boolean;
43
+ /**
44
+ * The line under the label, with real content: who received what from
45
+ * whom, the destination that answered. A sentence, with its period.
46
+ */
47
+ description?: ReactNode;
48
+ /** Trailing: how long it took — "59 ms". */
49
+ duration?: ReactNode;
50
+ /** Trailing: when — "2 min ago". */
51
+ time?: ReactNode;
52
+ /** Trailing content before the duration and time. */
53
+ children?: ReactNode;
54
+ /** The row is a link to its page, through the host's `LinkProvider`. */
55
+ href?: string;
56
+ /** The row is a button. */
57
+ onClick?: (event: MouseEvent<HTMLElement>) => void;
58
+ /**
59
+ * Replace the row's link element — a router's `Link`, the way Base UI
60
+ * components take `render`. The row's classes and handlers merge in.
61
+ */
62
+ render?: useRender.RenderProp;
63
+ /** The row whose page is open beside the list — it keeps the wash. */
64
+ current?: boolean;
65
+ ref?: Ref<HTMLDivElement>;
66
+ }
67
+ declare function Row({ id, status, method, label, code, description, duration, time, children, href, onClick, render, current, className, ...props }: LogListRowProps): import("react").JSX.Element;
68
+ export interface LogListEmptyProps extends Omit<ComponentProps<"div">, "title" | "children"> {
69
+ /** One short line naming the state. @default "Nothing here yet." */
70
+ title?: ReactNode;
71
+ /** What fills it, or why it is empty. */
72
+ description?: ReactNode;
73
+ /** An action, when there is one. */
74
+ children?: ReactNode;
75
+ }
76
+ /** The list with no rows — `StatusView` at card size. */
77
+ declare function Empty({ title, description, children, className, ...props }: LogListEmptyProps): import("react").JSX.Element;
78
+ /** Bones in the rows' place while the first page is on its way. */
79
+ declare function Loading({ rows }: {
80
+ rows?: number;
81
+ }): import("react").JSX.Element;
82
+ export interface LogListLoadMoreProps extends Omit<ComponentProps<"div">, "children"> {
83
+ /** Asked for as the sentinel scrolls into view, and on the button. */
84
+ onLoadMore: () => void;
85
+ /** The next page is on its way — the sentinel shows a spinner and waits. */
86
+ loading?: boolean;
87
+ /** Nothing left to load — renders nothing. @default true */
88
+ hasMore?: boolean;
89
+ /** How far ahead of the viewport to ask. @default "200px" */
90
+ rootMargin?: string;
91
+ /** The button's words. @default "Load more" */
92
+ label?: ReactNode;
93
+ }
94
+ /**
95
+ * The sentinel at the end of the list. An `IntersectionObserver` asks for
96
+ * the next page as it comes into view (`rootMargin` ahead of it); while
97
+ * `loading` it shows a spinner and asks for nothing. The button is the
98
+ * same request for keyboards and for a browser without the observer.
99
+ * SSR-safe: the observer is created in an effect.
100
+ */
101
+ declare function LoadMore({ onLoadMore, loading, hasMore, rootMargin, label, className, ...props }: LogListLoadMoreProps): import("react").JSX.Element | null;
102
+ export interface LogListRootProps extends ComponentProps<"div"> {
103
+ ref?: Ref<HTMLDivElement>;
104
+ }
105
+ /** The card the rows stack in. Mark it `aria-busy` while bones show. */
106
+ declare function Root({ className, ...props }: LogListRootProps): import("react").JSX.Element;
107
+ /**
108
+ * Log List — a card of one-line log rows.
109
+ *
110
+ * ```tsx
111
+ * <LogList.Root>
112
+ * <LogList.Row
113
+ * id="pho_req_01m04axjqrfzxv4xjet40a84gb"
114
+ * status={<LogList.Status value={200} />}
115
+ * method="POST"
116
+ * code
117
+ * label="/v1/messages"
118
+ * description="+1 332 259 3374 received a message from +1 332 222 1111."
119
+ * duration="59 ms"
120
+ * time="2 min ago"
121
+ * href="/requests/pho_req_01m04axjqrfzxv4xjet40a84gb"
122
+ * />
123
+ * <LogList.LoadMore onLoadMore={fetchNextPage} loading={isFetching} hasMore={hasNextPage} />
124
+ * </LogList.Root>
125
+ * ```
126
+ */
127
+ export declare const LogList: {
128
+ Root: typeof Root;
129
+ Row: typeof Row;
130
+ Status: typeof Status;
131
+ Method: typeof Method;
132
+ Empty: typeof Empty;
133
+ Loading: typeof Loading;
134
+ LoadMore: typeof LoadMore;
135
+ };
136
+ export {};
@@ -0,0 +1,2 @@
1
+ export { Trace, type TraceRootProps, type TraceLogsProps, type TraceLog, type TraceLogLevel, } from './trace';
2
+ export { layoutTrace, niceStep, formatDuration, formatTick, type TraceSpan, type TraceRow, type TraceLayout, } from './layout';
@@ -0,0 +1,48 @@
1
+ /**
2
+ * The waterfall's arithmetic, apart from the drawing: spans in, rows out
3
+ * — each with its depth and its bar's place along the trace's length —
4
+ * plus the tick marks for the time axis.
5
+ */
6
+ export interface TraceSpan {
7
+ id: string;
8
+ /** The span this one runs inside. Absent (or unknown) means a root. */
9
+ parentId?: string | null;
10
+ name: string;
11
+ /** Start, in ms, on any shared clock — only the differences matter. */
12
+ startMs: number;
13
+ durationMs: number;
14
+ status?: "ok" | "error" | "unset";
15
+ /** A hint after the name — the service, the host. */
16
+ service?: string;
17
+ /** A hint after the service — client, server, db. */
18
+ kind?: string;
19
+ }
20
+ export interface TraceRow {
21
+ span: TraceSpan;
22
+ depth: number;
23
+ /** The bar's start, as a fraction of the trace's length. */
24
+ left: number;
25
+ /** The bar's length, as a fraction of the trace's length. */
26
+ width: number;
27
+ children: string[];
28
+ /** Every span beneath this one, at any depth. */
29
+ descendants: number;
30
+ }
31
+ export interface TraceLayout {
32
+ /** Every span, root first, each parent before its children. */
33
+ rows: TraceRow[];
34
+ startMs: number;
35
+ endMs: number;
36
+ durationMs: number;
37
+ /** Tick marks along the axis, in ms from the start. */
38
+ ticks: number[];
39
+ }
40
+ /** A tick step from the 1 / 2 / 5 ladder so the axis has at most `max` ticks. */
41
+ export declare function niceStep(durationMs: number, max?: number): number;
42
+ export declare function layoutTrace(spans: readonly TraceSpan[]): TraceLayout;
43
+ /** "0.42 ms", "59.2 ms", "1.25 s" — the precision follows the size. */
44
+ export declare function formatDuration(ms: number): string;
45
+ /** An axis tick's label: whole numbers where the step allows, "2 s" past a second. */
46
+ export declare function formatTick(ms: number): string;
47
+ /** A fraction as a CSS percentage, rounded so floats never leak into styles. */
48
+ export declare function percent(fraction: number): string;
@@ -0,0 +1,53 @@
1
+ import { ComponentProps, ReactNode, Ref } from 'react';
2
+ import { TraceSpan } from './layout';
3
+ export interface TraceRootProps extends Omit<ComponentProps<"div">, "children" | "onSelect" | "title"> {
4
+ spans: readonly TraceSpan[];
5
+ /** The span whose details are open — it keeps the wash. */
6
+ selectedId?: string | null;
7
+ /** Rows select on click when given. */
8
+ onSelect?: (id: string) => void;
9
+ /** Spans folded at first (uncontrolled). */
10
+ defaultCollapsed?: readonly string[];
11
+ /** Spans folded (controlled). */
12
+ collapsed?: readonly string[];
13
+ onCollapsedChange?: (ids: string[]) => void;
14
+ /** A title row above the axis — "Waterfall". Omit for none. */
15
+ title?: ReactNode;
16
+ ref?: Ref<HTMLDivElement>;
17
+ }
18
+ declare function Root({ spans, selectedId, onSelect, defaultCollapsed, collapsed: collapsedProp, onCollapsedChange, title, className, ...props }: TraceRootProps): import("react").JSX.Element;
19
+ export type TraceLogLevel = "debug" | "info" | "warn" | "error";
20
+ export interface TraceLog {
21
+ id?: string;
22
+ /** When, in ms after the trace's start. */
23
+ offsetMs: number;
24
+ level?: TraceLogLevel;
25
+ message: string;
26
+ /** The span it was written in, when known — its name shows after. */
27
+ spanId?: string;
28
+ }
29
+ export interface TraceLogsProps extends Omit<ComponentProps<"section">, "children" | "title"> {
30
+ logs?: readonly TraceLog[] | null;
31
+ /** The spans, to name the one each line was written in. */
32
+ spans?: readonly TraceSpan[];
33
+ /** @default "Logs" */
34
+ title?: ReactNode;
35
+ ref?: Ref<HTMLElement>;
36
+ }
37
+ /**
38
+ * The log lines that belong to the trace, each at its offset from the
39
+ * start, in the mono face. Renders nothing when there are none — a
40
+ * trace with no logs shows no empty block.
41
+ */
42
+ declare function Logs({ logs, spans, title, className, ...props }: TraceLogsProps): import("react").JSX.Element | null;
43
+ /**
44
+ * ```tsx
45
+ * <Trace.Root spans={spans} selectedId={id} onSelect={setId} title="Waterfall" />
46
+ * <Trace.Logs logs={logs} spans={spans} />
47
+ * ```
48
+ */
49
+ export declare const Trace: {
50
+ Root: typeof Root;
51
+ Logs: typeof Logs;
52
+ };
53
+ export {};
@@ -20,3 +20,9 @@ export * from './components/chart';
20
20
  export * from './components/stat';
21
21
  export * from './components/bar-chart';
22
22
  export * from './components/line-chart';
23
+ export * from './components/copy-button';
24
+ export * from './components/filter-bar';
25
+ export * from './components/log-list';
26
+ export * from './components/description-list';
27
+ export * from './components/code-block';
28
+ export * from './components/trace';