@photon-ai/pho-ui 2.11.0 → 2.13.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/dist/chunks/badge-DlLJPLeZ.js +78 -0
- package/dist/chunks/badge-DlLJPLeZ.js.map +1 -0
- package/dist/chunks/bar-chart-BJfr3eyd.js +190 -0
- package/dist/chunks/bar-chart-BJfr3eyd.js.map +1 -0
- package/dist/chunks/legend-C0mU7dqd.js +60 -0
- package/dist/chunks/legend-C0mU7dqd.js.map +1 -0
- package/dist/chunks/line-chart-CUR3AxrR.js +453 -0
- package/dist/chunks/line-chart-CUR3AxrR.js.map +1 -0
- package/dist/chunks/stat-hnNqjWVG.js +85 -0
- package/dist/chunks/stat-hnNqjWVG.js.map +1 -0
- package/dist/chunks/use-measure-CMVgLouO.js +616 -0
- package/dist/chunks/use-measure-CMVgLouO.js.map +1 -0
- package/dist/components/badge.js +5 -71
- package/dist/components/bar-chart.js +5 -0
- package/dist/components/chart.js +8 -0
- package/dist/components/line-chart.js +5 -0
- package/dist/components/stat.js +6 -0
- package/dist/components/toggle.js +14 -14
- package/dist/components/toggle.js.map +1 -1
- package/dist/index.js +89 -76
- package/dist/src/components/badge/badge.d.ts +7 -3
- package/dist/src/components/bar-chart/bar-chart.d.ts +9 -0
- package/dist/src/components/bar-chart/index.d.ts +2 -0
- package/dist/src/components/chart/axes.d.ts +22 -0
- package/dist/src/components/chart/color.d.ts +10 -0
- package/dist/src/components/chart/format.d.ts +25 -0
- package/dist/src/components/chart/index.d.ts +8 -0
- package/dist/src/components/chart/legend.d.ts +26 -0
- package/dist/src/components/chart/scale.d.ts +34 -0
- package/dist/src/components/chart/shell.d.ts +42 -0
- package/dist/src/components/chart/tooltip.d.ts +30 -0
- package/dist/src/components/chart/types.d.ts +76 -0
- package/dist/src/components/chart/use-measure.d.ts +8 -0
- package/dist/src/components/line-chart/index.d.ts +2 -0
- package/dist/src/components/line-chart/line-chart.d.ts +11 -0
- package/dist/src/components/stat/index.d.ts +1 -0
- package/dist/src/components/stat/stat.d.ts +61 -0
- package/dist/src/components/toggle/toggle.d.ts +5 -1
- package/dist/src/index.d.ts +4 -0
- package/package.json +23 -1
- package/src/styles/theme.css +51 -0
- package/dist/components/badge.js.map +0 -1
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { ComponentProps } from 'react';
|
|
2
|
+
/** A legend or tooltip key mirrors its mark: a square for a bar, a stroke for a line. */
|
|
3
|
+
export type ChartSwatchKind = "rect" | "line";
|
|
4
|
+
export interface ChartSwatchProps {
|
|
5
|
+
/** A CSS colour value — what `chartColor` returns. */
|
|
6
|
+
color: string;
|
|
7
|
+
kind?: ChartSwatchKind;
|
|
8
|
+
dashed?: boolean;
|
|
9
|
+
}
|
|
10
|
+
export declare function ChartSwatch({ color, kind, dashed, }: ChartSwatchProps): import("react").JSX.Element;
|
|
11
|
+
export interface ChartLegendItem {
|
|
12
|
+
label: string;
|
|
13
|
+
/** A CSS colour value — what `chartColor` returns. */
|
|
14
|
+
color: string;
|
|
15
|
+
kind?: ChartSwatchKind;
|
|
16
|
+
dashed?: boolean;
|
|
17
|
+
}
|
|
18
|
+
export interface ChartLegendProps extends Omit<ComponentProps<"ul">, "children"> {
|
|
19
|
+
items: ReadonlyArray<ChartLegendItem>;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* The legend a chart of two or more series carries below the plot: a key
|
|
23
|
+
* per series, in series order, wrapping when the row runs out. Text stays
|
|
24
|
+
* in the UI ink; the swatch alone carries the colour.
|
|
25
|
+
*/
|
|
26
|
+
export declare function ChartLegend({ items, className, ...props }: ChartLegendProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/** Epoch milliseconds for a datum's `x`. */
|
|
2
|
+
export declare function toTime(x: Date | number): number;
|
|
3
|
+
/** A linear map from `domain` to `range`; a flat domain maps to its start. */
|
|
4
|
+
export declare function linearScale(domain: readonly [number, number], range: readonly [number, number]): (value: number) => number;
|
|
5
|
+
/**
|
|
6
|
+
* A y domain on round numbers with three to five ticks, the last tick on
|
|
7
|
+
* or above the data's high end so the top of the plot is labelled.
|
|
8
|
+
*/
|
|
9
|
+
export declare function niceLinearDomain(min: number, max: number): {
|
|
10
|
+
domain: [number, number];
|
|
11
|
+
ticks: number[];
|
|
12
|
+
};
|
|
13
|
+
/** The gap between buckets, in ms — the median step, so one hole doesn't skew it. */
|
|
14
|
+
export declare function bucketSpan(times: ReadonlyArray<number>): number;
|
|
15
|
+
/**
|
|
16
|
+
* Time ticks for a plot `width` px wide: one every ~96px, on the round
|
|
17
|
+
* boundaries d3-time picks (5 minutes, an hour, a day, a month…).
|
|
18
|
+
*/
|
|
19
|
+
export declare function timeAxisTicks(start: number, stop: number, width: number): Date[];
|
|
20
|
+
/**
|
|
21
|
+
* Labels a tick by the boundary it sits on: a time within a day, a date at
|
|
22
|
+
* midnight, month and year at a new year. `Intl` does the wording, so the
|
|
23
|
+
* labels follow the locale.
|
|
24
|
+
*/
|
|
25
|
+
export declare function timeTickFormatter(locale?: string): (date: Date) => string;
|
|
26
|
+
/**
|
|
27
|
+
* The tooltip's heading for a bucket: the date alone when buckets are a
|
|
28
|
+
* day or longer, date and time below that.
|
|
29
|
+
*/
|
|
30
|
+
export declare function bucketTimeFormatter(locale: string | undefined, span: number): (date: Date) => string;
|
|
31
|
+
/** Keep every nth tick so the labels fit the width without touching. */
|
|
32
|
+
export declare function thinTicks<T>(values: ReadonlyArray<T>, labelOf: (value: T) => string, width: number): T[];
|
|
33
|
+
/** The index of the position nearest `px` in an ascending list. */
|
|
34
|
+
export declare function nearestIndex(positions: ReadonlyArray<number>, px: number): number;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { ComponentProps, PointerEvent, ReactNode, RefObject } from 'react';
|
|
2
|
+
/** The inner box the marks draw in, once the axes have taken their bands. */
|
|
3
|
+
export interface ChartLayout {
|
|
4
|
+
width: number;
|
|
5
|
+
height: number;
|
|
6
|
+
left: number;
|
|
7
|
+
top: number;
|
|
8
|
+
right: number;
|
|
9
|
+
bottom: number;
|
|
10
|
+
innerWidth: number;
|
|
11
|
+
innerHeight: number;
|
|
12
|
+
}
|
|
13
|
+
/** The plot's box for a measured width and the y-axis labels it must fit. */
|
|
14
|
+
export declare function chartLayout(width: number, height: number, yLabels: ReadonlyArray<string>): ChartLayout;
|
|
15
|
+
export interface ChartShellProps extends Omit<ComponentProps<"div">, "children"> {
|
|
16
|
+
/** The figure's `aria-label`. */
|
|
17
|
+
label: string;
|
|
18
|
+
/** The figure's spoken summary. */
|
|
19
|
+
description: string;
|
|
20
|
+
height: number;
|
|
21
|
+
/** The measured width; 0 before the browser has measured. */
|
|
22
|
+
width: number;
|
|
23
|
+
containerRef: RefObject<HTMLDivElement | null>;
|
|
24
|
+
legend?: ReactNode;
|
|
25
|
+
tooltip?: ReactNode;
|
|
26
|
+
loading?: boolean;
|
|
27
|
+
empty?: ReactNode;
|
|
28
|
+
/** The frame says `empty` instead of drawing. */
|
|
29
|
+
showEmpty?: boolean;
|
|
30
|
+
/** The pointer over the plot — the chart snaps to the nearest bucket. */
|
|
31
|
+
onPlotPointerMove?: (event: PointerEvent<SVGSVGElement>) => void;
|
|
32
|
+
onPlotPointerLeave?: () => void;
|
|
33
|
+
children?: ReactNode;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* The frame every chart draws in: a fixed-height plot box holding the
|
|
37
|
+
* SVG (`role="img"`, labelled and described for assistive tech), the
|
|
38
|
+
* tooltip layer over it, the legend on its own line below. Width comes
|
|
39
|
+
* from the parent; `height` covers the plot and the x-axis band, so a
|
|
40
|
+
* card never grows a nested scroll.
|
|
41
|
+
*/
|
|
42
|
+
export declare function ChartShell({ label, description, height, width, containerRef, legend, tooltip, loading, empty, showEmpty, onPlotPointerMove, onPlotPointerLeave, className, children, ...props }: ChartShellProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { ChartSwatchKind } from './legend';
|
|
3
|
+
import { ChartBreakdownItem } from './types';
|
|
4
|
+
export interface ChartTooltipRow {
|
|
5
|
+
label: string;
|
|
6
|
+
value: string;
|
|
7
|
+
color: string;
|
|
8
|
+
kind?: ChartSwatchKind;
|
|
9
|
+
dashed?: boolean;
|
|
10
|
+
}
|
|
11
|
+
export interface ChartTooltipProps {
|
|
12
|
+
/** The snapped x of the hovered bucket, in container px. */
|
|
13
|
+
x: number;
|
|
14
|
+
/** The container's width — the tooltip flips to the left past the middle. */
|
|
15
|
+
width: number;
|
|
16
|
+
/** Where the tooltip's top sits — the plot's top. */
|
|
17
|
+
top: number;
|
|
18
|
+
heading: string;
|
|
19
|
+
rows: ReadonlyArray<ChartTooltipRow>;
|
|
20
|
+
breakdown?: ReadonlyArray<ChartBreakdownItem>;
|
|
21
|
+
breakdownTitle?: ReactNode;
|
|
22
|
+
valueFormat: (value: number) => string;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* The readout for one bucket: its time, then every series' value (values
|
|
26
|
+
* lead, in primary ink; labels follow), then the bucket's breakdown when
|
|
27
|
+
* it carries one. Presentational — the figure's description already
|
|
28
|
+
* speaks the data — and it never takes the pointer.
|
|
29
|
+
*/
|
|
30
|
+
export declare function ChartTooltip({ x, width, top, heading, rows, breakdown, breakdownTitle, valueFormat, }: ChartTooltipProps): import("react").JSX.Element;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { ComponentProps, ReactNode } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* A series colour: the six ordered categorical slots, the two status
|
|
4
|
+
* inks (a series that MEANS successful / failed), or the monochrome ink
|
|
5
|
+
* for a one-series chart on the site's black and white.
|
|
6
|
+
*/
|
|
7
|
+
export type ChartColor = "chart-1" | "chart-2" | "chart-3" | "chart-4" | "chart-5" | "chart-6" | "success" | "error" | "ink";
|
|
8
|
+
/** One line of the per-bucket detail a tooltip lists under the series. */
|
|
9
|
+
export interface ChartBreakdownItem {
|
|
10
|
+
label: string;
|
|
11
|
+
value: number;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* One bucket on the time axis. Series values sit beside `x` under the
|
|
15
|
+
* keys the `series` name — `{ x, inbound: 12, outbound: 4 }`.
|
|
16
|
+
*/
|
|
17
|
+
export interface ChartDatum {
|
|
18
|
+
/** When the bucket starts: a `Date` or epoch milliseconds. */
|
|
19
|
+
x: Date | number;
|
|
20
|
+
/**
|
|
21
|
+
* Detail for this bucket — errors by route, say — listed in the tooltip
|
|
22
|
+
* under the series rows.
|
|
23
|
+
*/
|
|
24
|
+
breakdown?: ReadonlyArray<ChartBreakdownItem>;
|
|
25
|
+
}
|
|
26
|
+
/** The keys of `T` that hold a number (or nothing yet). */
|
|
27
|
+
export type ChartValueKey<T> = {
|
|
28
|
+
[K in keyof T]-?: K extends "x" | "breakdown" ? never : T[K] extends number | null | undefined ? K : never;
|
|
29
|
+
}[keyof T] & string;
|
|
30
|
+
export interface ChartSeries<T extends ChartDatum = ChartDatum> {
|
|
31
|
+
/** The field of each datum this series plots. */
|
|
32
|
+
key: ChartValueKey<T>;
|
|
33
|
+
/** The name in the legend and the tooltip. */
|
|
34
|
+
label: string;
|
|
35
|
+
/** Defaults to the next categorical slot, in series order. */
|
|
36
|
+
color?: ChartColor;
|
|
37
|
+
/** Line charts: a dashed stroke — a min / max beside an average. */
|
|
38
|
+
dashed?: boolean;
|
|
39
|
+
}
|
|
40
|
+
/** What every chart takes, on top of the div it renders. */
|
|
41
|
+
export interface ChartBaseProps<T extends ChartDatum> extends Omit<ComponentProps<"div">, "children"> {
|
|
42
|
+
/** The buckets, oldest first, evenly spaced in time. */
|
|
43
|
+
data: ReadonlyArray<T>;
|
|
44
|
+
/**
|
|
45
|
+
* One entry per series, in drawing (and legend) order. `T` comes from
|
|
46
|
+
* `data`; the keys here are checked against it.
|
|
47
|
+
*/
|
|
48
|
+
series: ReadonlyArray<ChartSeries<NoInfer<T>>>;
|
|
49
|
+
/** Names the chart for assistive tech — the figure's `aria-label`. */
|
|
50
|
+
label: string;
|
|
51
|
+
/**
|
|
52
|
+
* What the figure says about itself to assistive tech. Generated from
|
|
53
|
+
* the series (range, totals or extremes, peaks) unless given.
|
|
54
|
+
*/
|
|
55
|
+
description?: string;
|
|
56
|
+
/** Plot plus x-axis band, in px; the legend adds its own line below. @default 200 */
|
|
57
|
+
height?: number;
|
|
58
|
+
/** A fixed width instead of measuring the parent — SSR renders, tests. */
|
|
59
|
+
width?: number;
|
|
60
|
+
/** Formats a value on the y-axis and in the tooltip. */
|
|
61
|
+
valueFormat?: (value: number) => string;
|
|
62
|
+
/** Formats a bucket's time in the tooltip heading and the description. */
|
|
63
|
+
timeFormat?: (date: Date) => string;
|
|
64
|
+
/** Locale for the default number and time formats. Runtime locale by default. */
|
|
65
|
+
locale?: string;
|
|
66
|
+
/** Show the legend. On for two or more series; a lone series is named by its title. */
|
|
67
|
+
legend?: boolean;
|
|
68
|
+
/** Where the y-axis starts: at zero, or at the data's low end. @default "zero" */
|
|
69
|
+
baseline?: "zero" | "auto";
|
|
70
|
+
/** A heading over a datum's `breakdown` list in the tooltip. */
|
|
71
|
+
breakdownTitle?: ReactNode;
|
|
72
|
+
/** Data is on its way: the chart holds its last render at half opacity. */
|
|
73
|
+
loading?: boolean;
|
|
74
|
+
/** What the frame says with no buckets to draw. */
|
|
75
|
+
empty?: ReactNode;
|
|
76
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { RefObject } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* The width of the element the ref lands on, kept current through a
|
|
4
|
+
* ResizeObserver. Nothing runs on the server: the first render is 0 wide
|
|
5
|
+
* and the plot fills in once the browser has measured. A `fixed` width
|
|
6
|
+
* skips measuring altogether.
|
|
7
|
+
*/
|
|
8
|
+
export declare function useMeasuredWidth<T extends HTMLElement>(fixed?: number): [RefObject<T | null>, number];
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { ChartBaseProps, ChartDatum } from '../chart/types';
|
|
2
|
+
export interface LineChartProps<T extends ChartDatum> extends ChartBaseProps<T> {
|
|
3
|
+
/** Straight segments, or a monotone curve that never overshoots a sample. @default "linear" */
|
|
4
|
+
curve?: "linear" | "monotone";
|
|
5
|
+
/** A soft fill under the first series (a lone one, as a rule). */
|
|
6
|
+
area?: boolean;
|
|
7
|
+
}
|
|
8
|
+
export declare function LineChart<T extends ChartDatum>({ data, series, label, description, height, width: fixedWidth, valueFormat, timeFormat, locale, legend, baseline, curve, area, breakdownTitle, loading, empty, className, ...props }: LineChartProps<T>): import("react").JSX.Element;
|
|
9
|
+
export declare namespace LineChart {
|
|
10
|
+
var displayName: string;
|
|
11
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { Stat, StatGroup, type StatDirection, type StatGroupProps, type StatProps, } from './stat';
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { ComponentProps, ReactNode } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* Stat — a figure with its name: a label, a value, and, when it
|
|
4
|
+
* matters, how the value moved and against what.
|
|
5
|
+
*
|
|
6
|
+
* Design notes:
|
|
7
|
+
* - The value is the loud element: display size, medium weight, the
|
|
8
|
+
* font's proportional figures (tabular digits make a big `121` look
|
|
9
|
+
* loose). Label and note stay in the UI inks; nothing else competes.
|
|
10
|
+
* - The delta is a low-contrast `Badge` beside the label, with an arrow so
|
|
11
|
+
* the direction never rides on colour alone. Its ink says whether the
|
|
12
|
+
* move is good news: `deltaGood` names the good direction, because a
|
|
13
|
+
* drop in bounce rate is green and a drop in visitors is red.
|
|
14
|
+
* - A tile has no chrome of its own. Alone, it sits in whatever card holds
|
|
15
|
+
* it; in a `Stat.Group` the tiles share one frame and hairlines.
|
|
16
|
+
*/
|
|
17
|
+
export type StatDirection = "up" | "down" | "flat";
|
|
18
|
+
export interface StatProps extends Omit<ComponentProps<"div">, "children"> {
|
|
19
|
+
/** What the figure counts — "Visitors", "Active chats". */
|
|
20
|
+
label: ReactNode;
|
|
21
|
+
/** The figure, already formatted — "20.8K", "8m 32s", "1:1". */
|
|
22
|
+
value: ReactNode;
|
|
23
|
+
/**
|
|
24
|
+
* How the value moved: a number is a percentage change and renders
|
|
25
|
+
* signed with one decimal ("−42.0%"); a string renders as written and
|
|
26
|
+
* its sign sets the direction.
|
|
27
|
+
*/
|
|
28
|
+
delta?: number | string;
|
|
29
|
+
/** The delta's direction, when the string can't say. Derived otherwise. */
|
|
30
|
+
deltaDirection?: StatDirection;
|
|
31
|
+
/**
|
|
32
|
+
* Which direction is good news: `up` (visitors, revenue), `down` (bounce
|
|
33
|
+
* rate, latency), `none` when a move is just information. @default "up"
|
|
34
|
+
*/
|
|
35
|
+
deltaGood?: "up" | "down" | "none";
|
|
36
|
+
/** What the delta is against — "vs. 36.2K prior". */
|
|
37
|
+
note?: ReactNode;
|
|
38
|
+
}
|
|
39
|
+
export declare function Stat({ label, value, delta, deltaDirection, deltaGood, note, className, ...props }: StatProps): import("react").JSX.Element;
|
|
40
|
+
export declare namespace Stat {
|
|
41
|
+
var displayName: string;
|
|
42
|
+
var Group: typeof StatGroup;
|
|
43
|
+
}
|
|
44
|
+
export interface StatGroupProps extends ComponentProps<"div"> {
|
|
45
|
+
/**
|
|
46
|
+
* `card` frames the row as a card of its own; `plain` keeps only the
|
|
47
|
+
* hairlines between tiles, for a row inside a card or under a chart.
|
|
48
|
+
* @default "card"
|
|
49
|
+
*/
|
|
50
|
+
variant?: "card" | "plain";
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* A row of tiles that reads as one card: hairlines between tiles, and
|
|
54
|
+
* between rows once the tiles wrap on a narrow width. Each tile takes an
|
|
55
|
+
* equal share of its row, never narrower than 12rem; a tile that wraps
|
|
56
|
+
* alone stretches across its line, so the frame never shows a hole.
|
|
57
|
+
*/
|
|
58
|
+
export declare function StatGroup({ variant, className, ...props }: StatGroupProps): import("react").JSX.Element;
|
|
59
|
+
export declare namespace StatGroup {
|
|
60
|
+
var displayName: string;
|
|
61
|
+
}
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
import { ComponentProps } from 'react';
|
|
2
2
|
import { Toggle as BaseToggle } from '@base-ui/react/toggle';
|
|
3
|
-
/**
|
|
3
|
+
/**
|
|
4
|
+
* Size axis — three heights. An icon-only toggle is square (the padding
|
|
5
|
+
* plus the icon add up to the height); one carrying a short label — a
|
|
6
|
+
* range picker's `7d` — grows to fit it. `md` is default.
|
|
7
|
+
*/
|
|
4
8
|
export declare const TOGGLE_SIZES: {
|
|
5
9
|
sm: {
|
|
6
10
|
classes: string;
|
package/dist/src/index.d.ts
CHANGED
|
@@ -16,3 +16,7 @@ export * from './components/status-view';
|
|
|
16
16
|
export * from './components/error';
|
|
17
17
|
export * from './sections/sidebar';
|
|
18
18
|
export * from './sections/basic-page';
|
|
19
|
+
export * from './components/chart';
|
|
20
|
+
export * from './components/stat';
|
|
21
|
+
export * from './components/bar-chart';
|
|
22
|
+
export * from './components/line-chart';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@photon-ai/pho-ui",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.13.0",
|
|
4
4
|
"description": "Pho Design System — Photon's React component library, built on Base UI",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"repository": {
|
|
@@ -407,6 +407,22 @@
|
|
|
407
407
|
"./primitives/tooltip": {
|
|
408
408
|
"types": "./dist/src/primitives/tooltip.d.ts",
|
|
409
409
|
"import": "./dist/primitives/tooltip.js"
|
|
410
|
+
},
|
|
411
|
+
"./components/chart": {
|
|
412
|
+
"types": "./dist/src/components/chart/index.d.ts",
|
|
413
|
+
"import": "./dist/components/chart.js"
|
|
414
|
+
},
|
|
415
|
+
"./components/stat": {
|
|
416
|
+
"types": "./dist/src/components/stat/index.d.ts",
|
|
417
|
+
"import": "./dist/components/stat.js"
|
|
418
|
+
},
|
|
419
|
+
"./components/bar-chart": {
|
|
420
|
+
"types": "./dist/src/components/bar-chart/index.d.ts",
|
|
421
|
+
"import": "./dist/components/bar-chart.js"
|
|
422
|
+
},
|
|
423
|
+
"./components/line-chart": {
|
|
424
|
+
"types": "./dist/src/components/line-chart/index.d.ts",
|
|
425
|
+
"import": "./dist/components/line-chart.js"
|
|
410
426
|
}
|
|
411
427
|
},
|
|
412
428
|
"peerDependencies": {
|
|
@@ -420,6 +436,9 @@
|
|
|
420
436
|
"@testing-library/jest-dom": "^7.0.1",
|
|
421
437
|
"@testing-library/react": "^16.3.2",
|
|
422
438
|
"@testing-library/user-event": "^14.6.5",
|
|
439
|
+
"@types/d3-array": "3.2.2",
|
|
440
|
+
"@types/d3-shape": "3.2.0",
|
|
441
|
+
"@types/d3-time": "3.0.4",
|
|
423
442
|
"@types/node": "^26.2.0",
|
|
424
443
|
"@types/react": "^19.2.18",
|
|
425
444
|
"@types/react-dom": "^19.2.4",
|
|
@@ -442,6 +461,9 @@
|
|
|
442
461
|
"clsx": "^2.1.1",
|
|
443
462
|
"cmdk": "^1.1.1",
|
|
444
463
|
"country-flag-icons": "^1.6.20",
|
|
464
|
+
"d3-array": "3.2.4",
|
|
465
|
+
"d3-shape": "3.2.0",
|
|
466
|
+
"d3-time": "3.1.0",
|
|
445
467
|
"libphonenumber-js": "^1.13.11",
|
|
446
468
|
"motion": "^13.1.0",
|
|
447
469
|
"tailwind-merge": "^3.6.0"
|
package/src/styles/theme.css
CHANGED
|
@@ -436,4 +436,55 @@
|
|
|
436
436
|
opacity: 0.45;
|
|
437
437
|
}
|
|
438
438
|
}
|
|
439
|
+
|
|
440
|
+
/* ============================== Charts ============================== */
|
|
441
|
+
/* charts — series colours for BarChart / LineChart. An ORDERED set:
|
|
442
|
+
assign slot 1, 2, 3… in series order and never cycle past 6 (fold the
|
|
443
|
+
tail into "Other"). Validated with the dataviz six checks in both modes
|
|
444
|
+
against the card (#111) and page (#000 / #fff) surfaces: lightness band,
|
|
445
|
+
chroma floor, adjacent-pair CVD ΔE ≥ 8, normal-vision ΔE ≥ 15, 3:1 on
|
|
446
|
+
the surface. Slots 1–2 are the site's sky and orange (orange stepped
|
|
447
|
+
from L 0.70 to 0.66 so a bar clears 3:1 on white); 3–6 are purple,
|
|
448
|
+
olive, magenta, indigo. Dark values are the same hues re-stepped into
|
|
449
|
+
the dark band (L 0.48–0.67), not a flip. */
|
|
450
|
+
--color-pho-chart-1: light-dark(
|
|
451
|
+
oklch(0.6 0.101 239.2),
|
|
452
|
+
oklch(0.66 0.11 239.2)
|
|
453
|
+
);
|
|
454
|
+
--color-pho-chart-2: oklch(0.66 0.15 57.8);
|
|
455
|
+
--color-pho-chart-3: light-dark(oklch(0.62 0.2 307.5), oklch(0.66 0.2 307.5));
|
|
456
|
+
--color-pho-chart-4: oklch(0.66 0.14 106);
|
|
457
|
+
--color-pho-chart-5: light-dark(oklch(0.62 0.2 350), oklch(0.65 0.2 350));
|
|
458
|
+
--color-pho-chart-6: oklch(0.639 0.146 269.6);
|
|
459
|
+
/* Status series — successful vs failed. The state text inks, so a failed
|
|
460
|
+
segment is the same red as a Failed badge. Reserved: a series wears
|
|
461
|
+
these only when it MEANS good / bad, never as "series 4". */
|
|
462
|
+
--color-pho-chart-success: light-dark(
|
|
463
|
+
oklch(0.549 0.136 149.3),
|
|
464
|
+
oklch(0.735 0.162 150.5)
|
|
465
|
+
);
|
|
466
|
+
--color-pho-chart-error: light-dark(
|
|
467
|
+
oklch(0.565 0.212 20.2),
|
|
468
|
+
oklch(0.696 0.198 14.9)
|
|
469
|
+
);
|
|
470
|
+
/* The monochrome series — a one-series chart on the site's black/white. */
|
|
471
|
+
--color-pho-chart-ink: light-dark(oklch(0 0 0 / 0.8), oklch(1 0 0 / 0.8));
|
|
472
|
+
/* Chart furniture: gridlines one step off the surface, the crosshair and
|
|
473
|
+
baseline a touch stronger. Hairlines, solid, recessive. */
|
|
474
|
+
--color-pho-chart-grid: light-dark(oklch(0 0 0 / 0.06), oklch(1 0 0 / 0.08));
|
|
475
|
+
--color-pho-chart-crosshair: light-dark(
|
|
476
|
+
oklch(0 0 0 / 0.2),
|
|
477
|
+
oklch(1 0 0 / 0.25)
|
|
478
|
+
);
|
|
479
|
+
|
|
480
|
+
/* ==================== Animation: chart mount ==================== */
|
|
481
|
+
/* A chart surfaces once on mount — opacity only, nothing moves. The
|
|
482
|
+
global reduced-motion guard in pho.css collapses it. */
|
|
483
|
+
--animate-pho-chart-in: pho-chart-in 300ms ease-out both;
|
|
484
|
+
|
|
485
|
+
@keyframes pho-chart-in {
|
|
486
|
+
from {
|
|
487
|
+
opacity: 0;
|
|
488
|
+
}
|
|
489
|
+
}
|
|
439
490
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"badge.js","names":[],"sources":["../../src/components/badge/badge.tsx"],"sourcesContent":["import { type ComponentProps } from \"react\";\nimport { cn } from \"../../utils/cn\";\nimport { resolveVariant, type VariantMap } from \"../../utils/resolve-variant\";\n\n/**\n * Design notes (Geist-aligned):\n * - ONE color axis, a tight semantic set (`gray` / `muted` / `brand` /\n * `success` / `warning` / `error`). Untitled UI's `type` triplication\n * (modern / pill / badge-color) is dropped.\n * - TWO contrasts (`high` / `low`, default `high`). High is the solid state\n * fill — the site's \"Most Popular\" pill — pairing each color's ink with\n * flipping on-ink content. Low is the soft accent material: fill and\n * hairline ring derive from `currentColor` at low opacity, so every color\n * shares one recipe.\n * - THREE sizes (`xs` / `sm` / `md`, default `md`). A badge is inherently small.\n * - The richer Untitled features (dot, icon, avatar, count, dismiss button) are\n * deliberately left out — a dismissible or selectable chip is a Tag, not a\n * Badge, and a badge that triggers an action is a Button.\n */\n\nconst BADGE_BASE =\n \"inline-flex shrink-0 items-center whitespace-nowrap rounded-full font-medium\";\n\n/** Low-contrast material — tint and hairline derived from the color's text token. */\nconst LOW_MATERIAL = \"bg-current/10 ring-1 ring-current/20 ring-inset\";\n\n/**\n * Size axis — fixed heights on a 4px step (16 / 20 / 24) so the ladder stays\n * proportional. Horizontal padding and type scale with each step; vertical\n * centering comes from `items-center` on the base (no `py`).\n */\nexport const BADGE_SIZES = {\n xs: {\n classes: \"h-4 gap-0.5 px-1.5 text-[10px] leading-none\",\n description: \"Extra small — 16px; inline next to 14px labels (plan chips)\",\n },\n sm: {\n classes: \"h-5 gap-0.5 px-2 text-xs leading-none\",\n description: \"Small — 20px; dense rows, table cells\",\n },\n md: {\n classes: \"h-6 gap-1 px-2.5 text-xs leading-none\",\n description: \"Medium — 24px; the default\",\n },\n} satisfies VariantMap;\n\n/**\n * Color axis — a closed semantic set with one recipe per contrast. `high`\n * fills with the state ink (text flips with it per mode); `low` tints text\n * only and lets `LOW_MATERIAL` derive fill and ring from it.\n */\nexport const BADGE_COLORS = {\n gray: {\n high: \"bg-pho-inverse text-pho-inverse\",\n low: \"text-pho-secondary\",\n description: \"Neutral — the low-signal default (solid inverse)\",\n },\n muted: {\n high: \"bg-pho-secondary text-pho-primary\",\n low: \"text-pho-description\",\n description: \"Muted — soft solid surface for quieter labels (Free, Shared)\",\n },\n brand: {\n high: \"bg-pho-brand-solid text-pho-on-brand\",\n low: \"text-pho-brand\",\n description: \"Brand — plan tiers, feature flags, highlights\",\n },\n success: {\n high: \"bg-pho-success-ink text-pho-on-brand\",\n low: \"text-pho-success\",\n description: \"Success — healthy, live, complete\",\n },\n warning: {\n high: \"bg-pho-warning-ink text-pho-on-brand\",\n low: \"text-pho-warning\",\n description: \"Warning — needs attention, degraded\",\n },\n error: {\n high: \"bg-pho-error-ink text-pho-on-brand\",\n low: \"text-pho-error\",\n description: \"Error — failed, blocked, over limit\",\n },\n} satisfies Record<string, { high: string; low: string; description: string }>;\n\nexport type BadgeSize = keyof typeof BADGE_SIZES;\nexport type BadgeColor = keyof typeof BADGE_COLORS;\nexport type BadgeContrast = \"high\" | \"low\";\n\n/** Compose the full class string for a badge — exported for reuse/testing. */\nexport function badgeVariants(opts?: {\n color?: BadgeColor;\n contrast?: BadgeContrast;\n size?: BadgeSize;\n className?: string;\n}): string {\n const {\n color = \"gray\",\n contrast = \"high\",\n size = \"md\",\n className,\n } = opts ?? {};\n const def = BADGE_COLORS[color] as\n (typeof BADGE_COLORS)[BadgeColor] | undefined;\n return cn(\n BADGE_BASE,\n resolveVariant(BADGE_SIZES, size),\n contrast === \"low\" ? cn(LOW_MATERIAL, def?.low) : def?.high,\n className,\n );\n}\n\ninterface BadgeBaseProps {\n /** Semantic color. @default \"gray\" */\n color?: BadgeColor;\n /** Solid state fill (`high`) or the soft currentColor tint (`low`). @default \"high\" */\n contrast?: BadgeContrast;\n /** Size variant. @default \"md\" */\n size?: BadgeSize;\n}\n\nexport interface BadgeProps\n extends BadgeBaseProps, Omit<ComponentProps<\"span\">, keyof BadgeBaseProps> {}\n\n/**\n * Badge — a small, non-interactive status label: a plan tier (`Pro`), a state\n * (`Live`, `Failed`), a count. It's a plain `<span>`, so it never takes focus or\n * handles clicks — for a dismissible or selectable chip reach for a `Tag`, and\n * for a standalone action use a `Button`. Let `color` carry the meaning and keep\n * the label to a word or two.\n */\nexport function Badge({\n color,\n contrast,\n size,\n className,\n children,\n ...props\n}: BadgeProps) {\n return (\n <span\n className={cn(badgeVariants({ color, contrast, size }), className)}\n {...props}\n >\n {children}\n </span>\n );\n}\n\nBadge.displayName = \"Badge\";\n"],"mappings":";;;;;AAoBA,IAAM,IACJ,gFAGI,IAAe,mDAOR,IAAc;AAAA,EACzB,IAAI;AAAA,IACF,SAAS;AAAA,IACT,aAAa;AAAA,EACf;AAAA,EACA,IAAI;AAAA,IACF,SAAS;AAAA,IACT,aAAa;AAAA,EACf;AAAA,EACA,IAAI;AAAA,IACF,SAAS;AAAA,IACT,aAAa;AAAA,EACf;AACF,GAOa,IAAe;AAAA,EAC1B,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,KAAK;AAAA,IACL,aAAa;AAAA,EACf;AAAA,EACA,OAAO;AAAA,IACL,MAAM;AAAA,IACN,KAAK;AAAA,IACL,aAAa;AAAA,EACf;AAAA,EACA,OAAO;AAAA,IACL,MAAM;AAAA,IACN,KAAK;AAAA,IACL,aAAa;AAAA,EACf;AAAA,EACA,SAAS;AAAA,IACP,MAAM;AAAA,IACN,KAAK;AAAA,IACL,aAAa;AAAA,EACf;AAAA,EACA,SAAS;AAAA,IACP,MAAM;AAAA,IACN,KAAK;AAAA,IACL,aAAa;AAAA,EACf;AAAA,EACA,OAAO;AAAA,IACL,MAAM;AAAA,IACN,KAAK;AAAA,IACL,aAAa;AAAA,EACf;AACF;AAOA,SAAgB,EAAc,GAKnB;AACT,QAAM,EACJ,OAAA,IAAQ,QACR,UAAA,IAAW,QACX,MAAA,IAAO,MACP,WAAA,EAAA,IACE,KAAQ,CAAC,GACP,IAAM,EAAa,CAAA;AAEzB,SAAO,EACL,GACA,EAAe,GAAa,CAAI,GAChC,MAAa,QAAQ,EAAG,GAAc,GAAK,GAAG,IAAI,GAAK,MACvD,CACF;AACF;AAqBA,SAAgB,EAAM,EACpB,OAAA,GACA,UAAA,GACA,MAAA,GACA,WAAA,GACA,UAAA,GACA,GAAG,EAAA,GACU;AACb,SACE,gBAAA,EAAC,QAAD;AAAA,IACE,WAAW,EAAG,EAAc;AAAA,MAAE,OAAA;AAAA,MAAO,UAAA;AAAA,MAAU,MAAA;AAAA,IAAK,CAAC,GAAG,CAAS;AAAA,IACjE,GAAI;AAAA,IAEH,UAAA;AAAA,EACG,CAAA;AAEV;AAEA,EAAM,cAAc"}
|