@surflane/ui 0.10.1 → 0.12.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 (45) hide show
  1. package/dist/app-shell.d.ts +10 -0
  2. package/dist/app-shell.js +7 -1
  3. package/dist/bar-list.d.ts +31 -0
  4. package/dist/bar-list.js +25 -0
  5. package/dist/bottom-navigation.d.ts +6 -2
  6. package/dist/bottom-navigation.js +2 -2
  7. package/dist/chart.d.ts +56 -3
  8. package/dist/chart.js +266 -48
  9. package/dist/css/bar-list.css +9 -0
  10. package/dist/css/chart.css +2 -0
  11. package/dist/css/dashboard.css +20 -0
  12. package/dist/css/rules/alert-dialog.css +4 -0
  13. package/dist/css/rules/app-shell.css +10 -0
  14. package/dist/css/rules/bar-list.css +101 -0
  15. package/dist/css/rules/bottom-navigation.css +16 -0
  16. package/dist/css/rules/card.css +5 -0
  17. package/dist/css/rules/chart.css +74 -3
  18. package/dist/css/rules/dashboard.css +66 -0
  19. package/dist/css/rules/date-picker.css +10 -3
  20. package/dist/css/rules/dialog.css +11 -0
  21. package/dist/css/rules/field-control.css +7 -0
  22. package/dist/css/rules/filter-bar.css +8 -1
  23. package/dist/css/rules/input-group.css +9 -0
  24. package/dist/css/rules/otp-field.css +7 -4
  25. package/dist/css/rules/panel.css +9 -1
  26. package/dist/css/rules/select.css +25 -1
  27. package/dist/css/rules/sizing.css +10 -0
  28. package/dist/css/rules/slider.css +4 -2
  29. package/dist/css/rules/stat.css +57 -0
  30. package/dist/css/rules/time-range-picker.css +14 -0
  31. package/dist/css/styles.css +3 -0
  32. package/dist/css/time-range-picker.css +14 -0
  33. package/dist/dashboard.d.ts +46 -0
  34. package/dist/dashboard.js +35 -0
  35. package/dist/icon.d.ts +10 -0
  36. package/dist/icon.js +11 -0
  37. package/dist/index.d.ts +6 -3
  38. package/dist/index.js +5 -2
  39. package/dist/select.d.ts +33 -6
  40. package/dist/select.js +94 -21
  41. package/dist/stat.d.ts +20 -0
  42. package/dist/stat.js +15 -1
  43. package/dist/time-range-picker.d.ts +42 -0
  44. package/dist/time-range-picker.js +69 -0
  45. package/package.json +18 -3
@@ -25,6 +25,11 @@ export type AppShellSidebarToggleProps = Omit<ButtonProps, 'children'> & {
25
25
  labels?: Partial<AppShellSidebarToggleLabels>;
26
26
  children?: React.ReactNode;
27
27
  };
28
+ export type AppShellMenuTriggerProps = Omit<ButtonProps, 'children'> & {
29
+ /** The button's name. Say what it opens. */
30
+ label?: string;
31
+ children?: React.ReactNode;
32
+ };
28
33
  export type AppShellBrandProps = Omit<useRender.ComponentProps<'div'>, 'ref' | 'children'> & {
29
34
  /** The product mark, about 24px. It is decorative: the name names the brand. */
30
35
  mark?: React.ReactNode;
@@ -55,6 +60,9 @@ export declare const AppShell: {
55
60
  SidebarToggle: ({ labels, className, children, onClick, ref, ...props }: AppShellSidebarToggleProps & {
56
61
  ref?: React.Ref<HTMLButtonElement>;
57
62
  }) => React.JSX.Element;
63
+ MenuTrigger: ({ label, className, children, ref, ...props }: AppShellMenuTriggerProps & {
64
+ ref?: React.Ref<HTMLButtonElement>;
65
+ }) => React.JSX.Element;
58
66
  Brand: ({ mark, name, description, render, className, ref, ...props }: AppShellBrandProps & {
59
67
  ref?: React.Ref<HTMLDivElement>;
60
68
  }) => React.ReactElement<unknown, string | React.JSXElementConstructor<any>>;
@@ -85,6 +93,8 @@ export declare const AppShellRoot: ({ collapsed, defaultCollapsed, onCollapsedCh
85
93
  ref?: React.Ref<HTMLElement>;
86
94
  }) => React.JSX.Element, AppShellSidebarToggle: ({ labels, className, children, onClick, ref, ...props }: AppShellSidebarToggleProps & {
87
95
  ref?: React.Ref<HTMLButtonElement>;
96
+ }) => React.JSX.Element, AppShellMenuTrigger: ({ label, className, children, ref, ...props }: AppShellMenuTriggerProps & {
97
+ ref?: React.Ref<HTMLButtonElement>;
88
98
  }) => React.JSX.Element, AppShellBrand: ({ mark, name, description, render, className, ref, ...props }: AppShellBrandProps & {
89
99
  ref?: React.Ref<HTMLDivElement>;
90
100
  }) => React.ReactElement<unknown, string | React.JSXElementConstructor<any>>, AppShellNav: ({ label, className, children, ref, ...props }: AppShellNavProps & {
package/dist/app-shell.js CHANGED
@@ -75,6 +75,11 @@ const SidebarToggle = function AppShellSidebarToggle({ labels, className, childr
75
75
  shell.setCollapsed(!shell.collapsed);
76
76
  }, children: children ?? _jsx(Icon, { name: 'sidebar' }) }) }));
