banhaten 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/CHANGELOG.md +78 -1
- package/CONTRIBUTING.md +6 -4
- package/README.md +4 -2
- package/docs/design-spacing.md +13 -0
- package/docs/design-system/README.md +2 -0
- package/docs/design-system/appearances/default.md +1 -1
- package/docs/design-system/appearances/rounded.md +1 -1
- package/docs/design-system/appearances/sharp.md +1 -1
- package/docs/design-system/component-showcase-consistency-report.md +5 -5
- package/docs/design-system/components/README.md +15 -0
- package/docs/design-system/components/accordion.md +1 -1
- package/docs/design-system/components/activity-feed.md +1 -1
- package/docs/design-system/components/activity-heatmap.md +1 -1
- package/docs/design-system/components/agent-input.md +85 -0
- package/docs/design-system/components/alert-dialog.md +1 -1
- package/docs/design-system/components/alert.md +10 -4
- package/docs/design-system/components/app-header.md +97 -0
- package/docs/design-system/components/approval-card.md +134 -0
- package/docs/design-system/components/attribute.md +14 -2
- package/docs/design-system/components/avatar.md +1 -1
- package/docs/design-system/components/badge.md +1 -1
- package/docs/design-system/components/banner.md +1 -1
- package/docs/design-system/components/breadcrumbs.md +8 -3
- package/docs/design-system/components/button-group.md +1 -1
- package/docs/design-system/components/button.md +8 -5
- package/docs/design-system/components/card.md +15 -1
- package/docs/design-system/components/catalog-components.md +1 -1
- package/docs/design-system/components/chart.md +95 -24
- package/docs/design-system/components/checkbox.md +1 -1
- package/docs/design-system/components/collapsible.md +20 -6
- package/docs/design-system/components/command.md +1 -1
- package/docs/design-system/components/context-menu.md +1 -1
- package/docs/design-system/components/date-picker.md +1 -1
- package/docs/design-system/components/file-upload.md +1 -1
- package/docs/design-system/components/hover-card.md +1 -1
- package/docs/design-system/components/inline-citations.md +93 -0
- package/docs/design-system/components/input-group.md +1 -1
- package/docs/design-system/components/input.md +59 -3
- package/docs/design-system/components/item.md +1 -1
- package/docs/design-system/components/kbd.md +6 -4
- package/docs/design-system/components/menu.md +35 -4
- package/docs/design-system/components/menubar.md +1 -1
- package/docs/design-system/components/modal.md +2 -2
- package/docs/design-system/components/native-select.md +1 -1
- package/docs/design-system/components/navigation-menu.md +1 -1
- package/docs/design-system/components/onboarding-step-list-item.md +1 -1
- package/docs/design-system/components/page-header.md +58 -17
- package/docs/design-system/components/pagination.md +2 -2
- package/docs/design-system/components/popover.md +1 -1
- package/docs/design-system/components/progress-slider.md +1 -1
- package/docs/design-system/components/radio-card.md +1 -1
- package/docs/design-system/components/radio-group.md +1 -1
- package/docs/design-system/components/resizable.md +1 -1
- package/docs/design-system/components/rolling-count.md +61 -0
- package/docs/design-system/components/scroll-area.md +1 -1
- package/docs/design-system/components/select.md +12 -2
- package/docs/design-system/components/sheet.md +1 -1
- package/docs/design-system/components/shimmer-text.md +67 -0
- package/docs/design-system/components/sidebar.md +75 -8
- package/docs/design-system/components/skeleton.md +2 -2
- package/docs/design-system/components/slideout.md +1 -1
- package/docs/design-system/components/slider.md +2 -2
- package/docs/design-system/components/social-button.md +2 -2
- package/docs/design-system/components/streaming-text.md +82 -0
- package/docs/design-system/components/table.md +103 -21
- package/docs/design-system/components/tabs.md +25 -6
- package/docs/design-system/components/tag.md +1 -1
- package/docs/design-system/components/task-list.md +95 -0
- package/docs/design-system/components/textarea.md +1 -1
- package/docs/design-system/components/thinking-reasoning.md +72 -0
- package/docs/design-system/components/thinking-state.md +67 -0
- package/docs/design-system/components/timeline.md +1 -1
- package/docs/design-system/components/toast.md +1 -1
- package/docs/design-system/components/toggle.md +2 -2
- package/docs/design-system/components/toolbar.md +11 -6
- package/docs/design-system/components/tooltip.md +6 -4
- package/docs/design-system/density-and-elevation.md +16 -16
- package/docs/design-system/design-system-test-missing-items.md +8 -8
- package/docs/design-system/installation.md +2 -0
- package/docs/design-system/tabs.md +2 -1
- package/docs/design-system/template-gap-audit.md +32 -0
- package/docs/design-system/templates.md +59 -0
- package/docs/design-system/token-governance.md +15 -2
- package/package.json +2 -2
- package/registry/components/accordion.tsx +2 -2
- package/registry/components/agent-input-parts.tsx +552 -0
- package/registry/components/agent-input-state.ts +156 -0
- package/registry/components/agent-input.css +307 -0
- package/registry/components/agent-input.tsx +382 -0
- package/registry/components/alert-dialog.tsx +2 -2
- package/registry/components/alert.tsx +23 -7
- package/registry/components/app-header.tsx +151 -0
- package/registry/components/approval-card.css +409 -0
- package/registry/components/approval-card.tsx +401 -0
- package/registry/components/approval-frame.tsx +108 -0
- package/registry/components/approval-questions.tsx +559 -0
- package/registry/components/attribute.tsx +48 -13
- package/registry/components/autocomplete.tsx +15 -68
- package/registry/components/avatar.tsx +2 -2
- package/registry/components/badge.tsx +8 -7
- package/registry/components/button-group.tsx +2 -2
- package/registry/components/button.tsx +19 -14
- package/registry/components/card.tsx +18 -5
- package/registry/components/chart-block-data.ts +177 -0
- package/registry/components/chart-block.css +171 -0
- package/registry/components/chart-block.tsx +260 -0
- package/registry/components/chart-interactions.ts +123 -0
- package/registry/components/chart-options.cartesian.ts +162 -0
- package/registry/components/chart-options.paint.ts +99 -0
- package/registry/components/chart-options.parts.ts +72 -0
- package/registry/components/chart-options.radial.ts +109 -0
- package/registry/components/chart-options.ts +44 -0
- package/registry/components/chart-options.types.ts +67 -0
- package/registry/components/chart.tsx +1 -1
- package/registry/components/checkbox.tsx +6 -6
- package/registry/components/collapsible.tsx +43 -3
- package/registry/components/command.tsx +1 -1
- package/registry/components/context-menu.tsx +1 -1
- package/registry/components/data-chart.tsx +40 -0
- package/registry/components/date-picker.tsx +9 -9
- package/registry/components/echart-theme.ts +246 -0
- package/registry/components/echart.css +49 -0
- package/registry/components/echart.tsx +178 -0
- package/registry/components/expanded/Breadcrumbs.tsx +5 -1
- package/registry/components/expanded/PageHeader.tsx +67 -24
- package/registry/components/expanded/Table.tsx +60 -22
- package/registry/components/expanded/activityFeed.css +2 -2
- package/registry/components/expanded/activityHeatmap.css +1 -1
- package/registry/components/expanded/banner.css +2 -2
- package/registry/components/expanded/breadcrumbs.css +19 -2
- package/registry/components/expanded/catalogComponentsShowcase.css +1 -1
- package/registry/components/expanded/fileUpload.css +7 -7
- package/registry/components/expanded/onboardingStepListItem.css +2 -2
- package/registry/components/expanded/pageHeader.css +38 -44
- package/registry/components/expanded/slideout.css +4 -4
- package/registry/components/expanded/table.css +58 -9
- package/registry/components/expanded/timeline.css +1 -1
- package/registry/components/hover-card.tsx +1 -1
- package/registry/components/inline-citations.css +126 -0
- package/registry/components/inline-citations.tsx +292 -0
- package/registry/components/input-group.tsx +4 -4
- package/registry/components/input.tsx +150 -137
- package/registry/components/item.tsx +1 -1
- package/registry/components/kbd.tsx +3 -2
- package/registry/components/menu.tsx +117 -12
- package/registry/components/menubar.tsx +2 -2
- package/registry/components/modal.tsx +3 -3
- package/registry/components/native-select.tsx +4 -4
- package/registry/components/navigation-menu.tsx +2 -2
- package/registry/components/pagination.tsx +4 -4
- package/registry/components/popover.tsx +3 -3
- package/registry/components/progress-slider.tsx +1 -1
- package/registry/components/radio-card.tsx +7 -7
- package/registry/components/radio-group.tsx +2 -2
- package/registry/components/resizable.tsx +2 -2
- package/registry/components/rolling-count.css +37 -0
- package/registry/components/rolling-count.tsx +110 -0
- package/registry/components/scroll-area.tsx +1 -1
- package/registry/components/select.tsx +15 -10
- package/registry/components/sheet.tsx +2 -2
- package/registry/components/shimmer-text.css +69 -0
- package/registry/components/shimmer-text.tsx +43 -0
- package/registry/components/sidebar.tsx +528 -223
- package/registry/components/skeleton.tsx +1 -1
- package/registry/components/slider.tsx +2 -2
- package/registry/components/social-button.tsx +1 -1
- package/registry/components/streaming-text.css +45 -0
- package/registry/components/streaming-text.tsx +165 -0
- package/registry/components/table-elements.tsx +164 -5
- package/registry/components/tabs.css +32 -4
- package/registry/components/tabs.tsx +5 -1
- package/registry/components/tag.tsx +1 -1
- package/registry/components/task-list.css +328 -0
- package/registry/components/task-list.tsx +429 -0
- package/registry/components/textarea.tsx +4 -4
- package/registry/components/thinking-reasoning.css +178 -0
- package/registry/components/thinking-reasoning.tsx +253 -0
- package/registry/components/thinking-state.css +8 -0
- package/registry/components/thinking-state.tsx +46 -0
- package/registry/components/toast.tsx +1 -1
- package/registry/components/toggle.tsx +2 -2
- package/registry/components/toolbar.tsx +6 -6
- package/registry/components/tooltip.tsx +6 -4
- package/registry/examples/agent-input-demo.tsx +90 -0
- package/registry/examples/app-header-demo.tsx +40 -0
- package/registry/examples/approval-card-demo.tsx +83 -0
- package/registry/examples/button-demo.tsx +3 -0
- package/registry/examples/chart-block-demo.tsx +5 -0
- package/registry/examples/chart-demo.tsx +6 -21
- package/registry/examples/collection-filter-bar-demo.tsx +1 -1
- package/registry/examples/control-density-contract-demo.tsx +5 -1
- package/registry/examples/inline-citations-demo.tsx +31 -0
- package/registry/examples/input-actions-demo.tsx +36 -0
- package/registry/examples/menu-demo.tsx +1 -1
- package/registry/examples/popover-demo.tsx +1 -0
- package/registry/examples/rolling-count-demo.tsx +39 -0
- package/registry/examples/shimmer-text-demo.tsx +20 -0
- package/registry/examples/streaming-text-demo.tsx +28 -0
- package/registry/examples/task-list-demo.tsx +74 -0
- package/registry/examples/thinking-reasoning-demo.tsx +74 -0
- package/registry/examples/thinking-state-demo.tsx +13 -0
- package/registry/guidance/charts.LICENSE.txt +24 -0
- package/registry/hooks/use-controllable-state.ts +33 -0
- package/registry/hooks/use-listbox-navigation.ts +73 -0
- package/registry/hooks/use-motion-end.ts +55 -0
- package/registry/hooks/use-reduced-motion.ts +28 -0
- package/registry/index.json +1808 -190
- package/registry/styles/globals.css +992 -1088
- package/registry.json +385 -10
- package/schema/registry.schema.json +5 -1
- package/schema/tokens.schema.json +8 -4
- package/src/cli/file-transaction.js +15 -8
- package/src/cli/index.js +22 -29
- package/tokens/banhaten.tokens.json +490 -192
|
@@ -9,6 +9,7 @@ import "./breadcrumbs.css";
|
|
|
9
9
|
|
|
10
10
|
export type BreadcrumbSeparator = "slash" | "chevron";
|
|
11
11
|
export type BreadcrumbStyle = "default" | "raised";
|
|
12
|
+
export type BreadcrumbSize = "md" | "sm";
|
|
12
13
|
|
|
13
14
|
export type BreadcrumbItem = {
|
|
14
15
|
label: string;
|
|
@@ -26,6 +27,7 @@ export type BreadcrumbsProps = {
|
|
|
26
27
|
maxItems?: number;
|
|
27
28
|
overflowLabel?: string;
|
|
28
29
|
separator?: BreadcrumbSeparator;
|
|
30
|
+
size?: BreadcrumbSize;
|
|
29
31
|
style?: BreadcrumbStyle;
|
|
30
32
|
};
|
|
31
33
|
|
|
@@ -57,6 +59,7 @@ export function Breadcrumbs({
|
|
|
57
59
|
maxItems,
|
|
58
60
|
overflowLabel,
|
|
59
61
|
separator = "slash",
|
|
62
|
+
size = "md",
|
|
60
63
|
style: surfaceStyle = "default",
|
|
61
64
|
}: BreadcrumbsProps) {
|
|
62
65
|
const renderedItems = visibleItems(items, maxItems, overflowLabel);
|
|
@@ -68,6 +71,7 @@ export function Breadcrumbs({
|
|
|
68
71
|
"ds-breadcrumbs",
|
|
69
72
|
`ds-breadcrumbs--${surfaceStyle}`,
|
|
70
73
|
`ds-breadcrumbs--${separator}`,
|
|
74
|
+
size === "sm" && "ds-breadcrumbs--sm",
|
|
71
75
|
iconOnly && "ds-breadcrumbs--icon-only",
|
|
72
76
|
className,
|
|
73
77
|
)}
|
|
@@ -82,7 +86,7 @@ export function Breadcrumbs({
|
|
|
82
86
|
<span className="ds-breadcrumbs__icon" aria-hidden={item.icon ? "true" : undefined}>
|
|
83
87
|
{item.overflow ? <OverflowIcon /> : item.icon}
|
|
84
88
|
</span>
|
|
85
|
-
<span className={cx("ds-breadcrumbs__label", iconOnly && "ds-breadcrumbs__label--hidden")}>
|
|
89
|
+
<span className={cx("ds-breadcrumbs__label", iconOnly && "ds-breadcrumbs__label--hidden")} dir="auto">
|
|
86
90
|
{item.label}
|
|
87
91
|
</span>
|
|
88
92
|
</>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { isValidElement, type ElementType, type ReactNode } from "react";
|
|
2
2
|
import { HomeIcon as LucideHomeIcon } from "lucide-react";
|
|
3
3
|
import { Button } from "@/components/ui/button";
|
|
4
4
|
import { Breadcrumbs as OwnedBreadcrumbs } from "./Breadcrumbs";
|
|
@@ -22,38 +22,68 @@ export type PageHeaderAction = {
|
|
|
22
22
|
|
|
23
23
|
export type PageHeaderTabs = Pick<
|
|
24
24
|
TabsProps,
|
|
25
|
-
|
|
25
|
+
| "activeIndex"
|
|
26
|
+
| "ariaLabel"
|
|
27
|
+
| "defaultActiveIndex"
|
|
28
|
+
| "fullWidth"
|
|
29
|
+
| "items"
|
|
30
|
+
| "onActiveIndexChange"
|
|
26
31
|
>;
|
|
27
32
|
|
|
33
|
+
export type PageHeaderSize = "default" | "comfortable";
|
|
34
|
+
|
|
28
35
|
export type PageHeaderProps = {
|
|
29
|
-
|
|
36
|
+
/** Action data rendered as secondary Buttons, or your own action nodes. */
|
|
37
|
+
actions?: PageHeaderAction[] | ReactNode | false;
|
|
30
38
|
breadcrumbLabel?: string;
|
|
31
39
|
breadcrumbs?: PageHeaderBreadcrumb[] | false;
|
|
40
|
+
/** Supporting content under the description, such as a status badge. */
|
|
41
|
+
children?: ReactNode;
|
|
32
42
|
className?: string;
|
|
33
|
-
description?:
|
|
43
|
+
description?: ReactNode;
|
|
34
44
|
dir?: "ltr" | "rtl";
|
|
35
45
|
icon?: ReactNode | false;
|
|
36
46
|
headingLevel?: 1 | 2 | 3 | 4 | 5 | 6;
|
|
37
47
|
metaInfo?: string;
|
|
48
|
+
/**
|
|
49
|
+
* `comfortable` is the page heading inside an app shell whose header already
|
|
50
|
+
* carries the breadcrumbs: no block padding, 8px between title and
|
|
51
|
+
* description, 12px between actions, 40px action Buttons, and no icon or tabs
|
|
52
|
+
* unless you pass them.
|
|
53
|
+
*/
|
|
54
|
+
size?: PageHeaderSize;
|
|
38
55
|
tabs?: PageHeaderTabs | false;
|
|
39
|
-
|
|
56
|
+
/** Heading text; inline content such as a record name and its type is allowed. */
|
|
57
|
+
title?: ReactNode;
|
|
40
58
|
};
|
|
41
59
|
|
|
42
60
|
function classes(...names: Array<string | false | undefined>) {
|
|
43
61
|
return names.filter(Boolean).join(" ");
|
|
44
62
|
}
|
|
45
63
|
|
|
64
|
+
/** Action data is an array of plain `{ label }` objects; anything else is rendered as nodes. */
|
|
65
|
+
function isActionData(actions: PageHeaderProps["actions"]): actions is PageHeaderAction[] {
|
|
66
|
+
return Array.isArray(actions) && actions.every((action) => action !== null && typeof action === "object" && !isValidElement(action) && "label" in action);
|
|
67
|
+
}
|
|
68
|
+
|
|
46
69
|
function HomeIcon() {
|
|
47
70
|
return <LucideHomeIcon aria-hidden="true" className="ds-page-header__home-icon" strokeWidth="var(--bh-icon-stroke-190)" />;
|
|
48
71
|
}
|
|
49
72
|
|
|
50
|
-
function Action({ action }: { action: PageHeaderAction }) {
|
|
51
|
-
const
|
|
52
|
-
|
|
73
|
+
function Action({ action, density }: { action: PageHeaderAction; density: "default" | "comfortable" }) {
|
|
74
|
+
const label = (
|
|
75
|
+
<span
|
|
76
|
+
className="min-w-0 px-[var(--bh-button-label-padding-x)]"
|
|
77
|
+
data-slot="button-label"
|
|
78
|
+
dir="auto"
|
|
79
|
+
>
|
|
80
|
+
{action.label}
|
|
81
|
+
</span>
|
|
82
|
+
);
|
|
53
83
|
|
|
54
84
|
if (action.href) {
|
|
55
85
|
return (
|
|
56
|
-
<Button asChild
|
|
86
|
+
<Button asChild density={density} variant="secondary">
|
|
57
87
|
<a
|
|
58
88
|
aria-disabled={action.disabled || undefined}
|
|
59
89
|
aria-label={action.ariaLabel}
|
|
@@ -76,9 +106,9 @@ function Action({ action }: { action: PageHeaderAction }) {
|
|
|
76
106
|
return (
|
|
77
107
|
<Button
|
|
78
108
|
aria-label={action.ariaLabel}
|
|
79
|
-
className={className}
|
|
80
109
|
disabled={action.disabled}
|
|
81
110
|
onClick={action.onClick}
|
|
111
|
+
density={density}
|
|
82
112
|
type="button"
|
|
83
113
|
variant="secondary"
|
|
84
114
|
>
|
|
@@ -91,22 +121,32 @@ export function PageHeader({
|
|
|
91
121
|
actions = [],
|
|
92
122
|
breadcrumbLabel,
|
|
93
123
|
breadcrumbs = [],
|
|
124
|
+
children,
|
|
94
125
|
className,
|
|
95
126
|
description,
|
|
96
127
|
dir,
|
|
97
128
|
headingLevel = 1,
|
|
98
129
|
icon,
|
|
99
130
|
metaInfo,
|
|
100
|
-
|
|
131
|
+
size = "default",
|
|
132
|
+
tabs,
|
|
101
133
|
title,
|
|
102
134
|
}: PageHeaderProps) {
|
|
135
|
+
const comfortable = size === "comfortable";
|
|
103
136
|
const breadcrumbItems = breadcrumbs === false ? [] : breadcrumbs;
|
|
104
|
-
const actionItems = actions
|
|
105
|
-
const
|
|
137
|
+
const actionItems = isActionData(actions) ? actions : [];
|
|
138
|
+
const actionNodes = actions !== false && !isActionData(actions) ? actions : null;
|
|
139
|
+
// The comfortable heading has no icon or tabs unless they are passed.
|
|
140
|
+
const showIcon = icon !== false && !(comfortable && icon === undefined);
|
|
141
|
+
const tabsConfig = tabs ?? (comfortable ? false : {});
|
|
106
142
|
const Heading = `h${headingLevel}` as ElementType;
|
|
107
143
|
|
|
108
144
|
return (
|
|
109
|
-
<header
|
|
145
|
+
<header
|
|
146
|
+
className={classes("ds-page-header", comfortable && "ds-page-header--comfortable", className)}
|
|
147
|
+
data-size={size}
|
|
148
|
+
dir={dir}
|
|
149
|
+
>
|
|
110
150
|
{breadcrumbItems.length > 0 && (
|
|
111
151
|
<OwnedBreadcrumbs
|
|
112
152
|
aria-label={breadcrumbLabel ?? "Breadcrumb"}
|
|
@@ -122,7 +162,7 @@ export function PageHeader({
|
|
|
122
162
|
<div className="ds-page-header__heading-row">
|
|
123
163
|
<div className="ds-page-header__heading-main">
|
|
124
164
|
{showIcon && <span className="ds-page-header__icon">{icon ?? <HomeIcon />}</span>}
|
|
125
|
-
{title && <Heading className="ds-page-header__title">{title}</Heading>}
|
|
165
|
+
{title && <Heading className="ds-page-header__title" dir="auto">{title}</Heading>}
|
|
126
166
|
</div>
|
|
127
167
|
{metaInfo && (
|
|
128
168
|
<span className="ds-page-header__meta">
|
|
@@ -131,30 +171,33 @@ export function PageHeader({
|
|
|
131
171
|
)}
|
|
132
172
|
</div>
|
|
133
173
|
{description && (
|
|
134
|
-
<p className="ds-page-header__description">
|
|
174
|
+
<p className="ds-page-header__description" dir="auto">
|
|
135
175
|
{description}
|
|
136
176
|
</p>
|
|
137
177
|
)}
|
|
178
|
+
{children && <div className="ds-page-header__supporting">{children}</div>}
|
|
138
179
|
</div>
|
|
139
180
|
|
|
140
181
|
{actionItems.length > 0 && (
|
|
141
182
|
<div className="ds-page-header__actions">
|
|
142
183
|
{actionItems.map((action, index) => (
|
|
143
|
-
<Action action={action} key={`${action.label}-${index}`} />
|
|
184
|
+
<Action action={action} density={comfortable ? "comfortable" : "default"} key={`${action.label}-${index}`} />
|
|
144
185
|
))}
|
|
145
186
|
</div>
|
|
146
187
|
)}
|
|
188
|
+
{actionNodes && <div className="ds-page-header__actions">{actionNodes}</div>}
|
|
147
189
|
</div>
|
|
148
190
|
|
|
149
|
-
{
|
|
191
|
+
{tabsConfig !== false && (
|
|
150
192
|
<Tabs
|
|
151
|
-
ariaLabel={
|
|
193
|
+
ariaLabel={tabsConfig.ariaLabel}
|
|
152
194
|
className="ds-page-header__tabs"
|
|
153
|
-
fullWidth
|
|
154
|
-
items={
|
|
155
|
-
activeIndex={
|
|
156
|
-
defaultActiveIndex={
|
|
157
|
-
onActiveIndexChange={
|
|
195
|
+
fullWidth={tabsConfig.fullWidth ?? true}
|
|
196
|
+
items={tabsConfig.items}
|
|
197
|
+
activeIndex={tabsConfig.activeIndex}
|
|
198
|
+
defaultActiveIndex={tabsConfig.defaultActiveIndex}
|
|
199
|
+
onActiveIndexChange={tabsConfig.onActiveIndexChange}
|
|
200
|
+
rootClassName="ds-page-header__tabs-root"
|
|
158
201
|
size="md"
|
|
159
202
|
variant="underline"
|
|
160
203
|
dir={dir}
|
|
@@ -29,7 +29,7 @@ import {
|
|
|
29
29
|
import "./table.css";
|
|
30
30
|
|
|
31
31
|
export type TableDirection = "ltr" | "rtl";
|
|
32
|
-
export type TableSize = "sm" | "lg";
|
|
32
|
+
export type TableSize = "sm" | "lg" | "comfortable";
|
|
33
33
|
export type TableRowState = "default" | "selected" | "disabled";
|
|
34
34
|
export type TableSortDirection = "asc" | "desc";
|
|
35
35
|
export type TableSortValue = string | number | boolean | Date | null | undefined;
|
|
@@ -79,7 +79,7 @@ export type TableAction = {
|
|
|
79
79
|
|
|
80
80
|
export type TableItem =
|
|
81
81
|
| { type: "checkbox"; ariaLabel?: string; checked: boolean; disabled?: boolean; indeterminate?: boolean; onCheckedChange?: (checked: boolean) => void }
|
|
82
|
-
| { type: "text"; tone?: "default" | "subtle"; value: string; weight?: "regular" | "medium" }
|
|
82
|
+
| { type: "text"; caption?: string; tone?: "default" | "subtle"; value: string; weight?: "regular" | "medium" }
|
|
83
83
|
| { type: "avatarText"; caption?: string; name: string; src?: string; status?: "top" | "bottom" }
|
|
84
84
|
| { type: "rating"; max?: 5; value: number }
|
|
85
85
|
| { type: "progress"; label?: string; tone?: "success" | "brand"; value: number }
|
|
@@ -89,9 +89,9 @@ export type TableItem =
|
|
|
89
89
|
| { type: "avatarStack"; addLabel?: string; avatars: AvatarItem[]; canAdd?: boolean; count?: number; onAdd?: () => void }
|
|
90
90
|
| { type: "tags"; items: string[]; maxVisible?: number }
|
|
91
91
|
| { type: "file"; label?: string }
|
|
92
|
-
| { type: "brandLogoText"; label: string; logoSrc?: string }
|
|
93
|
-
| { type: "payment"; brand: string; label?: string }
|
|
94
|
-
| { type: "image"; label: string; src: string }
|
|
92
|
+
| { type: "brandLogoText"; caption?: string; label: string; logoSrc?: string }
|
|
93
|
+
| { type: "payment"; brand: string; caption?: string; label?: string }
|
|
94
|
+
| { type: "image"; caption?: string; label: string; src: string }
|
|
95
95
|
| { type: "action"; icon: TableAction["icon"]; label: string; onAction?: () => void }
|
|
96
96
|
| { type: "actionGroup"; actions: TableAction[] };
|
|
97
97
|
|
|
@@ -139,6 +139,7 @@ export type DataTablePagination = {
|
|
|
139
139
|
ariaLabel?: string;
|
|
140
140
|
defaultPage?: number;
|
|
141
141
|
manual?: boolean;
|
|
142
|
+
messages?: PaginationProps["messages"];
|
|
142
143
|
onPageChange?: (page: number) => void;
|
|
143
144
|
page?: number;
|
|
144
145
|
pageSize?: number;
|
|
@@ -293,11 +294,9 @@ export function Table<Row extends TableRowBase>({
|
|
|
293
294
|
label={`Select row ${row.id}`}
|
|
294
295
|
onChange={(checked) => toggleRow(row, checked)}
|
|
295
296
|
/>
|
|
296
|
-
) :
|
|
297
|
-
column
|
|
298
|
-
)
|
|
299
|
-
renderTableItem(column.item(row), size)
|
|
300
|
-
) : null}
|
|
297
|
+
) : (
|
|
298
|
+
renderTableCell(column, row, size === "comfortable" ? "lg" : size)
|
|
299
|
+
)}
|
|
301
300
|
</td>
|
|
302
301
|
))}
|
|
303
302
|
</tr>
|
|
@@ -309,6 +308,22 @@ export function Table<Row extends TableRowBase>({
|
|
|
309
308
|
);
|
|
310
309
|
}
|
|
311
310
|
|
|
311
|
+
function renderTableCell<Row extends TableRowBase>(
|
|
312
|
+
column: TableColumn<Row>,
|
|
313
|
+
row: Row,
|
|
314
|
+
size: TableSize,
|
|
315
|
+
) {
|
|
316
|
+
if (column.renderCell) return column.renderCell(row);
|
|
317
|
+
if (column.item) return renderTableItem(column.item(row), size);
|
|
318
|
+
if ((column.kind ?? "data") !== "data") return null;
|
|
319
|
+
if (!Object.prototype.hasOwnProperty.call(row, column.id)) return null;
|
|
320
|
+
|
|
321
|
+
const value: unknown = Reflect.get(row, column.id);
|
|
322
|
+
if (typeof value !== "string" && typeof value !== "number") return null;
|
|
323
|
+
|
|
324
|
+
return renderTableItem({ type: "text", value: String(value) }, size);
|
|
325
|
+
}
|
|
326
|
+
|
|
312
327
|
const defaultDataTablePagination: DataTablePagination = {};
|
|
313
328
|
|
|
314
329
|
const defaultDataTableLabels: DataTableLabels = {
|
|
@@ -389,6 +404,9 @@ export function DataTable<Row extends TableRowBase>({
|
|
|
389
404
|
const displayedRows = paginationConfig?.manual ? processedRows : paginationConfig ? processedRows.slice(startIndex, startIndex + pageSize) : processedRows;
|
|
390
405
|
const visibleFrom = totalRows === 0 ? 0 : startIndex + 1;
|
|
391
406
|
const visibleTo = paginationConfig?.manual ? Math.min(currentPage * pageSize, totalRows) : Math.min(startIndex + displayedRows.length, totalRows);
|
|
407
|
+
const resultsSummary = paginationConfig
|
|
408
|
+
? labels.resultsSummary({ from: visibleFrom, to: visibleTo, total: totalRows })
|
|
409
|
+
: null;
|
|
392
410
|
const hasHeader = Boolean(title || description || actions.length > 0);
|
|
393
411
|
const hasToolbar = Boolean(searchConfig || filters.length > 0 || selectedRowIds.length > 0 || bulkActions.length > 0);
|
|
394
412
|
const activeBulkActions = selectedRowIds.length > 0 ? bulkActions : [];
|
|
@@ -503,20 +521,23 @@ export function DataTable<Row extends TableRowBase>({
|
|
|
503
521
|
|
|
504
522
|
{paginationConfig && (
|
|
505
523
|
<footer className="ds-data-table__footer">
|
|
506
|
-
<ToolbarText>{
|
|
524
|
+
<ToolbarText>{resultsSummary}</ToolbarText>
|
|
507
525
|
<Pagination
|
|
508
526
|
aria-label={
|
|
509
527
|
paginationConfig.ariaLabel ??
|
|
528
|
+
paginationConfig.messages?.navigation ??
|
|
510
529
|
(typeof title === "string" ? `${title} pagination` : "Table pagination")
|
|
511
530
|
}
|
|
512
531
|
dir={dir}
|
|
532
|
+
messages={paginationConfig.messages}
|
|
513
533
|
nextDisabled={currentPage >= pageCount}
|
|
514
534
|
onPageChange={setDataTablePage}
|
|
515
535
|
page={currentPage}
|
|
516
536
|
pages={paginationConfig.pages ?? getDataTablePaginationPages(currentPage, pageCount)}
|
|
517
537
|
previousDisabled={currentPage <= 1}
|
|
538
|
+
caption={resultsSummary}
|
|
518
539
|
showCaption={paginationConfig.showCaption ?? false}
|
|
519
|
-
summary={
|
|
540
|
+
summary={resultsSummary}
|
|
520
541
|
type={paginationConfig.type ?? "numeric"}
|
|
521
542
|
variant={paginationConfig.variant ?? "soft"}
|
|
522
543
|
/>
|
|
@@ -729,7 +750,9 @@ function getTableItemSortValue(item: TableItem): TableSortValue {
|
|
|
729
750
|
|
|
730
751
|
function getTableItemText(item: TableItem) {
|
|
731
752
|
const value = getTableItemSortValue(item);
|
|
732
|
-
|
|
753
|
+
const text = value === null || value === undefined ? "" : String(value);
|
|
754
|
+
const caption = "caption" in item ? item.caption : undefined;
|
|
755
|
+
return caption ? `${text} ${caption}` : text;
|
|
733
756
|
}
|
|
734
757
|
|
|
735
758
|
function getDataTablePaginationPages(currentPage: number, pageCount: number): PaginationPage[] {
|
|
@@ -784,15 +807,23 @@ function renderTableItem(item: TableItem, tableSize: TableSize) {
|
|
|
784
807
|
onChange={item.onCheckedChange}
|
|
785
808
|
/>
|
|
786
809
|
);
|
|
787
|
-
case "text":
|
|
788
|
-
|
|
810
|
+
case "text": {
|
|
811
|
+
const className = `ds-table-item-text ds-table-item-text--${item.tone ?? "default"} ds-table-item-text--${item.weight ?? "regular"}`;
|
|
812
|
+
if (!item.caption) return <span className={className}>{item.value}</span>;
|
|
813
|
+
return (
|
|
814
|
+
<span className={`${className} ds-table-text-stack`}>
|
|
815
|
+
<span dir="auto">{item.value}</span>
|
|
816
|
+
<span className="ds-table-caption" dir="auto">{item.caption}</span>
|
|
817
|
+
</span>
|
|
818
|
+
);
|
|
819
|
+
}
|
|
789
820
|
case "avatarText":
|
|
790
821
|
return (
|
|
791
822
|
<span className="ds-table-avatar-text">
|
|
792
823
|
<Avatar name={item.name} size={tableSize === "lg" ? "md" : "sm"} src={item.src} />
|
|
793
824
|
<span>
|
|
794
|
-
<strong>{item.name}</strong>
|
|
795
|
-
{item.caption && <em>{item.caption}</em>}
|
|
825
|
+
<strong dir="auto">{item.name}</strong>
|
|
826
|
+
{item.caption && <em className="ds-table-caption" dir="auto">{item.caption}</em>}
|
|
796
827
|
</span>
|
|
797
828
|
</span>
|
|
798
829
|
);
|
|
@@ -830,11 +861,11 @@ function renderTableItem(item: TableItem, tableSize: TableSize) {
|
|
|
830
861
|
case "file":
|
|
831
862
|
return item.label ? <IconLabel icon={<FileIcon />} label={item.label} /> : null;
|
|
832
863
|
case "brandLogoText":
|
|
833
|
-
return <IconLabel icon={item.logoSrc ? <img alt="" src={item.logoSrc} /> : <BrandIcon />} label={item.label} />;
|
|
864
|
+
return <IconLabel caption={item.caption} icon={item.logoSrc ? <img alt="" src={item.logoSrc} /> : <BrandIcon />} label={item.label} />;
|
|
834
865
|
case "payment":
|
|
835
|
-
return <IconLabel icon={<PaymentIcon />} label={item.label ?? item.brand} />;
|
|
866
|
+
return <IconLabel caption={item.caption} icon={<PaymentIcon />} label={item.label ?? item.brand} />;
|
|
836
867
|
case "image":
|
|
837
|
-
return <IconLabel icon={<img alt="" src={item.src} />} label={item.label} />;
|
|
868
|
+
return <IconLabel caption={item.caption} icon={<img alt="" src={item.src} />} label={item.label} />;
|
|
838
869
|
case "action":
|
|
839
870
|
return <IconButton icon={item.icon} label={item.label} onClick={item.onAction} />;
|
|
840
871
|
case "actionGroup":
|
|
@@ -989,11 +1020,18 @@ function Rating({ max, value }: { max: number; value: number }) {
|
|
|
989
1020
|
);
|
|
990
1021
|
}
|
|
991
1022
|
|
|
992
|
-
function IconLabel({ icon, label }: { icon: ReactNode; label: string }) {
|
|
1023
|
+
function IconLabel({ caption, icon, label }: { caption?: string; icon: ReactNode; label: string }) {
|
|
993
1024
|
return (
|
|
994
1025
|
<span className="ds-table-icon-label">
|
|
995
1026
|
<span aria-hidden="true">{icon}</span>
|
|
996
|
-
|
|
1027
|
+
{caption ? (
|
|
1028
|
+
<span className="ds-table-text-stack">
|
|
1029
|
+
<span dir="auto">{label}</span>
|
|
1030
|
+
<span className="ds-table-caption" dir="auto">{caption}</span>
|
|
1031
|
+
</span>
|
|
1032
|
+
) : (
|
|
1033
|
+
<span>{label}</span>
|
|
1034
|
+
)}
|
|
997
1035
|
</span>
|
|
998
1036
|
);
|
|
999
1037
|
}
|
|
@@ -19,8 +19,8 @@
|
|
|
19
19
|
--activity-feed-space-md: var(--bh-space-md-8);
|
|
20
20
|
--activity-feed-space-lg: var(--bh-space-lg-10);
|
|
21
21
|
--activity-feed-space-xl: var(--bh-space-xl-12);
|
|
22
|
-
--activity-feed-
|
|
23
|
-
--activity-feed-
|
|
22
|
+
--activity-feed-elevation-component: var(--elevation-component-default);
|
|
23
|
+
--activity-feed-elevation-color-button: var(--elevation-button-raised);
|
|
24
24
|
|
|
25
25
|
box-sizing: border-box;
|
|
26
26
|
position: relative;
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
--banner-height-default: calc(var(--bh-space-8xl-48) + var(--bh-space-xl-12));
|
|
18
18
|
--banner-height-title: calc(var(--bh-space-8xl-48) + var(--bh-space-xs-4));
|
|
19
19
|
--banner-input-width: var(--bh-input-width);
|
|
20
|
-
--banner-
|
|
20
|
+
--banner-elevation-floating: var(--elevation-05);
|
|
21
21
|
|
|
22
22
|
box-sizing: border-box;
|
|
23
23
|
position: relative;
|
|
@@ -92,7 +92,7 @@
|
|
|
92
92
|
.ds-banner--floating.ds-banner--brand.ds-banner--single-action-inline,
|
|
93
93
|
.ds-banner--floating.ds-banner--brand.ds-banner--input,
|
|
94
94
|
.ds-banner--floating.ds-banner--brand.ds-banner--title-description {
|
|
95
|
-
box-shadow: var(--banner-
|
|
95
|
+
box-shadow: var(--banner-elevation-floating);
|
|
96
96
|
}
|
|
97
97
|
|
|
98
98
|
.ds-banner__main,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
.ds-breadcrumbs {
|
|
2
2
|
--breadcrumbs-color: var(--bh-content-subtle);
|
|
3
|
-
--breadcrumbs-current: var(--bh-content
|
|
3
|
+
--breadcrumbs-current: var(--bh-breadcrumbs-current-content);
|
|
4
|
+
--breadcrumbs-hover: var(--bh-content-default);
|
|
4
5
|
--breadcrumbs-border: var(--bh-border-subtle);
|
|
5
6
|
--breadcrumbs-surface: var(--bh-bg-raised);
|
|
6
7
|
--breadcrumbs-radius: var(--bh-radius-lg-8);
|
|
@@ -19,6 +20,13 @@
|
|
|
19
20
|
line-height: var(--bh-text-body-md-line-height);
|
|
20
21
|
}
|
|
21
22
|
|
|
23
|
+
.ds-breadcrumbs--sm {
|
|
24
|
+
font-size: var(--bh-text-body-sm-medium-font-size);
|
|
25
|
+
font-weight: var(--bh-text-body-sm-medium-font-weight);
|
|
26
|
+
letter-spacing: var(--bh-text-body-sm-medium-letter-spacing);
|
|
27
|
+
line-height: var(--bh-text-body-sm-medium-line-height);
|
|
28
|
+
}
|
|
29
|
+
|
|
22
30
|
.ds-breadcrumbs *,
|
|
23
31
|
.ds-breadcrumbs *::before,
|
|
24
32
|
.ds-breadcrumbs *::after {
|
|
@@ -59,7 +67,7 @@
|
|
|
59
67
|
}
|
|
60
68
|
|
|
61
69
|
.ds-breadcrumbs a:hover {
|
|
62
|
-
color: var(--breadcrumbs-
|
|
70
|
+
color: var(--breadcrumbs-hover);
|
|
63
71
|
}
|
|
64
72
|
|
|
65
73
|
.ds-breadcrumbs a:focus-visible {
|
|
@@ -123,6 +131,15 @@
|
|
|
123
131
|
display: block;
|
|
124
132
|
}
|
|
125
133
|
|
|
134
|
+
.ds-breadcrumbs--sm .ds-breadcrumbs__separator,
|
|
135
|
+
.ds-breadcrumbs--sm .ds-breadcrumbs__separator svg {
|
|
136
|
+
width: var(--bh-space-xl-12);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
.ds-breadcrumbs--sm .ds-breadcrumbs__separator svg {
|
|
140
|
+
height: var(--bh-space-xl-12);
|
|
141
|
+
}
|
|
142
|
+
|
|
126
143
|
.ds-breadcrumbs:dir(rtl) .ds-breadcrumbs__separator svg {
|
|
127
144
|
transform: scaleX(-1);
|
|
128
145
|
}
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
border-radius: var(--bh-radius-lg-8);
|
|
16
16
|
background: var(--bh-bg-raised);
|
|
17
17
|
padding: var(--bh-space-4xl-20);
|
|
18
|
-
box-shadow: var(--
|
|
18
|
+
box-shadow: var(--elevation-component-default);
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
.catalog-showcase__card:nth-child(4),
|
|
@@ -76,7 +76,7 @@
|
|
|
76
76
|
color: var(--bh-content-default);
|
|
77
77
|
box-shadow:
|
|
78
78
|
inset 0px 0px 0px var(--bh-border-width-default) var(--bh-border-subtle),
|
|
79
|
-
var(--
|
|
79
|
+
var(--elevation-component-default);
|
|
80
80
|
}
|
|
81
81
|
|
|
82
82
|
.ds-file-upload__dropzone:hover .ds-file-upload__icon,
|
|
@@ -84,7 +84,7 @@
|
|
|
84
84
|
.ds-file-upload__dropzone[aria-disabled="true"] .ds-file-upload__icon {
|
|
85
85
|
box-shadow:
|
|
86
86
|
inset 0px 0px 0px var(--bh-border-width-default) var(--bh-border-subtle),
|
|
87
|
-
var(--
|
|
87
|
+
var(--elevation-component-default);
|
|
88
88
|
}
|
|
89
89
|
|
|
90
90
|
.ds-file-upload__icon svg {
|
|
@@ -160,9 +160,9 @@
|
|
|
160
160
|
|
|
161
161
|
.ds-file-upload-row {
|
|
162
162
|
--ds-file-upload-row-border: var(--bh-border-subtle);
|
|
163
|
-
--ds-file-upload-row-
|
|
163
|
+
--ds-file-upload-row-elevation:
|
|
164
164
|
inset 0px 0px 0px var(--bh-border-width-default) var(--ds-file-upload-row-border),
|
|
165
|
-
var(--
|
|
165
|
+
var(--elevation-component-default);
|
|
166
166
|
|
|
167
167
|
min-height: calc(var(--bh-space-9xl-64) + var(--bh-space-xl-12));
|
|
168
168
|
display: flex;
|
|
@@ -172,7 +172,7 @@
|
|
|
172
172
|
border: 0;
|
|
173
173
|
border-radius: var(--bh-radius-2xl-12);
|
|
174
174
|
background: var(--bh-bg-raised);
|
|
175
|
-
box-shadow: var(--ds-file-upload-row-
|
|
175
|
+
box-shadow: var(--ds-file-upload-row-elevation);
|
|
176
176
|
overflow: clip;
|
|
177
177
|
}
|
|
178
178
|
|
|
@@ -193,9 +193,9 @@
|
|
|
193
193
|
|
|
194
194
|
.ds-file-upload-row--error {
|
|
195
195
|
--ds-file-upload-row-border: var(--bh-border-danger-strong);
|
|
196
|
-
--ds-file-upload-row-
|
|
196
|
+
--ds-file-upload-row-elevation:
|
|
197
197
|
inset 0px 0px 0px var(--bh-border-width-default) var(--ds-file-upload-row-border),
|
|
198
|
-
var(--
|
|
198
|
+
var(--elevation-02);
|
|
199
199
|
}
|
|
200
200
|
|
|
201
201
|
.ds-file-upload-row__content {
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
--onboarding-step-line-width: var(--bh-space-xxs-2);
|
|
19
19
|
--onboarding-step-line-offset: calc(-1 * var(--bh-space-md-8));
|
|
20
20
|
--onboarding-step-line-segment-height: calc(var(--bh-space-2xl-14) - var(--bh-space-xxxs-1));
|
|
21
|
-
--onboarding-step-
|
|
21
|
+
--onboarding-step-elevation: var(--elevation-component-default);
|
|
22
22
|
|
|
23
23
|
box-sizing: border-box;
|
|
24
24
|
position: relative;
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
border-color: var(--onboarding-step-border-default);
|
|
51
51
|
color: var(--onboarding-step-content-brand);
|
|
52
52
|
background: var(--onboarding-step-bg-raised);
|
|
53
|
-
box-shadow: var(--onboarding-step-
|
|
53
|
+
box-shadow: var(--onboarding-step-elevation);
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
.ds-onboarding-step--inactive {
|