banhaten 0.2.0 → 0.3.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 +28 -0
- package/README.md +1 -1
- package/docs/design-system/component-implementation-ownership-audit.md +244 -0
- package/docs/design-system/component-quality-audit-2026-08-20.md +223 -0
- package/docs/design-system/component-showcase-consistency-report.md +2 -0
- package/docs/design-system/components/README.md +1 -0
- package/docs/design-system/components/activity-feed.md +2 -0
- package/docs/design-system/components/activity-heatmap.md +73 -0
- package/docs/design-system/components/alert-dialog.md +1 -1
- package/docs/design-system/components/alert.md +2 -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 +5 -1
- package/docs/design-system/components/breadcrumbs.md +3 -0
- package/docs/design-system/components/button-group.md +1 -0
- package/docs/design-system/components/button.md +1 -1
- package/docs/design-system/components/card.md +11 -3
- package/docs/design-system/components/catalog-components.md +3 -0
- package/docs/design-system/components/date-picker.md +1 -1
- package/docs/design-system/components/file-upload.md +4 -0
- package/docs/design-system/components/modal.md +1 -1
- package/docs/design-system/components/navigation-menu.md +1 -1
- package/docs/design-system/components/onboarding-step-list-item.md +1 -0
- package/docs/design-system/components/page-header.md +3 -1
- package/docs/design-system/components/pagination.md +1 -0
- package/docs/design-system/components/resizable.md +1 -1
- package/docs/design-system/components/scroll-area.md +7 -3
- package/docs/design-system/components/sidebar.md +3 -1
- package/docs/design-system/components/slideout.md +4 -1
- package/docs/design-system/components/steps.md +7 -2
- package/docs/design-system/components/table.md +25 -7
- package/docs/design-system/components/tag.md +1 -1
- package/docs/design-system/components/timeline.md +4 -1
- package/docs/design-system/components/toggle.md +1 -1
- package/docs/design-system/components/toolbar.md +1 -1
- package/docs/design-system/components/tooltip.md +1 -1
- package/docs/design-system/density-and-elevation.md +18 -1
- package/docs/design-system/gap-promotion-report.md +1 -67
- package/docs/design-system/launch-comparison-shadcn.md +10 -10
- package/package.json +3 -2
- package/registry/components/alert-dialog.tsx +1 -1
- package/registry/components/alert.tsx +15 -11
- package/registry/components/avatar.tsx +7 -3
- package/registry/components/badge.tsx +17 -17
- package/registry/components/button-group.tsx +3 -1
- package/registry/components/button.tsx +2 -2
- package/registry/components/card.tsx +19 -3
- package/registry/components/carousel.tsx +14 -0
- package/registry/components/command.tsx +37 -3
- package/registry/components/date-picker.tsx +67 -31
- package/registry/components/expanded/ActivityFeed.tsx +3 -7
- package/registry/components/expanded/ActivityHeatmap.tsx +64 -0
- package/registry/components/expanded/Banner.tsx +0 -1
- package/registry/components/expanded/Breadcrumbs.tsx +3 -0
- package/registry/components/expanded/CatalogComponentsShowcase.tsx +3 -4
- package/registry/components/expanded/CatalogDivider.tsx +3 -2
- package/registry/components/expanded/FileUpload.tsx +7 -5
- package/registry/components/expanded/OnboardingStepListItem.tsx +0 -2
- package/registry/components/expanded/PageHeader.tsx +35 -44
- package/registry/components/expanded/Slideout.tsx +18 -13
- package/registry/components/expanded/Steps.tsx +147 -9
- package/registry/components/expanded/Table.tsx +50 -18
- package/registry/components/expanded/Timeline.tsx +11 -24
- package/registry/components/expanded/activityFeed.css +8 -8
- package/registry/components/expanded/activityHeatmap.css +66 -0
- package/registry/components/expanded/banner.css +21 -11
- package/registry/components/expanded/breadcrumbs.css +1 -1
- package/registry/components/expanded/fileUpload.css +1 -1
- package/registry/components/expanded/onboardingStepListItem.css +2 -2
- package/registry/components/expanded/pageHeader.css +14 -11
- package/registry/components/expanded/slideout.css +3 -7
- package/registry/components/expanded/steps.css +75 -12
- package/registry/components/expanded/table.css +58 -67
- package/registry/components/expanded/timeline.css +17 -16
- package/registry/components/field.tsx +61 -8
- package/registry/components/menu.tsx +56 -6
- package/registry/components/modal.tsx +1 -1
- package/registry/components/navigation-menu.tsx +1 -1
- package/registry/components/pagination.css +36 -0
- package/registry/components/pagination.tsx +8 -6
- package/registry/components/progress-slider.tsx +1 -1
- package/registry/components/resizable.tsx +36 -2
- package/registry/components/scroll-area.tsx +30 -6
- package/registry/components/select.tsx +34 -11
- package/registry/components/sidebar.tsx +11 -5
- package/registry/components/social-button.tsx +12 -5
- package/registry/components/table-elements.tsx +128 -0
- package/registry/components/tabs.tsx +5 -10
- package/registry/components/tag.tsx +1 -1
- package/registry/components/toggle.tsx +2 -2
- package/registry/components/toolbar.tsx +5 -5
- package/registry/components/tooltip.tsx +1 -1
- package/registry/examples/avatar-demo.tsx +7 -4
- package/registry/examples/expanded/activity-heatmap-demo.tsx +29 -0
- package/registry/examples/expanded/breadcrumbs-demo.tsx +3 -3
- package/registry/examples/pagination-demo.tsx +5 -5
- package/registry/examples/sidebar-demo.tsx +4 -2
- package/registry/index.json +392 -33
- package/registry/styles/globals.css +68 -42
- package/registry.json +40 -3
- package/tokens/banhaten.tokens.json +165 -55
|
@@ -25,6 +25,34 @@ export type StepsProps = {
|
|
|
25
25
|
items?: StepItem[];
|
|
26
26
|
};
|
|
27
27
|
|
|
28
|
+
export type ProgressStepState = "complete" | "active" | "todo";
|
|
29
|
+
|
|
30
|
+
export type ProgressStep = {
|
|
31
|
+
label?: ReactNode;
|
|
32
|
+
marker?: ReactNode;
|
|
33
|
+
state?: ProgressStepState;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export type ProgressStepsClassNames = {
|
|
37
|
+
connector?: string;
|
|
38
|
+
item?: string;
|
|
39
|
+
label?: string;
|
|
40
|
+
marker?: string;
|
|
41
|
+
segment?: string;
|
|
42
|
+
track?: string;
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export type ProgressStepsProps = {
|
|
46
|
+
activeIndex?: number;
|
|
47
|
+
ariaLabel: string;
|
|
48
|
+
className?: string;
|
|
49
|
+
classNames?: ProgressStepsClassNames;
|
|
50
|
+
dir?: "ltr" | "rtl";
|
|
51
|
+
items: ProgressStep[];
|
|
52
|
+
label?: ReactNode;
|
|
53
|
+
variant?: "bars" | "markers";
|
|
54
|
+
};
|
|
55
|
+
|
|
28
56
|
export type HorizontalStepItemProps = {
|
|
29
57
|
alignment?: StepAlignment;
|
|
30
58
|
caption?: ReactNode;
|
|
@@ -66,13 +94,12 @@ export function Steps({
|
|
|
66
94
|
indicator = "icon",
|
|
67
95
|
items,
|
|
68
96
|
}: StepsProps) {
|
|
69
|
-
const rtl = dir === "rtl";
|
|
70
97
|
const stepItems = items ?? [];
|
|
71
98
|
|
|
72
99
|
if (direction === "vertical") {
|
|
73
100
|
return (
|
|
74
101
|
<div
|
|
75
|
-
className={["ds-steps", "ds-steps--vertical",
|
|
102
|
+
className={["ds-steps", "ds-steps--vertical", className]
|
|
76
103
|
.filter(Boolean)
|
|
77
104
|
.join(" ")}
|
|
78
105
|
dir={dir}
|
|
@@ -102,7 +129,7 @@ export function Steps({
|
|
|
102
129
|
|
|
103
130
|
return (
|
|
104
131
|
<div
|
|
105
|
-
className={["ds-steps", "ds-steps--horizontal",
|
|
132
|
+
className={["ds-steps", "ds-steps--horizontal", className]
|
|
106
133
|
.filter(Boolean)
|
|
107
134
|
.join(" ")}
|
|
108
135
|
dir={dir}
|
|
@@ -122,6 +149,122 @@ export function Steps({
|
|
|
122
149
|
);
|
|
123
150
|
}
|
|
124
151
|
|
|
152
|
+
export function ProgressSteps({
|
|
153
|
+
activeIndex = 0,
|
|
154
|
+
ariaLabel,
|
|
155
|
+
className = "",
|
|
156
|
+
classNames = {},
|
|
157
|
+
dir,
|
|
158
|
+
items,
|
|
159
|
+
label,
|
|
160
|
+
variant = "markers",
|
|
161
|
+
}: ProgressStepsProps) {
|
|
162
|
+
const rootClassName = [
|
|
163
|
+
"ds-progress-steps",
|
|
164
|
+
`ds-progress-steps--${variant}`,
|
|
165
|
+
className,
|
|
166
|
+
]
|
|
167
|
+
.filter(Boolean)
|
|
168
|
+
.join(" ");
|
|
169
|
+
|
|
170
|
+
if (variant === "bars") {
|
|
171
|
+
return (
|
|
172
|
+
<div
|
|
173
|
+
aria-label={ariaLabel}
|
|
174
|
+
aria-valuemax={items.length}
|
|
175
|
+
aria-valuemin={1}
|
|
176
|
+
aria-valuenow={Math.min(activeIndex + 1, items.length)}
|
|
177
|
+
className={rootClassName}
|
|
178
|
+
dir={dir}
|
|
179
|
+
role="progressbar"
|
|
180
|
+
>
|
|
181
|
+
{label ? <span data-slot="progress-steps-label">{label}</span> : null}
|
|
182
|
+
<div
|
|
183
|
+
aria-hidden="true"
|
|
184
|
+
className={["ds-progress-steps__track", classNames.track]
|
|
185
|
+
.filter(Boolean)
|
|
186
|
+
.join(" ")}
|
|
187
|
+
data-slot="progress-steps-track"
|
|
188
|
+
>
|
|
189
|
+
{items.map((item, index) => (
|
|
190
|
+
<span
|
|
191
|
+
className={["ds-progress-steps__segment", classNames.segment]
|
|
192
|
+
.filter(Boolean)
|
|
193
|
+
.join(" ")}
|
|
194
|
+
data-active={index <= activeIndex ? "true" : "false"}
|
|
195
|
+
data-slot="progress-steps-segment"
|
|
196
|
+
data-state={item.state ?? (index < activeIndex ? "complete" : index === activeIndex ? "active" : "todo")}
|
|
197
|
+
key={index}
|
|
198
|
+
/>
|
|
199
|
+
))}
|
|
200
|
+
</div>
|
|
201
|
+
</div>
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
return (
|
|
206
|
+
<ol aria-label={ariaLabel} className={rootClassName} dir={dir}>
|
|
207
|
+
{items.map((item, index) => {
|
|
208
|
+
const state =
|
|
209
|
+
item.state ??
|
|
210
|
+
(index < activeIndex
|
|
211
|
+
? "complete"
|
|
212
|
+
: index === activeIndex
|
|
213
|
+
? "active"
|
|
214
|
+
: "todo");
|
|
215
|
+
|
|
216
|
+
return (
|
|
217
|
+
<li
|
|
218
|
+
className={[
|
|
219
|
+
"ds-progress-steps__item",
|
|
220
|
+
`is-${state}`,
|
|
221
|
+
classNames.item,
|
|
222
|
+
]
|
|
223
|
+
.filter(Boolean)
|
|
224
|
+
.join(" ")}
|
|
225
|
+
data-slot="progress-steps-item"
|
|
226
|
+
data-state={state}
|
|
227
|
+
key={index}
|
|
228
|
+
>
|
|
229
|
+
<span
|
|
230
|
+
aria-hidden="true"
|
|
231
|
+
className={["ds-progress-steps__marker", classNames.marker]
|
|
232
|
+
.filter(Boolean)
|
|
233
|
+
.join(" ")}
|
|
234
|
+
data-slot="progress-steps-marker"
|
|
235
|
+
>
|
|
236
|
+
{item.marker ?? index + 1}
|
|
237
|
+
</span>
|
|
238
|
+
{item.label ? (
|
|
239
|
+
<span
|
|
240
|
+
className={["ds-progress-steps__label", classNames.label]
|
|
241
|
+
.filter(Boolean)
|
|
242
|
+
.join(" ")}
|
|
243
|
+
data-slot="progress-steps-item-label"
|
|
244
|
+
>
|
|
245
|
+
{item.label}
|
|
246
|
+
</span>
|
|
247
|
+
) : null}
|
|
248
|
+
{index < items.length - 1 ? (
|
|
249
|
+
<span
|
|
250
|
+
aria-hidden="true"
|
|
251
|
+
className={[
|
|
252
|
+
"ds-progress-steps__connector",
|
|
253
|
+
state === "complete" && "is-complete",
|
|
254
|
+
classNames.connector,
|
|
255
|
+
]
|
|
256
|
+
.filter(Boolean)
|
|
257
|
+
.join(" ")}
|
|
258
|
+
data-slot="progress-steps-connector"
|
|
259
|
+
/>
|
|
260
|
+
) : null}
|
|
261
|
+
</li>
|
|
262
|
+
);
|
|
263
|
+
})}
|
|
264
|
+
</ol>
|
|
265
|
+
);
|
|
266
|
+
}
|
|
267
|
+
|
|
125
268
|
export function HorizontalStepItem({
|
|
126
269
|
alignment = "leading",
|
|
127
270
|
caption,
|
|
@@ -135,7 +278,6 @@ export function HorizontalStepItem({
|
|
|
135
278
|
showLeadingLine = true,
|
|
136
279
|
showTrailingLine = true,
|
|
137
280
|
}: HorizontalStepItemProps) {
|
|
138
|
-
const rtl = dir === "rtl";
|
|
139
281
|
const linePlacement = getHorizontalLinePlacement(alignment, showLeadingLine, showTrailingLine);
|
|
140
282
|
const text = (
|
|
141
283
|
<div className="ds-horizontal-step-item__text">
|
|
@@ -157,7 +299,6 @@ export function HorizontalStepItem({
|
|
|
157
299
|
"ds-horizontal-step-item",
|
|
158
300
|
`ds-horizontal-step-item--${alignment}`,
|
|
159
301
|
`ds-horizontal-step-item--${position}`,
|
|
160
|
-
rtl ? "ds-horizontal-step-item--rtl" : "ds-horizontal-step-item--ltr",
|
|
161
302
|
className,
|
|
162
303
|
]
|
|
163
304
|
.filter(Boolean)
|
|
@@ -189,7 +330,6 @@ export function VerticalStepItem({
|
|
|
189
330
|
slotContent,
|
|
190
331
|
supportText,
|
|
191
332
|
}: VerticalStepItemProps & { children?: ReactNode }) {
|
|
192
|
-
const rtl = dir === "rtl";
|
|
193
333
|
const marker = (
|
|
194
334
|
<div className="ds-vertical-step-item__rail" aria-hidden="true">
|
|
195
335
|
<StepMarker indicator={indicator} number={number} />
|
|
@@ -205,7 +345,6 @@ export function VerticalStepItem({
|
|
|
205
345
|
className={[
|
|
206
346
|
"ds-vertical-step-item",
|
|
207
347
|
`ds-vertical-step-item--${alignment}`,
|
|
208
|
-
rtl ? "ds-vertical-step-item--rtl" : "ds-vertical-step-item--ltr",
|
|
209
348
|
className,
|
|
210
349
|
]
|
|
211
350
|
.filter(Boolean)
|
|
@@ -216,9 +355,8 @@ export function VerticalStepItem({
|
|
|
216
355
|
<div className="ds-vertical-step-item__content">
|
|
217
356
|
<div className="ds-vertical-step-item__copy">
|
|
218
357
|
<div className="ds-vertical-step-item__header">
|
|
219
|
-
{rtl && hasSupportText && supportText && <div className="ds-vertical-step-item__support">{supportText}</div>}
|
|
220
358
|
{label && <div className="ds-vertical-step-item__label">{label}</div>}
|
|
221
|
-
{
|
|
359
|
+
{hasSupportText && supportText && <div className="ds-vertical-step-item__support">{supportText}</div>}
|
|
222
360
|
</div>
|
|
223
361
|
{hasCaption && caption && <div className="ds-vertical-step-item__caption">{caption}</div>}
|
|
224
362
|
</div>
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
EllipsisIcon,
|
|
6
6
|
EyeIcon,
|
|
7
7
|
FileIcon as LucideFileIcon,
|
|
8
|
+
StarIcon,
|
|
8
9
|
Trash2Icon,
|
|
9
10
|
} from "lucide-react";
|
|
10
11
|
import { Pagination, type PaginationPage, type PaginationProps } from "@/components/ui/pagination";
|
|
@@ -135,6 +136,7 @@ export type DataTableSearch<Row extends TableRowBase> =
|
|
|
135
136
|
};
|
|
136
137
|
|
|
137
138
|
export type DataTablePagination = {
|
|
139
|
+
ariaLabel?: string;
|
|
138
140
|
defaultPage?: number;
|
|
139
141
|
manual?: boolean;
|
|
140
142
|
onPageChange?: (page: number) => void;
|
|
@@ -216,7 +218,12 @@ export function Table<Row extends TableRowBase>({
|
|
|
216
218
|
}
|
|
217
219
|
|
|
218
220
|
return (
|
|
219
|
-
<div
|
|
221
|
+
<div
|
|
222
|
+
aria-label="Scrollable table"
|
|
223
|
+
className={`ds-table-wrap ds-table-wrap--${size}`}
|
|
224
|
+
dir={dir}
|
|
225
|
+
tabIndex={0}
|
|
226
|
+
>
|
|
220
227
|
<table className="ds-table">
|
|
221
228
|
<thead>
|
|
222
229
|
<tr>
|
|
@@ -238,18 +245,20 @@ export function Table<Row extends TableRowBase>({
|
|
|
238
245
|
) : column.header ? (
|
|
239
246
|
column.sortable ? (
|
|
240
247
|
onSortChange ? (
|
|
241
|
-
<
|
|
248
|
+
<Button
|
|
242
249
|
aria-label={`Sort by ${column.header}`}
|
|
243
250
|
className={cx(
|
|
244
251
|
"ds-table__sort",
|
|
245
252
|
sort?.columnId === column.id && `ds-table__sort--${sort.direction}`,
|
|
246
253
|
)}
|
|
247
254
|
onClick={() => onSortChange(getNextSort(sort, column.id))}
|
|
255
|
+
size="xs"
|
|
248
256
|
type="button"
|
|
257
|
+
variant="ghost"
|
|
249
258
|
>
|
|
250
259
|
<span>{column.header}</span>
|
|
251
260
|
<SortIcon direction={sort?.columnId === column.id ? sort.direction : undefined} />
|
|
252
|
-
</
|
|
261
|
+
</Button>
|
|
253
262
|
) : (
|
|
254
263
|
<span className="ds-table__sort ds-table__sort--static">
|
|
255
264
|
<span>{column.header}</span>
|
|
@@ -259,7 +268,11 @@ export function Table<Row extends TableRowBase>({
|
|
|
259
268
|
) : (
|
|
260
269
|
column.header
|
|
261
270
|
)
|
|
262
|
-
) :
|
|
271
|
+
) : (
|
|
272
|
+
<span className="sr-only">
|
|
273
|
+
{column.kind === "actions" ? "Actions" : column.id}
|
|
274
|
+
</span>
|
|
275
|
+
)}
|
|
263
276
|
</th>
|
|
264
277
|
))}
|
|
265
278
|
</tr>
|
|
@@ -283,7 +296,7 @@ export function Table<Row extends TableRowBase>({
|
|
|
283
296
|
) : column.renderCell ? (
|
|
284
297
|
column.renderCell(row)
|
|
285
298
|
) : column.item ? (
|
|
286
|
-
renderTableItem(column.item(row))
|
|
299
|
+
renderTableItem(column.item(row), size)
|
|
287
300
|
) : null}
|
|
288
301
|
</td>
|
|
289
302
|
))}
|
|
@@ -492,6 +505,10 @@ export function DataTable<Row extends TableRowBase>({
|
|
|
492
505
|
<footer className="ds-data-table__footer">
|
|
493
506
|
<ToolbarText>{labels.resultsSummary({ from: visibleFrom, to: visibleTo, total: totalRows })}</ToolbarText>
|
|
494
507
|
<Pagination
|
|
508
|
+
aria-label={
|
|
509
|
+
paginationConfig.ariaLabel ??
|
|
510
|
+
(typeof title === "string" ? `${title} pagination` : "Table pagination")
|
|
511
|
+
}
|
|
495
512
|
dir={dir}
|
|
496
513
|
nextDisabled={currentPage >= pageCount}
|
|
497
514
|
onPageChange={setDataTablePage}
|
|
@@ -755,7 +772,7 @@ function clampNumber(value: number, min: number, max: number) {
|
|
|
755
772
|
return Math.min(max, Math.max(min, Math.floor(value)));
|
|
756
773
|
}
|
|
757
774
|
|
|
758
|
-
function renderTableItem(item: TableItem) {
|
|
775
|
+
function renderTableItem(item: TableItem, tableSize: TableSize) {
|
|
759
776
|
switch (item.type) {
|
|
760
777
|
case "checkbox":
|
|
761
778
|
return (
|
|
@@ -772,7 +789,7 @@ function renderTableItem(item: TableItem) {
|
|
|
772
789
|
case "avatarText":
|
|
773
790
|
return (
|
|
774
791
|
<span className="ds-table-avatar-text">
|
|
775
|
-
<Avatar name={item.name} src={item.src} />
|
|
792
|
+
<Avatar name={item.name} size={tableSize === "lg" ? "md" : "sm"} src={item.src} />
|
|
776
793
|
<span>
|
|
777
794
|
<strong>{item.name}</strong>
|
|
778
795
|
{item.caption && <em>{item.caption}</em>}
|
|
@@ -796,7 +813,7 @@ function renderTableItem(item: TableItem) {
|
|
|
796
813
|
case "badges":
|
|
797
814
|
return <BadgeList items={item.items} maxVisible={item.maxVisible} />;
|
|
798
815
|
case "onlyAvatar":
|
|
799
|
-
return <Avatar name={item.alt} src={item.src} />;
|
|
816
|
+
return <Avatar name={item.alt} size={tableSize === "lg" ? "md" : "xs"} src={item.src} />;
|
|
800
817
|
case "avatarStack":
|
|
801
818
|
return (
|
|
802
819
|
<AvatarStack
|
|
@@ -805,6 +822,7 @@ function renderTableItem(item: TableItem) {
|
|
|
805
822
|
canAdd={item.canAdd}
|
|
806
823
|
count={item.count}
|
|
807
824
|
onAdd={item.onAdd}
|
|
825
|
+
size={tableSize}
|
|
808
826
|
/>
|
|
809
827
|
);
|
|
810
828
|
case "tags":
|
|
@@ -855,7 +873,9 @@ function SelectionCheckbox({
|
|
|
855
873
|
);
|
|
856
874
|
}
|
|
857
875
|
|
|
858
|
-
|
|
876
|
+
type TableAvatarSize = "xs" | "sm" | "md";
|
|
877
|
+
|
|
878
|
+
function Avatar({ name, size, src }: { name: string; size: TableAvatarSize; src?: string }) {
|
|
859
879
|
const initials = name
|
|
860
880
|
.split(" ")
|
|
861
881
|
.map((part) => part[0])
|
|
@@ -864,9 +884,9 @@ function Avatar({ name, src }: { name: string; src?: string }) {
|
|
|
864
884
|
.toUpperCase();
|
|
865
885
|
|
|
866
886
|
return (
|
|
867
|
-
<AvatarPrimitive className="ds-table-avatar" size=
|
|
887
|
+
<AvatarPrimitive className="ds-table-avatar" size={size}>
|
|
868
888
|
{src ? <AvatarImage alt="" src={src} /> : null}
|
|
869
|
-
<AvatarFallback>{initials}</AvatarFallback>
|
|
889
|
+
<AvatarFallback size={size}>{initials}</AvatarFallback>
|
|
870
890
|
</AvatarPrimitive>
|
|
871
891
|
);
|
|
872
892
|
}
|
|
@@ -877,23 +897,25 @@ function AvatarStack({
|
|
|
877
897
|
canAdd,
|
|
878
898
|
count,
|
|
879
899
|
onAdd,
|
|
900
|
+
size,
|
|
880
901
|
}: {
|
|
881
902
|
addLabel?: string;
|
|
882
903
|
avatars: AvatarItem[];
|
|
883
904
|
canAdd?: boolean;
|
|
884
905
|
count?: number;
|
|
885
906
|
onAdd?: () => void;
|
|
907
|
+
size: TableSize;
|
|
886
908
|
}) {
|
|
887
909
|
return (
|
|
888
|
-
<span className=
|
|
910
|
+
<span className={`ds-table-avatar-stack ds-table-avatar-stack--${size}`}>
|
|
889
911
|
{avatars.slice(0, 3).map((avatar) => (
|
|
890
|
-
<Avatar key={avatar.alt} name={avatar.alt} src={avatar.src} />
|
|
912
|
+
<Avatar key={avatar.alt} name={avatar.alt} size={size === "lg" ? "md" : "xs"} src={avatar.src} />
|
|
891
913
|
))}
|
|
892
914
|
{count ? <span className="ds-table-avatar ds-table-avatar--count">+{count}</span> : null}
|
|
893
915
|
{canAdd ? (
|
|
894
|
-
<
|
|
916
|
+
<Button aria-label={addLabel} disabled={!onAdd} onClick={onAdd} size="icon-xs" type="button" variant="ghost">
|
|
895
917
|
+
|
|
896
|
-
</
|
|
918
|
+
</Button>
|
|
897
919
|
) : null}
|
|
898
920
|
</span>
|
|
899
921
|
);
|
|
@@ -938,10 +960,11 @@ function TagList({ items, maxVisible = items.length }: { items: string[]; maxVis
|
|
|
938
960
|
function Progress({ label, tone, value }: { label?: string; tone: "success" | "brand"; value: number }) {
|
|
939
961
|
return (
|
|
940
962
|
<ProgressPrimitive
|
|
963
|
+
aria-label={label ?? "Progress"}
|
|
941
964
|
className={`ds-table-progress ds-table-progress--${tone}`}
|
|
942
965
|
indicator={label}
|
|
943
966
|
labelPosition="inline"
|
|
944
|
-
size="
|
|
967
|
+
size="lg"
|
|
945
968
|
value={value}
|
|
946
969
|
/>
|
|
947
970
|
);
|
|
@@ -949,9 +972,18 @@ function Progress({ label, tone, value }: { label?: string; tone: "success" | "b
|
|
|
949
972
|
|
|
950
973
|
function Rating({ max, value }: { max: number; value: number }) {
|
|
951
974
|
return (
|
|
952
|
-
<span
|
|
975
|
+
<span
|
|
976
|
+
aria-label={`${value} out of ${max}`}
|
|
977
|
+
className="ds-table-rating"
|
|
978
|
+
role="img"
|
|
979
|
+
>
|
|
953
980
|
{Array.from({ length: max }, (_, index) => (
|
|
954
|
-
<
|
|
981
|
+
<StarIcon
|
|
982
|
+
aria-hidden="true"
|
|
983
|
+
className={index < value ? "is-filled" : undefined}
|
|
984
|
+
key={index}
|
|
985
|
+
strokeWidth="var(--bh-icon-stroke-190)"
|
|
986
|
+
/>
|
|
955
987
|
))}
|
|
956
988
|
</span>
|
|
957
989
|
);
|
|
@@ -8,11 +8,12 @@ export type TimelineItemState = "finished" | "active" | "inactive";
|
|
|
8
8
|
|
|
9
9
|
export type TimelineStep = {
|
|
10
10
|
bottomDate?: string;
|
|
11
|
-
caption?:
|
|
11
|
+
caption?: ReactNode;
|
|
12
|
+
className?: string;
|
|
12
13
|
date?: string;
|
|
13
14
|
icon?: ReactNode;
|
|
14
15
|
id?: string;
|
|
15
|
-
label?:
|
|
16
|
+
label?: ReactNode;
|
|
16
17
|
showBottomDate?: boolean;
|
|
17
18
|
showCaption?: boolean;
|
|
18
19
|
showLeadingDate?: boolean;
|
|
@@ -27,6 +28,7 @@ export type TimelineItemProps = TimelineStep & {
|
|
|
27
28
|
className?: string;
|
|
28
29
|
dir?: "ltr" | "rtl";
|
|
29
30
|
orientation?: TimelineOrientation;
|
|
31
|
+
role?: "listitem" | "none" | "presentation";
|
|
30
32
|
variant?: TimelineVariant;
|
|
31
33
|
};
|
|
32
34
|
|
|
@@ -46,14 +48,12 @@ function classes(...names: Array<string | false | undefined>) {
|
|
|
46
48
|
function Indicator({
|
|
47
49
|
icon,
|
|
48
50
|
orientation,
|
|
49
|
-
rtl,
|
|
50
51
|
showLine,
|
|
51
52
|
state,
|
|
52
53
|
variant,
|
|
53
54
|
}: {
|
|
54
55
|
icon?: ReactNode;
|
|
55
56
|
orientation: TimelineOrientation;
|
|
56
|
-
rtl: boolean;
|
|
57
57
|
showLine: boolean;
|
|
58
58
|
state: TimelineItemState;
|
|
59
59
|
variant: TimelineVariant;
|
|
@@ -79,21 +79,11 @@ function Indicator({
|
|
|
79
79
|
className={classes(
|
|
80
80
|
"ds-timeline__indicator",
|
|
81
81
|
`ds-timeline__indicator--${orientation}`,
|
|
82
|
-
rtl && "ds-timeline__indicator--rtl",
|
|
83
82
|
)}
|
|
84
83
|
aria-hidden="true"
|
|
85
84
|
>
|
|
86
|
-
{
|
|
87
|
-
|
|
88
|
-
{line}
|
|
89
|
-
{marker}
|
|
90
|
-
</>
|
|
91
|
-
) : (
|
|
92
|
-
<>
|
|
93
|
-
{marker}
|
|
94
|
-
{line}
|
|
95
|
-
</>
|
|
96
|
-
)}
|
|
85
|
+
{marker}
|
|
86
|
+
{line}
|
|
97
87
|
</span>
|
|
98
88
|
);
|
|
99
89
|
}
|
|
@@ -107,6 +97,7 @@ export function TimelineItem({
|
|
|
107
97
|
icon,
|
|
108
98
|
label,
|
|
109
99
|
orientation = "vertical",
|
|
100
|
+
role,
|
|
110
101
|
showBottomDate = false,
|
|
111
102
|
showCaption = true,
|
|
112
103
|
showLeadingDate = true,
|
|
@@ -117,7 +108,6 @@ export function TimelineItem({
|
|
|
117
108
|
topDate,
|
|
118
109
|
variant = "default",
|
|
119
110
|
}: TimelineItemProps) {
|
|
120
|
-
const rtl = dir === "rtl";
|
|
121
111
|
const displayDate = date;
|
|
122
112
|
const displayLabel = label;
|
|
123
113
|
const displayCaption = caption;
|
|
@@ -141,7 +131,6 @@ export function TimelineItem({
|
|
|
141
131
|
<Indicator
|
|
142
132
|
icon={icon}
|
|
143
133
|
orientation={orientation}
|
|
144
|
-
rtl={rtl}
|
|
145
134
|
showLine={showLine}
|
|
146
135
|
state={state}
|
|
147
136
|
variant={variant}
|
|
@@ -159,11 +148,10 @@ export function TimelineItem({
|
|
|
159
148
|
`ds-timeline-item--${orientation}`,
|
|
160
149
|
`ds-timeline-item--${variant}`,
|
|
161
150
|
`ds-timeline-item--${state}`,
|
|
162
|
-
rtl ? "ds-timeline-item--rtl" : "ds-timeline-item--ltr",
|
|
163
151
|
className,
|
|
164
152
|
)}
|
|
165
153
|
dir={dir}
|
|
166
|
-
role=
|
|
154
|
+
role={role}
|
|
167
155
|
>
|
|
168
156
|
{leadingDate}
|
|
169
157
|
{indicator}
|
|
@@ -173,15 +161,13 @@ export function TimelineItem({
|
|
|
173
161
|
}
|
|
174
162
|
|
|
175
163
|
export function Timeline({
|
|
176
|
-
ariaLabel,
|
|
164
|
+
ariaLabel = "Timeline",
|
|
177
165
|
className,
|
|
178
166
|
dir,
|
|
179
167
|
orientation = "vertical",
|
|
180
168
|
steps = [],
|
|
181
169
|
variant = "default",
|
|
182
170
|
}: TimelineProps) {
|
|
183
|
-
const rtl = dir === "rtl";
|
|
184
|
-
|
|
185
171
|
return (
|
|
186
172
|
<div
|
|
187
173
|
aria-label={ariaLabel}
|
|
@@ -189,11 +175,11 @@ export function Timeline({
|
|
|
189
175
|
"ds-timeline",
|
|
190
176
|
`ds-timeline--${orientation}`,
|
|
191
177
|
`ds-timeline--${variant}`,
|
|
192
|
-
rtl ? "ds-timeline--rtl" : "ds-timeline--ltr",
|
|
193
178
|
className,
|
|
194
179
|
)}
|
|
195
180
|
dir={dir}
|
|
196
181
|
role="list"
|
|
182
|
+
tabIndex={orientation === "horizontal" ? 0 : undefined}
|
|
197
183
|
>
|
|
198
184
|
{steps.map((step, index) => (
|
|
199
185
|
<TimelineItem
|
|
@@ -201,6 +187,7 @@ export function Timeline({
|
|
|
201
187
|
key={step.id ?? index}
|
|
202
188
|
dir={dir}
|
|
203
189
|
orientation={orientation}
|
|
190
|
+
role="listitem"
|
|
204
191
|
showTopDate={step.showTopDate ?? orientation === "horizontal"}
|
|
205
192
|
showBottomDate={step.showBottomDate ?? false}
|
|
206
193
|
showPaddingBottom={step.showPaddingBottom ?? orientation === "vertical"}
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
text-decoration: none;
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
.ds-activity-feed
|
|
46
|
+
.ds-activity-feed:dir(rtl) {
|
|
47
47
|
font-family: var(--bh-font-family);
|
|
48
48
|
margin-inline-end: auto;
|
|
49
49
|
}
|
|
@@ -102,7 +102,7 @@
|
|
|
102
102
|
gap: var(--activity-feed-space-lg);
|
|
103
103
|
}
|
|
104
104
|
|
|
105
|
-
.ds-activity-feed-item
|
|
105
|
+
.ds-activity-feed-item:dir(rtl) .ds-activity-feed-item__content {
|
|
106
106
|
align-items: flex-start;
|
|
107
107
|
}
|
|
108
108
|
|
|
@@ -121,7 +121,7 @@
|
|
|
121
121
|
gap: var(--bh-space-sm-6);
|
|
122
122
|
}
|
|
123
123
|
|
|
124
|
-
.ds-activity-feed-item
|
|
124
|
+
.ds-activity-feed-item:dir(rtl) .ds-activity-feed-item__topline {
|
|
125
125
|
justify-content: flex-start;
|
|
126
126
|
}
|
|
127
127
|
|
|
@@ -139,7 +139,7 @@
|
|
|
139
139
|
word-break: break-word;
|
|
140
140
|
}
|
|
141
141
|
|
|
142
|
-
.ds-activity-feed-item
|
|
142
|
+
.ds-activity-feed-item:dir(rtl) .ds-activity-feed-item__text {
|
|
143
143
|
justify-content: flex-start;
|
|
144
144
|
text-align: right;
|
|
145
145
|
}
|
|
@@ -149,7 +149,7 @@
|
|
|
149
149
|
font-weight: var(--bh-font-weight-medium);
|
|
150
150
|
}
|
|
151
151
|
|
|
152
|
-
.ds-activity-feed-item
|
|
152
|
+
.ds-activity-feed-item:dir(rtl) .ds-activity-feed-item__text strong {
|
|
153
153
|
font-weight: var(--bh-font-weight-semibold);
|
|
154
154
|
}
|
|
155
155
|
|
|
@@ -199,7 +199,7 @@
|
|
|
199
199
|
padding: var(--activity-feed-space-xl);
|
|
200
200
|
}
|
|
201
201
|
|
|
202
|
-
.ds-activity-feed-item
|
|
202
|
+
.ds-activity-feed-item:dir(rtl) .ds-activity-feed-item__caption {
|
|
203
203
|
justify-content: flex-start;
|
|
204
204
|
text-align: right;
|
|
205
205
|
}
|
|
@@ -216,7 +216,7 @@
|
|
|
216
216
|
line-height: var(--bh-text-body-sm-regular-line-height);
|
|
217
217
|
}
|
|
218
218
|
|
|
219
|
-
.ds-activity-feed-item
|
|
219
|
+
.ds-activity-feed-item:dir(rtl) .ds-activity-feed-item__slot {
|
|
220
220
|
place-items: center start;
|
|
221
221
|
text-align: right;
|
|
222
222
|
}
|
|
@@ -230,7 +230,7 @@
|
|
|
230
230
|
line-height: var(--bh-text-body-sm-regular-line-height);
|
|
231
231
|
}
|
|
232
232
|
|
|
233
|
-
.ds-activity-feed-item
|
|
233
|
+
.ds-activity-feed-item:dir(rtl) .ds-activity-feed-item__timestamp {
|
|
234
234
|
text-align: right;
|
|
235
235
|
}
|
|
236
236
|
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
.ds-activity-heatmap {
|
|
2
|
+
--activity-heatmap-cell-size: var(--bh-space-3xl-16);
|
|
3
|
+
--activity-heatmap-gap: var(--bh-space-xs-4);
|
|
4
|
+
--activity-heatmap-radius: var(--bh-radius-sm-4);
|
|
5
|
+
--activity-heatmap-level-0: var(--bh-bg-neutral-medium);
|
|
6
|
+
--activity-heatmap-level-1: var(--bh-bg-accent-purple-subtle);
|
|
7
|
+
--activity-heatmap-level-2: var(--bh-bg-accent-purple-soft);
|
|
8
|
+
--activity-heatmap-level-3: var(--bh-bg-accent-purple-default);
|
|
9
|
+
--activity-heatmap-level-4: var(--bh-content-accent-purple-strong);
|
|
10
|
+
|
|
11
|
+
box-sizing: border-box;
|
|
12
|
+
width: 100%;
|
|
13
|
+
min-width: 0;
|
|
14
|
+
max-width: 100%;
|
|
15
|
+
overflow-x: auto;
|
|
16
|
+
overflow-y: hidden;
|
|
17
|
+
outline: none;
|
|
18
|
+
color: var(--bh-content-default);
|
|
19
|
+
font-family: var(--bh-font-family);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.ds-activity-heatmap:focus-visible {
|
|
23
|
+
box-shadow: var(--shadow-component-focus-ring);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.ds-activity-heatmap *,
|
|
27
|
+
.ds-activity-heatmap *::before,
|
|
28
|
+
.ds-activity-heatmap *::after {
|
|
29
|
+
box-sizing: border-box;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.ds-activity-heatmap__grid {
|
|
33
|
+
display: grid;
|
|
34
|
+
grid-auto-flow: column;
|
|
35
|
+
grid-auto-columns: var(--activity-heatmap-cell-size);
|
|
36
|
+
grid-template-rows: repeat(7, var(--activity-heatmap-cell-size));
|
|
37
|
+
justify-content: start;
|
|
38
|
+
gap: var(--activity-heatmap-gap);
|
|
39
|
+
width: max-content;
|
|
40
|
+
min-width: 100%;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.ds-activity-heatmap__cell {
|
|
44
|
+
display: block;
|
|
45
|
+
inline-size: var(--activity-heatmap-cell-size);
|
|
46
|
+
block-size: var(--activity-heatmap-cell-size);
|
|
47
|
+
aspect-ratio: 1;
|
|
48
|
+
border-radius: var(--activity-heatmap-radius);
|
|
49
|
+
background: var(--activity-heatmap-level-0);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.ds-activity-heatmap__cell[data-level="1"] {
|
|
53
|
+
background: var(--activity-heatmap-level-1);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.ds-activity-heatmap__cell[data-level="2"] {
|
|
57
|
+
background: var(--activity-heatmap-level-2);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.ds-activity-heatmap__cell[data-level="3"] {
|
|
61
|
+
background: var(--activity-heatmap-level-3);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.ds-activity-heatmap__cell[data-level="4"] {
|
|
65
|
+
background: var(--activity-heatmap-level-4);
|
|
66
|
+
}
|