77
77
  };
78
+ /** Opens the caller's navigation, such as a Sheet, where the sidebar is hidden: at
79
+ * 760px and narrower it shows at the header's end, and above that it is hidden. */
80
+ const MenuTrigger = function AppShellMenuTrigger({ label = 'Open navigation', className, children, ref, ...props }) {
81
+ return (_jsx(Button, { variant: 'ghost', size: 'icon', ...props, ref: ref, "aria-label": label, className: skin('surf-app-shell-menu-trigger', className), children: children ?? _jsx(Icon, { name: 'menu', decorative: true }) }));
82
+ };
78
83
  const Header = function AppShellHeader({ className, ref, ...props }) {
79
84
  return (_jsx("div", { ...props, ref: ref, className: cx('surf-app-shell-header', className) }));
80
85
  };
@@ -144,6 +149,7 @@ export const AppShell = {
144
149
  Header,
145
150
  Sidebar,
146
151
  SidebarToggle,
152
+ MenuTrigger,
147
153
  Brand,
148
154
  Nav,
149
155
  Content,
@@ -153,4 +159,4 @@ export const AppShell = {
153
159
  Link,
154
160
  };
155
161
  // Flat names for React Server Components, which cannot dot into client exports.
156
- export const { Root: AppShellRoot, Header: AppShellHeader, Sidebar: AppShellSidebar, SidebarToggle: AppShellSidebarToggle, Brand: AppShellBrand, Nav: AppShellNav, Content: AppShellContent, Page: AppShellPage, Footer: AppShellFooter, Label: AppShellLabel, Link: AppShellLink, } = AppShell;
162
+ export const { Root: AppShellRoot, Header: AppShellHeader, Sidebar: AppShellSidebar, SidebarToggle: AppShellSidebarToggle, MenuTrigger: AppShellMenuTrigger, Brand: AppShellBrand, Nav: AppShellNav, Content: AppShellContent, Page: AppShellPage, Footer: AppShellFooter, Label: AppShellLabel, Link: AppShellLink, } = AppShell;
@@ -0,0 +1,31 @@
1
+ import * as React from 'react';
2
+ export type BarListItem = {
3
+ id: string;
4
+ /** What the row measures, such as a directory or a project. */
5
+ label: string;
6
+ /** A second, quieter name under the label, such as a path. */
7
+ detail?: string;
8
+ value: number;
9
+ /** The value as written, such as "412 GiB". Defaults to the formatted value. */
10
+ text?: string;
11
+ };
12
+ export type BarListProps = Omit<React.ComponentPropsWithoutRef<'div'>, 'children'> & {
13
+ /** Names the list, such as "Disk used by directory". */
14
+ label: string;
15
+ items: readonly BarListItem[];
16
+ /** The value a full bar stands for. Defaults to the largest value. */
17
+ max?: number;
18
+ /** Orders the rows from the largest value down. Turn it off to keep your order. */
19
+ sorted?: boolean;
20
+ /** The rows shown before the list scrolls inside itself. */
21
+ maxRows?: number;
22
+ /** Writes a value that has no text. */
23
+ formatValue?: (value: number) => string;
24
+ locale?: string;
25
+ };
26
+ /** A ranked list of named values, each with a bar in proportion to the largest, such
27
+ * as disk by directory or tokens by project. Names and values are text; the bars are
28
+ * decoration. */
29
+ export declare const BarList: ({ label, items, max, sorted, maxRows, formatValue, locale, className, style, ref, ...props }: BarListProps & {
30
+ ref?: React.Ref<HTMLDivElement>;
31
+ }) => React.JSX.Element;
@@ -0,0 +1,25 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { cx } from './class-names.js';
3
+ import { ScrollArea } from './scroll-area.js';
4
+ /** A ranked list of named values, each with a bar in proportion to the largest, such
5
+ * as disk by directory or tokens by project. Names and values are text; the bars are
6
+ * decoration. */
7
+ export const BarList = function BarList({ label, items, max, sorted = true, maxRows, formatValue, locale, className, style, ref, ...props }) {
8
+ const rows = sorted ? [...items].sort((a, b) => b.value - a.value) : items;
9
+ const top = max ?? rows.reduce((largest, item) => Math.max(largest, item.value), 0);
10
+ const number = new Intl.NumberFormat(locale);
11
+ const write = (value) => formatValue ? formatValue(value) : number.format(value);
12
+ const scrolls = maxRows !== undefined && rows.length > maxRows;
13
+ const list = (_jsx("ol", { className: 'surf-bar-list-items', "aria-label": label, children: rows.map((item) => {
14
+ const share = top > 0 && Number.isFinite(item.value)
15
+ ? Math.min(100, Math.max(0, (item.value / top) * 100))
16
+ : 0;
17
+ return (_jsxs("li", { className: 'surf-bar-list-item', children: [_jsxs("span", { className: 'surf-bar-list-label', children: [_jsx("span", { className: 'surf-bar-list-name', title: item.label, children: item.label }), item.detail && (_jsx("span", { className: 'surf-bar-list-detail', title: item.detail, children: item.detail }))] }), _jsx("span", { className: 'surf-bar-list-bar', "aria-hidden": 'true', children: _jsx("span", { className: 'surf-bar-list-fill', style: { inlineSize: `${share}%` } }) }), _jsx("span", { className: 'surf-bar-list-value', children: item.text ?? write(item.value) })] }, item.id));
18
+ }) }));
19
+ return (_jsx("div", { ...props, ref: ref, className: cx('surf-bar-list', className), "data-detail": items.some((item) => item.detail) || undefined, style: scrolls
20
+ ? {
21
+ ...style,
22
+ '--surf-bar-list-rows': maxRows,
23
+ }
24
+ : style, children: scrolls ? (_jsx(ScrollArea, { orientation: 'vertical', label: label, children: list })) : (list) }));
25
+ };
@@ -1,5 +1,6 @@
1
1
  import * as React from 'react';
2
2
  import { useRender } from '@base-ui/react/use-render';
3
+ import type { StatusTone } from './status.js';
3
4
  export type BottomNavigationRootProps = React.ComponentPropsWithoutRef<'nav'> & {
4
5
  /** Names the navigation, such as "Primary". */
5
6
  'aria-label': string;
@@ -20,17 +21,20 @@ export type BottomNavigationItemProps = Omit<useRender.ComponentProps<'a'>, 'ref
20
21
  /** What the badge means, read after the label, such as "3 unread". A count reads
21
22
  * as its number without it; a dot needs it. */
22
23
  badgeLabel?: string;
24
+ /** The badge's color, by what it means: danger for what needs action now,
25
+ * caution for what needs a look soon, neutral for news. */
26
+ badgeTone?: StatusTone;
23
27
  };
24
28
  export declare const BottomNavigation: {
25
29
  Root: ({ visible, position, className, children, ref, ...props }: BottomNavigationRootProps & {
26
30
  ref?: React.Ref<HTMLElement>;
27
31
  }) => React.JSX.Element;
28
- Item: ({ icon, label, current, badge, badgeLabel, render, className, ref, ...props }: BottomNavigationItemProps & {
32
+ Item: ({ icon, label, current, badge, badgeLabel, badgeTone, render, className, ref, ...props }: BottomNavigationItemProps & {
29
33
  ref?: React.Ref<HTMLAnchorElement>;
30
34
  }) => React.JSX.Element;
31
35
  };
32
36
  export declare const BottomNavigationRoot: ({ visible, position, className, children, ref, ...props }: BottomNavigationRootProps & {
33
37
  ref?: React.Ref<HTMLElement>;
34
- }) => React.JSX.Element, BottomNavigationItem: ({ icon, label, current, badge, badgeLabel, render, className, ref, ...props }: BottomNavigationItemProps & {
38
+ }) => React.JSX.Element, BottomNavigationItem: ({ icon, label, current, badge, badgeLabel, badgeTone, render, className, ref, ...props }: BottomNavigationItemProps & {
35
39
  ref?: React.Ref<HTMLAnchorElement>;
36
40
  }) => React.JSX.Element;
@@ -9,7 +9,7 @@ const Root = function BottomNavigationRoot({ visible = 'mobile', position = 'fix
9
9
  };
10
10
  /** One destination: an icon above its label. Pass a router's link element as
11
11
  * `render` to keep client navigation. */
12
- const Item = function BottomNavigationItem({ icon, label, current, badge, badgeLabel, render, className, ref, ...props }) {
12
+ const Item = function BottomNavigationItem({ icon, label, current, badge, badgeLabel, badgeTone = 'danger', render, className, ref, ...props }) {
13
13
  const count = typeof badge === 'number' && badge > 0
14
14
  ? badge > 99
15
15
  ? '99+'
@@ -25,7 +25,7 @@ const Item = function BottomNavigationItem({ icon, label, current, badge, badgeL
25
25
  ...props,
26
26
  'aria-current': current ? 'page' : props['aria-current'],
27
27
  className: cx('surf-bottom-nav-item', className),
28
- children: (_jsxs(_Fragment, { children: [_jsxs("span", { className: 'surf-bottom-nav-icon', "aria-hidden": 'true', children: [icon, shown && (_jsx("span", { className: 'surf-bottom-nav-badge', "data-dot": count ? undefined : '', children: count }))] }), _jsx("span", { className: 'surf-bottom-nav-label', children: label }), shown && spoken && (_jsxs("span", { className: 'surf-feedback-sr', children: [", ", spoken] }))] })),
28
+ children: (_jsxs(_Fragment, { children: [_jsxs("span", { className: 'surf-bottom-nav-icon', "aria-hidden": 'true', children: [icon, shown && (_jsx("span", { className: 'surf-bottom-nav-badge', "data-tone": badgeTone, "data-dot": count ? undefined : '', children: count }))] }), _jsx("span", { className: 'surf-bottom-nav-label', children: label }), shown && spoken && (_jsxs("span", { className: 'surf-feedback-sr', children: [", ", spoken] }))] })),
29
29
  },
30
30
  });
31
31
  return _jsx("li", { className: 'surf-bottom-nav-entry', children: link });
package/dist/chart.d.ts CHANGED
@@ -1,12 +1,32 @@
1
1
  import * as React from 'react';
2
2
  export type ChartDatum = {
3
3
  id: string;
4
+ /** What the readout and the table call the row, such as its full date and time. */
4
5
  label: string;
6
+ /** When the row was measured, in ms since the epoch or as a Date. Required for
7
+ * xScale="time", where it places the row on the axis. */
8
+ time?: number | Date;
5
9
  values: Readonly<Record<string, number | null | undefined>>;
6
10
  };
7
11
  export type ChartSeries = {
8
12
  key: string;
9
13
  label: string;
14
+ /** A color of your own, such as var(--surf-chart-category-3), in place of the
15
+ * palette's. Marks and dashes still tell the series apart. */
16
+ color?: string;
17
+ };
18
+ export type ChartTone = 'neutral' | 'caution' | 'danger';
19
+ /** A threshold line at y, or a band from one value to another, such as a target
20
+ * range. The legend names it with its value. */
21
+ export type ChartReference = {
22
+ y: number;
23
+ label: string;
24
+ tone?: ChartTone;
25
+ } | {
26
+ from: number;
27
+ to: number;
28
+ label: string;
29
+ tone?: ChartTone;
10
30
  };
11
31
  export type ChartProps = Omit<React.ComponentPropsWithoutRef<'figure'>, 'children' | 'title'> & {
12
32
  title: string;
@@ -17,13 +37,33 @@ export type ChartProps = Omit<React.ComponentPropsWithoutRef<'figure'>, 'childre
17
37
  xLabel: string;
18
38
  yLabel: string;
19
39
  type?: 'line' | 'bar' | 'area';
40
+ /** Plot height in px: 280 by default, 180 when compact. */
20
41
  height?: number;
21
42
  /** Keeps 0 on the value axis. Turn it off for values far from zero, such as
22
43
  * prices, so the line uses the height; bars always start at zero. */
23
44
  includeZero?: boolean;
24
- /** neutral tells series apart by ink, dashes and markers. categorical adds six hues,
25
- * for categories that color must separate, such as buckets or sectors. */
45
+ /** neutral tells series apart by ink, dashes and markers. categorical adds twelve
46
+ * hues, for categories that color must separate, such as buckets or sectors. */
26
47
  palette?: 'neutral' | 'categorical';
48
+ /** category spaces the rows evenly and names them by label. time places them by
49
+ * data[].time, puts ticks on round times and breaks a line where sampling stops. */
50
+ xScale?: 'category' | 'time';
51
+ /** log suits values across orders of magnitude, such as prefill and decode
52
+ * throughput. Zero and negative values stay off the plot and in the table. */
53
+ yScale?: 'linear' | 'log';
54
+ /** step holds each value until the next, for values sampled when they change. */
55
+ curve?: 'linear' | 'step';
56
+ /** Stacks bar and area series, so the top of the stack is their total. */
57
+ stacked?: boolean;
58
+ /** Thresholds and target bands over the plot. The value axis reaches them. */
59
+ references?: readonly ChartReference[];
60
+ /** compact keeps the plot, legend and floating values for a dashboard card; the
61
+ * caption, keyboard help and readout stay for assistive technology. */
62
+ density?: 'default' | 'compact';
63
+ /** Above the plot, beside the value axis name, or below it. */
64
+ legendPosition?: 'top' | 'bottom';
65
+ /** Shows this many series in the legend; the rest fold behind a "+N" button. */
66
+ legendLimit?: number;
27
67
  locale?: string;
28
68
  /** Formats a value for the readout, the table and the value axis ticks. The unit
29
69
  * follows it in the readout and the table, and names the axis. */
@@ -52,9 +92,22 @@ export type ChartLabels = {
52
92
  legend: (title: string) => string;
53
93
  /** A legend button that shows or hides a series. */
54
94
  series: (label: string) => string;
95
+ /** The button that opens the series past legendLimit. */
96
+ moreSeries: (count: number) => string;
97
+ /** The sum of stacked series in the readout. */
98
+ total: string;
99
+ };
100
+ export type ChartSeriesMarkProps = {
101
+ type?: 'line' | 'bar' | 'area';
102
+ /** The series' place in the chart's series, which sets its dash, marker and color. */
103
+ index: number;
104
+ palette?: 'neutral' | 'categorical';
105
+ color?: string;
55
106
  };
107
+ /** A series' swatch as Chart's legend draws it, for a legend or key of your own. */
108
+ export declare function ChartSeriesMark({ type, index, palette, color, }: ChartSeriesMarkProps): React.JSX.Element;
56
109
  /** Cartesian trends with a persistent, keyboard-readable tooltip region and a
57
110
  * full data-table alternative. Missing values are gaps, never fabricated zeros. */
58
- export declare const Chart: ({ title, description, data, series, unit, xLabel, yLabel, type, height, includeZero, palette, locale, formatValue, labels, hiddenSeries, defaultHiddenSeries, onHiddenSeriesChange, className, ref, ...props }: ChartProps & {
111
+ export declare const Chart: ({ title, description, data, series, unit, xLabel, yLabel, type, height, includeZero, palette, xScale, yScale, curve, stacked, references, density, legendPosition, legendLimit, locale, formatValue, labels, hiddenSeries, defaultHiddenSeries, onHiddenSeriesChange, className, ref, ...props }: ChartProps & {
59
112
  ref?: React.Ref<HTMLElement>;
60
113
  }) => React.JSX.Element;