@comitor/ui 1.11.0 → 2.1.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/LICENSE +35 -0
- package/README.md +23 -7
- package/dist/components/ui/action-bar-constants.d.ts +31 -0
- package/dist/components/ui/action-bar-constants.js +9 -0
- package/dist/components/ui/action-bar-constants.js.map +1 -0
- package/dist/components/ui/action-bar.d.ts +67 -0
- package/dist/components/ui/action-bar.js +522 -0
- package/dist/components/ui/action-bar.js.map +1 -0
- package/dist/components/ui/badge-overflow.d.ts +30 -0
- package/dist/components/ui/badge-overflow.js +179 -0
- package/dist/components/ui/badge-overflow.js.map +1 -0
- package/dist/components/ui/banner.d.ts +79 -0
- package/dist/components/ui/banner.js +518 -0
- package/dist/components/ui/banner.js.map +1 -0
- package/dist/components/ui/circular-progress.d.ts +50 -0
- package/dist/components/ui/circular-progress.js +266 -0
- package/dist/components/ui/circular-progress.js.map +1 -0
- package/dist/components/ui/cropper-constants.d.ts +34 -0
- package/dist/components/ui/cropper-constants.js +10 -0
- package/dist/components/ui/cropper-constants.js.map +1 -0
- package/dist/components/ui/cropper.d.ts +106 -0
- package/dist/components/ui/cropper.js +1269 -0
- package/dist/components/ui/cropper.js.map +1 -0
- package/dist/components/ui/drawer.d.ts +1 -1
- package/dist/components/ui/drawer.js +2 -2
- package/dist/components/ui/drawer.js.map +1 -1
- package/dist/components/ui/kanban-constants.d.ts +61 -0
- package/dist/components/ui/kanban-constants.js +21 -0
- package/dist/components/ui/kanban-constants.js.map +1 -0
- package/dist/components/ui/kanban.d.ts +72 -0
- package/dist/components/ui/kanban.js +787 -0
- package/dist/components/ui/kanban.js.map +1 -0
- package/dist/components/ui/key-value-constants.d.ts +33 -0
- package/dist/components/ui/key-value-constants.js +11 -0
- package/dist/components/ui/key-value-constants.js.map +1 -0
- package/dist/components/ui/key-value.d.ts +96 -0
- package/dist/components/ui/key-value.js +641 -0
- package/dist/components/ui/key-value.js.map +1 -0
- package/dist/components/ui/mask-input-constants.d.ts +99 -0
- package/dist/components/ui/mask-input-constants.js +601 -0
- package/dist/components/ui/mask-input-constants.js.map +1 -0
- package/dist/components/ui/mask-input.d.ts +36 -0
- package/dist/components/ui/mask-input.js +558 -0
- package/dist/components/ui/mask-input.js.map +1 -0
- package/dist/components/ui/mention.d.ts +31 -0
- package/dist/components/ui/mention.js +128 -0
- package/dist/components/ui/mention.js.map +1 -0
- package/dist/components/ui/phone-input-constants.d.ts +54 -0
- package/dist/components/ui/phone-input-constants.js +9 -0
- package/dist/components/ui/phone-input-constants.js.map +1 -0
- package/dist/components/ui/phone-input.d.ts +85 -0
- package/dist/components/ui/phone-input.js +743 -0
- package/dist/components/ui/phone-input.js.map +1 -0
- package/dist/components/ui/rating.d.ts +56 -0
- package/dist/components/ui/rating.js +646 -0
- package/dist/components/ui/rating.js.map +1 -0
- package/dist/components/ui/responsive-dialog.d.ts +35 -0
- package/dist/components/ui/responsive-dialog.js +193 -0
- package/dist/components/ui/responsive-dialog.js.map +1 -0
- package/dist/components/ui/scroll-spy.d.ts +42 -0
- package/dist/components/ui/scroll-spy.js +334 -0
- package/dist/components/ui/scroll-spy.js.map +1 -0
- package/dist/components/ui/stepper-constants.d.ts +29 -0
- package/dist/components/ui/stepper-constants.js +9 -0
- package/dist/components/ui/stepper-constants.js.map +1 -0
- package/dist/components/ui/stepper.d.ts +80 -0
- package/dist/components/ui/stepper.js +902 -0
- package/dist/components/ui/stepper.js.map +1 -0
- package/dist/components/ui/tags-input.d.ts +41 -0
- package/dist/components/ui/tags-input.js +127 -0
- package/dist/components/ui/tags-input.js.map +1 -0
- package/dist/components/ui/time-picker-constants.d.ts +48 -0
- package/dist/components/ui/time-picker-constants.js +14 -0
- package/dist/components/ui/time-picker-constants.js.map +1 -0
- package/dist/components/ui/time-picker.d.ts +115 -0
- package/dist/components/ui/time-picker.js +1620 -0
- package/dist/components/ui/time-picker.js.map +1 -0
- package/dist/components/ui/timeline.d.ts +32 -0
- package/dist/components/ui/timeline.js +559 -0
- package/dist/components/ui/timeline.js.map +1 -0
- package/dist/components/ui/tour-constants.d.ts +39 -0
- package/dist/components/ui/tour-constants.js +12 -0
- package/dist/components/ui/tour-constants.js.map +1 -0
- package/dist/components/ui/tour.d.ts +124 -0
- package/dist/components/ui/tour.js +1207 -0
- package/dist/components/ui/tour.js.map +1 -0
- package/dist/data-grid/data-grid-cell-variants.js +10 -6
- package/dist/data-grid/data-grid-cell-variants.js.map +1 -1
- package/dist/data-grid/data-grid-cell-wrapper.js +1 -1
- package/dist/data-grid/data-grid-cell-wrapper.js.map +1 -1
- package/dist/data-grid/data-grid-column-header.js +4 -2
- package/dist/data-grid/data-grid-column-header.js.map +1 -1
- package/dist/data-grid/data-grid-context-menu.js +5 -4
- package/dist/data-grid/data-grid-context-menu.js.map +1 -1
- package/dist/data-grid/data-grid-filter-menu.d.ts +12 -1
- package/dist/data-grid/data-grid-filter-menu.js +28 -17
- package/dist/data-grid/data-grid-filter-menu.js.map +1 -1
- package/dist/data-grid/data-grid-keyboard-shortcuts.d.ts +12 -1
- package/dist/data-grid/data-grid-keyboard-shortcuts.js +7 -5
- package/dist/data-grid/data-grid-keyboard-shortcuts.js.map +1 -1
- package/dist/data-grid/data-grid-locale.d.ts +24 -0
- package/dist/data-grid/data-grid-locale.js +25 -0
- package/dist/data-grid/data-grid-locale.js.map +1 -0
- package/dist/data-grid/data-grid-paste-dialog.js +3 -2
- package/dist/data-grid/data-grid-paste-dialog.js.map +1 -1
- package/dist/data-grid/data-grid-row-height-menu.d.ts +11 -1
- package/dist/data-grid/data-grid-row-height-menu.js +25 -28
- package/dist/data-grid/data-grid-row-height-menu.js.map +1 -1
- package/dist/data-grid/data-grid-row.js +1 -1
- package/dist/data-grid/data-grid-row.js.map +1 -1
- package/dist/data-grid/data-grid-search.js +6 -5
- package/dist/data-grid/data-grid-search.js.map +1 -1
- package/dist/data-grid/data-grid-select-column.js +3 -1
- package/dist/data-grid/data-grid-select-column.js.map +1 -1
- package/dist/data-grid/data-grid-sort-menu.d.ts +12 -1
- package/dist/data-grid/data-grid-sort-menu.js +25 -13
- package/dist/data-grid/data-grid-sort-menu.js.map +1 -1
- package/dist/data-grid/data-grid-view-menu.d.ts +12 -1
- package/dist/data-grid/data-grid-view-menu.js +12 -4
- package/dist/data-grid/data-grid-view-menu.js.map +1 -1
- package/dist/data-grid/data-grid.d.ts +14 -2
- package/dist/data-grid/data-grid.js +7 -4
- package/dist/data-grid/data-grid.js.map +1 -1
- package/dist/data-grid/filters.d.ts +17 -21
- package/dist/data-grid/filters.js +73 -52
- package/dist/data-grid/filters.js.map +1 -1
- package/dist/data-grid/index.d.ts +4 -1
- package/dist/data-grid/index.js +20 -2
- package/dist/data-grid/index.js.map +1 -1
- package/dist/data-grid/messages-en.d.ts +294 -0
- package/dist/data-grid/messages-en.js +279 -0
- package/dist/data-grid/messages-en.js.map +1 -0
- package/dist/data-grid/messages-vi.d.ts +12 -0
- package/dist/data-grid/messages-vi.js +279 -0
- package/dist/data-grid/messages-vi.js.map +1 -0
- package/dist/data-grid/messages.d.ts +549 -262
- package/dist/data-grid/messages.js +16 -275
- package/dist/data-grid/messages.js.map +1 -1
- package/dist/data-grid/sortable.js +1 -1
- package/dist/data-grid/sortable.js.map +1 -1
- package/dist/data-grid/use-data-grid-undo-redo.d.ts +13 -1
- package/dist/data-grid/use-data-grid-undo-redo.js +13 -10
- package/dist/data-grid/use-data-grid-undo-redo.js.map +1 -1
- package/dist/data-grid/use-data-grid.d.ts +281 -1
- package/dist/data-grid/use-data-grid.js +24 -19
- package/dist/data-grid/use-data-grid.js.map +1 -1
- package/dist/data-grid/utils.d.ts +9 -1
- package/dist/data-grid/utils.js +3 -2
- package/dist/data-grid/utils.js.map +1 -1
- package/dist/index.d.ts +31 -0
- package/dist/index.js +42 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/compose-refs.js.map +1 -0
- package/dist/lib/use-as-ref.js.map +1 -0
- package/dist/lib/use-is-mobile.d.ts +10 -0
- package/dist/lib/use-is-mobile.js +21 -0
- package/dist/lib/use-is-mobile.js.map +1 -0
- package/dist/lib/use-isomorphic-layout-effect.js.map +1 -0
- package/dist/lib/use-lazy-ref.js.map +1 -0
- package/dist/lib/visually-hidden-input.d.ts +12 -0
- package/dist/lib/visually-hidden-input.js +105 -0
- package/dist/lib/visually-hidden-input.js.map +1 -0
- package/package.json +5 -1
- package/styles.css +19 -0
- package/dist/data-grid/compose-refs.js.map +0 -1
- package/dist/data-grid/use-as-ref.js.map +0 -1
- package/dist/data-grid/use-isomorphic-layout-effect.js.map +0 -1
- package/dist/data-grid/use-lazy-ref.js.map +0 -1
- /package/dist/{data-grid → lib}/compose-refs.d.ts +0 -0
- /package/dist/{data-grid → lib}/compose-refs.js +0 -0
- /package/dist/{data-grid → lib}/use-as-ref.d.ts +0 -0
- /package/dist/{data-grid → lib}/use-as-ref.js +0 -0
- /package/dist/{data-grid → lib}/use-isomorphic-layout-effect.d.ts +0 -0
- /package/dist/{data-grid → lib}/use-isomorphic-layout-effect.js +0 -0
- /package/dist/{data-grid → lib}/use-lazy-ref.d.ts +0 -0
- /package/dist/{data-grid → lib}/use-lazy-ref.js +0 -0
|
@@ -4,46 +4,43 @@ import { AlignVerticalSpaceAroundIcon, ChevronsDownUpIcon, EqualIcon, MinusIcon
|
|
|
4
4
|
import * as React from "react";
|
|
5
5
|
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from "../components/ui/select.js";
|
|
6
6
|
import { cn } from "../lib/cn.js";
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
label: msg.rowHeight.short,
|
|
11
|
-
value: "
|
|
12
|
-
icon:
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
value: "medium",
|
|
17
|
-
icon: EqualIcon
|
|
18
|
-
},
|
|
19
|
-
{
|
|
20
|
-
label: msg.rowHeight.tall,
|
|
21
|
-
value: "tall",
|
|
22
|
-
icon: AlignVerticalSpaceAroundIcon
|
|
23
|
-
},
|
|
24
|
-
{
|
|
25
|
-
label: msg.rowHeight.extraTall,
|
|
26
|
-
value: "extra-tall",
|
|
27
|
-
icon: ChevronsDownUpIcon
|
|
28
|
-
}
|
|
29
|
-
];
|
|
7
|
+
import { useResolvedDataGridMessages } from "./data-grid-locale.js";
|
|
8
|
+
function buildRowHeights(msg) {
|
|
9
|
+
return [
|
|
10
|
+
{ label: msg.rowHeight.short, value: "short", icon: MinusIcon },
|
|
11
|
+
{ label: msg.rowHeight.medium, value: "medium", icon: EqualIcon },
|
|
12
|
+
{ label: msg.rowHeight.tall, value: "tall", icon: AlignVerticalSpaceAroundIcon },
|
|
13
|
+
{ label: msg.rowHeight.extraTall, value: "extra-tall", icon: ChevronsDownUpIcon }
|
|
14
|
+
];
|
|
15
|
+
}
|
|
30
16
|
function DataGridRowHeightMenu({
|
|
31
17
|
table,
|
|
32
18
|
disabled,
|
|
33
19
|
triggerClassName,
|
|
20
|
+
locale,
|
|
34
21
|
...props
|
|
35
22
|
}) {
|
|
23
|
+
const msg = useResolvedDataGridMessages(locale);
|
|
24
|
+
const rowHeights = React.useMemo(() => buildRowHeights(msg), [msg]);
|
|
36
25
|
const rowHeight = table.options.meta?.rowHeight;
|
|
37
26
|
const onRowHeightChange = table.options.meta?.onRowHeightChange;
|
|
38
27
|
const selectedRowHeight = React.useMemo(
|
|
39
28
|
() => rowHeights.find((option) => option.value === rowHeight) ?? rowHeights[0],
|
|
40
|
-
[rowHeight]
|
|
29
|
+
[rowHeight, rowHeights]
|
|
41
30
|
);
|
|
42
31
|
return /* @__PURE__ */ jsxs(Select, { value: rowHeight, onValueChange: onRowHeightChange, disabled, children: [
|
|
43
|
-
/* @__PURE__ */ jsx(
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
32
|
+
/* @__PURE__ */ jsx(
|
|
33
|
+
SelectTrigger,
|
|
34
|
+
{
|
|
35
|
+
"aria-label": msg.rowHeight.label,
|
|
36
|
+
size: "sm",
|
|
37
|
+
className: cn("w-auto gap-2 font-normal", triggerClassName),
|
|
38
|
+
children: /* @__PURE__ */ jsx(SelectValue, { placeholder: msg.rowHeight.label, children: /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-2", children: [
|
|
39
|
+
/* @__PURE__ */ jsx(selectedRowHeight.icon, { "aria-hidden": "true", className: "size-3.5 text-muted-foreground" }),
|
|
40
|
+
selectedRowHeight.label
|
|
41
|
+
] }) })
|
|
42
|
+
}
|
|
43
|
+
),
|
|
47
44
|
/* @__PURE__ */ jsx(SelectContent, { ...props, children: /* @__PURE__ */ jsx(SelectGroup, { children: rowHeights.map((option) => /* @__PURE__ */ jsx(SelectItem, { value: option.value, children: /* @__PURE__ */ jsxs("span", { className: "flex items-center gap-2", children: [
|
|
48
45
|
/* @__PURE__ */ jsx(option.icon, { "aria-hidden": "true", className: "size-4 text-muted-foreground" }),
|
|
49
46
|
option.label
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/data-grid/data-grid-row-height-menu.tsx"],"sourcesContent":["\"use client\";\n\nimport type { Table } from \"@tanstack/react-table\";\nimport { AlignVerticalSpaceAroundIcon, ChevronsDownUpIcon, EqualIcon, MinusIcon } from \"lucide-react\";\nimport * as React from \"react\";\nimport { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from \"../components/ui/select.js\";\nimport { cn } from \"../lib/cn.js\";\nimport {
|
|
1
|
+
{"version":3,"sources":["../../src/data-grid/data-grid-row-height-menu.tsx"],"sourcesContent":["\"use client\";\n\nimport type { Table } from \"@tanstack/react-table\";\nimport { AlignVerticalSpaceAroundIcon, ChevronsDownUpIcon, EqualIcon, MinusIcon } from \"lucide-react\";\nimport * as React from \"react\";\nimport { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from \"../components/ui/select.js\";\nimport { cn } from \"../lib/cn.js\";\nimport { useResolvedDataGridMessages } from \"./data-grid-locale.js\";\nimport type { DataGridLocale, DataGridMessages } from \"./messages.js\";\n\n/*\n * Bốn mức chiều cao. PHẢI dựng theo bảng chuỗi chứ không đóng băng thành hằng ở đầu module —\n * nhãn (\"Short\" / \"Thấp\") đổi theo ngôn ngữ, còn `value` và icon thì không.\n */\nfunction buildRowHeights(msg: DataGridMessages) {\n // Tuple (không phải mảng) để `rowHeights[0]` có kiểu chắc chắn — bốn mức là cố định.\n return [\n { label: msg.rowHeight.short, value: \"short\" as const, icon: MinusIcon },\n { label: msg.rowHeight.medium, value: \"medium\" as const, icon: EqualIcon },\n { label: msg.rowHeight.tall, value: \"tall\" as const, icon: AlignVerticalSpaceAroundIcon },\n { label: msg.rowHeight.extraTall, value: \"extra-tall\" as const, icon: ChevronsDownUpIcon }\n ] as const;\n}\n\ninterface DataGridRowHeightMenuProps<TData> extends React.ComponentProps<typeof SelectContent> {\n table: Table<TData>;\n disabled?: boolean;\n /** className cho nút mở menu (mặc định cao 8 như các nút khác trên thanh công cụ) */\n triggerClassName?: string;\n /**\n * Ngôn ngữ của menu: `\"en\"` (mặc định) · `\"vi\"`, hoặc cả một bảng chuỗi tự soạn.\n *\n * ⚠ Thanh công cụ nằm NGOÀI `<DataGrid>`, nên `locale` truyền cho lưới không với tới đây. Bọc\n * cả màn bằng `DataGridLocaleProvider`, hoặc truyền prop này cho từng menu. Prop thắng provider.\n */\n locale?: DataGridLocale | DataGridMessages;\n}\n\n/** Chọn chiều cao dòng của lưới (thấp/vừa/cao/rất cao) — đặt trên thanh công cụ. */\nexport function DataGridRowHeightMenu<TData>({\n table,\n disabled,\n triggerClassName,\n locale,\n ...props\n}: DataGridRowHeightMenuProps<TData>) {\n const msg = useResolvedDataGridMessages(locale);\n const rowHeights = React.useMemo(() => buildRowHeights(msg), [msg]);\n const rowHeight = table.options.meta?.rowHeight;\n const onRowHeightChange = table.options.meta?.onRowHeightChange;\n\n const selectedRowHeight = React.useMemo(\n () => rowHeights.find((option) => option.value === rowHeight) ?? rowHeights[0],\n [rowHeight, rowHeights]\n );\n\n return (\n <Select value={rowHeight} onValueChange={onRowHeightChange} disabled={disabled}>\n <SelectTrigger\n aria-label={msg.rowHeight.label}\n size=\"sm\"\n className={cn(\"w-auto gap-2 font-normal\", triggerClassName)}\n >\n <SelectValue placeholder={msg.rowHeight.label}>\n <span className=\"flex items-center gap-2\">\n <selectedRowHeight.icon aria-hidden=\"true\" className=\"size-3.5 text-muted-foreground\" />\n {selectedRowHeight.label}\n </span>\n </SelectValue>\n </SelectTrigger>\n <SelectContent {...props}>\n <SelectGroup>\n {rowHeights.map((option) => (\n <SelectItem key={option.value} value={option.value}>\n <span className=\"flex items-center gap-2\">\n <option.icon aria-hidden=\"true\" className=\"size-4 text-muted-foreground\" />\n {option.label}\n </span>\n </SelectItem>\n ))}\n </SelectGroup>\n </SelectContent>\n </Select>\n );\n}\n"],"mappings":";AAgEU,SACE,KADF;AA7DV,SAAS,8BAA8B,oBAAoB,WAAW,iBAAiB;AACvF,YAAY,WAAW;AACvB,SAAS,QAAQ,eAAe,aAAa,YAAY,eAAe,mBAAmB;AAC3F,SAAS,UAAU;AACnB,SAAS,mCAAmC;AAO5C,SAAS,gBAAgB,KAAuB;AAE9C,SAAO;AAAA,IACL,EAAE,OAAO,IAAI,UAAU,OAAO,OAAO,SAAkB,MAAM,UAAU;AAAA,IACvE,EAAE,OAAO,IAAI,UAAU,QAAQ,OAAO,UAAmB,MAAM,UAAU;AAAA,IACzE,EAAE,OAAO,IAAI,UAAU,MAAM,OAAO,QAAiB,MAAM,6BAA6B;AAAA,IACxF,EAAE,OAAO,IAAI,UAAU,WAAW,OAAO,cAAuB,MAAM,mBAAmB;AAAA,EAC3F;AACF;AAiBO,SAAS,sBAA6B;AAAA,EAC3C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAAsC;AACpC,QAAM,MAAM,4BAA4B,MAAM;AAC9C,QAAM,aAAa,MAAM,QAAQ,MAAM,gBAAgB,GAAG,GAAG,CAAC,GAAG,CAAC;AAClE,QAAM,YAAY,MAAM,QAAQ,MAAM;AACtC,QAAM,oBAAoB,MAAM,QAAQ,MAAM;AAE9C,QAAM,oBAAoB,MAAM;AAAA,IAC9B,MAAM,WAAW,KAAK,CAAC,WAAW,OAAO,UAAU,SAAS,KAAK,WAAW,CAAC;AAAA,IAC7E,CAAC,WAAW,UAAU;AAAA,EACxB;AAEA,SACE,qBAAC,UAAO,OAAO,WAAW,eAAe,mBAAmB,UAC1D;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,cAAY,IAAI,UAAU;AAAA,QAC1B,MAAK;AAAA,QACL,WAAW,GAAG,4BAA4B,gBAAgB;AAAA,QAE1D,8BAAC,eAAY,aAAa,IAAI,UAAU,OACtC,+BAAC,UAAK,WAAU,2BACd;AAAA,8BAAC,kBAAkB,MAAlB,EAAuB,eAAY,QAAO,WAAU,kCAAiC;AAAA,UACrF,kBAAkB;AAAA,WACrB,GACF;AAAA;AAAA,IACF;AAAA,IACA,oBAAC,iBAAe,GAAG,OACjB,8BAAC,eACE,qBAAW,IAAI,CAAC,WACf,oBAAC,cAA8B,OAAO,OAAO,OAC3C,+BAAC,UAAK,WAAU,2BACd;AAAA,0BAAC,OAAO,MAAP,EAAY,eAAY,QAAO,WAAU,gCAA+B;AAAA,MACxE,OAAO;AAAA,OACV,KAJe,OAAO,KAKxB,CACD,GACH,GACF;AAAA,KACF;AAEJ;","names":[]}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { jsx } from "react/jsx-runtime";
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
import { cn } from "../lib/cn.js";
|
|
5
|
-
import { useComposedRefs } from "
|
|
5
|
+
import { useComposedRefs } from "../lib/compose-refs.js";
|
|
6
6
|
import { DataGridCell } from "./data-grid-cell.js";
|
|
7
7
|
import {
|
|
8
8
|
flexRender,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/data-grid/data-grid-row.tsx"],"sourcesContent":["\"use client\";\n\nimport type { ColumnPinningState, Row, TableMeta, VisibilityState } from \"@tanstack/react-table\";\nimport type { VirtualItem } from \"@tanstack/react-virtual\";\nimport * as React from \"react\";\nimport { cn } from \"../lib/cn.js\";\nimport { useComposedRefs } from \"./compose-refs.js\";\nimport { DataGridCell } from \"./data-grid-cell.js\";\nimport type { CellPosition, Direction, RowHeightValue } from \"./types.js\";\nimport {\n flexRender,\n getCellKey,\n getColumnBorderVisibility,\n getColumnPinningStyle,\n getRowHeightValue\n} from \"./utils.js\";\n\ninterface DataGridRowProps<TData> extends React.ComponentProps<\"div\"> {\n row: Row<TData>;\n tableMeta: TableMeta<TData>;\n virtualItem: VirtualItem;\n measureElement: (node: Element | null) => void;\n rowMapRef: React.RefObject<Map<number, HTMLDivElement>>;\n rowHeight: RowHeightValue;\n columnVisibility: VisibilityState;\n columnPinning: ColumnPinningState;\n focusedCell: CellPosition | null;\n editingCell: CellPosition | null;\n cellSelectionKeys: Set<string>;\n searchMatchColumns: Set<string> | null;\n activeSearchMatch: CellPosition | null;\n dir: Direction;\n readOnly: boolean;\n stretchColumns: boolean;\n adjustLayout: boolean;\n}\n\nexport const DataGridRow = React.memo(DataGridRowImpl, (prev, next) => {\n const prevRowIndex = prev.virtualItem.index;\n const nextRowIndex = next.virtualItem.index;\n\n // Re-render if row identity changed\n if (prev.row.id !== next.row.id) {\n return false;\n }\n\n // Re-render if row data (original) reference changed\n if (prev.row.original !== next.row.original) {\n return false;\n }\n\n // Re-render if virtual position changed (handles transform updates)\n if (prev.virtualItem.start !== next.virtualItem.start) {\n return false;\n }\n\n // Re-render if focus state changed for this row\n const prevHasFocus = prev.focusedCell?.rowIndex === prevRowIndex;\n const nextHasFocus = next.focusedCell?.rowIndex === nextRowIndex;\n\n if (prevHasFocus !== nextHasFocus) {\n return false;\n }\n\n // Re-render if focused column changed within this row\n if (nextHasFocus && prevHasFocus) {\n if (prev.focusedCell?.columnId !== next.focusedCell?.columnId) {\n return false;\n }\n }\n\n // Re-render if editing state changed for this row\n const prevHasEditing = prev.editingCell?.rowIndex === prevRowIndex;\n const nextHasEditing = next.editingCell?.rowIndex === nextRowIndex;\n\n if (prevHasEditing !== nextHasEditing) {\n return false;\n }\n\n // Re-render if editing column changed within this row\n if (nextHasEditing && prevHasEditing) {\n if (prev.editingCell?.columnId !== next.editingCell?.columnId) {\n return false;\n }\n }\n\n // Re-render if this row's selected cells changed\n // Using stable Set reference that only includes this row's cells\n if (prev.cellSelectionKeys !== next.cellSelectionKeys) {\n return false;\n }\n\n // Re-render if column visibility changed\n if (prev.columnVisibility !== next.columnVisibility) {\n return false;\n }\n\n // Re-render if row height changed\n if (prev.rowHeight !== next.rowHeight) {\n return false;\n }\n\n // Re-render if column pinning state changed\n if (prev.columnPinning !== next.columnPinning) {\n return false;\n }\n\n // Re-render if readOnly changed\n if (prev.readOnly !== next.readOnly) {\n return false;\n }\n\n // Re-render if search match columns changed for this row\n if (prev.searchMatchColumns !== next.searchMatchColumns) {\n return false;\n }\n\n // Re-render if active search match changed for this row\n if (prev.activeSearchMatch?.columnId !== next.activeSearchMatch?.columnId) {\n return false;\n }\n\n // Re-render if direction changed\n if (prev.dir !== next.dir) {\n return false;\n }\n\n // Re-render if adjustLayout state changed\n if (prev.adjustLayout !== next.adjustLayout) {\n return false;\n }\n\n // Re-render if stretchColumns changed\n if (prev.stretchColumns !== next.stretchColumns) {\n return false;\n }\n\n // Skip re-render - props are equal\n return true;\n}) as typeof DataGridRowImpl;\n\nfunction DataGridRowImpl<TData>({\n row,\n tableMeta,\n virtualItem,\n measureElement,\n rowMapRef,\n rowHeight,\n columnVisibility,\n columnPinning,\n focusedCell,\n editingCell,\n cellSelectionKeys,\n searchMatchColumns,\n activeSearchMatch,\n dir,\n readOnly,\n stretchColumns,\n adjustLayout,\n className,\n style,\n ref,\n ...props\n}: DataGridRowProps<TData>) {\n const virtualRowIndex = virtualItem.index;\n\n const onRowChange = React.useCallback(\n (node: HTMLDivElement | null) => {\n if (typeof virtualRowIndex === \"undefined\") return;\n\n if (node) {\n measureElement(node);\n rowMapRef.current?.set(virtualRowIndex, node);\n } else {\n rowMapRef.current?.delete(virtualRowIndex);\n }\n },\n [virtualRowIndex, measureElement, rowMapRef]\n );\n\n const rowRef = useComposedRefs(ref, onRowChange);\n\n const isRowSelected = row.getIsSelected();\n\n // Memoize visible cells to avoid recreating cell array on every render\n // Though TanStack returns new Cell wrappers, memoizing the array helps React's reconciliation\n // biome-ignore lint/correctness/useExhaustiveDependencies: columnVisibility and columnPinning are used for calculating the visible cells\n const visibleCells = React.useMemo(() => row.getVisibleCells(), [row, columnVisibility, columnPinning]);\n\n return (\n <div\n key={row.id}\n role=\"row\"\n aria-rowindex={virtualRowIndex + 2}\n aria-selected={isRowSelected}\n data-index={virtualRowIndex}\n data-slot=\"grid-row\"\n tabIndex={-1}\n {...props}\n ref={rowRef}\n className={cn(\n \"absolute flex w-full border-b [content-visibility:auto]\",\n !adjustLayout && \"will-change-transform\",\n className\n )}\n style={{\n height: `${getRowHeightValue(rowHeight)}px`,\n ...(adjustLayout ? { top: `${virtualItem.start}px` } : { transform: `translateY(${virtualItem.start}px)` }),\n ...style\n }}\n >\n {visibleCells.map((cell, colIndex) => {\n const columnId = cell.column.id;\n\n const isCellFocused = focusedCell?.rowIndex === virtualRowIndex && focusedCell?.columnId === columnId;\n const isCellEditing = editingCell?.rowIndex === virtualRowIndex && editingCell?.columnId === columnId;\n const isCellSelected = cellSelectionKeys?.has(getCellKey(virtualRowIndex, columnId)) ?? false;\n\n const isSearchMatch = searchMatchColumns?.has(columnId) ?? false;\n const isActiveSearchMatch = activeSearchMatch?.columnId === columnId;\n\n const nextCell = visibleCells[colIndex + 1];\n const isLastColumn = colIndex === visibleCells.length - 1;\n const { showEndBorder, showStartBorder } = getColumnBorderVisibility({\n column: cell.column,\n nextColumn: nextCell?.column,\n isLastColumn\n });\n\n return (\n <div\n key={cell.id}\n role=\"gridcell\"\n aria-colindex={colIndex + 1}\n data-highlighted={isCellFocused ? \"\" : undefined}\n data-slot=\"grid-cell\"\n tabIndex={-1}\n className={cn({\n grow: stretchColumns && columnId !== \"select\",\n \"border-e\": showEndBorder && columnId !== \"select\",\n \"border-s\": showStartBorder && columnId !== \"select\"\n })}\n style={{\n ...getColumnPinningStyle({ column: cell.column, dir }),\n width: `calc(var(--col-${columnId}-size) * 1px)`\n }}\n >\n {typeof cell.column.columnDef.header === \"function\" ? (\n <div\n className={cn(\"size-full px-3 py-1.5\", {\n // `--accent` là bậc tint TRẠNG THÁI của gói (Tabs/Switch/Progress dùng đúng nó\n // để nói \"đang bật\"). `bg-primary/10` là gold pha 10% — 1,05:1, một dấu hiệu giả.\n \"bg-accent\": isRowSelected\n })}\n >\n {flexRender(cell.column.columnDef.cell, cell.getContext())}\n </div>\n ) : (\n <DataGridCell\n cell={cell}\n tableMeta={tableMeta}\n rowIndex={virtualRowIndex}\n columnId={columnId}\n rowHeight={rowHeight}\n isFocused={isCellFocused}\n isEditing={isCellEditing}\n isSelected={isCellSelected}\n isSearchMatch={isSearchMatch}\n isActiveSearchMatch={isActiveSearchMatch}\n readOnly={readOnly}\n />\n )}\n </div>\n );\n })}\n </div>\n );\n}\n"],"mappings":";AAwPc;AApPd,YAAY,WAAW;AACvB,SAAS,UAAU;AACnB,SAAS,uBAAuB;AAChC,SAAS,oBAAoB;AAE7B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAsBA,MAAM,cAAc,MAAM,KAAK,iBAAiB,CAAC,MAAM,SAAS;AACrE,QAAM,eAAe,KAAK,YAAY;AACtC,QAAM,eAAe,KAAK,YAAY;AAGtC,MAAI,KAAK,IAAI,OAAO,KAAK,IAAI,IAAI;AAC/B,WAAO;AAAA,EACT;AAGA,MAAI,KAAK,IAAI,aAAa,KAAK,IAAI,UAAU;AAC3C,WAAO;AAAA,EACT;AAGA,MAAI,KAAK,YAAY,UAAU,KAAK,YAAY,OAAO;AACrD,WAAO;AAAA,EACT;AAGA,QAAM,eAAe,KAAK,aAAa,aAAa;AACpD,QAAM,eAAe,KAAK,aAAa,aAAa;AAEpD,MAAI,iBAAiB,cAAc;AACjC,WAAO;AAAA,EACT;AAGA,MAAI,gBAAgB,cAAc;AAChC,QAAI,KAAK,aAAa,aAAa,KAAK,aAAa,UAAU;AAC7D,aAAO;AAAA,IACT;AAAA,EACF;AAGA,QAAM,iBAAiB,KAAK,aAAa,aAAa;AACtD,QAAM,iBAAiB,KAAK,aAAa,aAAa;AAEtD,MAAI,mBAAmB,gBAAgB;AACrC,WAAO;AAAA,EACT;AAGA,MAAI,kBAAkB,gBAAgB;AACpC,QAAI,KAAK,aAAa,aAAa,KAAK,aAAa,UAAU;AAC7D,aAAO;AAAA,IACT;AAAA,EACF;AAIA,MAAI,KAAK,sBAAsB,KAAK,mBAAmB;AACrD,WAAO;AAAA,EACT;AAGA,MAAI,KAAK,qBAAqB,KAAK,kBAAkB;AACnD,WAAO;AAAA,EACT;AAGA,MAAI,KAAK,cAAc,KAAK,WAAW;AACrC,WAAO;AAAA,EACT;AAGA,MAAI,KAAK,kBAAkB,KAAK,eAAe;AAC7C,WAAO;AAAA,EACT;AAGA,MAAI,KAAK,aAAa,KAAK,UAAU;AACnC,WAAO;AAAA,EACT;AAGA,MAAI,KAAK,uBAAuB,KAAK,oBAAoB;AACvD,WAAO;AAAA,EACT;AAGA,MAAI,KAAK,mBAAmB,aAAa,KAAK,mBAAmB,UAAU;AACzE,WAAO;AAAA,EACT;AAGA,MAAI,KAAK,QAAQ,KAAK,KAAK;AACzB,WAAO;AAAA,EACT;AAGA,MAAI,KAAK,iBAAiB,KAAK,cAAc;AAC3C,WAAO;AAAA,EACT;AAGA,MAAI,KAAK,mBAAmB,KAAK,gBAAgB;AAC/C,WAAO;AAAA,EACT;AAGA,SAAO;AACT,CAAC;AAED,SAAS,gBAAuB;AAAA,EAC9B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAA4B;AAC1B,QAAM,kBAAkB,YAAY;AAEpC,QAAM,cAAc,MAAM;AAAA,IACxB,CAAC,SAAgC;AAC/B,UAAI,OAAO,oBAAoB,YAAa;AAE5C,UAAI,MAAM;AACR,uBAAe,IAAI;AACnB,kBAAU,SAAS,IAAI,iBAAiB,IAAI;AAAA,MAC9C,OAAO;AACL,kBAAU,SAAS,OAAO,eAAe;AAAA,MAC3C;AAAA,IACF;AAAA,IACA,CAAC,iBAAiB,gBAAgB,SAAS;AAAA,EAC7C;AAEA,QAAM,SAAS,gBAAgB,KAAK,WAAW;AAE/C,QAAM,gBAAgB,IAAI,cAAc;AAKxC,QAAM,eAAe,MAAM,QAAQ,MAAM,IAAI,gBAAgB,GAAG,CAAC,KAAK,kBAAkB,aAAa,CAAC;AAEtG,SACE;AAAA,IAAC;AAAA;AAAA,MAEC,MAAK;AAAA,MACL,iBAAe,kBAAkB;AAAA,MACjC,iBAAe;AAAA,MACf,cAAY;AAAA,MACZ,aAAU;AAAA,MACV,UAAU;AAAA,MACT,GAAG;AAAA,MACJ,KAAK;AAAA,MACL,WAAW;AAAA,QACT;AAAA,QACA,CAAC,gBAAgB;AAAA,QACjB;AAAA,MACF;AAAA,MACA,OAAO;AAAA,QACL,QAAQ,GAAG,kBAAkB,SAAS,CAAC;AAAA,QACvC,GAAI,eAAe,EAAE,KAAK,GAAG,YAAY,KAAK,KAAK,IAAI,EAAE,WAAW,cAAc,YAAY,KAAK,MAAM;AAAA,QACzG,GAAG;AAAA,MACL;AAAA,MAEC,uBAAa,IAAI,CAAC,MAAM,aAAa;AACpC,cAAM,WAAW,KAAK,OAAO;AAE7B,cAAM,gBAAgB,aAAa,aAAa,mBAAmB,aAAa,aAAa;AAC7F,cAAM,gBAAgB,aAAa,aAAa,mBAAmB,aAAa,aAAa;AAC7F,cAAM,iBAAiB,mBAAmB,IAAI,WAAW,iBAAiB,QAAQ,CAAC,KAAK;AAExF,cAAM,gBAAgB,oBAAoB,IAAI,QAAQ,KAAK;AAC3D,cAAM,sBAAsB,mBAAmB,aAAa;AAE5D,cAAM,WAAW,aAAa,WAAW,CAAC;AAC1C,cAAM,eAAe,aAAa,aAAa,SAAS;AACxD,cAAM,EAAE,eAAe,gBAAgB,IAAI,0BAA0B;AAAA,UACnE,QAAQ,KAAK;AAAA,UACb,YAAY,UAAU;AAAA,UACtB;AAAA,QACF,CAAC;AAED,eACE;AAAA,UAAC;AAAA;AAAA,YAEC,MAAK;AAAA,YACL,iBAAe,WAAW;AAAA,YAC1B,oBAAkB,gBAAgB,KAAK;AAAA,YACvC,aAAU;AAAA,YACV,UAAU;AAAA,YACV,WAAW,GAAG;AAAA,cACZ,MAAM,kBAAkB,aAAa;AAAA,cACrC,YAAY,iBAAiB,aAAa;AAAA,cAC1C,YAAY,mBAAmB,aAAa;AAAA,YAC9C,CAAC;AAAA,YACD,OAAO;AAAA,cACL,GAAG,sBAAsB,EAAE,QAAQ,KAAK,QAAQ,IAAI,CAAC;AAAA,cACrD,OAAO,kBAAkB,QAAQ;AAAA,YACnC;AAAA,YAEC,iBAAO,KAAK,OAAO,UAAU,WAAW,aACvC;AAAA,cAAC;AAAA;AAAA,gBACC,WAAW,GAAG,yBAAyB;AAAA;AAAA;AAAA,kBAGrC,aAAa;AAAA,gBACf,CAAC;AAAA,gBAEA,qBAAW,KAAK,OAAO,UAAU,MAAM,KAAK,WAAW,CAAC;AAAA;AAAA,YAC3D,IAEA;AAAA,cAAC;AAAA;AAAA,gBACC;AAAA,gBACA;AAAA,gBACA,UAAU;AAAA,gBACV;AAAA,gBACA;AAAA,gBACA,WAAW;AAAA,gBACX,WAAW;AAAA,gBACX,YAAY;AAAA,gBACZ;AAAA,gBACA;AAAA,gBACA;AAAA;AAAA,YACF;AAAA;AAAA,UAvCG,KAAK;AAAA,QAyCZ;AAAA,MAEJ,CAAC;AAAA;AAAA,IAnFI,IAAI;AAAA,EAoFX;AAEJ;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/data-grid/data-grid-row.tsx"],"sourcesContent":["\"use client\";\n\nimport type { ColumnPinningState, Row, TableMeta, VisibilityState } from \"@tanstack/react-table\";\nimport type { VirtualItem } from \"@tanstack/react-virtual\";\nimport * as React from \"react\";\nimport { cn } from \"../lib/cn.js\";\nimport { useComposedRefs } from \"../lib/compose-refs.js\";\nimport { DataGridCell } from \"./data-grid-cell.js\";\nimport type { CellPosition, Direction, RowHeightValue } from \"./types.js\";\nimport {\n flexRender,\n getCellKey,\n getColumnBorderVisibility,\n getColumnPinningStyle,\n getRowHeightValue\n} from \"./utils.js\";\n\ninterface DataGridRowProps<TData> extends React.ComponentProps<\"div\"> {\n row: Row<TData>;\n tableMeta: TableMeta<TData>;\n virtualItem: VirtualItem;\n measureElement: (node: Element | null) => void;\n rowMapRef: React.RefObject<Map<number, HTMLDivElement>>;\n rowHeight: RowHeightValue;\n columnVisibility: VisibilityState;\n columnPinning: ColumnPinningState;\n focusedCell: CellPosition | null;\n editingCell: CellPosition | null;\n cellSelectionKeys: Set<string>;\n searchMatchColumns: Set<string> | null;\n activeSearchMatch: CellPosition | null;\n dir: Direction;\n readOnly: boolean;\n stretchColumns: boolean;\n adjustLayout: boolean;\n}\n\nexport const DataGridRow = React.memo(DataGridRowImpl, (prev, next) => {\n const prevRowIndex = prev.virtualItem.index;\n const nextRowIndex = next.virtualItem.index;\n\n // Re-render if row identity changed\n if (prev.row.id !== next.row.id) {\n return false;\n }\n\n // Re-render if row data (original) reference changed\n if (prev.row.original !== next.row.original) {\n return false;\n }\n\n // Re-render if virtual position changed (handles transform updates)\n if (prev.virtualItem.start !== next.virtualItem.start) {\n return false;\n }\n\n // Re-render if focus state changed for this row\n const prevHasFocus = prev.focusedCell?.rowIndex === prevRowIndex;\n const nextHasFocus = next.focusedCell?.rowIndex === nextRowIndex;\n\n if (prevHasFocus !== nextHasFocus) {\n return false;\n }\n\n // Re-render if focused column changed within this row\n if (nextHasFocus && prevHasFocus) {\n if (prev.focusedCell?.columnId !== next.focusedCell?.columnId) {\n return false;\n }\n }\n\n // Re-render if editing state changed for this row\n const prevHasEditing = prev.editingCell?.rowIndex === prevRowIndex;\n const nextHasEditing = next.editingCell?.rowIndex === nextRowIndex;\n\n if (prevHasEditing !== nextHasEditing) {\n return false;\n }\n\n // Re-render if editing column changed within this row\n if (nextHasEditing && prevHasEditing) {\n if (prev.editingCell?.columnId !== next.editingCell?.columnId) {\n return false;\n }\n }\n\n // Re-render if this row's selected cells changed\n // Using stable Set reference that only includes this row's cells\n if (prev.cellSelectionKeys !== next.cellSelectionKeys) {\n return false;\n }\n\n // Re-render if column visibility changed\n if (prev.columnVisibility !== next.columnVisibility) {\n return false;\n }\n\n // Re-render if row height changed\n if (prev.rowHeight !== next.rowHeight) {\n return false;\n }\n\n // Re-render if column pinning state changed\n if (prev.columnPinning !== next.columnPinning) {\n return false;\n }\n\n // Re-render if readOnly changed\n if (prev.readOnly !== next.readOnly) {\n return false;\n }\n\n // Re-render if search match columns changed for this row\n if (prev.searchMatchColumns !== next.searchMatchColumns) {\n return false;\n }\n\n // Re-render if active search match changed for this row\n if (prev.activeSearchMatch?.columnId !== next.activeSearchMatch?.columnId) {\n return false;\n }\n\n // Re-render if direction changed\n if (prev.dir !== next.dir) {\n return false;\n }\n\n // Re-render if adjustLayout state changed\n if (prev.adjustLayout !== next.adjustLayout) {\n return false;\n }\n\n // Re-render if stretchColumns changed\n if (prev.stretchColumns !== next.stretchColumns) {\n return false;\n }\n\n // Skip re-render - props are equal\n return true;\n}) as typeof DataGridRowImpl;\n\nfunction DataGridRowImpl<TData>({\n row,\n tableMeta,\n virtualItem,\n measureElement,\n rowMapRef,\n rowHeight,\n columnVisibility,\n columnPinning,\n focusedCell,\n editingCell,\n cellSelectionKeys,\n searchMatchColumns,\n activeSearchMatch,\n dir,\n readOnly,\n stretchColumns,\n adjustLayout,\n className,\n style,\n ref,\n ...props\n}: DataGridRowProps<TData>) {\n const virtualRowIndex = virtualItem.index;\n\n const onRowChange = React.useCallback(\n (node: HTMLDivElement | null) => {\n if (typeof virtualRowIndex === \"undefined\") return;\n\n if (node) {\n measureElement(node);\n rowMapRef.current?.set(virtualRowIndex, node);\n } else {\n rowMapRef.current?.delete(virtualRowIndex);\n }\n },\n [virtualRowIndex, measureElement, rowMapRef]\n );\n\n const rowRef = useComposedRefs(ref, onRowChange);\n\n const isRowSelected = row.getIsSelected();\n\n // Memoize visible cells to avoid recreating cell array on every render\n // Though TanStack returns new Cell wrappers, memoizing the array helps React's reconciliation\n // biome-ignore lint/correctness/useExhaustiveDependencies: columnVisibility and columnPinning are used for calculating the visible cells\n const visibleCells = React.useMemo(() => row.getVisibleCells(), [row, columnVisibility, columnPinning]);\n\n return (\n <div\n key={row.id}\n role=\"row\"\n aria-rowindex={virtualRowIndex + 2}\n aria-selected={isRowSelected}\n data-index={virtualRowIndex}\n data-slot=\"grid-row\"\n tabIndex={-1}\n {...props}\n ref={rowRef}\n className={cn(\n \"absolute flex w-full border-b [content-visibility:auto]\",\n !adjustLayout && \"will-change-transform\",\n className\n )}\n style={{\n height: `${getRowHeightValue(rowHeight)}px`,\n ...(adjustLayout ? { top: `${virtualItem.start}px` } : { transform: `translateY(${virtualItem.start}px)` }),\n ...style\n }}\n >\n {visibleCells.map((cell, colIndex) => {\n const columnId = cell.column.id;\n\n const isCellFocused = focusedCell?.rowIndex === virtualRowIndex && focusedCell?.columnId === columnId;\n const isCellEditing = editingCell?.rowIndex === virtualRowIndex && editingCell?.columnId === columnId;\n const isCellSelected = cellSelectionKeys?.has(getCellKey(virtualRowIndex, columnId)) ?? false;\n\n const isSearchMatch = searchMatchColumns?.has(columnId) ?? false;\n const isActiveSearchMatch = activeSearchMatch?.columnId === columnId;\n\n const nextCell = visibleCells[colIndex + 1];\n const isLastColumn = colIndex === visibleCells.length - 1;\n const { showEndBorder, showStartBorder } = getColumnBorderVisibility({\n column: cell.column,\n nextColumn: nextCell?.column,\n isLastColumn\n });\n\n return (\n <div\n key={cell.id}\n role=\"gridcell\"\n aria-colindex={colIndex + 1}\n data-highlighted={isCellFocused ? \"\" : undefined}\n data-slot=\"grid-cell\"\n tabIndex={-1}\n className={cn({\n grow: stretchColumns && columnId !== \"select\",\n \"border-e\": showEndBorder && columnId !== \"select\",\n \"border-s\": showStartBorder && columnId !== \"select\"\n })}\n style={{\n ...getColumnPinningStyle({ column: cell.column, dir }),\n width: `calc(var(--col-${columnId}-size) * 1px)`\n }}\n >\n {typeof cell.column.columnDef.header === \"function\" ? (\n <div\n className={cn(\"size-full px-3 py-1.5\", {\n // `--accent` là bậc tint TRẠNG THÁI của gói (Tabs/Switch/Progress dùng đúng nó\n // để nói \"đang bật\"). `bg-primary/10` là gold pha 10% — 1,05:1, một dấu hiệu giả.\n \"bg-accent\": isRowSelected\n })}\n >\n {flexRender(cell.column.columnDef.cell, cell.getContext())}\n </div>\n ) : (\n <DataGridCell\n cell={cell}\n tableMeta={tableMeta}\n rowIndex={virtualRowIndex}\n columnId={columnId}\n rowHeight={rowHeight}\n isFocused={isCellFocused}\n isEditing={isCellEditing}\n isSelected={isCellSelected}\n isSearchMatch={isSearchMatch}\n isActiveSearchMatch={isActiveSearchMatch}\n readOnly={readOnly}\n />\n )}\n </div>\n );\n })}\n </div>\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -4,8 +4,8 @@ import { ChevronDown, ChevronUp, X } from "lucide-react";
|
|
|
4
4
|
import * as React from "react";
|
|
5
5
|
import { Button } from "../components/ui/button.js";
|
|
6
6
|
import { Input } from "../components/ui/input.js";
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
7
|
+
import { useAsRef } from "../lib/use-as-ref.js";
|
|
8
|
+
import { useDataGridMessages } from "./data-grid-locale.js";
|
|
9
9
|
import { useDebouncedCallback } from "./use-debounced-callback.js";
|
|
10
10
|
function onTriggerPointerDown(event) {
|
|
11
11
|
const target = event.target;
|
|
@@ -43,6 +43,7 @@ function DataGridSearchImpl({
|
|
|
43
43
|
onNavigateToNextMatch,
|
|
44
44
|
onNavigateToPrevMatch
|
|
45
45
|
}) {
|
|
46
|
+
const msg = useDataGridMessages();
|
|
46
47
|
const propsRef = useAsRef({
|
|
47
48
|
onSearchOpenChange,
|
|
48
49
|
onSearchQueryChange,
|
|
@@ -153,7 +154,7 @@ function DataGridSearchImpl({
|
|
|
153
154
|
onClick: onPrevMatch,
|
|
154
155
|
onPointerDown: onTriggerPointerDown,
|
|
155
156
|
disabled: searchMatches.length === 0,
|
|
156
|
-
children: /* @__PURE__ */ jsx(ChevronUp, {})
|
|
157
|
+
children: /* @__PURE__ */ jsx(ChevronUp, { className: "size-3.5" })
|
|
157
158
|
}
|
|
158
159
|
),
|
|
159
160
|
/* @__PURE__ */ jsx(
|
|
@@ -166,10 +167,10 @@ function DataGridSearchImpl({
|
|
|
166
167
|
onClick: onNextMatch,
|
|
167
168
|
onPointerDown: onTriggerPointerDown,
|
|
168
169
|
disabled: searchMatches.length === 0,
|
|
169
|
-
children: /* @__PURE__ */ jsx(ChevronDown, {})
|
|
170
|
+
children: /* @__PURE__ */ jsx(ChevronDown, { className: "size-3.5" })
|
|
170
171
|
}
|
|
171
172
|
),
|
|
172
|
-
/* @__PURE__ */ jsx(Button, { "aria-label": msg.search.close, variant: "ghost", size: "icon", className: "size-7", onClick: onClose, children: /* @__PURE__ */ jsx(X, {}) })
|
|
173
|
+
/* @__PURE__ */ jsx(Button, { "aria-label": msg.search.close, variant: "ghost", size: "icon", className: "size-7", onClick: onClose, children: /* @__PURE__ */ jsx(X, { className: "size-3.5" }) })
|
|
173
174
|
] })
|
|
174
175
|
] }),
|
|
175
176
|
/* @__PURE__ */ jsx("div", { role: "status", className: "flex items-center gap-1 whitespace-nowrap text-muted-foreground text-xs", children: searchMatches.length > 0 ? /* @__PURE__ */ jsx("span", { children: msg.search.matchPosition(matchIndex + 1, searchMatches.length) }) : hasQuery ? /* @__PURE__ */ jsx("span", { children: msg.search.noResults }) : /* @__PURE__ */ jsx("span", { children: msg.search.typeToSearch }) })
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/data-grid/data-grid-search.tsx"],"sourcesContent":["\"use client\";\n\nimport { ChevronDown, ChevronUp, X } from \"lucide-react\";\nimport * as React from \"react\";\nimport { Button } from \"../components/ui/button.js\";\nimport { Input } from \"../components/ui/input.js\";\nimport { msg } from \"./messages.js\";\nimport type { SearchState } from \"./types.js\";\nimport { useAsRef } from \"./use-as-ref.js\";\nimport { useDebouncedCallback } from \"./use-debounced-callback.js\";\n\nfunction onTriggerPointerDown(event: React.PointerEvent<HTMLButtonElement>) {\n const target = event.target;\n if (!(target instanceof HTMLElement)) return;\n if (target.hasPointerCapture(event.pointerId)) {\n target.releasePointerCapture(event.pointerId);\n }\n\n // Prevent the trigger from stealing focus away from the input\n if (\n event.button === 0 &&\n event.ctrlKey === false &&\n event.pointerType === \"mouse\" &&\n !(event.target instanceof HTMLInputElement)\n ) {\n event.preventDefault();\n }\n}\n\ninterface DataGridSearchProps extends SearchState {}\n\nexport const DataGridSearch = React.memo(DataGridSearchImpl, (prev, next) => {\n if (prev.searchOpen !== next.searchOpen) return false;\n\n if (!next.searchOpen) return true;\n\n // Exclude searchQuery because the input is uncontrolled, and hasQuery state handles the status text\n if (prev.matchIndex !== next.matchIndex) return false;\n\n if (prev.searchMatches.length !== next.searchMatches.length) return false;\n\n for (let i = 0; i < prev.searchMatches.length; i++) {\n const prevMatch = prev.searchMatches[i];\n const nextMatch = next.searchMatches[i];\n\n if (!prevMatch || !nextMatch) return false;\n\n if (prevMatch.rowIndex !== nextMatch.rowIndex || prevMatch.columnId !== nextMatch.columnId) {\n return false;\n }\n }\n\n return true;\n});\n\nfunction DataGridSearchImpl({\n searchMatches,\n matchIndex,\n searchOpen,\n onSearchOpenChange,\n searchQuery,\n onSearchQueryChange,\n onSearch,\n onNavigateToNextMatch,\n onNavigateToPrevMatch\n}: DataGridSearchProps) {\n const propsRef = useAsRef({\n onSearchOpenChange,\n onSearchQueryChange,\n onSearch,\n onNavigateToNextMatch,\n onNavigateToPrevMatch\n });\n\n const inputRef = React.useRef<HTMLInputElement>(null);\n const isComposingRef = React.useRef(false);\n const [hasQuery, setHasQuery] = React.useState(searchQuery.length > 0);\n\n React.useEffect(() => {\n if (searchOpen) {\n requestAnimationFrame(() => {\n inputRef.current?.focus();\n });\n return;\n }\n\n isComposingRef.current = false;\n setHasQuery(false);\n }, [searchOpen]);\n\n React.useEffect(() => {\n if (!searchOpen) return;\n\n function onEscape(event: KeyboardEvent) {\n if (event.key === \"Escape\") {\n event.preventDefault();\n propsRef.current.onSearchOpenChange(false);\n }\n }\n\n document.addEventListener(\"keydown\", onEscape);\n return () => document.removeEventListener(\"keydown\", onEscape);\n }, [searchOpen, propsRef]);\n\n const debouncedSearch = useDebouncedCallback((query: string) => {\n propsRef.current.onSearch(query);\n }, 150);\n\n function onCompositionStart() {\n isComposingRef.current = true;\n }\n\n function onCompositionEnd(event: React.CompositionEvent<HTMLInputElement>) {\n isComposingRef.current = false;\n const value = event.currentTarget.value;\n setHasQuery(value.length > 0);\n propsRef.current.onSearchQueryChange(value);\n debouncedSearch(value);\n }\n\n function onKeyDown(event: React.KeyboardEvent) {\n event.stopPropagation();\n\n if (event.key === \"Enter\") {\n if (event.nativeEvent.isComposing) return;\n event.preventDefault();\n if (event.shiftKey) {\n propsRef.current.onNavigateToPrevMatch();\n } else {\n propsRef.current.onNavigateToNextMatch();\n }\n }\n }\n\n function onChange(event: React.ChangeEvent<HTMLInputElement>) {\n if (isComposingRef.current) return;\n const value = event.target.value;\n setHasQuery(value.length > 0);\n propsRef.current.onSearchQueryChange(value);\n debouncedSearch(value);\n }\n\n function onClose() {\n propsRef.current.onSearchOpenChange(false);\n }\n\n function onPrevMatch() {\n propsRef.current.onNavigateToPrevMatch();\n }\n\n function onNextMatch() {\n propsRef.current.onNavigateToNextMatch();\n }\n\n if (!searchOpen) return null;\n\n return (\n <div\n role=\"search\"\n data-slot=\"grid-search\"\n // `shadow-overlay`, KHÔNG `shadow-lg`: bóng của gói đi qua `--elevation-*` nên nó đổi\n // theo sáng/tối; `shadow-lg` của Tailwind là rgba đen cố định, ở dark gần như vô hình.\n className=\"fade-in-0 slide-in-from-top-2 absolute end-4 top-4 z-50 flex animate-in flex-col gap-2 rounded-lg border bg-popover p-2 shadow-overlay\"\n >\n <div className=\"flex items-center gap-2\">\n <Input\n autoComplete=\"off\"\n autoCorrect=\"off\"\n autoCapitalize=\"off\"\n spellCheck={false}\n placeholder={msg.search.placeholder}\n // placeholder biến mất ngay khi người dùng gõ → vẫn phải có nhãn riêng\n aria-label={msg.search.label}\n className=\"h-8 w-64\"\n ref={inputRef}\n defaultValue={searchQuery}\n onChange={onChange}\n onKeyDown={onKeyDown}\n onCompositionStart={onCompositionStart}\n onCompositionEnd={onCompositionEnd}\n />\n <div className=\"flex items-center gap-1\">\n <Button\n aria-label={msg.search.prevMatch}\n variant=\"ghost\"\n size=\"icon\"\n className=\"size-7\"\n onClick={onPrevMatch}\n onPointerDown={onTriggerPointerDown}\n disabled={searchMatches.length === 0}\n >\n <ChevronUp />\n </Button>\n <Button\n aria-label={msg.search.nextMatch}\n variant=\"ghost\"\n size=\"icon\"\n className=\"size-7\"\n onClick={onNextMatch}\n onPointerDown={onTriggerPointerDown}\n disabled={searchMatches.length === 0}\n >\n <ChevronDown />\n </Button>\n <Button aria-label={msg.search.close} variant=\"ghost\" size=\"icon\" className=\"size-7\" onClick={onClose}>\n <X />\n </Button>\n </div>\n </div>\n <div role=\"status\" className=\"flex items-center gap-1 whitespace-nowrap text-muted-foreground text-xs\">\n {searchMatches.length > 0 ? (\n <span>{msg.search.matchPosition(matchIndex + 1, searchMatches.length)}</span>\n ) : hasQuery ? (\n <span>{msg.search.noResults}</span>\n ) : (\n <span>{msg.search.typeToSearch}</span>\n )}\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/data-grid/data-grid-search.tsx"],"sourcesContent":["\"use client\";\n\nimport { ChevronDown, ChevronUp, X } from \"lucide-react\";\nimport * as React from \"react\";\nimport { Button } from \"../components/ui/button.js\";\nimport { Input } from \"../components/ui/input.js\";\nimport { useAsRef } from \"../lib/use-as-ref.js\";\nimport { useDataGridMessages } from \"./data-grid-locale.js\";\nimport type { SearchState } from \"./types.js\";\nimport { useDebouncedCallback } from \"./use-debounced-callback.js\";\n\nfunction onTriggerPointerDown(event: React.PointerEvent<HTMLButtonElement>) {\n const target = event.target;\n if (!(target instanceof HTMLElement)) return;\n if (target.hasPointerCapture(event.pointerId)) {\n target.releasePointerCapture(event.pointerId);\n }\n\n // Prevent the trigger from stealing focus away from the input\n if (\n event.button === 0 &&\n event.ctrlKey === false &&\n event.pointerType === \"mouse\" &&\n !(event.target instanceof HTMLInputElement)\n ) {\n event.preventDefault();\n }\n}\n\ninterface DataGridSearchProps extends SearchState {}\n\nexport const DataGridSearch = React.memo(DataGridSearchImpl, (prev, next) => {\n if (prev.searchOpen !== next.searchOpen) return false;\n\n if (!next.searchOpen) return true;\n\n // Exclude searchQuery because the input is uncontrolled, and hasQuery state handles the status text\n if (prev.matchIndex !== next.matchIndex) return false;\n\n if (prev.searchMatches.length !== next.searchMatches.length) return false;\n\n for (let i = 0; i < prev.searchMatches.length; i++) {\n const prevMatch = prev.searchMatches[i];\n const nextMatch = next.searchMatches[i];\n\n if (!prevMatch || !nextMatch) return false;\n\n if (prevMatch.rowIndex !== nextMatch.rowIndex || prevMatch.columnId !== nextMatch.columnId) {\n return false;\n }\n }\n\n return true;\n});\n\nfunction DataGridSearchImpl({\n searchMatches,\n matchIndex,\n searchOpen,\n onSearchOpenChange,\n searchQuery,\n onSearchQueryChange,\n onSearch,\n onNavigateToNextMatch,\n onNavigateToPrevMatch\n}: DataGridSearchProps) {\n const msg = useDataGridMessages();\n\n const propsRef = useAsRef({\n onSearchOpenChange,\n onSearchQueryChange,\n onSearch,\n onNavigateToNextMatch,\n onNavigateToPrevMatch\n });\n\n const inputRef = React.useRef<HTMLInputElement>(null);\n const isComposingRef = React.useRef(false);\n const [hasQuery, setHasQuery] = React.useState(searchQuery.length > 0);\n\n React.useEffect(() => {\n if (searchOpen) {\n requestAnimationFrame(() => {\n inputRef.current?.focus();\n });\n return;\n }\n\n isComposingRef.current = false;\n setHasQuery(false);\n }, [searchOpen]);\n\n React.useEffect(() => {\n if (!searchOpen) return;\n\n function onEscape(event: KeyboardEvent) {\n if (event.key === \"Escape\") {\n event.preventDefault();\n propsRef.current.onSearchOpenChange(false);\n }\n }\n\n document.addEventListener(\"keydown\", onEscape);\n return () => document.removeEventListener(\"keydown\", onEscape);\n }, [searchOpen, propsRef]);\n\n const debouncedSearch = useDebouncedCallback((query: string) => {\n propsRef.current.onSearch(query);\n }, 150);\n\n function onCompositionStart() {\n isComposingRef.current = true;\n }\n\n function onCompositionEnd(event: React.CompositionEvent<HTMLInputElement>) {\n isComposingRef.current = false;\n const value = event.currentTarget.value;\n setHasQuery(value.length > 0);\n propsRef.current.onSearchQueryChange(value);\n debouncedSearch(value);\n }\n\n function onKeyDown(event: React.KeyboardEvent) {\n event.stopPropagation();\n\n if (event.key === \"Enter\") {\n if (event.nativeEvent.isComposing) return;\n event.preventDefault();\n if (event.shiftKey) {\n propsRef.current.onNavigateToPrevMatch();\n } else {\n propsRef.current.onNavigateToNextMatch();\n }\n }\n }\n\n function onChange(event: React.ChangeEvent<HTMLInputElement>) {\n if (isComposingRef.current) return;\n const value = event.target.value;\n setHasQuery(value.length > 0);\n propsRef.current.onSearchQueryChange(value);\n debouncedSearch(value);\n }\n\n function onClose() {\n propsRef.current.onSearchOpenChange(false);\n }\n\n function onPrevMatch() {\n propsRef.current.onNavigateToPrevMatch();\n }\n\n function onNextMatch() {\n propsRef.current.onNavigateToNextMatch();\n }\n\n if (!searchOpen) return null;\n\n return (\n <div\n role=\"search\"\n data-slot=\"grid-search\"\n // `shadow-overlay`, KHÔNG `shadow-lg`: bóng của gói đi qua `--elevation-*` nên nó đổi\n // theo sáng/tối; `shadow-lg` của Tailwind là rgba đen cố định, ở dark gần như vô hình.\n className=\"fade-in-0 slide-in-from-top-2 absolute end-4 top-4 z-50 flex animate-in flex-col gap-2 rounded-lg border bg-popover p-2 shadow-overlay\"\n >\n <div className=\"flex items-center gap-2\">\n <Input\n autoComplete=\"off\"\n autoCorrect=\"off\"\n autoCapitalize=\"off\"\n spellCheck={false}\n placeholder={msg.search.placeholder}\n // placeholder biến mất ngay khi người dùng gõ → vẫn phải có nhãn riêng\n aria-label={msg.search.label}\n className=\"h-8 w-64\"\n ref={inputRef}\n defaultValue={searchQuery}\n onChange={onChange}\n onKeyDown={onKeyDown}\n onCompositionStart={onCompositionStart}\n onCompositionEnd={onCompositionEnd}\n />\n <div className=\"flex items-center gap-1\">\n <Button\n aria-label={msg.search.prevMatch}\n variant=\"ghost\"\n size=\"icon\"\n className=\"size-7\"\n onClick={onPrevMatch}\n onPointerDown={onTriggerPointerDown}\n disabled={searchMatches.length === 0}\n >\n <ChevronUp className=\"size-3.5\" />\n </Button>\n <Button\n aria-label={msg.search.nextMatch}\n variant=\"ghost\"\n size=\"icon\"\n className=\"size-7\"\n onClick={onNextMatch}\n onPointerDown={onTriggerPointerDown}\n disabled={searchMatches.length === 0}\n >\n <ChevronDown className=\"size-3.5\" />\n </Button>\n <Button aria-label={msg.search.close} variant=\"ghost\" size=\"icon\" className=\"size-7\" onClick={onClose}>\n <X className=\"size-3.5\" />\n </Button>\n </div>\n </div>\n <div role=\"status\" className=\"flex items-center gap-1 whitespace-nowrap text-muted-foreground text-xs\">\n {searchMatches.length > 0 ? (\n <span>{msg.search.matchPosition(matchIndex + 1, searchMatches.length)}</span>\n ) : hasQuery ? (\n <span>{msg.search.noResults}</span>\n ) : (\n <span>{msg.search.typeToSearch}</span>\n )}\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -3,7 +3,7 @@ import { jsx, jsxs } from "react/jsx-runtime";
|
|
|
3
3
|
import * as React from "react";
|
|
4
4
|
import { Checkbox } from "../components/ui/checkbox.js";
|
|
5
5
|
import { cn } from "../lib/cn.js";
|
|
6
|
-
import {
|
|
6
|
+
import { useDataGridMessages } from "./data-grid-locale.js";
|
|
7
7
|
function DataGridSelectHitbox({ htmlFor, children, size, debug }) {
|
|
8
8
|
return /* @__PURE__ */ jsxs(
|
|
9
9
|
"div",
|
|
@@ -79,6 +79,7 @@ function DataGridSelectCheckbox({
|
|
|
79
79
|
return /* @__PURE__ */ jsx(DataGridSelectHitbox, { htmlFor: id, size: hitboxSize, debug, children: /* @__PURE__ */ jsx(Checkbox, { id, className: cn("relative transition-[shadow,border]", className), checked, ...props }) });
|
|
80
80
|
}
|
|
81
81
|
function DataGridSelectHeader({ table, hitboxSize, readOnly, debug }) {
|
|
82
|
+
const msg = useDataGridMessages();
|
|
82
83
|
const onCheckedChange = React.useCallback((value) => table.toggleAllPageRowsSelected(value), [table]);
|
|
83
84
|
if (readOnly) {
|
|
84
85
|
return /* @__PURE__ */ jsx("div", { className: "mt-1 flex items-center ps-1 text-muted-foreground text-sm", children: "#" });
|
|
@@ -102,6 +103,7 @@ function DataGridSelectCell({
|
|
|
102
103
|
readOnly,
|
|
103
104
|
debug
|
|
104
105
|
}) {
|
|
106
|
+
const msg = useDataGridMessages();
|
|
105
107
|
const meta = table.options.meta;
|
|
106
108
|
const rowNumber = enableRowMarkers ? meta?.getVisualRowIndex?.(row.id) ?? row.index + 1 : void 0;
|
|
107
109
|
const onCheckedChange = React.useCallback(
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/data-grid/data-grid-select-column.tsx"],"sourcesContent":["\"use client\";\n\nimport type { CellContext, ColumnDef, HeaderContext } from \"@tanstack/react-table\";\nimport * as React from \"react\";\nimport { Checkbox } from \"../components/ui/checkbox.js\";\nimport { cn } from \"../lib/cn.js\";\nimport {
|
|
1
|
+
{"version":3,"sources":["../../src/data-grid/data-grid-select-column.tsx"],"sourcesContent":["\"use client\";\n\nimport type { CellContext, ColumnDef, HeaderContext } from \"@tanstack/react-table\";\nimport * as React from \"react\";\nimport { Checkbox } from \"../components/ui/checkbox.js\";\nimport { cn } from \"../lib/cn.js\";\nimport { useDataGridMessages } from \"./data-grid-locale.js\";\n\ntype HitboxSize = \"default\" | \"sm\" | \"lg\";\n\ninterface DataGridSelectHitboxProps {\n htmlFor: string;\n children: React.ReactNode;\n size?: HitboxSize;\n debug?: boolean;\n}\n\nfunction DataGridSelectHitbox({ htmlFor, children, size, debug }: DataGridSelectHitboxProps) {\n return (\n <div\n className={cn(\n \"group relative -my-1.5 h-[calc(100%+0.75rem)] py-1.5\",\n size === \"default\" && \"-ms-3 -me-2 ps-3 pe-2\",\n size === \"sm\" && \"-ms-3 -me-1.5 ps-3 pe-1.5\",\n size === \"lg\" && \"-mx-3 px-3\"\n )}\n >\n {children}\n {/* biome-ignore lint/a11y/noLabelWithoutControl: htmlFor trỏ tới Checkbox ngay bên trên (vùng bấm mở rộng) */}\n <label\n htmlFor={htmlFor}\n className={cn(\n \"absolute inset-0 cursor-pointer\",\n debug && \"border border-destructive-ink border-dashed bg-destructive/20\"\n )}\n />\n </div>\n );\n}\n\ninterface DataGridSelectCheckboxProps extends Omit<React.ComponentProps<typeof Checkbox>, \"id\"> {\n rowNumber?: number;\n hitboxSize?: HitboxSize;\n debug?: boolean;\n}\n\nfunction DataGridSelectCheckbox({\n rowNumber,\n hitboxSize,\n debug,\n checked,\n className,\n ...props\n}: DataGridSelectCheckboxProps) {\n const id = React.useId();\n\n if (rowNumber !== undefined) {\n return (\n <DataGridSelectHitbox htmlFor={id} size={hitboxSize} debug={debug}>\n <div\n aria-hidden=\"true\"\n className={cn(\n // Ẩn bằng `visibility`, KHÔNG bằng `opacity-0`: số thứ tự là chữ, và cổng\n // `lint:a11y` nhân opacity vào màu chữ nên `opacity-0` đọc ra 1,00:1 — một chỗ\n // \"chữ không đọc được\" mà cổng không thể biết là cố ý. `invisible` cũng đúng hơn\n // về ngữ nghĩa: nó rút phần tử khỏi cây trợ năng thay vì để nó vẫn được đọc lên.\n \"pointer-events-none absolute start-3 top-1.5 flex size-4 items-center justify-center text-muted-foreground text-xs tabular-nums group-hover:invisible\",\n checked && \"invisible\"\n )}\n >\n {rowNumber}\n </div>\n <Checkbox\n id={id}\n className={cn(\n // Không ghi đè viền hover: `Checkbox` của gói đã đi qua `--choice-edge` /\n // `--choice-edge-strong`. `border-primary/40` vừa sai vai trò (bậc tô NỀN đem vẽ\n // NÉT) vừa chỉ 1,25:1 ở light.\n \"relative transition-[shadow,border,opacity]\",\n // Ở đây PHẢI là `opacity`, không phải `invisible` như số thứ tự bên trên: đây là\n // checkbox thật, `visibility:hidden` sẽ làm nó mất luôn khả năng nhận Tab.\n \"opacity-0 group-hover:opacity-100 data-[state=checked]:opacity-100\",\n className\n )}\n checked={checked}\n {...props}\n />\n </DataGridSelectHitbox>\n );\n }\n\n return (\n <DataGridSelectHitbox htmlFor={id} size={hitboxSize} debug={debug}>\n <Checkbox id={id} className={cn(\"relative transition-[shadow,border]\", className)} checked={checked} {...props} />\n </DataGridSelectHitbox>\n );\n}\n\ninterface DataGridSelectHeaderProps<TData> extends Pick<HeaderContext<TData, unknown>, \"table\"> {\n hitboxSize?: HitboxSize;\n readOnly?: boolean;\n debug?: boolean;\n}\n\nfunction DataGridSelectHeader<TData>({ table, hitboxSize, readOnly, debug }: DataGridSelectHeaderProps<TData>) {\n const msg = useDataGridMessages();\n const onCheckedChange = React.useCallback((value: boolean) => table.toggleAllPageRowsSelected(value), [table]);\n\n if (readOnly) {\n return <div className=\"mt-1 flex items-center ps-1 text-muted-foreground text-sm\">#</div>;\n }\n\n return (\n <DataGridSelectCheckbox\n aria-label={msg.select.all}\n checked={table.getIsAllPageRowsSelected() || (table.getIsSomePageRowsSelected() && \"indeterminate\")}\n onCheckedChange={onCheckedChange}\n hitboxSize={hitboxSize}\n debug={debug}\n />\n );\n}\n\ninterface DataGridSelectCellProps<TData> extends Pick<CellContext<TData, unknown>, \"row\" | \"table\"> {\n hitboxSize?: HitboxSize;\n enableRowMarkers?: boolean;\n readOnly?: boolean;\n debug?: boolean;\n}\n\nfunction DataGridSelectCell<TData>({\n row,\n table,\n hitboxSize,\n enableRowMarkers,\n readOnly,\n debug\n}: DataGridSelectCellProps<TData>) {\n const msg = useDataGridMessages();\n const meta = table.options.meta;\n const rowNumber = enableRowMarkers ? (meta?.getVisualRowIndex?.(row.id) ?? row.index + 1) : undefined;\n\n const onCheckedChange = React.useCallback(\n (value: boolean) => {\n if (meta?.onRowSelect) {\n meta.onRowSelect(row.id, value, false);\n } else {\n row.toggleSelected(value);\n }\n },\n [meta, row]\n );\n\n const onClick = React.useCallback(\n (event: React.MouseEvent<HTMLButtonElement>) => {\n if (event.shiftKey) {\n event.preventDefault();\n meta?.onRowSelect?.(row.id, !row.getIsSelected(), true);\n }\n },\n [meta, row]\n );\n\n if (readOnly) {\n return (\n <div className=\"flex items-center ps-1 text-muted-foreground text-xs tabular-nums\">\n {rowNumber ?? row.index + 1}\n </div>\n );\n }\n\n return (\n <DataGridSelectCheckbox\n aria-label={rowNumber ? msg.select.rowNumber(rowNumber) : msg.select.row}\n checked={row.getIsSelected()}\n onCheckedChange={onCheckedChange}\n onClick={onClick}\n rowNumber={rowNumber}\n hitboxSize={hitboxSize}\n debug={debug}\n />\n );\n}\n\ninterface GetDataGridSelectColumnOptions<TData> extends Omit<Partial<ColumnDef<TData>>, \"id\" | \"header\" | \"cell\"> {\n enableRowMarkers?: boolean;\n readOnly?: boolean;\n hitboxSize?: HitboxSize;\n debug?: boolean;\n}\n\nexport function getDataGridSelectColumn<TData>({\n size = 40,\n hitboxSize = \"default\",\n enableHiding = false,\n enableResizing = false,\n enableSorting = false,\n enableRowMarkers = false,\n readOnly = false,\n debug = false,\n ...props\n}: GetDataGridSelectColumnOptions<TData> = {}): ColumnDef<TData> {\n return {\n id: \"select\",\n header: ({ table }) => (\n <DataGridSelectHeader table={table} hitboxSize={hitboxSize} readOnly={readOnly} debug={debug} />\n ),\n cell: ({ row, table }) => (\n <DataGridSelectCell\n row={row}\n table={table}\n enableRowMarkers={enableRowMarkers}\n readOnly={readOnly}\n hitboxSize={hitboxSize}\n debug={debug}\n />\n ),\n size,\n enableHiding,\n enableResizing,\n enableSorting,\n ...props\n };\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,12 +1,23 @@
|
|
|
1
1
|
import { Table } from '@tanstack/react-table';
|
|
2
2
|
import * as React from 'react';
|
|
3
3
|
import { PopoverContent } from '../components/ui/popover.js';
|
|
4
|
+
import { DataGridLocale } from './messages.js';
|
|
5
|
+
import { DataGridMessages } from './messages-en.js';
|
|
4
6
|
import '@radix-ui/react-popover';
|
|
7
|
+
import './messages-vi.js';
|
|
5
8
|
|
|
6
9
|
interface DataGridSortMenuProps<TData> extends React.ComponentProps<typeof PopoverContent> {
|
|
7
10
|
table: Table<TData>;
|
|
8
11
|
disabled?: boolean;
|
|
12
|
+
/**
|
|
13
|
+
* Ngôn ngữ của menu: `"en"` (mặc định) · `"vi"`, hoặc cả một bảng chuỗi tự soạn.
|
|
14
|
+
*
|
|
15
|
+
* ⚠ Thanh công cụ nằm NGOÀI `<DataGrid>`, nên `locale` truyền cho lưới không với tới đây. Bọc
|
|
16
|
+
* cả màn bằng `DataGridLocaleProvider` (một lần, đúng cho mọi mảnh), hoặc truyền prop này cho
|
|
17
|
+
* từng menu. Prop thắng provider.
|
|
18
|
+
*/
|
|
19
|
+
locale?: DataGridLocale | DataGridMessages;
|
|
9
20
|
}
|
|
10
|
-
declare function DataGridSortMenu<TData>({ table, disabled, className, ...props }: DataGridSortMenuProps<TData>): React.JSX.Element;
|
|
21
|
+
declare function DataGridSortMenu<TData>({ table, disabled, className, locale, ...props }: DataGridSortMenuProps<TData>): React.JSX.Element;
|
|
11
22
|
|
|
12
23
|
export { DataGridSortMenu };
|
|
@@ -16,15 +16,24 @@ import {
|
|
|
16
16
|
import { Popover, PopoverContent, PopoverTrigger } from "../components/ui/popover.js";
|
|
17
17
|
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from "../components/ui/select.js";
|
|
18
18
|
import { cn } from "../lib/cn.js";
|
|
19
|
-
import {
|
|
19
|
+
import { DataGridLocaleProvider, useDataGridMessages, useResolvedDataGridMessages } from "./data-grid-locale.js";
|
|
20
20
|
import { Sortable, SortableContent, SortableItem, SortableItemHandle, SortableOverlay } from "./sortable.js";
|
|
21
21
|
const SORT_SHORTCUT_KEY = "s";
|
|
22
22
|
const REMOVE_SORT_SHORTCUTS = /* @__PURE__ */ new Set(["backspace", "delete"]);
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
23
|
+
function buildSortOrders(msg) {
|
|
24
|
+
return [
|
|
25
|
+
{ label: msg.sort.asc, value: "asc" },
|
|
26
|
+
{ label: msg.sort.desc, value: "desc" }
|
|
27
|
+
];
|
|
28
|
+
}
|
|
29
|
+
function DataGridSortMenu({
|
|
30
|
+
table,
|
|
31
|
+
disabled,
|
|
32
|
+
className,
|
|
33
|
+
locale,
|
|
34
|
+
...props
|
|
35
|
+
}) {
|
|
36
|
+
const msg = useResolvedDataGridMessages(locale);
|
|
28
37
|
const dir = useDirection();
|
|
29
38
|
const id = React.useId();
|
|
30
39
|
const labelId = React.useId();
|
|
@@ -96,18 +105,19 @@ function DataGridSortMenu({ table, disabled, className, ...props }) {
|
|
|
96
105
|
},
|
|
97
106
|
[sorting.length, onSortingReset]
|
|
98
107
|
);
|
|
99
|
-
return /* @__PURE__ */ jsxs(Sortable, { value: sorting, onValueChange: onSortingChange, getItemValue: (item) => item.id, children: [
|
|
108
|
+
return /* @__PURE__ */ jsx(DataGridLocaleProvider, { locale: msg, children: /* @__PURE__ */ jsxs(Sortable, { value: sorting, onValueChange: onSortingChange, getItemValue: (item) => item.id, children: [
|
|
100
109
|
/* @__PURE__ */ jsxs(Popover, { open, onOpenChange: setOpen, children: [
|
|
101
110
|
/* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
|
|
102
111
|
Button,
|
|
103
112
|
{
|
|
104
113
|
dir,
|
|
105
114
|
variant: "outline",
|
|
106
|
-
|
|
115
|
+
size: "sm",
|
|
116
|
+
className: "font-normal",
|
|
107
117
|
onKeyDown: onTriggerKeyDown,
|
|
108
118
|
disabled,
|
|
109
119
|
children: [
|
|
110
|
-
/* @__PURE__ */ jsx(ArrowDownUp, { "aria-hidden": "true", className: "text-muted-foreground" }),
|
|
120
|
+
/* @__PURE__ */ jsx(ArrowDownUp, { "aria-hidden": "true", className: "size-3.5 text-muted-foreground" }),
|
|
111
121
|
msg.sort.trigger,
|
|
112
122
|
sorting.length > 0 && /* @__PURE__ */ jsx(
|
|
113
123
|
"span",
|
|
@@ -175,7 +185,7 @@ function DataGridSortMenu({ table, disabled, className, ...props }) {
|
|
|
175
185
|
/* @__PURE__ */ jsx("div", { className: "size-8 shrink-0 rounded-sm bg-muted" }),
|
|
176
186
|
/* @__PURE__ */ jsx("div", { className: "size-8 shrink-0 rounded-sm bg-muted" })
|
|
177
187
|
] }) })
|
|
178
|
-
] });
|
|
188
|
+
] }) });
|
|
179
189
|
}
|
|
180
190
|
function DataTableSortItem({
|
|
181
191
|
sort,
|
|
@@ -186,6 +196,8 @@ function DataTableSortItem({
|
|
|
186
196
|
onSortUpdate,
|
|
187
197
|
onSortRemove
|
|
188
198
|
}) {
|
|
199
|
+
const msg = useDataGridMessages();
|
|
200
|
+
const sortOrders = React.useMemo(() => buildSortOrders(msg), [msg]);
|
|
189
201
|
const fieldListboxId = `${sortItemId}-field-listbox`;
|
|
190
202
|
const fieldTriggerId = `${sortItemId}-field-trigger`;
|
|
191
203
|
const directionListboxId = `${sortItemId}-direction-listbox`;
|
|
@@ -246,7 +258,7 @@ function DataTableSortItem({
|
|
|
246
258
|
onValueChange: (value) => onSortUpdate(sort.id, { desc: value === "desc" }),
|
|
247
259
|
children: [
|
|
248
260
|
/* @__PURE__ */ jsx(SelectTrigger, { "aria-controls": directionListboxId, "aria-label": msg.sort.title, className: "h-8 w-28 rounded", children: /* @__PURE__ */ jsx(SelectValue, {}) }),
|
|
249
|
-
/* @__PURE__ */ jsx(SelectContent, { id: directionListboxId, className: "min-w-[--radix-select-trigger-width]", children: /* @__PURE__ */ jsx(SelectGroup, { children:
|
|
261
|
+
/* @__PURE__ */ jsx(SelectContent, { id: directionListboxId, className: "min-w-[--radix-select-trigger-width]", children: /* @__PURE__ */ jsx(SelectGroup, { children: sortOrders.map((order) => /* @__PURE__ */ jsx(SelectItem, { value: order.value, children: order.label }, order.value)) }) })
|
|
250
262
|
]
|
|
251
263
|
}
|
|
252
264
|
),
|
|
@@ -259,10 +271,10 @@ function DataTableSortItem({
|
|
|
259
271
|
size: "icon",
|
|
260
272
|
className: "size-8 shrink-0 rounded",
|
|
261
273
|
onClick: () => onSortRemove(sort.id),
|
|
262
|
-
children: /* @__PURE__ */ jsx(Trash2, { "aria-hidden": "true" })
|
|
274
|
+
children: /* @__PURE__ */ jsx(Trash2, { "aria-hidden": "true", className: "size-3.5" })
|
|
263
275
|
}
|
|
264
276
|
),
|
|
265
|
-
/* @__PURE__ */ jsx(SortableItemHandle, { asChild: true, children: /* @__PURE__ */ jsx(Button, { "aria-label": msg.sort.drag, variant: "outline", size: "icon", className: "size-8 shrink-0 rounded", children: /* @__PURE__ */ jsx(GripVertical, { "aria-hidden": "true" }) }) })
|
|
277
|
+
/* @__PURE__ */ jsx(SortableItemHandle, { asChild: true, children: /* @__PURE__ */ jsx(Button, { "aria-label": msg.sort.drag, variant: "outline", size: "icon", className: "size-8 shrink-0 rounded", children: /* @__PURE__ */ jsx(GripVertical, { "aria-hidden": "true", className: "size-3.5" }) }) })
|
|
266
278
|
] }) });
|
|
267
279
|
}
|
|
268
280
|
export {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/data-grid/data-grid-sort-menu.tsx"],"sourcesContent":["\"use client\";\n\nimport { useDirection } from \"@radix-ui/react-direction\";\nimport type { ColumnSort, SortDirection, Table } from \"@tanstack/react-table\";\nimport { ArrowDownUp, ChevronsUpDown, GripVertical, Trash2 } from \"lucide-react\";\nimport * as React from \"react\";\nimport { badgeVariants } from \"../components/ui/badge.js\";\nimport { Button } from \"../components/ui/button.js\";\nimport {\n Command,\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n CommandList\n} from \"../components/ui/command.js\";\nimport { Popover, PopoverContent, PopoverTrigger } from \"../components/ui/popover.js\";\nimport { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from \"../components/ui/select.js\";\nimport { cn } from \"../lib/cn.js\";\nimport { msg } from \"./messages.js\";\nimport { Sortable, SortableContent, SortableItem, SortableItemHandle, SortableOverlay } from \"./sortable.js\";\n\nconst SORT_SHORTCUT_KEY = \"s\";\nconst REMOVE_SORT_SHORTCUTS = new Set([\"backspace\", \"delete\"]);\nconst SORT_ORDERS = [\n { label: msg.sort.asc, value: \"asc\" },\n { label: msg.sort.desc, value: \"desc\" }\n];\n\ninterface DataGridSortMenuProps<TData> extends React.ComponentProps<typeof PopoverContent> {\n table: Table<TData>;\n disabled?: boolean;\n}\n\nexport function DataGridSortMenu<TData>({ table, disabled, className, ...props }: DataGridSortMenuProps<TData>) {\n const dir = useDirection();\n const id = React.useId();\n const labelId = React.useId();\n const descriptionId = React.useId();\n const [open, setOpen] = React.useState(false);\n const addButtonRef = React.useRef<HTMLButtonElement>(null);\n\n const sorting = table.getState().sorting;\n const onSortingChange = table.setSorting;\n\n const { columnLabels, columns } = React.useMemo(() => {\n const labels = new Map<string, string>();\n const sortingIds = new Set(sorting.map((s) => s.id));\n const availableColumns: { id: string; label: string }[] = [];\n\n for (const column of table.getAllColumns()) {\n if (!column.getCanSort()) continue;\n\n const label = column.columnDef.meta?.label ?? column.id;\n labels.set(column.id, label);\n\n if (!sortingIds.has(column.id)) {\n availableColumns.push({ id: column.id, label });\n }\n }\n\n return {\n columnLabels: labels,\n columns: availableColumns\n };\n }, [sorting, table]);\n\n const onSortAdd = React.useCallback(() => {\n const firstColumn = columns[0];\n if (!firstColumn) return;\n\n onSortingChange((prevSorting) => [...prevSorting, { id: firstColumn.id, desc: false }]);\n }, [columns, onSortingChange]);\n\n const onSortUpdate = React.useCallback(\n (sortId: string, updates: Partial<ColumnSort>) => {\n onSortingChange((prevSorting) => {\n if (!prevSorting) return prevSorting;\n return prevSorting.map((sort) => (sort.id === sortId ? { ...sort, ...updates } : sort));\n });\n },\n [onSortingChange]\n );\n\n const onSortRemove = React.useCallback(\n (sortId: string) => {\n onSortingChange((prevSorting) => prevSorting.filter((item) => item.id !== sortId));\n },\n [onSortingChange]\n );\n\n const onSortingReset = React.useCallback(\n () => onSortingChange(table.initialState.sorting),\n [onSortingChange, table.initialState.sorting]\n );\n\n React.useEffect(() => {\n function onKeyDown(event: KeyboardEvent) {\n if (\n event.target instanceof HTMLInputElement ||\n event.target instanceof HTMLTextAreaElement ||\n (event.target instanceof HTMLElement && event.target.contentEditable === \"true\")\n ) {\n return;\n }\n\n if (event.key.toLowerCase() === SORT_SHORTCUT_KEY && (event.ctrlKey || event.metaKey) && event.shiftKey) {\n event.preventDefault();\n setOpen((prev) => !prev);\n }\n }\n\n window.addEventListener(\"keydown\", onKeyDown);\n return () => window.removeEventListener(\"keydown\", onKeyDown);\n }, []);\n\n const onTriggerKeyDown = React.useCallback(\n (event: React.KeyboardEvent<HTMLButtonElement>) => {\n if (REMOVE_SORT_SHORTCUTS.has(event.key.toLowerCase()) && sorting.length > 0) {\n event.preventDefault();\n onSortingReset();\n }\n },\n [sorting.length, onSortingReset]\n );\n\n return (\n <Sortable value={sorting} onValueChange={onSortingChange} getItemValue={(item) => item.id}>\n <Popover open={open} onOpenChange={setOpen}>\n <PopoverTrigger asChild>\n <Button\n dir={dir}\n variant=\"outline\"\n className=\"h-8 gap-2 font-normal\"\n onKeyDown={onTriggerKeyDown}\n disabled={disabled}\n >\n <ArrowDownUp aria-hidden=\"true\" className=\"text-muted-foreground\" />\n {msg.sort.trigger}\n {sorting.length > 0 && (\n <span\n className={cn(\n badgeVariants({ variant: \"secondary\" }),\n \"h-5 rounded px-1.5 font-mono text-[11px] font-medium\"\n )}\n >\n {sorting.length}\n </span>\n )}\n </Button>\n </PopoverTrigger>\n <PopoverContent\n aria-labelledby={labelId}\n aria-describedby={descriptionId}\n dir={dir}\n className={cn(\n \"flex w-full max-w-[--radix-popover-content-available-width] flex-col gap-3.5 p-4 sm:min-w-[380px]\",\n className\n )}\n {...props}\n >\n <div className=\"flex flex-col gap-1\">\n <h4 id={labelId} className=\"font-medium leading-none\">\n {sorting.length > 0 ? msg.sort.title : msg.sort.emptyTitle}\n </h4>\n <p id={descriptionId} className={cn(\"text-muted-foreground text-sm\", sorting.length > 0 && \"sr-only\")}>\n {sorting.length > 0 ? msg.sort.description : msg.sort.emptyDescription}\n </p>\n </div>\n {sorting.length > 0 && (\n <SortableContent asChild>\n <div role=\"list\" className=\"flex max-h-[300px] flex-col gap-2 overflow-y-auto p-1\">\n {sorting.map((sort) => (\n <DataTableSortItem\n key={sort.id}\n sort={sort}\n sortItemId={`${id}-sort-${sort.id}`}\n dir={dir}\n columns={columns}\n columnLabels={columnLabels}\n onSortUpdate={onSortUpdate}\n onSortRemove={onSortRemove}\n />\n ))}\n </div>\n </SortableContent>\n )}\n <div className=\"flex w-full items-center gap-2\">\n <Button\n size=\"sm\"\n className=\"rounded\"\n ref={addButtonRef}\n onClick={onSortAdd}\n disabled={columns.length === 0}\n >\n {msg.sort.add}\n </Button>\n {sorting.length > 0 && (\n <Button variant=\"outline\" size=\"sm\" className=\"rounded\" onClick={onSortingReset}>\n {msg.sort.reset}\n </Button>\n )}\n </div>\n </PopoverContent>\n </Popover>\n <SortableOverlay>\n <div dir={dir} className=\"flex items-center gap-2\">\n <div className=\"h-8 w-44 rounded-sm bg-muted\" />\n <div className=\"h-8 w-24 rounded-sm bg-muted\" />\n <div className=\"size-8 shrink-0 rounded-sm bg-muted\" />\n <div className=\"size-8 shrink-0 rounded-sm bg-muted\" />\n </div>\n </SortableOverlay>\n </Sortable>\n );\n}\n\ninterface DataTableSortItemProps {\n sort: ColumnSort;\n sortItemId: string;\n dir: \"ltr\" | \"rtl\";\n columns: { id: string; label: string }[];\n columnLabels: Map<string, string>;\n onSortUpdate: (sortId: string, updates: Partial<ColumnSort>) => void;\n onSortRemove: (sortId: string) => void;\n}\n\nfunction DataTableSortItem({\n sort,\n sortItemId,\n dir,\n columns,\n columnLabels,\n onSortUpdate,\n onSortRemove\n}: DataTableSortItemProps) {\n const fieldListboxId = `${sortItemId}-field-listbox`;\n const fieldTriggerId = `${sortItemId}-field-trigger`;\n const directionListboxId = `${sortItemId}-direction-listbox`;\n\n const [showFieldSelector, setShowFieldSelector] = React.useState(false);\n const [showDirectionSelector, setShowDirectionSelector] = React.useState(false);\n\n const onItemKeyDown = React.useCallback(\n (event: React.KeyboardEvent<HTMLDivElement>) => {\n if (event.target instanceof HTMLInputElement || event.target instanceof HTMLTextAreaElement) {\n return;\n }\n\n if (showFieldSelector || showDirectionSelector) {\n return;\n }\n\n if (REMOVE_SORT_SHORTCUTS.has(event.key.toLowerCase())) {\n event.preventDefault();\n onSortRemove(sort.id);\n }\n },\n [sort.id, showFieldSelector, showDirectionSelector, onSortRemove]\n );\n\n return (\n <SortableItem value={sort.id} asChild>\n <div role=\"listitem\" id={sortItemId} tabIndex={-1} className=\"flex items-center gap-2\" onKeyDown={onItemKeyDown}>\n <Popover open={showFieldSelector} onOpenChange={setShowFieldSelector}>\n <PopoverTrigger asChild>\n <Button\n id={fieldTriggerId}\n aria-controls={fieldListboxId}\n variant=\"outline\"\n className=\"h-8 w-44 justify-between rounded font-normal\"\n >\n <span className=\"truncate\">{columnLabels.get(sort.id)}</span>\n <ChevronsUpDown aria-hidden=\"true\" className=\"opacity-50\" />\n </Button>\n </PopoverTrigger>\n <PopoverContent id={fieldListboxId} dir={dir} className=\"w-[--radix-popover-trigger-width] p-0\">\n <Command>\n <CommandInput placeholder={msg.sort.fieldPlaceholder} aria-label={msg.sort.fieldPlaceholder} />\n <CommandList>\n <CommandEmpty>{msg.sort.fieldEmpty}</CommandEmpty>\n <CommandGroup>\n {columns.map((column) => (\n <CommandItem\n key={column.id}\n value={column.id}\n onSelect={(value) => onSortUpdate(sort.id, { id: value })}\n >\n <span className=\"truncate\">{column.label}</span>\n </CommandItem>\n ))}\n </CommandGroup>\n </CommandList>\n </Command>\n </PopoverContent>\n </Popover>\n <Select\n open={showDirectionSelector}\n onOpenChange={setShowDirectionSelector}\n value={sort.desc ? \"desc\" : \"asc\"}\n onValueChange={(value: SortDirection) => onSortUpdate(sort.id, { desc: value === \"desc\" })}\n >\n <SelectTrigger aria-controls={directionListboxId} aria-label={msg.sort.title} className=\"h-8 w-28 rounded\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent id={directionListboxId} className=\"min-w-[--radix-select-trigger-width]\">\n <SelectGroup>\n {SORT_ORDERS.map((order) => (\n <SelectItem key={order.value} value={order.value}>\n {order.label}\n </SelectItem>\n ))}\n </SelectGroup>\n </SelectContent>\n </Select>\n <Button\n aria-controls={sortItemId}\n aria-label={msg.sort.remove}\n variant=\"outline\"\n size=\"icon\"\n className=\"size-8 shrink-0 rounded\"\n onClick={() => onSortRemove(sort.id)}\n >\n <Trash2 aria-hidden=\"true\" />\n </Button>\n <SortableItemHandle asChild>\n <Button aria-label={msg.sort.drag} variant=\"outline\" size=\"icon\" className=\"size-8 shrink-0 rounded\">\n <GripVertical aria-hidden=\"true\" />\n </Button>\n </SortableItemHandle>\n </div>\n </SortableItem>\n );\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/data-grid/data-grid-sort-menu.tsx"],"sourcesContent":["\"use client\";\n\nimport { useDirection } from \"@radix-ui/react-direction\";\nimport type { ColumnSort, SortDirection, Table } from \"@tanstack/react-table\";\nimport { ArrowDownUp, ChevronsUpDown, GripVertical, Trash2 } from \"lucide-react\";\nimport * as React from \"react\";\nimport { badgeVariants } from \"../components/ui/badge.js\";\nimport { Button } from \"../components/ui/button.js\";\nimport {\n Command,\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n CommandList\n} from \"../components/ui/command.js\";\nimport { Popover, PopoverContent, PopoverTrigger } from \"../components/ui/popover.js\";\nimport { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from \"../components/ui/select.js\";\nimport { cn } from \"../lib/cn.js\";\nimport { DataGridLocaleProvider, useDataGridMessages, useResolvedDataGridMessages } from \"./data-grid-locale.js\";\nimport type { DataGridLocale, DataGridMessages } from \"./messages.js\";\nimport { Sortable, SortableContent, SortableItem, SortableItemHandle, SortableOverlay } from \"./sortable.js\";\n\nconst SORT_SHORTCUT_KEY = \"s\";\nconst REMOVE_SORT_SHORTCUTS = new Set([\"backspace\", \"delete\"]);\n/* Nhãn đổi theo ngôn ngữ, `value` thì không — nên đây là hàm, không phải hằng module. */\nfunction buildSortOrders(msg: DataGridMessages) {\n return [\n { label: msg.sort.asc, value: \"asc\" },\n { label: msg.sort.desc, value: \"desc\" }\n ];\n}\n\ninterface DataGridSortMenuProps<TData> extends React.ComponentProps<typeof PopoverContent> {\n table: Table<TData>;\n disabled?: boolean;\n /**\n * Ngôn ngữ của menu: `\"en\"` (mặc định) · `\"vi\"`, hoặc cả một bảng chuỗi tự soạn.\n *\n * ⚠ Thanh công cụ nằm NGOÀI `<DataGrid>`, nên `locale` truyền cho lưới không với tới đây. Bọc\n * cả màn bằng `DataGridLocaleProvider` (một lần, đúng cho mọi mảnh), hoặc truyền prop này cho\n * từng menu. Prop thắng provider.\n */\n locale?: DataGridLocale | DataGridMessages;\n}\n\nexport function DataGridSortMenu<TData>({\n table,\n disabled,\n className,\n locale,\n ...props\n}: DataGridSortMenuProps<TData>) {\n // Menu TỰ giữ bảng chuỗi rồi PHÁT xuống cho `DataTableSortItem` bên dưới — nó là bên cung\n // cấp context nên không đọc context của chính mình được.\n const msg = useResolvedDataGridMessages(locale);\n const dir = useDirection();\n const id = React.useId();\n const labelId = React.useId();\n const descriptionId = React.useId();\n const [open, setOpen] = React.useState(false);\n const addButtonRef = React.useRef<HTMLButtonElement>(null);\n\n const sorting = table.getState().sorting;\n const onSortingChange = table.setSorting;\n\n const { columnLabels, columns } = React.useMemo(() => {\n const labels = new Map<string, string>();\n const sortingIds = new Set(sorting.map((s) => s.id));\n const availableColumns: { id: string; label: string }[] = [];\n\n for (const column of table.getAllColumns()) {\n if (!column.getCanSort()) continue;\n\n const label = column.columnDef.meta?.label ?? column.id;\n labels.set(column.id, label);\n\n if (!sortingIds.has(column.id)) {\n availableColumns.push({ id: column.id, label });\n }\n }\n\n return {\n columnLabels: labels,\n columns: availableColumns\n };\n }, [sorting, table]);\n\n const onSortAdd = React.useCallback(() => {\n const firstColumn = columns[0];\n if (!firstColumn) return;\n\n onSortingChange((prevSorting) => [...prevSorting, { id: firstColumn.id, desc: false }]);\n }, [columns, onSortingChange]);\n\n const onSortUpdate = React.useCallback(\n (sortId: string, updates: Partial<ColumnSort>) => {\n onSortingChange((prevSorting) => {\n if (!prevSorting) return prevSorting;\n return prevSorting.map((sort) => (sort.id === sortId ? { ...sort, ...updates } : sort));\n });\n },\n [onSortingChange]\n );\n\n const onSortRemove = React.useCallback(\n (sortId: string) => {\n onSortingChange((prevSorting) => prevSorting.filter((item) => item.id !== sortId));\n },\n [onSortingChange]\n );\n\n const onSortingReset = React.useCallback(\n () => onSortingChange(table.initialState.sorting),\n [onSortingChange, table.initialState.sorting]\n );\n\n React.useEffect(() => {\n function onKeyDown(event: KeyboardEvent) {\n if (\n event.target instanceof HTMLInputElement ||\n event.target instanceof HTMLTextAreaElement ||\n (event.target instanceof HTMLElement && event.target.contentEditable === \"true\")\n ) {\n return;\n }\n\n if (event.key.toLowerCase() === SORT_SHORTCUT_KEY && (event.ctrlKey || event.metaKey) && event.shiftKey) {\n event.preventDefault();\n setOpen((prev) => !prev);\n }\n }\n\n window.addEventListener(\"keydown\", onKeyDown);\n return () => window.removeEventListener(\"keydown\", onKeyDown);\n }, []);\n\n const onTriggerKeyDown = React.useCallback(\n (event: React.KeyboardEvent<HTMLButtonElement>) => {\n if (REMOVE_SORT_SHORTCUTS.has(event.key.toLowerCase()) && sorting.length > 0) {\n event.preventDefault();\n onSortingReset();\n }\n },\n [sorting.length, onSortingReset]\n );\n\n return (\n <DataGridLocaleProvider locale={msg}>\n <Sortable value={sorting} onValueChange={onSortingChange} getItemValue={(item) => item.id}>\n <Popover open={open} onOpenChange={setOpen}>\n <PopoverTrigger asChild>\n <Button\n dir={dir}\n variant=\"outline\"\n size=\"sm\"\n className=\"font-normal\"\n onKeyDown={onTriggerKeyDown}\n disabled={disabled}\n >\n <ArrowDownUp aria-hidden=\"true\" className=\"size-3.5 text-muted-foreground\" />\n {msg.sort.trigger}\n {sorting.length > 0 && (\n <span\n className={cn(\n badgeVariants({ variant: \"secondary\" }),\n \"h-5 rounded px-1.5 font-mono text-[11px] font-medium\"\n )}\n >\n {sorting.length}\n </span>\n )}\n </Button>\n </PopoverTrigger>\n <PopoverContent\n aria-labelledby={labelId}\n aria-describedby={descriptionId}\n dir={dir}\n className={cn(\n \"flex w-full max-w-[--radix-popover-content-available-width] flex-col gap-3.5 p-4 sm:min-w-[380px]\",\n className\n )}\n {...props}\n >\n <div className=\"flex flex-col gap-1\">\n <h4 id={labelId} className=\"font-medium leading-none\">\n {sorting.length > 0 ? msg.sort.title : msg.sort.emptyTitle}\n </h4>\n <p id={descriptionId} className={cn(\"text-muted-foreground text-sm\", sorting.length > 0 && \"sr-only\")}>\n {sorting.length > 0 ? msg.sort.description : msg.sort.emptyDescription}\n </p>\n </div>\n {sorting.length > 0 && (\n <SortableContent asChild>\n <div role=\"list\" className=\"flex max-h-[300px] flex-col gap-2 overflow-y-auto p-1\">\n {sorting.map((sort) => (\n <DataTableSortItem\n key={sort.id}\n sort={sort}\n sortItemId={`${id}-sort-${sort.id}`}\n dir={dir}\n columns={columns}\n columnLabels={columnLabels}\n onSortUpdate={onSortUpdate}\n onSortRemove={onSortRemove}\n />\n ))}\n </div>\n </SortableContent>\n )}\n <div className=\"flex w-full items-center gap-2\">\n <Button\n size=\"sm\"\n className=\"rounded\"\n ref={addButtonRef}\n onClick={onSortAdd}\n disabled={columns.length === 0}\n >\n {msg.sort.add}\n </Button>\n {sorting.length > 0 && (\n <Button variant=\"outline\" size=\"sm\" className=\"rounded\" onClick={onSortingReset}>\n {msg.sort.reset}\n </Button>\n )}\n </div>\n </PopoverContent>\n </Popover>\n <SortableOverlay>\n <div dir={dir} className=\"flex items-center gap-2\">\n <div className=\"h-8 w-44 rounded-sm bg-muted\" />\n <div className=\"h-8 w-24 rounded-sm bg-muted\" />\n <div className=\"size-8 shrink-0 rounded-sm bg-muted\" />\n <div className=\"size-8 shrink-0 rounded-sm bg-muted\" />\n </div>\n </SortableOverlay>\n </Sortable>\n </DataGridLocaleProvider>\n );\n}\n\ninterface DataTableSortItemProps {\n sort: ColumnSort;\n sortItemId: string;\n dir: \"ltr\" | \"rtl\";\n columns: { id: string; label: string }[];\n columnLabels: Map<string, string>;\n onSortUpdate: (sortId: string, updates: Partial<ColumnSort>) => void;\n onSortRemove: (sortId: string) => void;\n}\n\nfunction DataTableSortItem({\n sort,\n sortItemId,\n dir,\n columns,\n columnLabels,\n onSortUpdate,\n onSortRemove\n}: DataTableSortItemProps) {\n const msg = useDataGridMessages();\n const sortOrders = React.useMemo(() => buildSortOrders(msg), [msg]);\n const fieldListboxId = `${sortItemId}-field-listbox`;\n const fieldTriggerId = `${sortItemId}-field-trigger`;\n const directionListboxId = `${sortItemId}-direction-listbox`;\n\n const [showFieldSelector, setShowFieldSelector] = React.useState(false);\n const [showDirectionSelector, setShowDirectionSelector] = React.useState(false);\n\n const onItemKeyDown = React.useCallback(\n (event: React.KeyboardEvent<HTMLDivElement>) => {\n if (event.target instanceof HTMLInputElement || event.target instanceof HTMLTextAreaElement) {\n return;\n }\n\n if (showFieldSelector || showDirectionSelector) {\n return;\n }\n\n if (REMOVE_SORT_SHORTCUTS.has(event.key.toLowerCase())) {\n event.preventDefault();\n onSortRemove(sort.id);\n }\n },\n [sort.id, showFieldSelector, showDirectionSelector, onSortRemove]\n );\n\n return (\n <SortableItem value={sort.id} asChild>\n <div role=\"listitem\" id={sortItemId} tabIndex={-1} className=\"flex items-center gap-2\" onKeyDown={onItemKeyDown}>\n <Popover open={showFieldSelector} onOpenChange={setShowFieldSelector}>\n <PopoverTrigger asChild>\n <Button\n id={fieldTriggerId}\n aria-controls={fieldListboxId}\n variant=\"outline\"\n className=\"h-8 w-44 justify-between rounded font-normal\"\n >\n <span className=\"truncate\">{columnLabels.get(sort.id)}</span>\n <ChevronsUpDown aria-hidden=\"true\" className=\"opacity-50\" />\n </Button>\n </PopoverTrigger>\n <PopoverContent id={fieldListboxId} dir={dir} className=\"w-[--radix-popover-trigger-width] p-0\">\n <Command>\n <CommandInput placeholder={msg.sort.fieldPlaceholder} aria-label={msg.sort.fieldPlaceholder} />\n <CommandList>\n <CommandEmpty>{msg.sort.fieldEmpty}</CommandEmpty>\n <CommandGroup>\n {columns.map((column) => (\n <CommandItem\n key={column.id}\n value={column.id}\n onSelect={(value) => onSortUpdate(sort.id, { id: value })}\n >\n <span className=\"truncate\">{column.label}</span>\n </CommandItem>\n ))}\n </CommandGroup>\n </CommandList>\n </Command>\n </PopoverContent>\n </Popover>\n <Select\n open={showDirectionSelector}\n onOpenChange={setShowDirectionSelector}\n value={sort.desc ? \"desc\" : \"asc\"}\n onValueChange={(value: SortDirection) => onSortUpdate(sort.id, { desc: value === \"desc\" })}\n >\n <SelectTrigger aria-controls={directionListboxId} aria-label={msg.sort.title} className=\"h-8 w-28 rounded\">\n <SelectValue />\n </SelectTrigger>\n <SelectContent id={directionListboxId} className=\"min-w-[--radix-select-trigger-width]\">\n <SelectGroup>\n {sortOrders.map((order) => (\n <SelectItem key={order.value} value={order.value}>\n {order.label}\n </SelectItem>\n ))}\n </SelectGroup>\n </SelectContent>\n </Select>\n <Button\n aria-controls={sortItemId}\n aria-label={msg.sort.remove}\n variant=\"outline\"\n size=\"icon\"\n className=\"size-8 shrink-0 rounded\"\n onClick={() => onSortRemove(sort.id)}\n >\n <Trash2 aria-hidden=\"true\" className=\"size-3.5\" />\n </Button>\n <SortableItemHandle asChild>\n <Button aria-label={msg.sort.drag} variant=\"outline\" size=\"icon\" className=\"size-8 shrink-0 rounded\">\n <GripVertical aria-hidden=\"true\" className=\"size-3.5\" />\n </Button>\n </SortableItemHandle>\n </div>\n </SortableItem>\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,13 +1,24 @@
|
|
|
1
1
|
import { Table } from '@tanstack/react-table';
|
|
2
2
|
import * as React from 'react';
|
|
3
3
|
import { PopoverContent } from '../components/ui/popover.js';
|
|
4
|
+
import { DataGridLocale } from './messages.js';
|
|
5
|
+
import { DataGridMessages } from './messages-en.js';
|
|
4
6
|
import '@radix-ui/react-popover';
|
|
7
|
+
import './messages-vi.js';
|
|
5
8
|
|
|
6
9
|
interface DataGridViewMenuProps<TData> extends React.ComponentProps<typeof PopoverContent> {
|
|
7
10
|
table: Table<TData>;
|
|
8
11
|
disabled?: boolean;
|
|
12
|
+
/**
|
|
13
|
+
* Ngôn ngữ của menu: `"en"` (mặc định) · `"vi"`, hoặc cả một bảng chuỗi tự soạn.
|
|
14
|
+
*
|
|
15
|
+
* ⚠ Thanh công cụ nằm NGOÀI `<DataGrid>`, nên `locale` truyền cho lưới không với tới đây. Bọc
|
|
16
|
+
* cả màn bằng `DataGridLocaleProvider` (một lần, đúng cho mọi mảnh), hoặc truyền prop này cho
|
|
17
|
+
* từng menu. Prop thắng provider.
|
|
18
|
+
*/
|
|
19
|
+
locale?: DataGridLocale | DataGridMessages;
|
|
9
20
|
}
|
|
10
21
|
/** Ẩn/hiện cột của lưới. Cột muốn khoá luôn hiển thị thì đặt `enableHiding: false`. */
|
|
11
|
-
declare function DataGridViewMenu<TData>({ table, disabled, className, ...props }: DataGridViewMenuProps<TData>): React.JSX.Element;
|
|
22
|
+
declare function DataGridViewMenu<TData>({ table, disabled, className, locale, ...props }: DataGridViewMenuProps<TData>): React.JSX.Element;
|
|
12
23
|
|
|
13
24
|
export { DataGridViewMenu };
|