@surflane/ui 0.4.0 → 0.6.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/README.md +2 -2
- package/dist/{disclosure.d.ts → accordion.d.ts} +1 -17
- package/dist/{disclosure.js → accordion.js} +3 -17
- package/dist/alert-dialog.d.ts +31 -0
- package/dist/alert-dialog.js +22 -0
- package/dist/app-shell.d.ts +44 -3
- package/dist/app-shell.js +86 -13
- package/dist/{input-extensions.d.ts → autocomplete.d.ts} +4 -42
- package/dist/{input-extensions.js → autocomplete.js} +7 -26
- package/dist/avatar.js +3 -5
- package/dist/badge.d.ts +20 -0
- package/dist/badge.js +16 -0
- package/dist/bottom-navigation.d.ts +66 -0
- package/dist/bottom-navigation.js +36 -0
- package/dist/{navigation.d.ts → breadcrumbs.d.ts} +2 -6
- package/dist/breadcrumbs.js +31 -0
- package/dist/button.d.ts +11 -0
- package/dist/button.js +27 -4
- package/dist/{content.d.ts → card.d.ts} +6 -24
- package/dist/card.js +26 -0
- package/dist/chart.d.ts +35 -0
- package/dist/chart.js +123 -50
- package/dist/checkbox-group.d.ts +2 -0
- package/dist/checkbox-group.js +16 -0
- package/dist/checkbox.d.ts +9 -0
- package/dist/checkbox.js +29 -0
- package/dist/choice-label.d.ts +25 -0
- package/dist/choice-label.js +14 -0
- package/dist/choice.d.ts +7 -0
- package/dist/choice.js +3 -0
- package/dist/code.d.ts +21 -0
- package/dist/{content.js → code.js} +5 -30
- package/dist/collapsible.d.ts +18 -0
- package/dist/collapsible.js +21 -0
- package/dist/{advanced-forms.d.ts → combobox.d.ts} +5 -25
- package/dist/{advanced-forms.js → combobox.js} +13 -49
- package/dist/{context-overlays.d.ts → context-menu.d.ts} +6 -28
- package/dist/{context-overlays.js → context-menu.js} +5 -25
- package/dist/css/accordion.css +11 -0
- package/dist/css/alert-dialog.css +11 -0
- package/{src → dist/css}/all.css +1 -1
- package/dist/css/app-shell.css +12 -0
- package/dist/css/autocomplete.css +15 -0
- package/dist/css/avatar.css +10 -0
- package/dist/css/badge.css +10 -0
- package/dist/css/bottom-navigation.css +8 -0
- package/dist/css/breadcrumbs.css +12 -0
- package/dist/css/button.css +8 -0
- package/dist/css/card.css +11 -0
- package/dist/css/chart.css +13 -0
- package/dist/css/checkbox-group.css +9 -0
- package/dist/css/checkbox.css +9 -0
- package/dist/css/choice-label.css +9 -0
- package/dist/css/code.css +13 -0
- package/dist/css/collapsible.css +11 -0
- package/dist/css/combobox.css +14 -0
- package/dist/css/context-menu.css +15 -0
- package/dist/css/date-picker.css +12 -0
- package/dist/css/dialog.css +10 -0
- package/dist/css/drawer.css +11 -0
- package/dist/css/empty-state.css +9 -0
- package/dist/css/field.css +10 -0
- package/dist/css/fieldset.css +8 -0
- package/dist/css/file-upload.css +17 -0
- package/dist/css/filter-bar.css +8 -0
- package/dist/css/form.css +8 -0
- package/dist/css/icon.css +8 -0
- package/dist/css/inline-message.css +10 -0
- package/dist/css/input.css +9 -0
- package/dist/css/layout.css +9 -0
- package/dist/css/link.css +9 -0
- package/dist/css/list.css +9 -0
- package/dist/css/markdown.css +18 -0
- package/dist/css/menu.css +14 -0
- package/dist/css/menubar.css +9 -0
- package/dist/css/meter.css +9 -0
- package/dist/css/native-select.css +13 -0
- package/dist/css/navigation-menu.css +11 -0
- package/dist/css/number-field.css +11 -0
- package/dist/css/otp-field.css +10 -0
- package/dist/css/page-header.css +11 -0
- package/dist/css/pagination.css +11 -0
- package/dist/css/popover.css +9 -0
- package/dist/css/preview-card.css +11 -0
- package/dist/css/progress.css +9 -0
- package/dist/css/radio-group.css +9 -0
- package/dist/css/rules/accordion.css +21 -0
- package/dist/css/rules/alert-dialog.css +23 -0
- package/dist/css/rules/app-shell.css +220 -0
- package/dist/css/rules/autocomplete.css +3 -0
- package/dist/css/rules/avatar.css +17 -0
- package/dist/css/rules/badge.css +17 -0
- package/dist/css/rules/bar.css +38 -0
- package/dist/css/rules/base.css +46 -0
- package/dist/css/rules/bottom-navigation.css +142 -0
- package/dist/css/rules/breadcrumbs.css +9 -0
- package/dist/css/rules/button.css +131 -0
- package/dist/css/rules/card.css +10 -0
- package/dist/css/rules/chart.css +256 -0
- package/dist/css/rules/checkbox-group.css +3 -0
- package/dist/css/rules/checkbox.css +25 -0
- package/dist/css/rules/choice-label.css +52 -0
- package/dist/css/rules/choice.css +104 -0
- package/dist/css/rules/code.css +9 -0
- package/dist/css/rules/collapsible.css +12 -0
- package/dist/css/rules/combobox.css +177 -0
- package/dist/css/rules/context-menu.css +9 -0
- package/dist/css/rules/date-picker.css +301 -0
- package/dist/css/rules/dialog.css +160 -0
- package/dist/css/rules/disclosure.css +107 -0
- package/dist/css/rules/drawer.css +18 -0
- package/dist/css/rules/empty-state.css +9 -0
- package/dist/css/rules/field-control.css +70 -0
- package/dist/css/rules/field.css +56 -0
- package/dist/css/rules/fieldset.css +23 -0
- package/dist/css/rules/file-upload.css +156 -0
- package/dist/css/rules/filter-bar.css +56 -0
- package/dist/css/rules/form.css +15 -0
- package/dist/css/rules/gauge.css +61 -0
- package/dist/css/rules/icon.css +27 -0
- package/dist/css/rules/inline-message.css +10 -0
- package/dist/css/rules/input-group.css +69 -0
- package/dist/css/rules/input.css +33 -0
- package/dist/css/rules/item.css +14 -0
- package/dist/css/rules/layout.css +3 -0
- package/dist/css/rules/link.css +9 -0
- package/dist/css/rules/list.css +10 -0
- package/dist/css/rules/markdown.css +63 -0
- package/dist/css/rules/menu.css +97 -0
- package/dist/css/rules/menubar.css +18 -0
- package/dist/css/rules/meter.css +3 -0
- package/dist/css/rules/native-select.css +3 -0
- package/dist/css/rules/navigation-menu.css +159 -0
- package/dist/css/rules/number-field.css +55 -0
- package/dist/css/rules/otp-field.css +68 -0
- package/dist/css/rules/page-header.css +3 -0
- package/dist/css/rules/pagination.css +3 -0
- package/dist/css/rules/panel.css +221 -0
- package/dist/css/rules/popover.css +41 -0
- package/dist/css/rules/popup.css +27 -0
- package/dist/css/rules/preview-card.css +60 -0
- package/dist/css/rules/progress.css +14 -0
- package/dist/css/rules/radio-group.css +26 -0
- package/dist/css/rules/scroll-area.css +101 -0
- package/dist/css/rules/select.css +88 -0
- package/dist/css/rules/separator.css +3 -0
- package/dist/css/rules/sheet.css +3 -0
- package/dist/css/rules/sizing.css +140 -0
- package/dist/css/rules/skeleton.css +41 -0
- package/dist/css/rules/slider.css +123 -0
- package/dist/css/rules/sparkline.css +52 -0
- package/dist/css/rules/spinner.css +38 -0
- package/dist/css/rules/stat.css +59 -0
- package/dist/css/rules/switch.css +50 -0
- package/dist/css/rules/syntax-highlighter.css +82 -0
- package/dist/css/rules/table.css +28 -0
- package/dist/css/rules/tabs.css +126 -0
- package/dist/css/rules/textarea.css +21 -0
- package/dist/css/rules/toast.css +247 -0
- package/dist/css/rules/toggle-group.css +3 -0
- package/dist/css/rules/toggle.css +27 -0
- package/dist/css/rules/toolbar.css +62 -0
- package/dist/css/rules/tooltip.css +38 -0
- package/dist/css/rules/tree.css +98 -0
- package/dist/css/rules/typography.css +3 -0
- package/dist/css/scroll-area.css +8 -0
- package/dist/css/select.css +12 -0
- package/dist/css/separator.css +9 -0
- package/dist/css/sheet.css +11 -0
- package/dist/css/sizing.css +7 -0
- package/dist/css/skeleton.css +8 -0
- package/dist/css/slider.css +8 -0
- package/dist/css/sparkline.css +8 -0
- package/dist/css/spinner.css +8 -0
- package/dist/css/stat.css +9 -0
- package/dist/css/styles.css +100 -0
- package/dist/css/switch.css +9 -0
- package/dist/css/syntax-highlighter.css +9 -0
- package/dist/css/table.css +12 -0
- package/dist/css/tabs.css +8 -0
- package/dist/css/textarea.css +10 -0
- package/dist/css/toast.css +11 -0
- package/dist/css/toggle-group.css +9 -0
- package/dist/css/toggle.css +10 -0
- package/dist/css/toolbar.css +12 -0
- package/dist/css/tooltip.css +9 -0
- package/dist/css/tree.css +10 -0
- package/dist/css/typography.css +9 -0
- package/dist/date-picker.js +3 -2
- package/dist/dialog.d.ts +6 -24
- package/dist/dialog.js +7 -20
- package/dist/{panels.d.ts → drawer.d.ts} +3 -34
- package/dist/drawer.js +47 -0
- package/dist/empty-state.d.ts +29 -0
- package/dist/empty-state.js +19 -0
- package/dist/field.d.ts +42 -0
- package/dist/field.js +21 -0
- package/dist/fieldset.d.ts +14 -0
- package/dist/fieldset.js +10 -0
- package/dist/file-upload.d.ts +3 -1
- package/dist/file-upload.js +7 -5
- package/dist/filter-bar.js +1 -1
- package/dist/form.d.ts +2 -0
- package/dist/form.js +7 -0
- package/dist/format.d.ts +25 -0
- package/dist/format.js +42 -0
- package/dist/icon.d.ts +11 -0
- package/dist/icon.js +19 -3
- package/dist/index.d.ts +61 -30
- package/dist/index.js +75 -33
- package/dist/{messages.d.ts → inline-message.d.ts} +0 -28
- package/dist/{messages.js → inline-message.js} +3 -18
- package/dist/input.js +2 -2
- package/dist/{foundations.d.ts → layout.d.ts} +5 -23
- package/dist/{foundations.js → layout.js} +4 -19
- package/dist/link.d.ts +6 -0
- package/dist/link.js +17 -0
- package/dist/list.d.ts +33 -0
- package/dist/list.js +21 -0
- package/dist/markdown.js +4 -5
- package/dist/menu.d.ts +7 -5
- package/dist/menu.js +12 -8
- package/dist/menubar.d.ts +4 -0
- package/dist/menubar.js +4 -0
- package/dist/meter.d.ts +29 -0
- package/dist/meter.js +13 -0
- package/dist/native-select.d.ts +8 -0
- package/dist/native-select.js +54 -0
- package/dist/navigation-menu.js +8 -5
- package/dist/number-field.d.ts +23 -0
- package/dist/number-field.js +33 -0
- package/dist/page-header.d.ts +12 -0
- package/dist/page-header.js +9 -0
- package/dist/pagination.js +3 -4
- package/dist/panel.d.ts +13 -0
- package/dist/panel.js +13 -0
- package/dist/parts.d.ts +19 -1
- package/dist/parts.js +32 -6
- package/dist/popover.d.ts +23 -6
- package/dist/popover.js +17 -7
- package/dist/preview-card.d.ts +29 -0
- package/dist/preview-card.js +27 -0
- package/dist/progress.d.ts +29 -0
- package/dist/progress.js +13 -0
- package/dist/radio-group.d.ts +16 -0
- package/dist/radio-group.js +31 -0
- package/dist/scroll-area.js +3 -4
- package/dist/select.d.ts +8 -8
- package/dist/select.js +19 -54
- package/dist/separator.d.ts +4 -0
- package/dist/separator.js +8 -0
- package/dist/sheet.d.ts +29 -0
- package/dist/sheet.js +39 -0
- package/dist/skeleton.d.ts +8 -0
- package/dist/skeleton.js +8 -0
- package/dist/slider.d.ts +40 -0
- package/dist/slider.js +27 -0
- package/dist/sparkline.d.ts +41 -0
- package/dist/sparkline.js +50 -0
- package/dist/spinner.d.ts +13 -0
- package/dist/spinner.js +10 -0
- package/dist/stat.d.ts +59 -0
- package/dist/stat.js +26 -0
- package/dist/status.d.ts +2 -20
- package/dist/status.js +11 -14
- package/dist/switch.d.ts +13 -0
- package/dist/switch.js +25 -0
- package/dist/syntax-highlighter.js +2 -1
- package/dist/{data.d.ts → table.d.ts} +8 -32
- package/dist/{data.js → table.js} +15 -30
- package/dist/textarea.d.ts +7 -0
- package/dist/textarea.js +12 -0
- package/dist/toast.d.ts +57 -1
- package/dist/toast.js +80 -8
- package/dist/toggle-group.d.ts +5 -0
- package/dist/toggle-group.js +7 -0
- package/dist/toggle.d.ts +7 -0
- package/dist/toggle.js +9 -0
- package/dist/{commands.d.ts → toolbar.d.ts} +0 -13
- package/dist/toolbar.js +14 -0
- package/dist/tooltip.d.ts +10 -3
- package/dist/tooltip.js +4 -4
- package/dist/tree.js +4 -2
- package/dist/typography.d.ts +12 -0
- package/dist/typography.js +14 -0
- package/package.json +324 -25
- package/dist/chevron.d.ts +0 -3
- package/dist/chevron.js +0 -6
- package/dist/commands.js +0 -27
- package/dist/feedback.d.ts +0 -76
- package/dist/feedback.js +0 -35
- package/dist/forms.d.ts +0 -91
- package/dist/forms.js +0 -109
- package/dist/navigation.js +0 -41
- package/dist/panels.js +0 -100
- package/src/styles.css +0 -3780
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { useRender } from '@base-ui/react/use-render';
|
|
3
|
+
export type BottomNavigationRootProps = React.ComponentPropsWithoutRef<'nav'> & {
|
|
4
|
+
/** Names the navigation, such as "Primary". */
|
|
5
|
+
'aria-label': string;
|
|
6
|
+
/** mobile: shown at 760px and narrower, where AppShell hides its sidebar. always:
|
|
7
|
+
* at every width. */
|
|
8
|
+
visible?: 'mobile' | 'always';
|
|
9
|
+
/** fixed: pinned to the bottom of the viewport, above the safe area. static: in the
|
|
10
|
+
* flow, for a frame of your own. */
|
|
11
|
+
position?: 'fixed' | 'static';
|
|
12
|
+
};
|
|
13
|
+
export type BottomNavigationItemProps = Omit<useRender.ComponentProps<'a'>, 'ref' | 'children'> & {
|
|
14
|
+
icon: React.ReactNode;
|
|
15
|
+
label: string;
|
|
16
|
+
/** Marks the current destination with aria-current="page". */
|
|
17
|
+
current?: boolean;
|
|
18
|
+
/** A count, shown up to 99+, or true for a dot. */
|
|
19
|
+
badge?: number | boolean;
|
|
20
|
+
/** What the badge means, read after the label, such as "3 unread". A count reads
|
|
21
|
+
* as its number without it; a dot needs it. */
|
|
22
|
+
badgeLabel?: string;
|
|
23
|
+
};
|
|
24
|
+
export declare const BottomNavigation: {
|
|
25
|
+
Root: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>, "ref"> & {
|
|
26
|
+
/** Names the navigation, such as "Primary". */
|
|
27
|
+
'aria-label': string;
|
|
28
|
+
/** mobile: shown at 760px and narrower, where AppShell hides its sidebar. always:
|
|
29
|
+
* at every width. */
|
|
30
|
+
visible?: "mobile" | "always";
|
|
31
|
+
/** fixed: pinned to the bottom of the viewport, above the safe area. static: in the
|
|
32
|
+
* flow, for a frame of your own. */
|
|
33
|
+
position?: "fixed" | "static";
|
|
34
|
+
} & React.RefAttributes<HTMLElement>>;
|
|
35
|
+
Item: React.ForwardRefExoticComponent<Omit<useRender.ComponentProps<"a", {}, import("@base-ui/react/types").HTMLProps>, "children" | "ref"> & {
|
|
36
|
+
icon: React.ReactNode;
|
|
37
|
+
label: string;
|
|
38
|
+
/** Marks the current destination with aria-current="page". */
|
|
39
|
+
current?: boolean;
|
|
40
|
+
/** A count, shown up to 99+, or true for a dot. */
|
|
41
|
+
badge?: number | boolean;
|
|
42
|
+
/** What the badge means, read after the label, such as "3 unread". A count reads
|
|
43
|
+
* as its number without it; a dot needs it. */
|
|
44
|
+
badgeLabel?: string;
|
|
45
|
+
} & React.RefAttributes<HTMLAnchorElement>>;
|
|
46
|
+
};
|
|
47
|
+
export declare const BottomNavigationRoot: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>, "ref"> & {
|
|
48
|
+
/** Names the navigation, such as "Primary". */
|
|
49
|
+
'aria-label': string;
|
|
50
|
+
/** mobile: shown at 760px and narrower, where AppShell hides its sidebar. always:
|
|
51
|
+
* at every width. */
|
|
52
|
+
visible?: "mobile" | "always";
|
|
53
|
+
/** fixed: pinned to the bottom of the viewport, above the safe area. static: in the
|
|
54
|
+
* flow, for a frame of your own. */
|
|
55
|
+
position?: "fixed" | "static";
|
|
56
|
+
} & React.RefAttributes<HTMLElement>>, BottomNavigationItem: React.ForwardRefExoticComponent<Omit<useRender.ComponentProps<"a", {}, import("@base-ui/react/types").HTMLProps>, "children" | "ref"> & {
|
|
57
|
+
icon: React.ReactNode;
|
|
58
|
+
label: string;
|
|
59
|
+
/** Marks the current destination with aria-current="page". */
|
|
60
|
+
current?: boolean;
|
|
61
|
+
/** A count, shown up to 99+, or true for a dot. */
|
|
62
|
+
badge?: number | boolean;
|
|
63
|
+
/** What the badge means, read after the label, such as "3 unread". A count reads
|
|
64
|
+
* as its number without it; a dot needs it. */
|
|
65
|
+
badgeLabel?: string;
|
|
66
|
+
} & React.RefAttributes<HTMLAnchorElement>>;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { useRender } from '@base-ui/react/use-render';
|
|
5
|
+
import { cx } from './parts.js';
|
|
6
|
+
/** A phone's primary destinations along the bottom edge, within thumb reach. Pad the
|
|
7
|
+
* scrolling content by --size-bottom-navigation so the last line stays visible. */
|
|
8
|
+
const Root = /* @__PURE__ */ React.forwardRef(function BottomNavigationRoot({ visible = 'mobile', position = 'fixed', className, children, ...props }, ref) {
|
|
9
|
+
return (_jsx("nav", { ...props, ref: ref, "data-visible": visible, "data-position": position, className: cx('pui-bottom-nav', className), children: _jsx("ul", { role: 'list', className: 'pui-bottom-nav-list', children: children }) }));
|
|
10
|
+
});
|
|
11
|
+
/** One destination: an icon above its label. Pass a router's link element as
|
|
12
|
+
* `render` to keep client navigation. */
|
|
13
|
+
const Item = /* @__PURE__ */ React.forwardRef(function BottomNavigationItem({ icon, label, current, badge, badgeLabel, render, className, ...props }, ref) {
|
|
14
|
+
const count = typeof badge === 'number' && badge > 0
|
|
15
|
+
? badge > 99
|
|
16
|
+
? '99+'
|
|
17
|
+
: String(badge)
|
|
18
|
+
: undefined;
|
|
19
|
+
const shown = Boolean(count || badge === true);
|
|
20
|
+
const spoken = badgeLabel ?? count;
|
|
21
|
+
const link = useRender({
|
|
22
|
+
defaultTagName: 'a',
|
|
23
|
+
render,
|
|
24
|
+
ref,
|
|
25
|
+
props: {
|
|
26
|
+
...props,
|
|
27
|
+
'aria-current': current ? 'page' : props['aria-current'],
|
|
28
|
+
className: cx('pui-bottom-nav-item', className),
|
|
29
|
+
children: (_jsxs(_Fragment, { children: [_jsxs("span", { className: 'pui-bottom-nav-icon', "aria-hidden": 'true', children: [icon, shown && (_jsx("span", { className: 'pui-bottom-nav-badge', "data-dot": count ? undefined : '', children: count }))] }), _jsx("span", { className: 'pui-bottom-nav-label', children: label }), shown && spoken && (_jsxs("span", { className: 'pui-feedback-sr', children: [", ", spoken] }))] })),
|
|
30
|
+
},
|
|
31
|
+
});
|
|
32
|
+
return _jsx("li", { className: 'pui-bottom-nav-entry', children: link });
|
|
33
|
+
});
|
|
34
|
+
export const BottomNavigation = { Root, Item };
|
|
35
|
+
// Flat names for React Server Components, which cannot dot into client exports.
|
|
36
|
+
export const { Root: BottomNavigationRoot, Item: BottomNavigationItem } = BottomNavigation;
|
|
@@ -1,17 +1,13 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
export declare const Separator: React.ForwardRefExoticComponent<Omit<Omit<import("@base-ui/react/separator").SeparatorProps, "ref"> & React.RefAttributes<HTMLDivElement>, "ref"> & {
|
|
3
|
-
inset?: boolean;
|
|
4
|
-
} & React.RefAttributes<HTMLDivElement>>;
|
|
5
|
-
export declare const Link: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.AnchorHTMLAttributes<HTMLAnchorElement>, HTMLAnchorElement>, "ref"> & React.RefAttributes<HTMLAnchorElement>>;
|
|
6
2
|
declare function BreadcrumbSeparator({ className, ...props }: React.ComponentProps<'span'>): React.JSX.Element;
|
|
7
3
|
declare function BreadcrumbCurrent({ className, ...props }: React.ComponentProps<'span'>): React.JSX.Element;
|
|
8
4
|
export declare const Breadcrumbs: {
|
|
9
5
|
Root: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>, "ref"> & React.RefAttributes<HTMLElement>>;
|
|
10
6
|
List: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.OlHTMLAttributes<HTMLOListElement>, HTMLOListElement>, "ref"> & React.RefAttributes<HTMLOListElement>>;
|
|
11
7
|
Item: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>, "ref"> & React.RefAttributes<HTMLLIElement>>;
|
|
12
|
-
Link: React.ForwardRefExoticComponent<
|
|
8
|
+
Link: React.ForwardRefExoticComponent<import("./link.js").LinkProps & React.RefAttributes<HTMLAnchorElement>>;
|
|
13
9
|
Separator: typeof BreadcrumbSeparator;
|
|
14
10
|
Current: typeof BreadcrumbCurrent;
|
|
15
11
|
};
|
|
16
|
-
export declare const BreadcrumbsRoot: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>, "ref"> & React.RefAttributes<HTMLElement>>, BreadcrumbsList: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.OlHTMLAttributes<HTMLOListElement>, HTMLOListElement>, "ref"> & React.RefAttributes<HTMLOListElement>>, BreadcrumbsItem: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>, "ref"> & React.RefAttributes<HTMLLIElement>>, BreadcrumbsLink: React.ForwardRefExoticComponent<
|
|
12
|
+
export declare const BreadcrumbsRoot: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>, "ref"> & React.RefAttributes<HTMLElement>>, BreadcrumbsList: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.OlHTMLAttributes<HTMLOListElement>, HTMLOListElement>, "ref"> & React.RefAttributes<HTMLOListElement>>, BreadcrumbsItem: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.LiHTMLAttributes<HTMLLIElement>, HTMLLIElement>, "ref"> & React.RefAttributes<HTMLLIElement>>, BreadcrumbsLink: React.ForwardRefExoticComponent<import("./link.js").LinkProps & React.RefAttributes<HTMLAnchorElement>>, BreadcrumbsSeparator: typeof BreadcrumbSeparator, BreadcrumbsCurrent: typeof BreadcrumbCurrent;
|
|
17
13
|
export {};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { Icon } from './icon.js';
|
|
5
|
+
import { cx } from './parts.js';
|
|
6
|
+
import { Link } from './link.js';
|
|
7
|
+
const BreadcrumbRoot = /* @__PURE__ */ React.forwardRef(function BreadcrumbRoot({ className, 'aria-label': label = 'Breadcrumb', ...props }, ref) {
|
|
8
|
+
return (_jsx("nav", { ...props, ref: ref, "aria-label": label, className: cx('pui-breadcrumbs', className) }));
|
|
9
|
+
});
|
|
10
|
+
const BreadcrumbList = /* @__PURE__ */ React.forwardRef(function BreadcrumbList({ className, role = 'list', ...props }, ref) {
|
|
11
|
+
return (_jsx("ol", { ...props, role: role, ref: ref, className: cx('pui-breadcrumb-list', className) }));
|
|
12
|
+
});
|
|
13
|
+
const BreadcrumbItem = /* @__PURE__ */ React.forwardRef(function BreadcrumbItem({ className, ...props }, ref) {
|
|
14
|
+
return (_jsx("li", { ...props, ref: ref, className: cx('pui-breadcrumb-item', className) }));
|
|
15
|
+
});
|
|
16
|
+
function BreadcrumbSeparator({ className, ...props }) {
|
|
17
|
+
return (_jsx("span", { ...props, className: cx('pui-breadcrumb-separator', className), "aria-hidden": 'true', children: _jsx(Icon, { name: 'chevron-forward' }) }));
|
|
18
|
+
}
|
|
19
|
+
function BreadcrumbCurrent({ className, ...props }) {
|
|
20
|
+
return (_jsx("span", { ...props, className: cx('pui-breadcrumb-current', className), "aria-current": 'page' }));
|
|
21
|
+
}
|
|
22
|
+
export const Breadcrumbs = {
|
|
23
|
+
Root: BreadcrumbRoot,
|
|
24
|
+
List: BreadcrumbList,
|
|
25
|
+
Item: BreadcrumbItem,
|
|
26
|
+
Link,
|
|
27
|
+
Separator: BreadcrumbSeparator,
|
|
28
|
+
Current: BreadcrumbCurrent,
|
|
29
|
+
};
|
|
30
|
+
// Flat names for React Server Components, which cannot dot into client exports.
|
|
31
|
+
export const { Root: BreadcrumbsRoot, List: BreadcrumbsList, Item: BreadcrumbsItem, Link: BreadcrumbsLink, Separator: BreadcrumbsSeparator, Current: BreadcrumbsCurrent, } = Breadcrumbs;
|
package/dist/button.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { Button as BaseButton } from '@base-ui/react/button';
|
|
3
|
+
import { useRender } from '@base-ui/react/use-render';
|
|
3
4
|
import { type ComponentSizeAlias } from './sizing.js';
|
|
4
5
|
/** Visual priority. `default` remains a compatibility alias of `primary`. */
|
|
5
6
|
export type ButtonVariant = 'primary' | 'default' | 'secondary' | 'outline' | 'ghost' | 'destructive' | 'link';
|
|
@@ -9,3 +10,13 @@ export type ButtonProps = React.ComponentProps<typeof BaseButton> & {
|
|
|
9
10
|
size?: ButtonSize;
|
|
10
11
|
};
|
|
11
12
|
export declare const Button: React.ForwardRefExoticComponent<Omit<ButtonProps, "ref"> & React.RefAttributes<HTMLButtonElement>>;
|
|
13
|
+
export type LinkButtonProps = Omit<useRender.ComponentProps<'a'>, 'ref'> & {
|
|
14
|
+
variant?: ButtonVariant;
|
|
15
|
+
size?: ButtonSize;
|
|
16
|
+
};
|
|
17
|
+
/** A link that looks like a Button. It navigates, so it stays a link for assistive
|
|
18
|
+
* technology; pass a router's link element as `render` to keep client navigation. */
|
|
19
|
+
export declare const LinkButton: React.ForwardRefExoticComponent<Omit<useRender.ComponentProps<"a", {}, import("@base-ui/react/types").HTMLProps>, "ref"> & {
|
|
20
|
+
variant?: ButtonVariant;
|
|
21
|
+
size?: ButtonSize;
|
|
22
|
+
} & React.RefAttributes<HTMLAnchorElement>>;
|
package/dist/button.js
CHANGED
|
@@ -2,15 +2,38 @@
|
|
|
2
2
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
3
|
import * as React from 'react';
|
|
4
4
|
import { Button as BaseButton } from '@base-ui/react/button';
|
|
5
|
+
import { useRender } from '@base-ui/react/use-render';
|
|
5
6
|
import { useComponentSize } from './sizing.js';
|
|
6
|
-
import { sizeName, skin } from './parts.js';
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
import { sizeName, skin, cx } from './parts.js';
|
|
8
|
+
/** The size scheme a button size implies: icon sizes follow the scale, xs and icon
|
|
9
|
+
* keep the surrounding scheme. */
|
|
10
|
+
function schemeOf(size) {
|
|
11
|
+
return size === 'icon-sm' || size === 'icon-xs'
|
|
9
12
|
? 'small'
|
|
10
13
|
: size === 'icon-lg'
|
|
11
14
|
? 'large'
|
|
12
15
|
: size === 'xs' || size === 'icon'
|
|
13
16
|
? undefined
|
|
14
|
-
: size
|
|
17
|
+
: size;
|
|
18
|
+
}
|
|
19
|
+
export const Button = /* @__PURE__ */ React.forwardRef(function Button({ className, variant = 'default', size, ...props }, ref) {
|
|
20
|
+
const scheme = useComponentSize(schemeOf(size));
|
|
15
21
|
return (_jsx(BaseButton, { ref: ref, ...props, className: skin('pui-button', className), "data-variant": variant, "data-size": sizeName(size), "data-ui-size": scheme }));
|
|
16
22
|
});
|
|
23
|
+
/** A link that looks like a Button. It navigates, so it stays a link for assistive
|
|
24
|
+
* technology; pass a router's link element as `render` to keep client navigation. */
|
|
25
|
+
export const LinkButton = /* @__PURE__ */ React.forwardRef(function LinkButton({ render, className, variant = 'default', size, ...props }, ref) {
|
|
26
|
+
const scheme = useComponentSize(schemeOf(size));
|
|
27
|
+
return useRender({
|
|
28
|
+
defaultTagName: 'a',
|
|
29
|
+
render,
|
|
30
|
+
ref,
|
|
31
|
+
props: {
|
|
32
|
+
...props,
|
|
33
|
+
className: cx('pui-button', className),
|
|
34
|
+
'data-variant': variant,
|
|
35
|
+
'data-size': sizeName(size),
|
|
36
|
+
'data-ui-size': scheme,
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
});
|
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
declare const CardRoot: React.ForwardRefExoticComponent<Omit<Omit<React.ClassAttributes<HTMLDivElement> & React.HTMLAttributes<HTMLDivElement> & {
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
surface?: import("./layout.js").SurfaceKind;
|
|
4
|
+
tone?: import("./layout.js").SurfaceKind;
|
|
5
|
+
padding?: import("./layout.js").Space;
|
|
5
6
|
}, "ref"> & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
6
7
|
declare const CardTitle: React.ForwardRefExoticComponent<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLHeadingElement>, HTMLHeadingElement>, "ref"> & {
|
|
7
8
|
level?: 2 | 3 | 4 | 5 | 6;
|
|
8
9
|
} & React.RefAttributes<HTMLHeadingElement>>;
|
|
9
10
|
export declare const Card: {
|
|
10
11
|
Root: React.ForwardRefExoticComponent<Omit<Omit<React.ClassAttributes<HTMLDivElement> & React.HTMLAttributes<HTMLDivElement> & {
|
|
11
|
-
|
|
12
|
-
|
|
12
|
+
surface?: import("./layout.js").SurfaceKind;
|
|
13
|
+
tone?: import("./layout.js").SurfaceKind;
|
|
14
|
+
padding?: import("./layout.js").Space;
|
|
13
15
|
}, "ref"> & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
|
|
14
16
|
Header: React.ForwardRefExoticComponent<Omit<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref">, "size"> & {
|
|
15
17
|
size?: import("./sizing.js").ComponentSize;
|
|
@@ -27,26 +29,6 @@ export declare const Card: {
|
|
|
27
29
|
size?: import("./sizing.js").ComponentSize;
|
|
28
30
|
} & React.RefAttributes<HTMLDivElement>>;
|
|
29
31
|
};
|
|
30
|
-
export type CodeBlockProps = Omit<React.ComponentPropsWithoutRef<'div'>, 'children' | 'onCopy'> & {
|
|
31
|
-
code: string;
|
|
32
|
-
label?: string;
|
|
33
|
-
language?: string;
|
|
34
|
-
wrap?: boolean;
|
|
35
|
-
copyLabel?: string;
|
|
36
|
-
copiedLabel?: string;
|
|
37
|
-
copyErrorLabel?: string;
|
|
38
|
-
onCopy?: (code: string) => void | Promise<void>;
|
|
39
|
-
};
|
|
40
|
-
export declare const CodeBlock: React.ForwardRefExoticComponent<Omit<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref">, "children" | "onCopy"> & {
|
|
41
|
-
code: string;
|
|
42
|
-
label?: string;
|
|
43
|
-
language?: string;
|
|
44
|
-
wrap?: boolean;
|
|
45
|
-
copyLabel?: string;
|
|
46
|
-
copiedLabel?: string;
|
|
47
|
-
copyErrorLabel?: string;
|
|
48
|
-
onCopy?: (code: string) => void | Promise<void>;
|
|
49
|
-
} & React.RefAttributes<HTMLDivElement>>;
|
|
50
32
|
export { CardRoot, CardTitle };
|
|
51
33
|
export declare const CardHeader: React.ForwardRefExoticComponent<Omit<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref">, "size"> & {
|
|
52
34
|
size?: import("./sizing.js").ComponentSize;
|
package/dist/card.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { Surface } from './layout.js';
|
|
5
|
+
import { part, cx } from './parts.js';
|
|
6
|
+
const CardRoot = /* @__PURE__ */ React.forwardRef(function CardRoot({ className, padding, ...props }, ref) {
|
|
7
|
+
return (_jsx(Surface, { ...props, padding: padding, ref: ref, className: cx('pui-card', className) }));
|
|
8
|
+
});
|
|
9
|
+
const CardTitle = /* @__PURE__ */ React.forwardRef(function CardTitle({ level = 3, className, ...props }, ref) {
|
|
10
|
+
return React.createElement(`h${level}`, {
|
|
11
|
+
...props,
|
|
12
|
+
ref,
|
|
13
|
+
className: cx('pui-card-title', className),
|
|
14
|
+
});
|
|
15
|
+
});
|
|
16
|
+
export const Card = {
|
|
17
|
+
Root: CardRoot,
|
|
18
|
+
Header: /* @__PURE__ */ part('div', 'pui-card-header'),
|
|
19
|
+
Title: CardTitle,
|
|
20
|
+
Description: /* @__PURE__ */ part('p', 'pui-card-description'),
|
|
21
|
+
Body: /* @__PURE__ */ part('div', 'pui-card-body'),
|
|
22
|
+
Footer: /* @__PURE__ */ part('div', 'pui-card-footer'),
|
|
23
|
+
};
|
|
24
|
+
// Flat names for React Server Components, which cannot dot into client exports.
|
|
25
|
+
export { CardRoot, CardTitle };
|
|
26
|
+
export const { Header: CardHeader, Description: CardDescription, Body: CardBody, Footer: CardFooter, } = Card;
|
package/dist/chart.d.ts
CHANGED
|
@@ -18,14 +18,39 @@ export type ChartProps = Omit<React.ComponentPropsWithoutRef<'figure'>, 'childre
|
|
|
18
18
|
yLabel: string;
|
|
19
19
|
type?: 'line' | 'bar' | 'area';
|
|
20
20
|
height?: number;
|
|
21
|
+
/** Keeps 0 on the value axis. Turn it off for values far from zero, such as
|
|
22
|
+
* prices, so the line uses the height; bars always start at zero. */
|
|
23
|
+
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. */
|
|
26
|
+
palette?: 'neutral' | 'categorical';
|
|
21
27
|
locale?: string;
|
|
22
28
|
formatValue?: (value: number) => string;
|
|
29
|
+
/** Text the chart shows or announces; pass translations here. */
|
|
30
|
+
labels?: Partial<ChartLabels>;
|
|
31
|
+
/** @deprecated Use labels.missing. */
|
|
23
32
|
missingLabel?: string;
|
|
33
|
+
/** @deprecated Use labels.empty. */
|
|
24
34
|
emptyLabel?: string;
|
|
25
35
|
hiddenSeries?: readonly string[];
|
|
26
36
|
defaultHiddenSeries?: readonly string[];
|
|
27
37
|
onHiddenSeriesChange?: (keys: string[]) => void;
|
|
28
38
|
};
|
|
39
|
+
export type ChartLabels = {
|
|
40
|
+
missing: string;
|
|
41
|
+
empty: string;
|
|
42
|
+
noSeries: string;
|
|
43
|
+
showAll: string;
|
|
44
|
+
keyboardHelp: string;
|
|
45
|
+
values: (title: string) => string;
|
|
46
|
+
viewTable: string;
|
|
47
|
+
table: (title: string) => string;
|
|
48
|
+
tableCaption: (unit: string) => string;
|
|
49
|
+
/** The readout before any point is inspected. */
|
|
50
|
+
inspectHint: string;
|
|
51
|
+
/** The data table's only row when there is no data. */
|
|
52
|
+
noRows: string;
|
|
53
|
+
};
|
|
29
54
|
/** Cartesian trends with a persistent, keyboard-readable tooltip region and a
|
|
30
55
|
* full data-table alternative. Missing values are gaps, never fabricated zeros. */
|
|
31
56
|
export declare const Chart: React.ForwardRefExoticComponent<Omit<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>, "ref">, "children" | "title"> & {
|
|
@@ -38,9 +63,19 @@ export declare const Chart: React.ForwardRefExoticComponent<Omit<Omit<React.Deta
|
|
|
38
63
|
yLabel: string;
|
|
39
64
|
type?: "line" | "bar" | "area";
|
|
40
65
|
height?: number;
|
|
66
|
+
/** Keeps 0 on the value axis. Turn it off for values far from zero, such as
|
|
67
|
+
* prices, so the line uses the height; bars always start at zero. */
|
|
68
|
+
includeZero?: boolean;
|
|
69
|
+
/** neutral tells series apart by ink, dashes and markers. categorical adds six hues,
|
|
70
|
+
* for categories that color must separate, such as buckets or sectors. */
|
|
71
|
+
palette?: "neutral" | "categorical";
|
|
41
72
|
locale?: string;
|
|
42
73
|
formatValue?: (value: number) => string;
|
|
74
|
+
/** Text the chart shows or announces; pass translations here. */
|
|
75
|
+
labels?: Partial<ChartLabels>;
|
|
76
|
+
/** @deprecated Use labels.missing. */
|
|
43
77
|
missingLabel?: string;
|
|
78
|
+
/** @deprecated Use labels.empty. */
|
|
44
79
|
emptyLabel?: string;
|
|
45
80
|
hiddenSeries?: readonly string[];
|
|
46
81
|
defaultHiddenSeries?: readonly string[];
|
package/dist/chart.js
CHANGED
|
@@ -1,11 +1,32 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
3
|
import * as React from 'react';
|
|
4
|
-
import { Area, Bar, CartesianGrid, ComposedChart, Line, ReferenceLine, ResponsiveContainer, Tooltip, XAxis, YAxis, } from 'recharts';
|
|
5
|
-
import {
|
|
4
|
+
import { Area, Bar, CartesianGrid, ComposedChart, Line, ReferenceLine, ResponsiveContainer, Tooltip, XAxis, YAxis, useActiveTooltipCoordinate, useActiveTooltipLabel, useIsTooltipActive, usePlotArea, } from 'recharts';
|
|
5
|
+
import { createPortal } from 'react-dom';
|
|
6
|
+
import { Table } from './table.js';
|
|
6
7
|
import { Button } from './button.js';
|
|
8
|
+
import { cx } from './parts.js';
|
|
9
|
+
const chartLabels = {
|
|
10
|
+
missing: 'Not available',
|
|
11
|
+
empty: 'No numeric measurements to display.',
|
|
12
|
+
noSeries: 'No series selected.',
|
|
13
|
+
showAll: 'Show all series',
|
|
14
|
+
keyboardHelp: 'Focus the chart and use Left/Right to inspect points. Escape clears details. The data table includes every series.',
|
|
15
|
+
values: (title) => `${title} values`,
|
|
16
|
+
viewTable: 'View data table',
|
|
17
|
+
table: (title) => `${title} data table`,
|
|
18
|
+
tableCaption: (unit) => `All input measurements, including hidden series. Unit: ${unit}.`,
|
|
19
|
+
inspectHint: 'Hover, touch or use chart arrow keys to inspect a measurement.',
|
|
20
|
+
noRows: 'No rows.',
|
|
21
|
+
};
|
|
22
|
+
/** The round step at or above a raw step: 1, 2, 2.5 or 5 times a power of ten. */
|
|
23
|
+
function roundStep(raw) {
|
|
24
|
+
if (!(raw > 0))
|
|
25
|
+
return 0;
|
|
26
|
+
const power = 10 ** Math.floor(Math.log10(raw));
|
|
27
|
+
return power * ([1, 2, 2.5, 5, 10].find((f) => f * power >= raw) ?? 10);
|
|
28
|
+
}
|
|
7
29
|
const dashes = [undefined, '7 4', '2 4', '10 3 2 3', '12 5', '4 3'];
|
|
8
|
-
const colorFor = (index) => `var(--chart-series-${(index % 3) + 1})`;
|
|
9
30
|
function Marker({ cx, cy, color, index, }) {
|
|
10
31
|
if (typeof cx !== 'number' ||
|
|
11
32
|
typeof cy !== 'number' ||
|
|
@@ -18,14 +39,52 @@ function Marker({ cx, cy, color, index, }) {
|
|
|
18
39
|
function Pattern({ id, index, color, }) {
|
|
19
40
|
return (_jsxs("pattern", { id: id, patternUnits: 'userSpaceOnUse', width: '8', height: '8', children: [_jsx("rect", { width: '8', height: '8', fill: color }), index % 3 === 1 ? (_jsx("path", { d: 'M-2 2L2-2M0 8L8 0M6 10L10 6', stroke: 'var(--canvas)', strokeWidth: '1.5' })) : index % 3 === 2 ? (_jsx("circle", { cx: '4', cy: '4', r: '1.4', fill: 'var(--canvas)' })) : null] }));
|
|
20
41
|
}
|
|
42
|
+
/** A series' swatch, as the legend and the floating values draw it. */
|
|
43
|
+
function SeriesMark({ type, index, color, pattern, }) {
|
|
44
|
+
return (_jsx("svg", { className: 'pui-chart-mark', viewBox: '0 0 32 20', "aria-hidden": 'true', focusable: 'false', children: type === 'bar' ? (_jsxs(_Fragment, { children: [_jsx("defs", { children: _jsx(Pattern, { id: pattern, color: color, index: index }) }), _jsx("rect", { x: '4', y: '3', width: '24', height: '14', rx: '2', fill: `url(#${pattern})` })] })) : (_jsxs(_Fragment, { children: [_jsx("path", { d: 'M1 10h30', stroke: color, strokeWidth: '2', strokeDasharray: dashes[index % dashes.length] }), _jsx(Marker, { cx: 16, cy: 10, index: index, color: color })] })) }));
|
|
45
|
+
}
|
|
46
|
+
/** The active point's values beside it, for pointer and touch users. The readout
|
|
47
|
+
* below the plot announces the same values, so this copy stays out of the
|
|
48
|
+
* accessibility tree. It sits on the side of the point with more room and stays
|
|
49
|
+
* inside the plot. */
|
|
50
|
+
function FloatingValues({ host, hidden, render, }) {
|
|
51
|
+
const active = useIsTooltipActive();
|
|
52
|
+
const label = useActiveTooltipLabel();
|
|
53
|
+
const point = useActiveTooltipCoordinate();
|
|
54
|
+
const plot = usePlotArea();
|
|
55
|
+
const box = React.useRef(null);
|
|
56
|
+
const [width, setWidth] = React.useState(0);
|
|
57
|
+
const shown = Boolean(host && !hidden && active && label !== undefined && point && plot);
|
|
58
|
+
React.useLayoutEffect(() => {
|
|
59
|
+
if (shown && box.current)
|
|
60
|
+
setWidth(box.current.offsetWidth);
|
|
61
|
+
}, [shown, label, plot?.width]);
|
|
62
|
+
if (!shown || !point || !plot)
|
|
63
|
+
return null;
|
|
64
|
+
// The gap between the point and the box, in px: the --space-3 step.
|
|
65
|
+
const gap = 12;
|
|
66
|
+
const start = point.x > plot.x + plot.width / 2;
|
|
67
|
+
const left = Math.min(Math.max(start ? point.x - gap - width : point.x + gap, plot.x), plot.x + plot.width - width);
|
|
68
|
+
return createPortal(_jsx("div", { ref: box, className: 'pui-chart-tooltip', "aria-hidden": 'true', style: { left, top: plot.y, visibility: width ? undefined : 'hidden' }, children: render(String(label)) }), host);
|
|
69
|
+
}
|
|
21
70
|
/** Cartesian trends with a persistent, keyboard-readable tooltip region and a
|
|
22
71
|
* full data-table alternative. Missing values are gaps, never fabricated zeros. */
|
|
23
|
-
export const Chart = /* @__PURE__ */ React.forwardRef(function Chart({ title, description, data, series, unit, xLabel, yLabel, type = 'line', height = 280,
|
|
72
|
+
export const Chart = /* @__PURE__ */ React.forwardRef(function Chart({ title, description, data, series, unit, xLabel, yLabel, type = 'line', height = 280, includeZero = true, palette = 'neutral', locale = 'en-US', formatValue, labels, missingLabel, emptyLabel, hiddenSeries, defaultHiddenSeries = [], onHiddenSeriesChange, className, ...props }, ref) {
|
|
73
|
+
const text = {
|
|
74
|
+
...chartLabels,
|
|
75
|
+
...(missingLabel === undefined ? {} : { missing: missingLabel }),
|
|
76
|
+
...(emptyLabel === undefined ? {} : { empty: emptyLabel }),
|
|
77
|
+
...labels,
|
|
78
|
+
};
|
|
24
79
|
const id = React.useId().replace(/[^a-zA-Z0-9_-]/g, '_');
|
|
80
|
+
const colorFor = (index) => palette === 'categorical'
|
|
81
|
+
? `var(--chart-category-${(index % 6) + 1})`
|
|
82
|
+
: `var(--chart-series-${(index % 3) + 1})`;
|
|
25
83
|
const [internalHidden, setInternalHidden] = React.useState(defaultHiddenSeries);
|
|
26
84
|
const hidden = new Set(hiddenSeries ?? internalHidden);
|
|
27
85
|
const visible = series.filter((s) => !hidden.has(s.key));
|
|
28
86
|
const [host, setHost] = React.useState(null);
|
|
87
|
+
const [floatHost, setFloatHost] = React.useState(null);
|
|
29
88
|
const [dismissed, setDismissed] = React.useState(false);
|
|
30
89
|
const firstLegend = React.useRef(null);
|
|
31
90
|
const [restoreRequested, setRestoreRequested] = React.useState(false);
|
|
@@ -43,7 +102,7 @@ export const Chart = /* @__PURE__ */ React.forwardRef(function Chart({ title, de
|
|
|
43
102
|
}), [locale]);
|
|
44
103
|
const format = (value) => typeof value === 'number' && Number.isFinite(value)
|
|
45
104
|
? `${formatValue ? formatValue(value) : number.format(value)} ${unit}`
|
|
46
|
-
:
|
|
105
|
+
: text.missing;
|
|
47
106
|
const rows = React.useMemo(() => {
|
|
48
107
|
const ids = new Set(), keys = new Set();
|
|
49
108
|
for (const s of series) {
|
|
@@ -71,7 +130,16 @@ export const Chart = /* @__PURE__ */ React.forwardRef(function Chart({ title, de
|
|
|
71
130
|
const values = rows
|
|
72
131
|
.flatMap((row) => visible.map((s) => row.values[s.key]))
|
|
73
132
|
.filter((value) => typeof value === 'number');
|
|
74
|
-
|
|
133
|
+
// Bars grow from zero, so they always keep it on the axis. Without zero, the axis
|
|
134
|
+
// spans the values, widened to round steps so its ticks read cleanly.
|
|
135
|
+
const keepZero = includeZero || type === 'bar';
|
|
136
|
+
const start = keepZero ? 0 : (values[0] ?? 0);
|
|
137
|
+
const low = values.reduce((a, b) => Math.min(a, b), start), high = values.reduce((a, b) => Math.max(a, b), start);
|
|
138
|
+
const step = keepZero ? 0 : roundStep((high - low) / 4);
|
|
139
|
+
const min = step ? Math.floor(low / step) * step : low, max = step ? Math.ceil(high / step) * step : high;
|
|
140
|
+
const ticks = step
|
|
141
|
+
? Array.from({ length: Math.round((max - min) / step) + 1 }, (_, index) => min + index * step)
|
|
142
|
+
: undefined;
|
|
75
143
|
const hasValues = values.length > 0;
|
|
76
144
|
const changeHidden = (next) => {
|
|
77
145
|
if (hiddenSeries === undefined)
|
|
@@ -82,48 +150,53 @@ export const Chart = /* @__PURE__ */ React.forwardRef(function Chart({ title, de
|
|
|
82
150
|
.filter((s) => (s.key === key ? !hidden.has(key) : hidden.has(s.key)))
|
|
83
151
|
.map((s) => s.key));
|
|
84
152
|
const chartHeight = Number.isFinite(height) ? Math.max(200, height) : 280;
|
|
85
|
-
return (_jsxs("figure", { ...props, ref: ref, className:
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
153
|
+
return (_jsxs("figure", { ...props, ref: ref, className: cx('pui-chart', className), "aria-labelledby": `${id}-title`, children: [_jsxs("figcaption", { className: 'pui-chart-caption', children: [_jsx("strong", { id: `${id}-title`, children: title }), _jsx("p", { id: `${id}-summary`, children: description })] }), _jsxs("div", { className: 'pui-chart-frame', children: [_jsxs("div", { className: 'pui-chart-key', children: [_jsxs("p", { className: 'pui-chart-axis-label', children: [yLabel, " (", unit, ")"] }), _jsx("ul", { className: 'pui-chart-legend', "aria-label": `${title} series`, children: series.map((s, index) => (_jsx("li", { children: _jsxs("button", { ref: index === 0 ? firstLegend : undefined, type: 'button', className: 'pui-chart-legend-button', "aria-label": `${s.label} series`, "aria-pressed": !hidden.has(s.key), onClick: () => toggle(s.key), children: [_jsx(SeriesMark, { type: type, index: index, color: colorFor(index), pattern: `${id}-legend-${index}` }), _jsx("span", { children: s.label })] }) }, s.key))) })] }), hasValues ? (_jsxs(_Fragment, { children: [_jsxs("div", { className: 'pui-chart-plot', onKeyDownCapture: (event) => {
|
|
154
|
+
if (event.key === 'Escape')
|
|
155
|
+
setDismissed(true);
|
|
156
|
+
else if (event.key === 'ArrowLeft' ||
|
|
157
|
+
event.key === 'ArrowRight')
|
|
158
|
+
setDismissed(false);
|
|
159
|
+
}, onMouseMoveCapture: () => setDismissed(false), onTouchStartCapture: () => setDismissed(false), onFocusCapture: () => setDismissed(false), children: [_jsx(ResponsiveContainer, { width: '100%', height: chartHeight, minWidth: 0, initialDimension: { width: 320, height: chartHeight }, children: _jsxs(ComposedChart, { data: rows, accessibilityLayer: true, role: 'application', "aria-label": title, "aria-describedby": `${id}-summary ${id}-keys`, margin: { top: 16, right: 20, bottom: 8, left: 0 }, children: [_jsx("defs", { children: series.map((s, index) => (_jsx(Pattern, { id: `${id}-pattern-${index}`, index: index, color: colorFor(index) }, s.key))) }), _jsx(CartesianGrid, { vertical: false, stroke: 'var(--line)' }), _jsx(XAxis, { dataKey: 'id', tickFormatter: (value) => {
|
|
160
|
+
const label = byId.get(String(value))?.label ?? String(value);
|
|
161
|
+
// minTickGap already drops ticks that would overlap; the cap
|
|
162
|
+
// only keeps one very long label from crowding the axis.
|
|
163
|
+
return label.length > 24
|
|
164
|
+
? label.slice(0, 23) + '…'
|
|
165
|
+
: label;
|
|
166
|
+
}, tick: { fill: 'var(--ink-muted)', fontSize: 12 }, tickLine: false, axisLine: { stroke: 'var(--line)' }, minTickGap: 24, interval: 'preserveStartEnd' }), _jsx(YAxis, { width: 56, tickFormatter: (value) => compact.format(Number(value)), tick: { fill: 'var(--ink-muted)', fontSize: 12 }, tickLine: false, axisLine: false, domain: [min, max === min ? max + 1 : max], ticks: ticks }), _jsx(ReferenceLine, { y: 0, stroke: 'var(--ink-muted)' }), host && (_jsx(Tooltip, { portal: host, isAnimationActive: false, active: dismissed ? false : undefined, filterNull: false, cursor: dismissed
|
|
167
|
+
? false
|
|
168
|
+
: {
|
|
169
|
+
stroke: 'var(--control-border)',
|
|
170
|
+
fill: 'transparent',
|
|
171
|
+
}, wrapperStyle: {
|
|
172
|
+
position: 'static',
|
|
173
|
+
visibility: 'visible',
|
|
174
|
+
pointerEvents: 'auto',
|
|
175
|
+
}, content: (tooltip) => {
|
|
176
|
+
const row = tooltip.active && !dismissed
|
|
177
|
+
? byId.get(String(tooltip.label))
|
|
178
|
+
: undefined;
|
|
179
|
+
return (_jsx("div", { className: 'pui-chart-readout', "data-chart-readout": row?.id, children: row ? (_jsxs(_Fragment, { children: [_jsx("strong", { children: row.label }), _jsx("ul", { children: visible.map((s) => (_jsxs("li", { children: [s.label, ": ", format(row.values[s.key])] }, s.key))) })] })) : (_jsx("span", { children: text.inspectHint })) }));
|
|
180
|
+
} })), series.map((s, index) => {
|
|
181
|
+
const common = {
|
|
182
|
+
name: s.label,
|
|
183
|
+
dataKey: (row) => row.values[s.key] ?? null,
|
|
184
|
+
hide: hidden.has(s.key),
|
|
185
|
+
isAnimationActive: false,
|
|
186
|
+
stroke: colorFor(index),
|
|
187
|
+
};
|
|
188
|
+
return type === 'bar' ? (_jsx(Bar, { ...common, fill: `url(#${id}-pattern-${index})`, maxBarSize: 48 }, s.key)) : type === 'area' ? (_jsx(Area, { ...common, type: 'linear', strokeWidth: 2, strokeDasharray: dashes[index % dashes.length], fill: `url(#${id}-pattern-${index})`, fillOpacity: 0.12, connectNulls: false, dot: rows.length > 40
|
|
189
|
+
? false
|
|
190
|
+
: (dot) => (_jsx(Marker, { ...dot, color: colorFor(index), index: index })), activeDot: false }, s.key)) : (_jsx(Line, { ...common, type: 'linear', strokeWidth: 2, strokeDasharray: dashes[index % dashes.length], connectNulls: false, dot: rows.length > 40
|
|
191
|
+
? false
|
|
192
|
+
: (dot) => (_jsx(Marker, { ...dot, color: colorFor(index), index: index })), activeDot: false }, s.key));
|
|
193
|
+
}), _jsx(FloatingValues, { host: floatHost, hidden: dismissed, render: (label) => {
|
|
194
|
+
const row = byId.get(label);
|
|
195
|
+
if (!row)
|
|
196
|
+
return null;
|
|
197
|
+
return (_jsxs(_Fragment, { children: [_jsx("strong", { children: row.label }), _jsx("ul", { children: series.map((s, index) => hidden.has(s.key) ? null : (_jsxs("li", { children: [_jsx(SeriesMark, { type: type, index: index, color: colorFor(index), pattern: `${id}-float-${index}` }), _jsx("span", { children: s.label }), _jsx("span", { className: 'pui-chart-tooltip-value', children: format(row.values[s.key]) })] }, s.key))) })] }));
|
|
198
|
+
} })] }) }), _jsx("div", { className: 'pui-chart-float', ref: setFloatHost })] }), _jsx("p", { className: 'pui-chart-axis-label pui-chart-x-label', children: xLabel })] })) : (_jsx("div", { className: 'pui-chart-empty', role: 'status', children: visible.length === 0 && series.length > 0 ? (_jsxs(_Fragment, { children: [_jsx("p", { children: text.noSeries }), _jsx(Button, { variant: 'outline', onClick: () => {
|
|
199
|
+
setRestoreRequested(true);
|
|
200
|
+
changeHidden([]);
|
|
201
|
+
}, children: text.showAll })] })) : (_jsx("p", { children: text.empty })) }))] }), hasValues && (_jsx("p", { className: 'pui-chart-help', id: `${id}-keys`, children: text.keyboardHelp })), _jsx("div", { className: 'pui-chart-inspector', ref: setHost, role: 'status', "aria-live": 'polite', "aria-atomic": 'true', "aria-label": text.values(title), hidden: !hasValues }), _jsxs("details", { className: 'pui-chart-table', children: [_jsx("summary", { children: text.viewTable }), _jsx(Table.Container, { label: text.table(title), orientation: 'both', scrollChain: 'contain', children: _jsxs(Table.Root, { children: [_jsx(Table.Caption, { children: text.tableCaption(unit) }), _jsx(Table.Head, { children: _jsxs(Table.Row, { children: [_jsx(Table.HeaderCell, { scope: 'col', children: xLabel }), series.map((s) => (_jsxs(Table.HeaderCell, { scope: 'col', children: [s.label, " (", unit, ")"] }, s.key)))] }) }), _jsx(Table.Body, { children: rows.length ? (rows.map((row) => (_jsxs(Table.Row, { children: [_jsx(Table.HeaderCell, { scope: 'row', children: row.label }), series.map((s) => (_jsx(Table.Cell, { children: format(row.values[s.key]) }, s.key)))] }, row.id)))) : (_jsx(Table.Row, { children: _jsx(Table.Cell, { colSpan: series.length + 1, children: text.noRows }) })) })] }) })] })] }));
|
|
129
202
|
});
|