@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.
Files changed (170) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +77 -47
  3. package/dist/assets/background-pattern-grid.svg.js +7 -0
  4. package/dist/assets/empty-cloud.svg.js +5 -0
  5. package/dist/components/accordion/Accordion.d.ts +20 -0
  6. package/dist/components/accordion/Accordion.js +36 -0
  7. package/dist/components/accordion/AccordionTestStory.d.ts +3 -0
  8. package/dist/components/alert/Alert.d.ts +15 -0
  9. package/dist/components/alert/Alert.js +54 -0
  10. package/dist/components/avatar/Avatar.d.ts +13 -0
  11. package/dist/components/avatar/Avatar.js +64 -0
  12. package/dist/components/background-pattern/BackgroundPatternGrid.d.ts +1 -0
  13. package/dist/components/background-pattern/BackgroundPatternGrid.js +6 -0
  14. package/dist/components/badge/Badge.d.ts +1 -1
  15. package/dist/components/badge/BadgeTestStory.d.ts +1 -1
  16. package/dist/components/badge/variants/BadgeMore.d.ts +1 -1
  17. package/dist/components/badge/variants/BadgeMoreTestStory.d.ts +1 -1
  18. package/dist/components/badge/variants/BadgeTag.d.ts +1 -1
  19. package/dist/components/banner/Banner.d.ts +9 -0
  20. package/dist/components/banner/Banner.js +21 -0
  21. package/dist/components/breadcrumb/Breadcrumb.d.ts +13 -0
  22. package/dist/components/breadcrumb/Breadcrumb.js +36 -0
  23. package/dist/components/button/ButtonLoader.d.ts +1 -1
  24. package/dist/components/button/ButtonTestStory.d.ts +5 -5
  25. package/dist/components/card/Card.d.ts +1 -1
  26. package/dist/components/card/Card.stories-ct.d.ts +1 -1
  27. package/dist/components/card/CardBody.d.ts +1 -1
  28. package/dist/components/card/CardHeader.d.ts +1 -1
  29. package/dist/components/chart/chart-legend/ChartLegend.d.ts +38 -0
  30. package/dist/components/chart/chart-legend/ChartLegend.js +57 -0
  31. package/dist/components/chart/chart-legend/ChartLegendItem.d.ts +19 -0
  32. package/dist/components/chart/chart-legend/ChartLegendItem.js +30 -0
  33. package/dist/components/chart/chart-legend/types.d.ts +49 -0
  34. package/dist/components/chart/donut-chart/DonutChart.d.ts +55 -0
  35. package/dist/components/chart/donut-chart/DonutChart.js +110 -0
  36. package/dist/components/chart/donut-chart/DonutSegments.d.ts +25 -0
  37. package/dist/components/chart/donut-chart/DonutSegments.js +51 -0
  38. package/dist/components/chart/donut-chart/donut-tooltip.d.ts +20 -0
  39. package/dist/components/chart/donut-chart/donut-tooltip.js +37 -0
  40. package/dist/components/chart/types.d.ts +8 -0
  41. package/dist/components/checkbox/CheckboxTestStory.d.ts +7 -7
  42. package/dist/components/collapsible/Collapsible.d.ts +1 -1
  43. package/dist/components/combobox/Combobox.d.ts +1 -1
  44. package/dist/components/divider/Divider.d.ts +9 -0
  45. package/dist/components/divider/Divider.js +28 -0
  46. package/dist/components/drawer/Drawer.d.ts +8 -0
  47. package/dist/components/drawer/Drawer.js +68 -0
  48. package/dist/components/dropdown/Dropdown.d.ts +45 -0
  49. package/dist/components/dropdown/Dropdown.js +133 -0
  50. package/dist/components/dropdown/DropdownMenu.d.ts +20 -0
  51. package/dist/components/dropdown/DropdownMenu.js +78 -0
  52. package/dist/components/dropdown/DropdownMenuItem.d.ts +13 -0
  53. package/dist/components/dropdown/DropdownMenuItem.js +49 -0
  54. package/dist/components/dropdown/DropdownTestStory.d.ts +5 -0
  55. package/dist/components/dropdown/dropdown-utils.d.ts +4 -0
  56. package/dist/components/dropdown/dropdown-utils.js +14 -0
  57. package/dist/components/dropdown/types.d.ts +48 -0
  58. package/dist/components/dropdown/use-dropdown-keyboard.d.ts +12 -0
  59. package/dist/components/dropdown/use-dropdown-keyboard.js +49 -0
  60. package/dist/components/empty-state/EmptyState.d.ts +26 -0
  61. package/dist/components/empty-state/EmptyState.js +36 -0
  62. package/dist/components/error-state/ErrorState.d.ts +1 -1
  63. package/dist/components/featured-icon/FeaturedIcon.d.ts +12 -0
  64. package/dist/components/featured-icon/FeaturedIcon.js +44 -0
  65. package/dist/components/form-field/FormField.d.ts +13 -0
  66. package/dist/components/form-field/FormField.js +21 -0
  67. package/dist/components/keyboard-shortcut-label/KeyboardShortcutLabel.d.ts +8 -0
  68. package/dist/components/keyboard-shortcut-label/KeyboardShortcutLabel.js +18 -0
  69. package/dist/components/loading-state/Loader.d.ts +20 -0
  70. package/dist/components/loading-state/Loader.js +38 -0
  71. package/dist/components/loading-state/LoadingState.d.ts +15 -0
  72. package/dist/components/loading-state/LoadingState.js +47 -0
  73. package/dist/components/loading-state/locale/en.json.d.ts +6 -0
  74. package/dist/components/loading-state/locale/en.json.js +7 -0
  75. package/dist/components/loading-state/locale/vi.json.d.ts +6 -0
  76. package/dist/components/loading-state/locale/vi.json.js +7 -0
  77. package/dist/components/media/Media.d.ts +7 -0
  78. package/dist/components/media/Media.js +25 -0
  79. package/dist/components/modal/helpers/HeaderIcon.d.ts +1 -1
  80. package/dist/components/modal/helpers/Title.d.ts +1 -1
  81. package/dist/components/notification/NotificationBanner.d.ts +9 -0
  82. package/dist/components/notification/NotificationBanner.js +97 -0
  83. package/dist/components/notification/icons.d.ts +5 -0
  84. package/dist/components/notification/icons.js +29 -0
  85. package/dist/components/notification/index.d.ts +4 -0
  86. package/dist/components/notification/index.js +26 -0
  87. package/dist/components/notification/locale/en.json.d.ts +8 -0
  88. package/dist/components/notification/locale/en.json.js +7 -0
  89. package/dist/components/notification/locale/vi.json.d.ts +8 -0
  90. package/dist/components/notification/locale/vi.json.js +7 -0
  91. package/dist/components/operating-system-icon/OperatingSystemIcon.d.ts +6 -0
  92. package/dist/components/operating-system-icon/OperatingSystemIcon.js +19 -0
  93. package/dist/components/operating-system-icon/assets/logo-android.svg.js +5 -0
  94. package/dist/components/operating-system-icon/assets/logo-apple.svg.js +5 -0
  95. package/dist/components/operating-system-icon/assets/logo-ubuntu.svg.js +5 -0
  96. package/dist/components/operating-system-icon/assets/logo-windows-10.svg.js +5 -0
  97. package/dist/components/page-title/PageTitle.d.ts +1 -1
  98. package/dist/components/popover/Popover.d.ts +1 -1
  99. package/dist/components/progress-bar/ProgressBar.d.ts +9 -0
  100. package/dist/components/progress-bar/ProgressBar.js +31 -0
  101. package/dist/components/radio/Radio.d.ts +4 -0
  102. package/dist/components/radio/Radio.js +55 -0
  103. package/dist/components/searchbox/Searchbox.d.ts +7 -0
  104. package/dist/components/searchbox/Searchbox.js +15 -0
  105. package/dist/components/select/Select.d.ts +11 -0
  106. package/dist/components/select/Select.js +44 -0
  107. package/dist/components/sidebar/SidebarSecondMenu.d.ts +38 -0
  108. package/dist/components/sidebar/SidebarSecondMenu.js +50 -0
  109. package/dist/components/skeleton/Skeleton.d.ts +14 -0
  110. package/dist/components/skeleton/Skeleton.js +12 -0
  111. package/dist/components/stat-banner-card/StatBannerCard.d.ts +24 -0
  112. package/dist/components/stat-banner-card/StatBannerCard.js +49 -0
  113. package/dist/components/switch/Switch.d.ts +1 -1
  114. package/dist/components/table/Table.d.ts +32 -0
  115. package/dist/components/table/Table.js +128 -0
  116. package/dist/components/table/TableActionButton.d.ts +15 -0
  117. package/dist/components/table/TableActionButton.js +50 -0
  118. package/dist/components/table/TableCell.d.ts +8 -0
  119. package/dist/components/table/TableCell.js +26 -0
  120. package/dist/components/table/TableHeader.d.ts +15 -0
  121. package/dist/components/table/TableHeader.js +36 -0
  122. package/dist/components/table/TableHeaderCell.d.ts +10 -0
  123. package/dist/components/table/TableHeaderCell.js +35 -0
  124. package/dist/components/table/TablePagination.d.ts +6 -0
  125. package/dist/components/table/TablePagination.js +69 -0
  126. package/dist/components/table/TableRow.d.ts +12 -0
  127. package/dist/components/table/TableRow.js +9 -0
  128. package/dist/components/table/expandable/ExpandableTable.d.ts +30 -0
  129. package/dist/components/table/expandable/ExpandableTable.js +156 -0
  130. package/dist/components/table/hooks/use-fit-page-height.d.ts +14 -0
  131. package/dist/components/table/hooks/use-fit-page-height.js +21 -0
  132. package/dist/components/table/hooks/use-row-selection.d.ts +27 -0
  133. package/dist/components/table/hooks/use-row-selection.js +35 -0
  134. package/dist/components/table/locale/en.json.d.ts +13 -0
  135. package/dist/components/table/locale/en.json.js +21 -0
  136. package/dist/components/table/locale/vi.json.d.ts +13 -0
  137. package/dist/components/table/locale/vi.json.js +21 -0
  138. package/dist/components/table/table-utils.d.ts +10 -0
  139. package/dist/components/table/table-utils.js +10 -0
  140. package/dist/components/table/types.d.ts +84 -0
  141. package/dist/components/tabs/Tabs.d.ts +27 -0
  142. package/dist/components/tabs/Tabs.js +75 -0
  143. package/dist/components/tabs/TabsTestStory.d.ts +4 -0
  144. package/dist/components/tags-input/TagsInput.d.ts +18 -0
  145. package/dist/components/tags-input/TagsInput.js +78 -0
  146. package/dist/components/tags-input/TagsInputTestStory.d.ts +3 -0
  147. package/dist/components/textarea/Textarea.d.ts +7 -0
  148. package/dist/components/textarea/Textarea.js +36 -0
  149. package/dist/components/toast/ToastSlice.d.ts +1 -1
  150. package/dist/components/toast/index.d.ts +1 -1
  151. package/dist/components/tooltip/Tooltip.d.ts +1 -1
  152. package/dist/filters/FilterDropdown.d.ts +9 -0
  153. package/dist/filters/FilterDropdown.js +57 -0
  154. package/dist/filters/types.d.ts +11 -0
  155. package/dist/filters/url-params.d.ts +5 -0
  156. package/dist/filters/url-params.js +20 -0
  157. package/dist/filters/use-filters.d.ts +13 -0
  158. package/dist/filters/use-filters.js +63 -0
  159. package/dist/hooks/use-countdown.d.ts +4 -0
  160. package/dist/hooks/use-countdown.js +18 -0
  161. package/dist/i18n/resources.js +23 -0
  162. package/dist/index.d.ts +56 -0
  163. package/dist/index.js +126 -40
  164. package/dist/node_modules/tailwind-merge/dist/bundle-mjs.js +421 -350
  165. package/dist/utils/key-typeguard.d.ts +5 -0
  166. package/dist/utils/key-typeguard.js +6 -0
  167. package/dist/utils/use-debounce.d.ts +1 -0
  168. package/dist/utils/use-debounce.js +11 -0
  169. package/package.json +32 -10
  170. 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,10 @@
1
+ function l(u, e) {
2
+ const r = [];
3
+ e != null && e.prefixColumns && r.push(...e.prefixColumns), e != null && e.hasSelection && r.push("4rem");
4
+ for (const f of u)
5
+ r.push(f.size ?? "1fr");
6
+ return r.join(" ");
7
+ }
8
+ export {
9
+ l as buildGridTemplate
10
+ };
@@ -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
+ };
@@ -0,0 +1,4 @@
1
+ import { TabsVariant } from './Tabs';
2
+ export declare function TabsControlled({ variant, }: {
3
+ variant?: TabsVariant;
4
+ }): import("react").JSX.Element;