@shipfox/react-ui 0.16.0 → 0.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/card/card.d.ts +24 -0
- package/dist/components/card/card.js +56 -0
- package/dist/components/card/card.stories.js +216 -0
- package/dist/components/card/index.d.ts +2 -0
- package/dist/components/card/index.js +3 -0
- package/dist/components/count-up/count-up.d.ts +14 -0
- package/dist/components/count-up/count-up.js +98 -0
- package/dist/components/count-up/count-up.stories.js +568 -0
- package/dist/components/count-up/index.d.ts +2 -0
- package/dist/components/count-up/index.js +3 -0
- package/dist/components/dashboard/components/charts/bar-chart.d.ts +8 -17
- package/dist/components/dashboard/components/charts/bar-chart.js +127 -81
- package/dist/components/dashboard/components/charts/bar-chart.stories.js +287 -0
- package/dist/components/dashboard/components/charts/chart-tooltip.js +13 -12
- package/dist/components/dashboard/components/charts/colors.d.ts +3 -2
- package/dist/components/dashboard/components/charts/colors.js +5 -2
- package/dist/components/dashboard/components/charts/index.d.ts +1 -0
- package/dist/components/dashboard/components/charts/index.js +1 -0
- package/dist/components/dashboard/components/charts/line-chart.d.ts +7 -16
- package/dist/components/dashboard/components/charts/line-chart.js +132 -108
- package/dist/components/dashboard/components/charts/line-chart.stories.js +257 -0
- package/dist/components/dashboard/components/charts/utils.d.ts +13 -0
- package/dist/components/dashboard/components/charts/utils.js +18 -0
- package/dist/components/dashboard/components/kpi-card.d.ts +8 -9
- package/dist/components/dashboard/components/kpi-card.js +26 -44
- package/dist/components/dashboard/index.d.ts +2 -7
- package/dist/components/dashboard/index.js +0 -11
- package/dist/components/dashboard/pages/analytics-page.d.ts +0 -18
- package/dist/components/dashboard/pages/analytics-page.js +83 -37
- package/dist/components/dashboard/pages/jobs-page.d.ts +0 -18
- package/dist/components/dashboard/pages/jobs-page.js +27 -24
- package/dist/components/dashboard/table/table-wrapper.d.ts +21 -24
- package/dist/components/dashboard/table/table-wrapper.js +38 -51
- package/dist/components/empty-state/empty-state.d.ts +10 -0
- package/dist/components/empty-state/empty-state.js +40 -0
- package/dist/components/empty-state/empty-state.stories.js +74 -0
- package/dist/components/empty-state/index.d.ts +2 -0
- package/dist/components/empty-state/index.js +3 -0
- package/dist/components/index.d.ts +4 -0
- package/dist/components/index.js +4 -0
- package/dist/components/item/item.stories.js +3 -3
- package/dist/components/table/data-table.d.ts +12 -1
- package/dist/components/table/data-table.js +84 -71
- package/dist/components/table/table-column-header.d.ts +14 -1
- package/dist/components/table/table-column-header.js +12 -5
- package/dist/components/table/table-pagination.d.ts +14 -1
- package/dist/components/table/table-pagination.js +6 -2
- package/dist/components/table/table.js +3 -3
- package/dist/components/table/table.stories.components.js +6 -28
- package/dist/styles.css +1 -1
- package/package.json +3 -3
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Icon } from '../../components/icon/index.js';
|
|
3
|
+
import { Text } from '../../components/typography/index.js';
|
|
4
|
+
import { cn } from '../../utils/cn.js';
|
|
5
|
+
export function EmptyState({ icon = 'fileDamageLine', title, description, variant = 'default', className, ...props }) {
|
|
6
|
+
const containerClasses = variant === 'compact' ? 'flex flex-col gap-10 items-center justify-center' : 'flex flex-col items-center justify-center gap-12 py-48';
|
|
7
|
+
const iconContainerClasses = variant === 'compact' ? 'size-32 rounded-6 bg-background-neutral-base border border-border-neutral-strong flex items-center justify-center p-8' : 'size-32 rounded-6 bg-transparent border border-border-neutral-strong flex items-center justify-center';
|
|
8
|
+
const iconSize = variant === 'compact' ? 'size-20' : 'size-16';
|
|
9
|
+
return /*#__PURE__*/ _jsxs("div", {
|
|
10
|
+
className: cn(containerClasses, className),
|
|
11
|
+
...props,
|
|
12
|
+
children: [
|
|
13
|
+
/*#__PURE__*/ _jsx("div", {
|
|
14
|
+
className: iconContainerClasses,
|
|
15
|
+
children: /*#__PURE__*/ _jsx(Icon, {
|
|
16
|
+
name: icon,
|
|
17
|
+
className: cn(iconSize, 'text-foreground-neutral-subtle'),
|
|
18
|
+
color: "var(--foreground-neutral-subtle, #a1a1aa)"
|
|
19
|
+
})
|
|
20
|
+
}),
|
|
21
|
+
/*#__PURE__*/ _jsxs("div", {
|
|
22
|
+
className: cn('text-center', variant === 'default' && 'space-y-4'),
|
|
23
|
+
children: [
|
|
24
|
+
title && /*#__PURE__*/ _jsx(Text, {
|
|
25
|
+
size: "sm",
|
|
26
|
+
className: variant === 'compact' ? 'text-foreground-neutral-subtle' : 'text-foreground-neutral-base',
|
|
27
|
+
children: title
|
|
28
|
+
}),
|
|
29
|
+
description && /*#__PURE__*/ _jsx(Text, {
|
|
30
|
+
size: "xs",
|
|
31
|
+
className: "text-foreground-neutral-muted",
|
|
32
|
+
children: description
|
|
33
|
+
})
|
|
34
|
+
]
|
|
35
|
+
})
|
|
36
|
+
]
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
//# sourceMappingURL=empty-state.js.map
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { EmptyState } from './empty-state.js';
|
|
3
|
+
const meta = {
|
|
4
|
+
title: 'Components/EmptyState',
|
|
5
|
+
component: EmptyState,
|
|
6
|
+
tags: [
|
|
7
|
+
'autodocs'
|
|
8
|
+
],
|
|
9
|
+
parameters: {
|
|
10
|
+
layout: 'centered'
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
export default meta;
|
|
14
|
+
export const Default = {
|
|
15
|
+
render: (args)=>/*#__PURE__*/ _jsx("div", {
|
|
16
|
+
className: "w-400",
|
|
17
|
+
children: /*#__PURE__*/ _jsx(EmptyState, {
|
|
18
|
+
...args
|
|
19
|
+
})
|
|
20
|
+
}),
|
|
21
|
+
args: {}
|
|
22
|
+
};
|
|
23
|
+
export const CustomContent = {
|
|
24
|
+
render: (args)=>/*#__PURE__*/ _jsx("div", {
|
|
25
|
+
className: "w-400",
|
|
26
|
+
children: /*#__PURE__*/ _jsx(EmptyState, {
|
|
27
|
+
...args
|
|
28
|
+
})
|
|
29
|
+
}),
|
|
30
|
+
args: {
|
|
31
|
+
icon: 'shipfox',
|
|
32
|
+
title: 'No jobs yet',
|
|
33
|
+
description: 'Import past runs or start a runner.'
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
export const Compact = {
|
|
37
|
+
render: (args)=>/*#__PURE__*/ _jsx("div", {
|
|
38
|
+
className: "w-400 h-200 relative",
|
|
39
|
+
children: /*#__PURE__*/ _jsx(EmptyState, {
|
|
40
|
+
...args
|
|
41
|
+
})
|
|
42
|
+
}),
|
|
43
|
+
args: {
|
|
44
|
+
icon: 'lineChartLine',
|
|
45
|
+
title: 'Nothing here yet.',
|
|
46
|
+
variant: 'compact'
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
export const NoDescription = {
|
|
50
|
+
render: (args)=>/*#__PURE__*/ _jsx("div", {
|
|
51
|
+
className: "w-400",
|
|
52
|
+
children: /*#__PURE__*/ _jsx(EmptyState, {
|
|
53
|
+
...args
|
|
54
|
+
})
|
|
55
|
+
}),
|
|
56
|
+
args: {
|
|
57
|
+
title: 'No data available',
|
|
58
|
+
description: undefined
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
export const NoTitle = {
|
|
62
|
+
render: (args)=>/*#__PURE__*/ _jsx("div", {
|
|
63
|
+
className: "w-400",
|
|
64
|
+
children: /*#__PURE__*/ _jsx(EmptyState, {
|
|
65
|
+
...args
|
|
66
|
+
})
|
|
67
|
+
}),
|
|
68
|
+
args: {
|
|
69
|
+
title: undefined,
|
|
70
|
+
description: 'This is a description without a title.'
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
//# sourceMappingURL=empty-state.stories.js.map
|
|
@@ -4,15 +4,19 @@ export * from './badge';
|
|
|
4
4
|
export * from './button';
|
|
5
5
|
export * from './button-group';
|
|
6
6
|
export * from './calendar';
|
|
7
|
+
export * from './card';
|
|
7
8
|
export * from './checkbox';
|
|
8
9
|
export * from './code-block';
|
|
9
10
|
export * from './command';
|
|
10
11
|
export * from './confetti';
|
|
12
|
+
export * from './count-up';
|
|
13
|
+
export * from './dashboard';
|
|
11
14
|
export * from './date-picker';
|
|
12
15
|
export * from './date-time-range-picker';
|
|
13
16
|
export * from './dot-grid';
|
|
14
17
|
export * from './dropdown-menu';
|
|
15
18
|
export * from './dynamic-item';
|
|
19
|
+
export * from './empty-state';
|
|
16
20
|
export * from './form';
|
|
17
21
|
export * from './icon';
|
|
18
22
|
export * from './inline-tips';
|
package/dist/components/index.js
CHANGED
|
@@ -4,15 +4,19 @@ export * from './badge/index.js';
|
|
|
4
4
|
export * from './button/index.js';
|
|
5
5
|
export * from './button-group/index.js';
|
|
6
6
|
export * from './calendar/index.js';
|
|
7
|
+
export * from './card/index.js';
|
|
7
8
|
export * from './checkbox/index.js';
|
|
8
9
|
export * from './code-block/index.js';
|
|
9
10
|
export * from './command/index.js';
|
|
10
11
|
export * from './confetti/index.js';
|
|
12
|
+
export * from './count-up/index.js';
|
|
13
|
+
export * from './dashboard/index.js';
|
|
11
14
|
export * from './date-picker/index.js';
|
|
12
15
|
export * from './date-time-range-picker/index.js';
|
|
13
16
|
export * from './dot-grid/index.js';
|
|
14
17
|
export * from './dropdown-menu/index.js';
|
|
15
18
|
export * from './dynamic-item/index.js';
|
|
19
|
+
export * from './empty-state/index.js';
|
|
16
20
|
export * from './form/index.js';
|
|
17
21
|
export * from './icon/index.js';
|
|
18
22
|
export * from './inline-tips/index.js';
|
|
@@ -3,6 +3,7 @@ import { Button } from '../../components/button/button.js';
|
|
|
3
3
|
import { DatePicker } from '../../components/date-picker/index.js';
|
|
4
4
|
import { Icon } from '../../components/icon/icon.js';
|
|
5
5
|
import { Input } from '../../components/input/input.js';
|
|
6
|
+
import { Kbd } from '../../components/kbd/index.js';
|
|
6
7
|
import { Label } from '../../components/label/label.js';
|
|
7
8
|
import { useState } from 'react';
|
|
8
9
|
import { Item, ItemActions, ItemContent, ItemDescription, ItemFooter, ItemGroup, ItemHeader, ItemSeparator, ItemTitle } from './item.js';
|
|
@@ -139,9 +140,8 @@ export const ImportPastJobsModal = {
|
|
|
139
140
|
/*#__PURE__*/ _jsxs("div", {
|
|
140
141
|
className: "flex items-center gap-8",
|
|
141
142
|
children: [
|
|
142
|
-
/*#__PURE__*/ _jsx(
|
|
143
|
-
|
|
144
|
-
children: "esc"
|
|
143
|
+
/*#__PURE__*/ _jsx(Kbd, {
|
|
144
|
+
children: "Esc"
|
|
145
145
|
}),
|
|
146
146
|
/*#__PURE__*/ _jsx(Button, {
|
|
147
147
|
variant: "transparent",
|
|
@@ -77,7 +77,18 @@ interface DataTableProps<TData, TValue> extends Omit<ComponentProps<'div'>, 'chi
|
|
|
77
77
|
* This is only used when {@link columnVisibility} is provided as a controlled prop.
|
|
78
78
|
*/
|
|
79
79
|
onColumnVisibilityChange?: (visibility: VisibilityState) => void;
|
|
80
|
+
/**
|
|
81
|
+
* When `true`, displays a loading skeleton instead of the table.
|
|
82
|
+
*/
|
|
83
|
+
isLoading?: boolean;
|
|
84
|
+
/**
|
|
85
|
+
* Optional scoped container element for dropdown portals.
|
|
86
|
+
*
|
|
87
|
+
* When provided, dropdowns (like pagination select) will be rendered inside this container
|
|
88
|
+
* instead of the document body. This is useful for scoped CSS styling.
|
|
89
|
+
*/
|
|
90
|
+
scopedContainer?: HTMLElement | null;
|
|
80
91
|
}
|
|
81
|
-
export declare function DataTable<TData, TValue>({ columns, data, pagination, pageSize, pageSizeOptions, showSelectedCount, onRowClick, emptyState, columnVisibility: controlledColumnVisibility, onColumnVisibilityChange, className, ...props }: DataTableProps<TData, TValue>): import("react/jsx-runtime").JSX.Element;
|
|
92
|
+
export declare function DataTable<TData, TValue>({ columns, data, pagination, pageSize, pageSizeOptions, showSelectedCount, onRowClick, emptyState, columnVisibility: controlledColumnVisibility, onColumnVisibilityChange, isLoading, scopedContainer, className, ...props }: DataTableProps<TData, TValue>): import("react/jsx-runtime").JSX.Element;
|
|
82
93
|
export {};
|
|
83
94
|
//# sourceMappingURL=data-table.d.ts.map
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { flexRender, getCoreRowModel, getFilteredRowModel, getPaginationRowModel, getSortedRowModel, useReactTable } from '@tanstack/react-table';
|
|
3
|
+
import { Card, CardContent } from '../../components/card/index.js';
|
|
3
4
|
import { Checkbox } from '../../components/checkbox/index.js';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
5
|
+
import { EmptyState } from '../../components/empty-state/index.js';
|
|
6
|
+
import { Skeleton } from '../../components/skeleton/index.js';
|
|
6
7
|
import { useEffect, useMemo, useState } from 'react';
|
|
7
8
|
import { cn } from '../../utils/cn.js';
|
|
8
9
|
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from './table.js';
|
|
9
10
|
import { TablePagination } from './table-pagination.js';
|
|
10
|
-
export function DataTable({ columns, data, pagination = true, pageSize = 10, pageSizeOptions, showSelectedCount = false, onRowClick, emptyState, columnVisibility: controlledColumnVisibility, onColumnVisibilityChange, className, ...props }) {
|
|
11
|
+
export function DataTable({ columns, data, pagination = true, pageSize = 10, pageSizeOptions, showSelectedCount = false, onRowClick, emptyState, columnVisibility: controlledColumnVisibility, onColumnVisibilityChange, isLoading, scopedContainer, className, ...props }) {
|
|
11
12
|
const [sorting, setSorting] = useState([]);
|
|
12
13
|
const [columnFilters, setColumnFilters] = useState([]);
|
|
13
14
|
const [internalColumnVisibility, setInternalColumnVisibility] = useState({});
|
|
@@ -30,7 +31,6 @@ export function DataTable({ columns, data, pagination = true, pageSize = 10, pag
|
|
|
30
31
|
}, [
|
|
31
32
|
pageSize
|
|
32
33
|
]);
|
|
33
|
-
// Add selection column if showSelectedCount is enabled
|
|
34
34
|
const columnsWithSelection = useMemo(()=>{
|
|
35
35
|
if (!showSelectedCount) {
|
|
36
36
|
return columns;
|
|
@@ -85,78 +85,91 @@ export function DataTable({ columns, data, pagination = true, pageSize = 10, pag
|
|
|
85
85
|
pagination: pagination ? paginationState : undefined
|
|
86
86
|
}
|
|
87
87
|
});
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
onClick: ()=>onRowClick?.(row.original),
|
|
104
|
-
"data-selected": row.getIsSelected(),
|
|
105
|
-
className: onRowClick ? 'cursor-pointer' : '',
|
|
106
|
-
tabIndex: onRowClick ? 0 : undefined,
|
|
107
|
-
role: onRowClick ? 'button' : undefined,
|
|
108
|
-
onKeyDown: (event)=>{
|
|
109
|
-
if (!onRowClick) return;
|
|
110
|
-
if (event.key === 'Enter' || event.key === ' ') {
|
|
111
|
-
event.preventDefault();
|
|
112
|
-
onRowClick(row.original);
|
|
113
|
-
}
|
|
114
|
-
},
|
|
115
|
-
children: row.getVisibleCells().map((cell)=>/*#__PURE__*/ _jsx(TableCell, {
|
|
116
|
-
children: flexRender(cell.column.columnDef.cell, cell.getContext())
|
|
117
|
-
}, cell.id))
|
|
118
|
-
}, row.id)) : /*#__PURE__*/ _jsx(TableRow, {
|
|
119
|
-
className: "hover:bg-transparent",
|
|
120
|
-
children: /*#__PURE__*/ _jsx(TableCell, {
|
|
121
|
-
colSpan: table.getAllColumns().length,
|
|
122
|
-
className: "h-240 text-center",
|
|
123
|
-
children: emptyState || /*#__PURE__*/ _jsxs("div", {
|
|
124
|
-
className: "flex flex-col items-center justify-center gap-12 py-48",
|
|
125
|
-
children: [
|
|
126
|
-
/*#__PURE__*/ _jsx("div", {
|
|
127
|
-
className: "size-32 rounded-6 bg-transparent border border-border-neutral-strong flex items-center justify-center",
|
|
128
|
-
children: /*#__PURE__*/ _jsx(Icon, {
|
|
129
|
-
name: "fileDamageLine",
|
|
130
|
-
className: "size-16 text-foreground-neutral-subtle",
|
|
131
|
-
color: "var(--foreground-neutral-subtle, #a1a1aa)"
|
|
88
|
+
const skeletonRowCount = pageSize > 5 ? 5 : pageSize;
|
|
89
|
+
if (isLoading) {
|
|
90
|
+
return /*#__PURE__*/ _jsx(Card, {
|
|
91
|
+
className: cn('p-0 gap-0', className),
|
|
92
|
+
...props,
|
|
93
|
+
children: /*#__PURE__*/ _jsx(CardContent, {
|
|
94
|
+
className: "overflow-hidden p-0",
|
|
95
|
+
children: /*#__PURE__*/ _jsxs(Table, {
|
|
96
|
+
children: [
|
|
97
|
+
/*#__PURE__*/ _jsx(TableHeader, {
|
|
98
|
+
children: /*#__PURE__*/ _jsx(TableRow, {
|
|
99
|
+
className: "hover:bg-transparent border-b",
|
|
100
|
+
children: columns.map((_, idx)=>/*#__PURE__*/ _jsx(TableHead, {
|
|
101
|
+
children: /*#__PURE__*/ _jsx(Skeleton, {
|
|
102
|
+
className: "h-16 w-24"
|
|
132
103
|
})
|
|
133
|
-
})
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
/*#__PURE__*/ _jsx(
|
|
143
|
-
|
|
144
|
-
className: "text-foreground-neutral-muted",
|
|
145
|
-
children: "Looks like there are no results."
|
|
104
|
+
}, idx.toString()))
|
|
105
|
+
})
|
|
106
|
+
}),
|
|
107
|
+
/*#__PURE__*/ _jsx(TableBody, {
|
|
108
|
+
children: Array.from({
|
|
109
|
+
length: skeletonRowCount
|
|
110
|
+
}).map((_, rowIdx)=>/*#__PURE__*/ _jsx(TableRow, {
|
|
111
|
+
className: "hover:bg-transparent",
|
|
112
|
+
children: columns.map((_, colIdx)=>/*#__PURE__*/ _jsx(TableCell, {
|
|
113
|
+
children: /*#__PURE__*/ _jsx(Skeleton, {
|
|
114
|
+
className: "h-16 w-full"
|
|
146
115
|
})
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
116
|
+
}, colIdx.toString()))
|
|
117
|
+
}, rowIdx.toString()))
|
|
118
|
+
})
|
|
119
|
+
]
|
|
120
|
+
})
|
|
121
|
+
})
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
return /*#__PURE__*/ _jsx(Card, {
|
|
125
|
+
className: cn('p-0 gap-0', className),
|
|
126
|
+
...props,
|
|
127
|
+
children: /*#__PURE__*/ _jsx(CardContent, {
|
|
128
|
+
className: "overflow-hidden p-0",
|
|
129
|
+
children: /*#__PURE__*/ _jsxs(Table, {
|
|
130
|
+
children: [
|
|
131
|
+
table.getRowModel().rows.length > 0 ? /*#__PURE__*/ _jsx(TableHeader, {
|
|
132
|
+
children: table.getHeaderGroups().map((headerGroup)=>/*#__PURE__*/ _jsx(TableRow, {
|
|
133
|
+
className: "hover:bg-transparent border-b",
|
|
134
|
+
children: headerGroup.headers.map((header)=>/*#__PURE__*/ _jsx(TableHead, {
|
|
135
|
+
children: header.isPlaceholder ? null : flexRender(header.column.columnDef.header, header.getContext())
|
|
136
|
+
}, header.id))
|
|
137
|
+
}, headerGroup.id))
|
|
138
|
+
}) : null,
|
|
139
|
+
/*#__PURE__*/ _jsx(TableBody, {
|
|
140
|
+
children: table.getRowModel().rows?.length ? table.getRowModel().rows.map((row)=>/*#__PURE__*/ _jsx(TableRow, {
|
|
141
|
+
onClick: ()=>onRowClick?.(row.original),
|
|
142
|
+
"data-selected": row.getIsSelected(),
|
|
143
|
+
className: onRowClick ? 'cursor-pointer' : '',
|
|
144
|
+
tabIndex: onRowClick ? 0 : undefined,
|
|
145
|
+
role: onRowClick ? 'button' : undefined,
|
|
146
|
+
onKeyDown: (event)=>{
|
|
147
|
+
if (!onRowClick) return;
|
|
148
|
+
if (event.key === 'Enter' || event.key === ' ') {
|
|
149
|
+
event.preventDefault();
|
|
150
|
+
onRowClick(row.original);
|
|
151
|
+
}
|
|
152
|
+
},
|
|
153
|
+
children: row.getVisibleCells().map((cell)=>/*#__PURE__*/ _jsx(TableCell, {
|
|
154
|
+
children: flexRender(cell.column.columnDef.cell, cell.getContext())
|
|
155
|
+
}, cell.id))
|
|
156
|
+
}, row.id)) : /*#__PURE__*/ _jsx(TableRow, {
|
|
157
|
+
className: "hover:bg-transparent",
|
|
158
|
+
children: /*#__PURE__*/ _jsx(TableCell, {
|
|
159
|
+
colSpan: table.getAllColumns().length,
|
|
160
|
+
className: "h-240 text-center rounded-t-8",
|
|
161
|
+
children: emptyState || /*#__PURE__*/ _jsx(EmptyState, {})
|
|
150
162
|
})
|
|
151
163
|
})
|
|
164
|
+
}),
|
|
165
|
+
pagination && table.getRowModel().rows?.length > 0 && /*#__PURE__*/ _jsx(TablePagination, {
|
|
166
|
+
table: table,
|
|
167
|
+
pageSizeOptions: pageSizeOptions,
|
|
168
|
+
showSelectedCount: showSelectedCount,
|
|
169
|
+
scopedContainer: scopedContainer
|
|
152
170
|
})
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
table: table,
|
|
156
|
-
pageSizeOptions: pageSizeOptions,
|
|
157
|
-
showSelectedCount: showSelectedCount
|
|
158
|
-
})
|
|
159
|
-
]
|
|
171
|
+
]
|
|
172
|
+
})
|
|
160
173
|
})
|
|
161
174
|
});
|
|
162
175
|
}
|
|
@@ -39,6 +39,19 @@ export interface TableColumnHeaderProps<TData, TValue> extends HTMLAttributes<HT
|
|
|
39
39
|
* ```
|
|
40
40
|
*/
|
|
41
41
|
title: string;
|
|
42
|
+
/**
|
|
43
|
+
* Optional scoped container element for dropdown portal.
|
|
44
|
+
*
|
|
45
|
+
* When provided, the dropdown menu will be rendered inside this container
|
|
46
|
+
* instead of the document body. This is useful for scoped CSS styling.
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* ```tsx
|
|
50
|
+
* const {scopedContainer} = useScopedContainer();
|
|
51
|
+
* <TableColumnHeader column={column} title="Name" scopedContainer={scopedContainer} />
|
|
52
|
+
* ```
|
|
53
|
+
*/
|
|
54
|
+
scopedContainer?: HTMLElement | null;
|
|
42
55
|
}
|
|
43
56
|
/**
|
|
44
57
|
* Renders a table column header with optional sorting functionality.
|
|
@@ -75,5 +88,5 @@ export interface TableColumnHeaderProps<TData, TValue> extends HTMLAttributes<HT
|
|
|
75
88
|
* ];
|
|
76
89
|
* ```
|
|
77
90
|
*/
|
|
78
|
-
export declare function TableColumnHeader<TData, TValue>({ column, title, className, }: TableColumnHeaderProps<TData, TValue>): import("react/jsx-runtime").JSX.Element;
|
|
91
|
+
export declare function TableColumnHeader<TData, TValue>({ column, title, className, scopedContainer, }: TableColumnHeaderProps<TData, TValue>): import("react/jsx-runtime").JSX.Element;
|
|
79
92
|
//# sourceMappingURL=table-column-header.d.ts.map
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { Icon } from '../../components/icon/index.js';
|
|
3
|
+
import { useRef } from 'react';
|
|
3
4
|
import { cn } from '../../utils/cn.js';
|
|
4
5
|
import { Button } from '../button/index.js';
|
|
5
6
|
import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from '../dropdown-menu/index.js';
|
|
7
|
+
import { Text } from '../typography/index.js';
|
|
6
8
|
/**
|
|
7
9
|
* Renders a table column header with optional sorting functionality.
|
|
8
10
|
*
|
|
@@ -37,15 +39,18 @@ import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigge
|
|
|
37
39
|
* },
|
|
38
40
|
* ];
|
|
39
41
|
* ```
|
|
40
|
-
*/ export function TableColumnHeader({ column, title, className }) {
|
|
42
|
+
*/ export function TableColumnHeader({ column, title, className, scopedContainer }) {
|
|
43
|
+
const headerRef = useRef(null);
|
|
41
44
|
if (!column.getCanSort()) {
|
|
42
|
-
return /*#__PURE__*/ _jsx(
|
|
43
|
-
|
|
45
|
+
return /*#__PURE__*/ _jsx(Text, {
|
|
46
|
+
size: "xs",
|
|
47
|
+
className: cn('font-medium', className),
|
|
44
48
|
children: title
|
|
45
49
|
});
|
|
46
50
|
}
|
|
47
51
|
const isSorted = column.getIsSorted();
|
|
48
52
|
return /*#__PURE__*/ _jsx("div", {
|
|
53
|
+
ref: headerRef,
|
|
49
54
|
className: cn('flex items-center space-x-2', className),
|
|
50
55
|
children: /*#__PURE__*/ _jsxs(DropdownMenu, {
|
|
51
56
|
children: [
|
|
@@ -56,8 +61,9 @@ import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigge
|
|
|
56
61
|
size: "xs",
|
|
57
62
|
className: "-ml-12 h-32 px-8 data-[state=open]:bg-background-components-hover gap-0",
|
|
58
63
|
children: [
|
|
59
|
-
/*#__PURE__*/ _jsx(
|
|
60
|
-
|
|
64
|
+
/*#__PURE__*/ _jsx(Text, {
|
|
65
|
+
size: "xs",
|
|
66
|
+
className: "font-medium text-foreground-neutral-subtle",
|
|
61
67
|
children: title
|
|
62
68
|
}),
|
|
63
69
|
isSorted === 'desc' ? /*#__PURE__*/ _jsx(Icon, {
|
|
@@ -76,6 +82,7 @@ import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigge
|
|
|
76
82
|
/*#__PURE__*/ _jsxs(DropdownMenuContent, {
|
|
77
83
|
align: "start",
|
|
78
84
|
size: "sm",
|
|
85
|
+
container: scopedContainer ?? undefined,
|
|
79
86
|
children: [
|
|
80
87
|
/*#__PURE__*/ _jsx(DropdownMenuItem, {
|
|
81
88
|
icon: "arrowUpLongLine",
|
|
@@ -47,7 +47,20 @@ interface TablePaginationProps<TData> extends ComponentProps<'tfoot'> {
|
|
|
47
47
|
* ```
|
|
48
48
|
*/
|
|
49
49
|
showSelectedCount?: boolean;
|
|
50
|
+
/**
|
|
51
|
+
* Optional scoped container element for select dropdown portal.
|
|
52
|
+
*
|
|
53
|
+
* When provided, the select dropdown will be rendered inside this container
|
|
54
|
+
* instead of the document body. This is useful for scoped CSS styling.
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* ```tsx
|
|
58
|
+
* const {scopedContainer} = useScopedContainer();
|
|
59
|
+
* <TablePagination table={table} scopedContainer={scopedContainer} />
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
scopedContainer?: HTMLElement | null;
|
|
50
63
|
}
|
|
51
|
-
export declare function TablePagination<TData>({ table, className, pageSizeOptions, showSelectedCount, ...props }: TablePaginationProps<TData>): import("react/jsx-runtime").JSX.Element;
|
|
64
|
+
export declare function TablePagination<TData>({ table, className, pageSizeOptions, showSelectedCount, scopedContainer, ...props }: TablePaginationProps<TData>): import("react/jsx-runtime").JSX.Element;
|
|
52
65
|
export {};
|
|
53
66
|
//# sourceMappingURL=table-pagination.d.ts.map
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { Text } from '../../components/typography/index.js';
|
|
3
|
+
import { useRef } from 'react';
|
|
3
4
|
import { Button } from '../button/index.js';
|
|
4
5
|
import { Icon } from '../icon/index.js';
|
|
5
6
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../select/select.js';
|
|
@@ -9,17 +10,19 @@ export function TablePagination({ table, className, pageSizeOptions = [
|
|
|
9
10
|
20,
|
|
10
11
|
50,
|
|
11
12
|
100
|
|
12
|
-
], showSelectedCount = false, ...props }) {
|
|
13
|
+
], showSelectedCount = false, scopedContainer, ...props }) {
|
|
14
|
+
const paginationRef = useRef(null);
|
|
13
15
|
const currentPage = table.getState().pagination.pageIndex + 1;
|
|
14
16
|
const pageSize = table.getState().pagination.pageSize;
|
|
15
17
|
const totalRows = table.getFilteredRowModel().rows.length;
|
|
16
18
|
const startRow = totalRows === 0 ? 0 : currentPage === 1 ? 1 : (currentPage - 1) * pageSize + 1;
|
|
17
19
|
const endRow = Math.min(currentPage * pageSize, totalRows);
|
|
18
20
|
return /*#__PURE__*/ _jsx(TableFooter, {
|
|
21
|
+
ref: paginationRef,
|
|
19
22
|
className: className,
|
|
20
23
|
...props,
|
|
21
24
|
children: /*#__PURE__*/ _jsx(TableRow, {
|
|
22
|
-
className: "hover:bg-transparent",
|
|
25
|
+
className: "hover:bg-transparent border-b-0",
|
|
23
26
|
children: /*#__PURE__*/ _jsx(TableCell, {
|
|
24
27
|
colSpan: table.getAllColumns().length,
|
|
25
28
|
className: "group-hover/row:bg-transparent",
|
|
@@ -71,6 +74,7 @@ export function TablePagination({ table, className, pageSizeOptions = [
|
|
|
71
74
|
children: /*#__PURE__*/ _jsx(SelectValue, {})
|
|
72
75
|
}),
|
|
73
76
|
/*#__PURE__*/ _jsx(SelectContent, {
|
|
77
|
+
container: scopedContainer ?? undefined,
|
|
74
78
|
children: pageSizeOptions.map((size)=>/*#__PURE__*/ _jsx(SelectItem, {
|
|
75
79
|
value: String(size),
|
|
76
80
|
children: size
|
|
@@ -2,7 +2,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
2
2
|
import { cn } from '../../utils/cn.js';
|
|
3
3
|
function Table({ className, ...props }) {
|
|
4
4
|
return /*#__PURE__*/ _jsx("div", {
|
|
5
|
-
className: "relative w-full overflow-auto scrollbar",
|
|
5
|
+
className: "relative w-full overflow-auto scrollbar rounded-x-8 rounded-b-8",
|
|
6
6
|
children: /*#__PURE__*/ _jsx("table", {
|
|
7
7
|
"data-slot": "table",
|
|
8
8
|
className: cn('w-full caption-bottom text-sm', className),
|
|
@@ -34,14 +34,14 @@ function TableFooter({ className, ...props }) {
|
|
|
34
34
|
function TableRow({ className, ...props }) {
|
|
35
35
|
return /*#__PURE__*/ _jsx("tr", {
|
|
36
36
|
"data-slot": "table-row",
|
|
37
|
-
className: cn('group/row border-b border-border-neutral-base transition-colors', 'last:border-b-0', 'hover:bg-background-neutral-hover', 'data-[selected=true]:bg-background-neutral-pressed data-[selected=true]:hover:bg-background-neutral-pressed', className),
|
|
37
|
+
className: cn('group/row border-b border-border-neutral-base transition-colors', 'last:rounded-b-8 last:border-b-0', 'hover:bg-background-neutral-hover', 'data-[selected=true]:bg-background-neutral-pressed data-[selected=true]:hover:bg-background-neutral-pressed', className),
|
|
38
38
|
...props
|
|
39
39
|
});
|
|
40
40
|
}
|
|
41
41
|
function TableHead({ className, ...props }) {
|
|
42
42
|
return /*#__PURE__*/ _jsx("th", {
|
|
43
43
|
"data-slot": "table-head",
|
|
44
|
-
className: cn('h-40 px-16 text-left align-middle text-xs font-medium leading-20 text-foreground-neutral-subtle', 'bg-background-subtle-base', '[&:has([role=checkbox])]:pr-0 [&:has([role=checkbox])]:px-12 [&:has([role=checkbox])]:w-0 [&:has([role=checkbox])]:pt-6', className),
|
|
44
|
+
className: cn('h-40 px-16 text-left align-middle text-xs font-medium leading-20 text-foreground-neutral-subtle', 'bg-background-subtle-base border-b border-border-neutral-base', '[&:has([role=checkbox])]:pr-0 [&:has([role=checkbox])]:px-12 [&:has([role=checkbox])]:w-0 [&:has([role=checkbox])]:pt-6', className),
|
|
45
45
|
...props
|
|
46
46
|
});
|
|
47
47
|
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
/**
|
|
3
3
|
* Shared components for Table stories
|
|
4
|
-
*/ import {
|
|
4
|
+
*/ import { EmptyState } from '../../components/empty-state/index.js';
|
|
5
|
+
import { Icon } from '../../components/icon/index.js';
|
|
5
6
|
import { useSearchContext } from '../../components/search/search-context.js';
|
|
6
7
|
import { SearchEmpty, SearchFooter, SearchGroup, SearchInput, SearchItem, SearchList } from '../../components/search/search-modal.js';
|
|
7
8
|
import { Text } from '../../components/typography/index.js';
|
|
@@ -10,33 +11,10 @@ import { searchJobsData } from './table.stories.data.js';
|
|
|
10
11
|
/**
|
|
11
12
|
* Empty state component for job tables
|
|
12
13
|
*/ export function JobsEmptyState() {
|
|
13
|
-
return /*#__PURE__*/
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
className: "size-32 rounded-6 bg-transparent border border-border-neutral-strong flex items-center justify-center",
|
|
18
|
-
children: /*#__PURE__*/ _jsx(Icon, {
|
|
19
|
-
name: "shipfox",
|
|
20
|
-
className: "size-16 text-foreground-neutral-subtle",
|
|
21
|
-
color: "var(--foreground-neutral-subtle, #a1a1aa)"
|
|
22
|
-
})
|
|
23
|
-
}),
|
|
24
|
-
/*#__PURE__*/ _jsxs("div", {
|
|
25
|
-
className: "text-center space-y-4",
|
|
26
|
-
children: [
|
|
27
|
-
/*#__PURE__*/ _jsx(Text, {
|
|
28
|
-
size: "sm",
|
|
29
|
-
className: "text-foreground-neutral-base",
|
|
30
|
-
children: "No jobs yet"
|
|
31
|
-
}),
|
|
32
|
-
/*#__PURE__*/ _jsx(Text, {
|
|
33
|
-
size: "xs",
|
|
34
|
-
className: "text-foreground-neutral-muted",
|
|
35
|
-
children: "Import past runs or start a runner."
|
|
36
|
-
})
|
|
37
|
-
]
|
|
38
|
-
})
|
|
39
|
-
]
|
|
14
|
+
return /*#__PURE__*/ _jsx(EmptyState, {
|
|
15
|
+
icon: "shipfox",
|
|
16
|
+
title: "No jobs yet",
|
|
17
|
+
description: "Import past runs or start a runner."
|
|
40
18
|
});
|
|
41
19
|
}
|
|
42
20
|
/**
|