@cystackapp/ui 1.5.0 → 2.0.1
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/LICENSE +21 -0
- package/README.md +77 -47
- package/dist/assets/background-pattern-grid.svg.js +7 -0
- package/dist/assets/empty-cloud.svg.js +5 -0
- package/dist/components/accordion/Accordion.d.ts +20 -0
- package/dist/components/accordion/Accordion.js +36 -0
- package/dist/components/accordion/AccordionTestStory.d.ts +3 -0
- package/dist/components/alert/Alert.d.ts +15 -0
- package/dist/components/alert/Alert.js +54 -0
- package/dist/components/avatar/Avatar.d.ts +13 -0
- package/dist/components/avatar/Avatar.js +64 -0
- package/dist/components/background-pattern/BackgroundPatternGrid.d.ts +1 -0
- package/dist/components/background-pattern/BackgroundPatternGrid.js +6 -0
- package/dist/components/badge/Badge.d.ts +1 -1
- package/dist/components/badge/BadgeTestStory.d.ts +1 -1
- package/dist/components/badge/variants/BadgeMore.d.ts +1 -1
- package/dist/components/badge/variants/BadgeMoreTestStory.d.ts +1 -1
- package/dist/components/badge/variants/BadgeTag.d.ts +1 -1
- package/dist/components/banner/Banner.d.ts +9 -0
- package/dist/components/banner/Banner.js +21 -0
- package/dist/components/breadcrumb/Breadcrumb.d.ts +13 -0
- package/dist/components/breadcrumb/Breadcrumb.js +36 -0
- package/dist/components/button/ButtonLoader.d.ts +1 -1
- package/dist/components/button/ButtonTestStory.d.ts +5 -5
- package/dist/components/card/Card.d.ts +1 -1
- package/dist/components/card/Card.stories-ct.d.ts +1 -1
- package/dist/components/card/CardBody.d.ts +1 -1
- package/dist/components/card/CardHeader.d.ts +1 -1
- package/dist/components/chart/chart-legend/ChartLegend.d.ts +38 -0
- package/dist/components/chart/chart-legend/ChartLegend.js +57 -0
- package/dist/components/chart/chart-legend/ChartLegendItem.d.ts +19 -0
- package/dist/components/chart/chart-legend/ChartLegendItem.js +30 -0
- package/dist/components/chart/chart-legend/types.d.ts +49 -0
- package/dist/components/chart/donut-chart/DonutChart.d.ts +55 -0
- package/dist/components/chart/donut-chart/DonutChart.js +110 -0
- package/dist/components/chart/donut-chart/DonutSegments.d.ts +25 -0
- package/dist/components/chart/donut-chart/DonutSegments.js +51 -0
- package/dist/components/chart/donut-chart/donut-tooltip.d.ts +20 -0
- package/dist/components/chart/donut-chart/donut-tooltip.js +37 -0
- package/dist/components/chart/types.d.ts +8 -0
- package/dist/components/checkbox/CheckboxTestStory.d.ts +7 -7
- package/dist/components/collapsible/Collapsible.d.ts +1 -1
- package/dist/components/combobox/Combobox.d.ts +1 -1
- package/dist/components/divider/Divider.d.ts +9 -0
- package/dist/components/divider/Divider.js +28 -0
- package/dist/components/drawer/Drawer.d.ts +8 -0
- package/dist/components/drawer/Drawer.js +68 -0
- package/dist/components/dropdown/Dropdown.d.ts +45 -0
- package/dist/components/dropdown/Dropdown.js +133 -0
- package/dist/components/dropdown/DropdownMenu.d.ts +20 -0
- package/dist/components/dropdown/DropdownMenu.js +78 -0
- package/dist/components/dropdown/DropdownMenuItem.d.ts +13 -0
- package/dist/components/dropdown/DropdownMenuItem.js +49 -0
- package/dist/components/dropdown/DropdownTestStory.d.ts +5 -0
- package/dist/components/dropdown/dropdown-utils.d.ts +4 -0
- package/dist/components/dropdown/dropdown-utils.js +14 -0
- package/dist/components/dropdown/types.d.ts +48 -0
- package/dist/components/dropdown/use-dropdown-keyboard.d.ts +12 -0
- package/dist/components/dropdown/use-dropdown-keyboard.js +49 -0
- package/dist/components/empty-state/EmptyState.d.ts +26 -0
- package/dist/components/empty-state/EmptyState.js +36 -0
- package/dist/components/error-state/ErrorState.d.ts +1 -1
- package/dist/components/featured-icon/FeaturedIcon.d.ts +12 -0
- package/dist/components/featured-icon/FeaturedIcon.js +44 -0
- package/dist/components/form-field/FormField.d.ts +13 -0
- package/dist/components/form-field/FormField.js +21 -0
- package/dist/components/keyboard-shortcut-label/KeyboardShortcutLabel.d.ts +8 -0
- package/dist/components/keyboard-shortcut-label/KeyboardShortcutLabel.js +18 -0
- package/dist/components/loading-state/Loader.d.ts +20 -0
- package/dist/components/loading-state/Loader.js +38 -0
- package/dist/components/loading-state/LoadingState.d.ts +15 -0
- package/dist/components/loading-state/LoadingState.js +47 -0
- package/dist/components/loading-state/locale/en.json.d.ts +6 -0
- package/dist/components/loading-state/locale/en.json.js +7 -0
- package/dist/components/loading-state/locale/vi.json.d.ts +6 -0
- package/dist/components/loading-state/locale/vi.json.js +7 -0
- package/dist/components/media/Media.d.ts +7 -0
- package/dist/components/media/Media.js +25 -0
- package/dist/components/modal/helpers/HeaderIcon.d.ts +1 -1
- package/dist/components/modal/helpers/Title.d.ts +1 -1
- package/dist/components/notification/NotificationBanner.d.ts +9 -0
- package/dist/components/notification/NotificationBanner.js +97 -0
- package/dist/components/notification/icons.d.ts +5 -0
- package/dist/components/notification/icons.js +29 -0
- package/dist/components/notification/index.d.ts +4 -0
- package/dist/components/notification/index.js +26 -0
- package/dist/components/notification/locale/en.json.d.ts +8 -0
- package/dist/components/notification/locale/en.json.js +7 -0
- package/dist/components/notification/locale/vi.json.d.ts +8 -0
- package/dist/components/notification/locale/vi.json.js +7 -0
- package/dist/components/operating-system-icon/OperatingSystemIcon.d.ts +6 -0
- package/dist/components/operating-system-icon/OperatingSystemIcon.js +19 -0
- package/dist/components/operating-system-icon/assets/logo-android.svg.js +5 -0
- package/dist/components/operating-system-icon/assets/logo-apple.svg.js +5 -0
- package/dist/components/operating-system-icon/assets/logo-ubuntu.svg.js +5 -0
- package/dist/components/operating-system-icon/assets/logo-windows-10.svg.js +5 -0
- package/dist/components/page-title/PageTitle.d.ts +1 -1
- package/dist/components/popover/Popover.d.ts +1 -1
- package/dist/components/progress-bar/ProgressBar.d.ts +9 -0
- package/dist/components/progress-bar/ProgressBar.js +31 -0
- package/dist/components/radio/Radio.d.ts +4 -0
- package/dist/components/radio/Radio.js +55 -0
- package/dist/components/searchbox/Searchbox.d.ts +7 -0
- package/dist/components/searchbox/Searchbox.js +15 -0
- package/dist/components/select/Select.d.ts +11 -0
- package/dist/components/select/Select.js +44 -0
- package/dist/components/sidebar/SidebarSecondMenu.d.ts +38 -0
- package/dist/components/sidebar/SidebarSecondMenu.js +50 -0
- package/dist/components/skeleton/Skeleton.d.ts +14 -0
- package/dist/components/skeleton/Skeleton.js +12 -0
- package/dist/components/stat-banner-card/StatBannerCard.d.ts +24 -0
- package/dist/components/stat-banner-card/StatBannerCard.js +49 -0
- package/dist/components/switch/Switch.d.ts +1 -1
- package/dist/components/table/Table.d.ts +32 -0
- package/dist/components/table/Table.js +128 -0
- package/dist/components/table/TableActionButton.d.ts +15 -0
- package/dist/components/table/TableActionButton.js +50 -0
- package/dist/components/table/TableCell.d.ts +8 -0
- package/dist/components/table/TableCell.js +26 -0
- package/dist/components/table/TableHeader.d.ts +15 -0
- package/dist/components/table/TableHeader.js +36 -0
- package/dist/components/table/TableHeaderCell.d.ts +10 -0
- package/dist/components/table/TableHeaderCell.js +35 -0
- package/dist/components/table/TablePagination.d.ts +6 -0
- package/dist/components/table/TablePagination.js +69 -0
- package/dist/components/table/TableRow.d.ts +12 -0
- package/dist/components/table/TableRow.js +9 -0
- package/dist/components/table/expandable/ExpandableTable.d.ts +30 -0
- package/dist/components/table/expandable/ExpandableTable.js +156 -0
- package/dist/components/table/hooks/use-fit-page-height.d.ts +14 -0
- package/dist/components/table/hooks/use-fit-page-height.js +21 -0
- package/dist/components/table/hooks/use-row-selection.d.ts +27 -0
- package/dist/components/table/hooks/use-row-selection.js +35 -0
- package/dist/components/table/locale/en.json.d.ts +13 -0
- package/dist/components/table/locale/en.json.js +21 -0
- package/dist/components/table/locale/vi.json.d.ts +13 -0
- package/dist/components/table/locale/vi.json.js +21 -0
- package/dist/components/table/table-utils.d.ts +10 -0
- package/dist/components/table/table-utils.js +10 -0
- package/dist/components/table/types.d.ts +84 -0
- package/dist/components/tabs/Tabs.d.ts +27 -0
- package/dist/components/tabs/Tabs.js +75 -0
- package/dist/components/tabs/TabsTestStory.d.ts +4 -0
- package/dist/components/tags-input/TagsInput.d.ts +18 -0
- package/dist/components/tags-input/TagsInput.js +78 -0
- package/dist/components/tags-input/TagsInputTestStory.d.ts +3 -0
- package/dist/components/textarea/Textarea.d.ts +7 -0
- package/dist/components/textarea/Textarea.js +36 -0
- package/dist/components/toast/ToastSlice.d.ts +1 -1
- package/dist/components/toast/index.d.ts +1 -1
- package/dist/components/tooltip/Tooltip.d.ts +1 -1
- package/dist/filters/FilterDropdown.d.ts +9 -0
- package/dist/filters/FilterDropdown.js +57 -0
- package/dist/filters/types.d.ts +11 -0
- package/dist/filters/url-params.d.ts +5 -0
- package/dist/filters/url-params.js +20 -0
- package/dist/filters/use-filters.d.ts +13 -0
- package/dist/filters/use-filters.js +63 -0
- package/dist/hooks/use-countdown.d.ts +4 -0
- package/dist/hooks/use-countdown.js +18 -0
- package/dist/i18n/resources.js +23 -0
- package/dist/index.d.ts +56 -0
- package/dist/index.js +126 -40
- package/dist/node_modules/tailwind-merge/dist/bundle-mjs.js +421 -350
- package/dist/utils/key-typeguard.d.ts +5 -0
- package/dist/utils/key-typeguard.js +6 -0
- package/dist/utils/use-debounce.d.ts +1 -0
- package/dist/utils/use-debounce.js +11 -0
- package/package.json +32 -10
- package/theme.css +4 -1
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { jsxs as r, jsx as n } from "react/jsx-runtime";
|
|
2
|
+
import { ChevronDown as u } from "@untitled-ui/icons-react";
|
|
3
|
+
import { forwardRef as h } from "react";
|
|
4
|
+
import { useTranslation as f } from "react-i18next";
|
|
5
|
+
import { Button as i } from "../button/Button.js";
|
|
6
|
+
import { Dropdown as y } from "../dropdown/Dropdown.js";
|
|
7
|
+
const v = [10, 25, 50, 100], x = h(
|
|
8
|
+
({ pagination: d }, g) => {
|
|
9
|
+
const { t: e } = f("components/table"), { total: s, page: t, pageSize: o, onPageChange: l, onPageSizeChange: c } = d, m = Math.max(1, Math.ceil(s / o)), p = v.map((a) => ({
|
|
10
|
+
id: String(a),
|
|
11
|
+
label: e("perPage", { count: a })
|
|
12
|
+
}));
|
|
13
|
+
return /* @__PURE__ */ r(
|
|
14
|
+
"div",
|
|
15
|
+
{
|
|
16
|
+
ref: g,
|
|
17
|
+
className: "flex items-center justify-between px-3 py-2 h-14.5 border-t border-gray-v2-200",
|
|
18
|
+
children: [
|
|
19
|
+
/* @__PURE__ */ r("div", { className: "text-sm font-medium text-gray-v2-700", children: [
|
|
20
|
+
/* @__PURE__ */ r("b", { children: [
|
|
21
|
+
e("numOfResults", { count: s }),
|
|
22
|
+
" |"
|
|
23
|
+
] }),
|
|
24
|
+
" ",
|
|
25
|
+
e("pageNumber", { current: t, total: m })
|
|
26
|
+
] }),
|
|
27
|
+
/* @__PURE__ */ r("div", { className: "flex items-center gap-2", children: [
|
|
28
|
+
t > 1 ? /* @__PURE__ */ n(
|
|
29
|
+
i,
|
|
30
|
+
{
|
|
31
|
+
variant: "secondary",
|
|
32
|
+
color: "gray",
|
|
33
|
+
size: "sm",
|
|
34
|
+
onClick: () => l(t - 1),
|
|
35
|
+
children: e("previous")
|
|
36
|
+
}
|
|
37
|
+
) : null,
|
|
38
|
+
t < m ? /* @__PURE__ */ n(
|
|
39
|
+
i,
|
|
40
|
+
{
|
|
41
|
+
variant: "secondary",
|
|
42
|
+
color: "gray",
|
|
43
|
+
size: "sm",
|
|
44
|
+
onClick: () => l(t + 1),
|
|
45
|
+
children: e("next")
|
|
46
|
+
}
|
|
47
|
+
) : null,
|
|
48
|
+
c ? /* @__PURE__ */ n(
|
|
49
|
+
y,
|
|
50
|
+
{
|
|
51
|
+
items: p,
|
|
52
|
+
selected: String(o),
|
|
53
|
+
onSelect: (a) => c(Number(a.id)),
|
|
54
|
+
children: /* @__PURE__ */ r(i, { variant: "secondary", color: "gray", size: "sm", children: [
|
|
55
|
+
e("perPage", { count: o }),
|
|
56
|
+
/* @__PURE__ */ n(u, { className: "h-4 w-4 text-gray-v2-400" })
|
|
57
|
+
] })
|
|
58
|
+
}
|
|
59
|
+
) : null
|
|
60
|
+
] })
|
|
61
|
+
]
|
|
62
|
+
}
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
);
|
|
66
|
+
x.displayName = "TablePagination";
|
|
67
|
+
export {
|
|
68
|
+
x as TablePagination
|
|
69
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { HTMLAttributes, ReactNode } from 'react';
|
|
2
|
+
import { To } from 'react-router-dom';
|
|
3
|
+
interface Props extends HTMLAttributes<HTMLElement> {
|
|
4
|
+
href?: To;
|
|
5
|
+
children?: ReactNode;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Renders a row as either a `<Link>` (when `href` is provided) or a `<div>`.
|
|
9
|
+
* Both forms participate in the parent grid via `grid-cols-subgrid`.
|
|
10
|
+
*/
|
|
11
|
+
export declare const TableRow: ({ href, className, ...props }: Props) => import("react").JSX.Element;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { jsx as i } from "react/jsx-runtime";
|
|
2
|
+
import { Link as l } from "react-router-dom";
|
|
3
|
+
import { cn as n } from "../../utils/cn.js";
|
|
4
|
+
const t = "grid grid-cols-subgrid col-span-full relative no-underline bg-white text-current transition-colors duration-200 hover:bg-gray-v2-50 last:rounded-b-xl", d = ({ href: r, className: e, ...o }) => r !== void 0 ? (o.onClick !== void 0 && console.warn(
|
|
5
|
+
"TableRow: onClick is ignored when href is set. Use one or the other."
|
|
6
|
+
), /* @__PURE__ */ i(l, { to: r, ...o, className: n(t, e) })) : /* @__PURE__ */ i("div", { ...o, className: n(t, e) });
|
|
7
|
+
export {
|
|
8
|
+
d as TableRow
|
|
9
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { ColumnDef, SelectionState, SortState, PaginationState, EmptyStateConfig } from '../types';
|
|
3
|
+
interface Props<TData> {
|
|
4
|
+
data?: TData[];
|
|
5
|
+
/** Returns the unique key for a row. */
|
|
6
|
+
rowKey: (row: TData) => string;
|
|
7
|
+
isLoading?: boolean;
|
|
8
|
+
columns: ColumnDef<TData>[];
|
|
9
|
+
selection?: SelectionState;
|
|
10
|
+
sort?: SortState;
|
|
11
|
+
pagination?: PaginationState;
|
|
12
|
+
/**
|
|
13
|
+
* When true, the table body height is calculated so the table never causes
|
|
14
|
+
* the page to scroll — it fits exactly within the remaining viewport height.
|
|
15
|
+
*/
|
|
16
|
+
fitPageHeight?: boolean;
|
|
17
|
+
maxHeight?: string;
|
|
18
|
+
/** Configures the empty-state view. Falls back to a generic message. */
|
|
19
|
+
emptyState?: EmptyStateConfig;
|
|
20
|
+
/** Renders the expanded content below a row when it is toggled open. */
|
|
21
|
+
expandContent: (item: TData) => ReactNode;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Data table with accordion-style expandable rows.
|
|
25
|
+
*
|
|
26
|
+
* Pass `fitPageHeight` to make the body fill the remaining viewport height
|
|
27
|
+
* without causing the page to scroll.
|
|
28
|
+
*/
|
|
29
|
+
export declare const ExpandableTable: <TData>({ data, rowKey, isLoading, columns, selection, sort, pagination, fitPageHeight, maxHeight, emptyState, expandContent, }: Props<TData>) => import("react").JSX.Element;
|
|
30
|
+
export {};
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { jsx as e, jsxs as f, Fragment as $ } from "react/jsx-runtime";
|
|
2
|
+
import { useState as C, useMemo as q, useCallback as z } from "react";
|
|
3
|
+
import { ChevronDown as B } from "@untitled-ui/icons-react";
|
|
4
|
+
import { Collapsible as J } from "../../collapsible/Collapsible.js";
|
|
5
|
+
import { Checkbox as O } from "../../checkbox/Checkbox.js";
|
|
6
|
+
import { EmptyState as Q } from "../../empty-state/EmptyState.js";
|
|
7
|
+
import { LoadingState as U } from "../../loading-state/LoadingState.js";
|
|
8
|
+
import { cn as a } from "../../../utils/cn.js";
|
|
9
|
+
import { TableCell as m } from "../TableCell.js";
|
|
10
|
+
import { TableHeader as V } from "../TableHeader.js";
|
|
11
|
+
import { TablePagination as W } from "../TablePagination.js";
|
|
12
|
+
import { TableRow as X } from "../TableRow.js";
|
|
13
|
+
import { useRowSelection as Y } from "../hooks/use-row-selection.js";
|
|
14
|
+
import { buildGridTemplate as Z } from "../table-utils.js";
|
|
15
|
+
import { useFitPageHeight as _ } from "../hooks/use-fit-page-height.js";
|
|
16
|
+
const te = ({
|
|
17
|
+
data: n = [],
|
|
18
|
+
rowKey: b,
|
|
19
|
+
isLoading: h,
|
|
20
|
+
columns: c,
|
|
21
|
+
selection: g,
|
|
22
|
+
sort: N,
|
|
23
|
+
pagination: x,
|
|
24
|
+
fitPageHeight: T,
|
|
25
|
+
maxHeight: w,
|
|
26
|
+
emptyState: r,
|
|
27
|
+
expandContent: H
|
|
28
|
+
}) => {
|
|
29
|
+
const {
|
|
30
|
+
bodyRef: R,
|
|
31
|
+
paginationRef: E,
|
|
32
|
+
maxHeight: j
|
|
33
|
+
} = _(), k = T ? j : w, { toggleRow: K, selectAllProps: M, isSelected: u } = Y({
|
|
34
|
+
selection: g,
|
|
35
|
+
data: n,
|
|
36
|
+
rowKey: b,
|
|
37
|
+
isLoading: h
|
|
38
|
+
}), [t, P] = C(null), [A, p] = C([]), F = q(
|
|
39
|
+
() => Z(c, {
|
|
40
|
+
prefixColumns: ["3.25rem"],
|
|
41
|
+
hasSelection: !!g
|
|
42
|
+
}),
|
|
43
|
+
[c, g]
|
|
44
|
+
), v = h || n.length === 0, D = z(
|
|
45
|
+
(i) => {
|
|
46
|
+
setTimeout(() => {
|
|
47
|
+
p((l) => l.filter((o) => o !== t));
|
|
48
|
+
}, 300), P((l) => l === i ? null : i), p((l) => t !== i ? [...l, i] : l);
|
|
49
|
+
},
|
|
50
|
+
[t]
|
|
51
|
+
);
|
|
52
|
+
return /* @__PURE__ */ e(
|
|
53
|
+
"div",
|
|
54
|
+
{
|
|
55
|
+
className: a(
|
|
56
|
+
"border border-gray-v2-200 shadow-xs rounded-xl flex flex-col overflow-hidden",
|
|
57
|
+
{ "items-center justify-center flex-1": v }
|
|
58
|
+
),
|
|
59
|
+
children: v ? /* @__PURE__ */ e("div", { className: "flex flex-1 items-center justify-center", children: h ? /* @__PURE__ */ e(U, {}) : /* @__PURE__ */ e(
|
|
60
|
+
Q,
|
|
61
|
+
{
|
|
62
|
+
title: (r == null ? void 0 : r.title) ?? "No data",
|
|
63
|
+
supportingText: r == null ? void 0 : r.supportingText,
|
|
64
|
+
type: r == null ? void 0 : r.type,
|
|
65
|
+
buttons: r == null ? void 0 : r.actions
|
|
66
|
+
}
|
|
67
|
+
) }) : /* @__PURE__ */ f($, { children: [
|
|
68
|
+
/* @__PURE__ */ f("div", { className: "grid overflow-x-auto", style: { gridTemplateColumns: F }, children: [
|
|
69
|
+
/* @__PURE__ */ e(
|
|
70
|
+
V,
|
|
71
|
+
{
|
|
72
|
+
columns: c,
|
|
73
|
+
sort: N,
|
|
74
|
+
selectAll: M,
|
|
75
|
+
leadingCells: 1
|
|
76
|
+
}
|
|
77
|
+
),
|
|
78
|
+
/* @__PURE__ */ e(
|
|
79
|
+
"div",
|
|
80
|
+
{
|
|
81
|
+
ref: R,
|
|
82
|
+
className: "grid grid-cols-subgrid col-span-full overflow-x-hidden overflow-y-auto",
|
|
83
|
+
style: { maxHeight: k },
|
|
84
|
+
children: n.map((i, l) => {
|
|
85
|
+
const o = b(i), d = t === o;
|
|
86
|
+
return /* @__PURE__ */ f(
|
|
87
|
+
"div",
|
|
88
|
+
{
|
|
89
|
+
className: a("grid grid-cols-subgrid col-span-full", {
|
|
90
|
+
"border-b border-gray-v2-200": l !== n.length - 1
|
|
91
|
+
}),
|
|
92
|
+
children: [
|
|
93
|
+
/* @__PURE__ */ f(
|
|
94
|
+
X,
|
|
95
|
+
{
|
|
96
|
+
className: a("cursor-pointer", {
|
|
97
|
+
"bg-gray-v2-100": d,
|
|
98
|
+
"bg-gray-v2-50": !d && u(o)
|
|
99
|
+
}),
|
|
100
|
+
onClick: () => D(o),
|
|
101
|
+
children: [
|
|
102
|
+
/* @__PURE__ */ e(m, { align: "center", children: /* @__PURE__ */ e(
|
|
103
|
+
B,
|
|
104
|
+
{
|
|
105
|
+
className: a(
|
|
106
|
+
"h-4 w-4 min-w-4 text-gray-v2-400 transition-all",
|
|
107
|
+
{ "rotate-180": d }
|
|
108
|
+
)
|
|
109
|
+
}
|
|
110
|
+
) }),
|
|
111
|
+
g ? /* @__PURE__ */ e(m, { align: "center", children: /* @__PURE__ */ e(
|
|
112
|
+
O,
|
|
113
|
+
{
|
|
114
|
+
checked: u(o),
|
|
115
|
+
onClick: (s) => K(o, s)
|
|
116
|
+
}
|
|
117
|
+
) }) : null,
|
|
118
|
+
c.map((s, G) => /* @__PURE__ */ e(
|
|
119
|
+
m,
|
|
120
|
+
{
|
|
121
|
+
align: s.align,
|
|
122
|
+
className: s.cellClassName,
|
|
123
|
+
children: s.cell(i, l)
|
|
124
|
+
},
|
|
125
|
+
s.id ? s.id : G
|
|
126
|
+
))
|
|
127
|
+
]
|
|
128
|
+
}
|
|
129
|
+
),
|
|
130
|
+
/* @__PURE__ */ e(
|
|
131
|
+
J,
|
|
132
|
+
{
|
|
133
|
+
className: a(
|
|
134
|
+
"col-span-full bg-gray-v2-100 border-t",
|
|
135
|
+
d ? "border-gray-v2-200" : "border-transparent"
|
|
136
|
+
),
|
|
137
|
+
expanded: d,
|
|
138
|
+
children: A.includes(o) ? H(i) : null
|
|
139
|
+
}
|
|
140
|
+
)
|
|
141
|
+
]
|
|
142
|
+
},
|
|
143
|
+
`table-${o}`
|
|
144
|
+
);
|
|
145
|
+
})
|
|
146
|
+
}
|
|
147
|
+
)
|
|
148
|
+
] }),
|
|
149
|
+
x && n.length > 0 ? /* @__PURE__ */ e(W, { ref: E, pagination: x }) : null
|
|
150
|
+
] })
|
|
151
|
+
}
|
|
152
|
+
);
|
|
153
|
+
};
|
|
154
|
+
export {
|
|
155
|
+
te as ExpandableTable
|
|
156
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Computes a table body height so the table fits within the viewport without
|
|
3
|
+
* causing the page to scroll.
|
|
4
|
+
*
|
|
5
|
+
* Automatically re-measures when the body or pagination elements resize
|
|
6
|
+
* (e.g. when data loads) or when the window is resized.
|
|
7
|
+
*
|
|
8
|
+
* Uses refs instead of DOM IDs so multiple tables on the same page won't collide.
|
|
9
|
+
*/
|
|
10
|
+
export declare function useFitPageHeight(): {
|
|
11
|
+
bodyRef: import('react').RefObject<HTMLDivElement>;
|
|
12
|
+
paginationRef: import('react').RefObject<HTMLDivElement>;
|
|
13
|
+
maxHeight: string;
|
|
14
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { useRef as o, useState as f, useMemo as g, useLayoutEffect as a } from "react";
|
|
2
|
+
function d() {
|
|
3
|
+
const e = o(null), t = o(null), [n, s] = f(), c = g(
|
|
4
|
+
() => n ? `calc(100vh - ${n}px - 2rem)` : "65vh",
|
|
5
|
+
[n]
|
|
6
|
+
);
|
|
7
|
+
return a(() => {
|
|
8
|
+
const r = () => {
|
|
9
|
+
let u = 0;
|
|
10
|
+
e.current && (u += e.current.getBoundingClientRect().top), t.current && (u += t.current.getBoundingClientRect().height), s(u);
|
|
11
|
+
};
|
|
12
|
+
r();
|
|
13
|
+
const i = new ResizeObserver(r);
|
|
14
|
+
return e.current && i.observe(e.current), t.current && i.observe(t.current), window.addEventListener("resize", r), () => {
|
|
15
|
+
i.disconnect(), window.removeEventListener("resize", r);
|
|
16
|
+
};
|
|
17
|
+
}, []), { bodyRef: e, paginationRef: t, maxHeight: c };
|
|
18
|
+
}
|
|
19
|
+
export {
|
|
20
|
+
d as useFitPageHeight
|
|
21
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { SelectionState } from '../types';
|
|
2
|
+
interface UseRowSelectionProps<TData> {
|
|
3
|
+
selection?: SelectionState;
|
|
4
|
+
data: TData[];
|
|
5
|
+
rowKey: (row: TData) => string;
|
|
6
|
+
isLoading?: boolean;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Centralises row-selection logic for the Table component.
|
|
10
|
+
*
|
|
11
|
+
* Returns:
|
|
12
|
+
* - `isSelected` — whether a given key is in the current selection
|
|
13
|
+
* - `toggleRow` — toggle a single row's selection (stops event propagation
|
|
14
|
+
* so it works correctly inside link rows)
|
|
15
|
+
* - `selectAllProps` — props for the header "select all" checkbox; undefined
|
|
16
|
+
* when selection is disabled
|
|
17
|
+
*/
|
|
18
|
+
export declare function useRowSelection<TData>({ selection, data, rowKey, isLoading, }: UseRowSelectionProps<TData>): {
|
|
19
|
+
isSelected: (key: string) => boolean;
|
|
20
|
+
toggleRow: (key: string, e: React.MouseEvent) => void;
|
|
21
|
+
selectAllProps: {
|
|
22
|
+
checked: boolean;
|
|
23
|
+
ready: boolean;
|
|
24
|
+
onChange: () => void;
|
|
25
|
+
} | undefined;
|
|
26
|
+
};
|
|
27
|
+
export {};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { useCallback as g, useMemo as l } from "react";
|
|
2
|
+
function m({
|
|
3
|
+
selection: e,
|
|
4
|
+
data: t,
|
|
5
|
+
rowKey: u,
|
|
6
|
+
isLoading: d
|
|
7
|
+
}) {
|
|
8
|
+
const n = g(
|
|
9
|
+
(r) => (e == null ? void 0 : e.selectedKeys.includes(r)) ?? !1,
|
|
10
|
+
[e]
|
|
11
|
+
), f = g(
|
|
12
|
+
(r, s) => {
|
|
13
|
+
if (!e) return;
|
|
14
|
+
s.preventDefault(), s.stopPropagation();
|
|
15
|
+
const p = e.selectedKeys.includes(r) ? e.selectedKeys.filter((a) => a !== r) : [...e.selectedKeys, r];
|
|
16
|
+
e.onChange(p);
|
|
17
|
+
},
|
|
18
|
+
[e]
|
|
19
|
+
), h = l(() => {
|
|
20
|
+
if (e)
|
|
21
|
+
return {
|
|
22
|
+
checked: e.selectedKeys.length > 0,
|
|
23
|
+
ready: !d && t.length > 0,
|
|
24
|
+
onChange: () => {
|
|
25
|
+
e.onChange(
|
|
26
|
+
e.selectedKeys.length === 0 ? t.map(u) : []
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
}, [e, t, u, d]);
|
|
31
|
+
return { isSelected: n, toggleRow: f, selectAllProps: h };
|
|
32
|
+
}
|
|
33
|
+
export {
|
|
34
|
+
m as useRowSelection
|
|
35
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
declare const _default: {
|
|
2
|
+
"emptyState": "No data",
|
|
3
|
+
"numOfResults_one": "{{count}} result",
|
|
4
|
+
"numOfResults_other": "{{count}} results",
|
|
5
|
+
"pageNumber": "Page {{current}} of {{total}}",
|
|
6
|
+
"previous": "Previous",
|
|
7
|
+
"next": "Next",
|
|
8
|
+
"perPage_one": "{{count}} / page",
|
|
9
|
+
"perPage_other": "{{count}} / pages"
|
|
10
|
+
}
|
|
11
|
+
;
|
|
12
|
+
|
|
13
|
+
export default _default;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
const t = "No data", e = "{{count}} result", o = "{{count}} results", n = "Page {{current}} of {{total}}", s = "Previous", u = "Next", c = "{{count}} / page", a = "{{count}} / pages", r = {
|
|
2
|
+
emptyState: t,
|
|
3
|
+
numOfResults_one: e,
|
|
4
|
+
numOfResults_other: o,
|
|
5
|
+
pageNumber: n,
|
|
6
|
+
previous: s,
|
|
7
|
+
next: u,
|
|
8
|
+
perPage_one: c,
|
|
9
|
+
perPage_other: a
|
|
10
|
+
};
|
|
11
|
+
export {
|
|
12
|
+
r as default,
|
|
13
|
+
t as emptyState,
|
|
14
|
+
u as next,
|
|
15
|
+
e as numOfResults_one,
|
|
16
|
+
o as numOfResults_other,
|
|
17
|
+
n as pageNumber,
|
|
18
|
+
c as perPage_one,
|
|
19
|
+
a as perPage_other,
|
|
20
|
+
s as previous
|
|
21
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
declare const _default: {
|
|
2
|
+
"emptyState": "Không có dữ liệu",
|
|
3
|
+
"numOfResults_one": "{{count}} kết quả",
|
|
4
|
+
"numOfResults_other": "{{count}} kết quả",
|
|
5
|
+
"pageNumber": "Trang {{current}} / {{total}}",
|
|
6
|
+
"previous": "Trước",
|
|
7
|
+
"next": "Sau",
|
|
8
|
+
"perPage_one": "{{count}} / trang",
|
|
9
|
+
"perPage_other": "{{count}} / trang"
|
|
10
|
+
}
|
|
11
|
+
;
|
|
12
|
+
|
|
13
|
+
export default _default;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
const t = "Không có dữ liệu", n = "{{count}} kết quả", e = "{{count}} kết quả", o = "Trang {{current}} / {{total}}", c = "Trước", r = "Sau", s = "{{count}} / trang", u = "{{count}} / trang", a = {
|
|
2
|
+
emptyState: t,
|
|
3
|
+
numOfResults_one: n,
|
|
4
|
+
numOfResults_other: e,
|
|
5
|
+
pageNumber: o,
|
|
6
|
+
previous: c,
|
|
7
|
+
next: "Sau",
|
|
8
|
+
perPage_one: s,
|
|
9
|
+
perPage_other: u
|
|
10
|
+
};
|
|
11
|
+
export {
|
|
12
|
+
a as default,
|
|
13
|
+
t as emptyState,
|
|
14
|
+
r as next,
|
|
15
|
+
n as numOfResults_one,
|
|
16
|
+
e as numOfResults_other,
|
|
17
|
+
o as pageNumber,
|
|
18
|
+
s as perPage_one,
|
|
19
|
+
u as perPage_other,
|
|
20
|
+
c as previous
|
|
21
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { ColumnDef } from './types';
|
|
2
|
+
interface BuildGridOptions {
|
|
3
|
+
/** Extra columns prepended before the data columns (e.g. expand chevron, drag handle). */
|
|
4
|
+
prefixColumns?: string[];
|
|
5
|
+
/** When true, prepends a 4rem selection-checkbox column. */
|
|
6
|
+
hasSelection?: boolean;
|
|
7
|
+
}
|
|
8
|
+
/** Builds a CSS `grid-template-columns` string from column definitions. */
|
|
9
|
+
export declare function buildGridTemplate<TData>(columns: ColumnDef<TData>[], options?: BuildGridOptions): string;
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
export type ColumnAlign = "left" | "center" | "right";
|
|
3
|
+
/**
|
|
4
|
+
* Definition for a single table column.
|
|
5
|
+
*
|
|
6
|
+
* @todo (breaking) Make generic: `ColumnDef<TData, TSort extends string = string>`.
|
|
7
|
+
* Change `sortKeys` to use template literals so TypeScript can infer `TSort`
|
|
8
|
+
* from the literal values:
|
|
9
|
+
* ```ts
|
|
10
|
+
* sortKeys?: { asc: `${TSort}_asc`; desc: `${TSort}_desc` };
|
|
11
|
+
* ```
|
|
12
|
+
* Wire `Table` and `TableHeader` as `<TData, TSort extends string = string>`
|
|
13
|
+
* and type the `sort` prop as `SortState<SortParam<TSort>>` (where
|
|
14
|
+
* `SortParam<T>` lives in `#ui/api/types`). `SortState.value` becomes
|
|
15
|
+
* `TSort | undefined` instead of `string`.
|
|
16
|
+
*
|
|
17
|
+
* Note: when passing multiple sort attributes in a story or callsite, TypeScript
|
|
18
|
+
* cannot union template-literal inferences across heterogeneous array elements,
|
|
19
|
+
* so explicit generic args are required:
|
|
20
|
+
* `<Table<TData, "name" | "role"> ... />`.
|
|
21
|
+
*/
|
|
22
|
+
export interface ColumnDef<TData> {
|
|
23
|
+
/** Optional stable identifier — used as React key and for future sort/visibility features. Falls back to column index. */
|
|
24
|
+
id?: string;
|
|
25
|
+
/** Header cell content. */
|
|
26
|
+
header?: ReactNode;
|
|
27
|
+
/** Horizontal alignment of the header and body cells. Defaults to "left". */
|
|
28
|
+
align?: ColumnAlign;
|
|
29
|
+
/** Renders the cell content for a given row. */
|
|
30
|
+
cell: (row: TData, index: number) => ReactNode;
|
|
31
|
+
/**
|
|
32
|
+
* CSS grid column size, e.g. "2fr", "150px", "minmax(100px, 2fr)".
|
|
33
|
+
* Defaults to "1fr".
|
|
34
|
+
*/
|
|
35
|
+
size?: string;
|
|
36
|
+
/**
|
|
37
|
+
* Backend sort param values for ascending and descending order.
|
|
38
|
+
* When present, the header becomes clickable and shows sort controls.
|
|
39
|
+
*/
|
|
40
|
+
sortKeys?: {
|
|
41
|
+
asc: string;
|
|
42
|
+
desc: string;
|
|
43
|
+
};
|
|
44
|
+
/** Extra className applied to every cell in this column. */
|
|
45
|
+
cellClassName?: string;
|
|
46
|
+
}
|
|
47
|
+
/** Controlled row-selection state passed to the Table. */
|
|
48
|
+
export interface SelectionState {
|
|
49
|
+
selectedKeys: string[];
|
|
50
|
+
/** Keys that cannot be selected. Their checkboxes render as disabled. */
|
|
51
|
+
disabledKeys?: string[];
|
|
52
|
+
onChange: (keys: string[]) => void;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Controlled sort state passed to the Table.
|
|
56
|
+
*
|
|
57
|
+
* @todo (breaking) Make generic: `SortState<TSort extends string = string>`.
|
|
58
|
+
* Change `value` to `TSort | undefined` (undefined = unsorted, replacing the
|
|
59
|
+
* current empty-string sentinel) and `onChange` to
|
|
60
|
+
* `(key: TSort | undefined) => void`.
|
|
61
|
+
*/
|
|
62
|
+
export interface SortState {
|
|
63
|
+
/** Active sort param, e.g. "name_asc". Empty string means unsorted. */
|
|
64
|
+
value: string;
|
|
65
|
+
onChange: (key: string) => void;
|
|
66
|
+
}
|
|
67
|
+
/** Controlled pagination state passed to the Table. */
|
|
68
|
+
export interface PaginationState {
|
|
69
|
+
/** Total number of records across all pages. */
|
|
70
|
+
total: number;
|
|
71
|
+
page: number;
|
|
72
|
+
pageSize: number;
|
|
73
|
+
onPageChange: (page: number) => void;
|
|
74
|
+
/** When omitted, the page-size selector is hidden. */
|
|
75
|
+
onPageSizeChange?: (size: number) => void;
|
|
76
|
+
}
|
|
77
|
+
/** Configuration for the empty-state view shown when data is an empty array. */
|
|
78
|
+
export interface EmptyStateConfig {
|
|
79
|
+
title: string;
|
|
80
|
+
supportingText?: string;
|
|
81
|
+
type?: "featured-icon" | "illustration";
|
|
82
|
+
/** Action buttons rendered below the empty-state message. */
|
|
83
|
+
actions?: ReactNode;
|
|
84
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
export type TabsVariant = "underline" | "button";
|
|
3
|
+
export interface TabItem {
|
|
4
|
+
key: string;
|
|
5
|
+
label: ReactNode;
|
|
6
|
+
/** Optional counter/badge rendered after the label. */
|
|
7
|
+
badge?: ReactNode;
|
|
8
|
+
disabled?: boolean;
|
|
9
|
+
}
|
|
10
|
+
interface Props {
|
|
11
|
+
items: TabItem[];
|
|
12
|
+
/** Key of the active tab. */
|
|
13
|
+
value: string;
|
|
14
|
+
onValueChange: (key: string) => void;
|
|
15
|
+
variant?: TabsVariant;
|
|
16
|
+
className?: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Horizontal tab navigation. Two visual variants:
|
|
20
|
+
* - `underline` — bottom-bordered tabs on a hairline rule
|
|
21
|
+
* - `button` — segmented buttons on a gray well
|
|
22
|
+
*
|
|
23
|
+
* Keyboard: ArrowLeft/ArrowRight move between enabled tabs, Home/End jump to
|
|
24
|
+
* the first/last enabled tab.
|
|
25
|
+
*/
|
|
26
|
+
export declare const Tabs: ({ items, value, onValueChange, variant, className, }: Props) => import("react").JSX.Element;
|
|
27
|
+
export {};
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { jsx as v, jsxs as x } from "react/jsx-runtime";
|
|
2
|
+
import { useRef as g } from "react";
|
|
3
|
+
import { cn as u } from "../../utils/cn.js";
|
|
4
|
+
const p = {
|
|
5
|
+
underline: {
|
|
6
|
+
base: "px-1 pb-3 -mb-px border-b-2 font-semibold text-sm transition-colors",
|
|
7
|
+
active: "border-brand-v2-600 text-brand-v2-700",
|
|
8
|
+
inactive: "border-transparent text-gray-v2-500 hover:text-gray-v2-700 hover:border-gray-v2-300"
|
|
9
|
+
},
|
|
10
|
+
button: {
|
|
11
|
+
base: "px-3 py-2 rounded-md font-semibold text-sm transition-colors",
|
|
12
|
+
active: "bg-white text-gray-v2-700 shadow-xs",
|
|
13
|
+
inactive: "text-gray-v2-500 hover:text-gray-v2-700"
|
|
14
|
+
}
|
|
15
|
+
}, S = ({
|
|
16
|
+
items: a,
|
|
17
|
+
value: l,
|
|
18
|
+
onValueChange: i,
|
|
19
|
+
variant: o = "underline",
|
|
20
|
+
className: f
|
|
21
|
+
}) => {
|
|
22
|
+
const d = g(null);
|
|
23
|
+
return /* @__PURE__ */ v(
|
|
24
|
+
"div",
|
|
25
|
+
{
|
|
26
|
+
ref: d,
|
|
27
|
+
role: "tablist",
|
|
28
|
+
onKeyDown: (e) => {
|
|
29
|
+
var c, y;
|
|
30
|
+
const t = a.filter((s) => !s.disabled);
|
|
31
|
+
if (t.length === 0) return;
|
|
32
|
+
const r = t.findIndex((s) => s.key === l);
|
|
33
|
+
let n = null;
|
|
34
|
+
if (e.key === "ArrowRight" ? n = (r + 1) % t.length : e.key === "ArrowLeft" ? n = (r - 1 + t.length) % t.length : e.key === "Home" ? n = 0 : e.key === "End" && (n = t.length - 1), n === null) return;
|
|
35
|
+
e.preventDefault();
|
|
36
|
+
const b = t[n].key;
|
|
37
|
+
i(b), (y = (c = d.current) == null ? void 0 : c.querySelector(`[data-tab-key="${CSS.escape(b)}"]`)) == null || y.focus();
|
|
38
|
+
},
|
|
39
|
+
className: u(
|
|
40
|
+
"flex items-center gap-1",
|
|
41
|
+
o === "underline" && "gap-3 border-b border-gray-v2-200",
|
|
42
|
+
o === "button" && "w-fit p-1 rounded-lg bg-gray-v2-50 border border-gray-v2-200",
|
|
43
|
+
f
|
|
44
|
+
),
|
|
45
|
+
children: a.map((e) => {
|
|
46
|
+
const t = e.key === l, r = p[o];
|
|
47
|
+
return /* @__PURE__ */ x(
|
|
48
|
+
"button",
|
|
49
|
+
{
|
|
50
|
+
type: "button",
|
|
51
|
+
role: "tab",
|
|
52
|
+
"data-tab-key": e.key,
|
|
53
|
+
"aria-selected": t,
|
|
54
|
+
disabled: e.disabled,
|
|
55
|
+
tabIndex: t ? 0 : -1,
|
|
56
|
+
onClick: () => i(e.key),
|
|
57
|
+
className: u(
|
|
58
|
+
"inline-flex items-center gap-2 whitespace-nowrap cursor-pointer focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-brand-v2-400 disabled:cursor-not-allowed disabled:text-gray-v2-300",
|
|
59
|
+
r.base,
|
|
60
|
+
t ? r.active : r.inactive
|
|
61
|
+
),
|
|
62
|
+
children: [
|
|
63
|
+
e.label,
|
|
64
|
+
e.badge
|
|
65
|
+
]
|
|
66
|
+
},
|
|
67
|
+
e.key
|
|
68
|
+
);
|
|
69
|
+
})
|
|
70
|
+
}
|
|
71
|
+
);
|
|
72
|
+
};
|
|
73
|
+
export {
|
|
74
|
+
S as Tabs
|
|
75
|
+
};
|