@comitor/ui 1.11.0 → 2.0.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/README.md +10 -2
- 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-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 +4 -3
- 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 +2 -1
- 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-search.js +5 -4
- 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 +6 -3
- 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/use-data-grid-undo-redo.d.ts +13 -1
- package/dist/data-grid/use-data-grid-undo-redo.js +11 -8
- 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 +21 -16
- 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/package.json +1 -1
|
@@ -15,10 +15,10 @@ import {
|
|
|
15
15
|
import { Input } from "../components/ui/input.js";
|
|
16
16
|
import { Kbd, KbdGroup } from "../components/ui/kbd.js";
|
|
17
17
|
import { Separator } from "../components/ui/separator.js";
|
|
18
|
-
import {
|
|
18
|
+
import { useResolvedDataGridMessages } from "./data-grid-locale.js";
|
|
19
19
|
const SHORTCUT_KEY = "/";
|
|
20
20
|
const DataGridKeyboardShortcuts = React.memo(DataGridKeyboardShortcutsImpl, (prev, next) => {
|
|
21
|
-
return prev.enableSearch === next.enableSearch && prev.enableUndoRedo === next.enableUndoRedo && prev.enablePaste === next.enablePaste && prev.enableRowAdd === next.enableRowAdd && prev.enableRowsDelete === next.enableRowsDelete && prev.hideTrigger === next.hideTrigger;
|
|
21
|
+
return prev.enableSearch === next.enableSearch && prev.enableUndoRedo === next.enableUndoRedo && prev.enablePaste === next.enablePaste && prev.enableRowAdd === next.enableRowAdd && prev.enableRowsDelete === next.enableRowsDelete && prev.hideTrigger === next.hideTrigger && prev.locale === next.locale;
|
|
22
22
|
});
|
|
23
23
|
function DataGridKeyboardShortcutsImpl({
|
|
24
24
|
enableSearch = false,
|
|
@@ -26,8 +26,10 @@ function DataGridKeyboardShortcutsImpl({
|
|
|
26
26
|
enablePaste = false,
|
|
27
27
|
enableRowAdd = false,
|
|
28
28
|
enableRowsDelete = false,
|
|
29
|
-
hideTrigger = false
|
|
29
|
+
hideTrigger = false,
|
|
30
|
+
locale
|
|
30
31
|
}) {
|
|
32
|
+
const msg = useResolvedDataGridMessages(locale);
|
|
31
33
|
const dir = useDirection();
|
|
32
34
|
const [open, setOpen] = React.useState(false);
|
|
33
35
|
const [input, setInput] = React.useState("");
|
|
@@ -140,7 +142,7 @@ function DataGridKeyboardShortcutsImpl({
|
|
|
140
142
|
shortcuts: [{ keys: [modKey, "/"], description: msg.shortcuts.general.shortcuts }]
|
|
141
143
|
}
|
|
142
144
|
],
|
|
143
|
-
[modKey, altKey, enableSearch, enableUndoRedo, enablePaste, enableRowAdd, enableRowsDelete]
|
|
145
|
+
[msg, modKey, altKey, enableSearch, enableUndoRedo, enablePaste, enableRowAdd, enableRowsDelete]
|
|
144
146
|
);
|
|
145
147
|
const filteredGroups = React.useMemo(() => {
|
|
146
148
|
if (!input.trim()) return shortcutGroups;
|
|
@@ -165,7 +167,7 @@ function DataGridKeyboardShortcutsImpl({
|
|
|
165
167
|
};
|
|
166
168
|
}, []);
|
|
167
169
|
return /* @__PURE__ */ jsxs(Dialog, { open, onOpenChange, children: [
|
|
168
|
-
!hideTrigger && /* @__PURE__ */ jsx(DialogTrigger, { asChild: true, children: /* @__PURE__ */ jsx(Button, { "aria-label": msg.shortcuts.trigger, variant: "outline", size: "icon
|
|
170
|
+
!hideTrigger && /* @__PURE__ */ jsx(DialogTrigger, { asChild: true, children: /* @__PURE__ */ jsx(Button, { "aria-label": msg.shortcuts.trigger, variant: "outline", size: "icon-sm", children: /* @__PURE__ */ jsx(Keyboard, { "aria-hidden": "true", className: "size-3.5 text-muted-foreground" }) }) }),
|
|
169
171
|
/* @__PURE__ */ jsxs(DialogContent, { dir, className: "max-w-2xl px-0", onOpenAutoFocus, children: [
|
|
170
172
|
/* @__PURE__ */ jsxs(DialogHeader, { className: "px-6", children: [
|
|
171
173
|
/* @__PURE__ */ jsx(DialogTitle, { children: msg.shortcuts.title }),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/data-grid/data-grid-keyboard-shortcuts.tsx"],"sourcesContent":["\"use client\";\n\nimport { useDirection } from \"@radix-ui/react-direction\";\nimport { Keyboard, SearchIcon } from \"lucide-react\";\nimport * as React from \"react\";\nimport { Button } from \"../components/ui/button.js\";\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogHeader,\n DialogTitle,\n DialogTrigger\n} from \"../components/ui/dialog.js\";\nimport { Input } from \"../components/ui/input.js\";\nimport { Kbd, KbdGroup } from \"../components/ui/kbd.js\";\nimport { Separator } from \"../components/ui/separator.js\";\nimport { msg } from \"./messages.js\";\n\nconst SHORTCUT_KEY = \"/\";\n\ninterface ShortcutGroup {\n title: string;\n shortcuts: Array<{\n keys: string[];\n description: string;\n }>;\n}\n\ninterface DataGridKeyboardShortcutsProps {\n /** Hiện phím tắt của ô tìm kiếm (bật cùng `enableSearch` của lưới) */\n enableSearch?: boolean;\n enableUndoRedo?: boolean;\n enablePaste?: boolean;\n enableRowAdd?: boolean;\n enableRowsDelete?: boolean;\n /** Ẩn nút mở trên thanh công cụ — vẫn mở được bằng Ctrl+/ */\n hideTrigger?: boolean;\n}\n\n/**\n * Hộp thoại liệt kê phím tắt của lưới (mở bằng Ctrl/⌘ + `/`, hoặc nút trên thanh công cụ).\n * Danh sách hiển thị theo đúng những tính năng đang bật, nên truyền các cờ giống lưới.\n */\nexport const DataGridKeyboardShortcuts = React.memo(DataGridKeyboardShortcutsImpl, (prev, next) => {\n return (\n prev.enableSearch === next.enableSearch &&\n prev.enableUndoRedo === next.enableUndoRedo &&\n prev.enablePaste === next.enablePaste &&\n prev.enableRowAdd === next.enableRowAdd &&\n prev.enableRowsDelete === next.enableRowsDelete &&\n prev.hideTrigger === next.hideTrigger\n );\n});\n\nfunction DataGridKeyboardShortcutsImpl({\n enableSearch = false,\n enableUndoRedo = false,\n enablePaste = false,\n enableRowAdd = false,\n enableRowsDelete = false,\n hideTrigger = false\n}: DataGridKeyboardShortcutsProps) {\n const dir = useDirection();\n const [open, setOpen] = React.useState(false);\n const [input, setInput] = React.useState(\"\");\n const inputRef = React.useRef<HTMLInputElement>(null);\n\n const isMac = typeof navigator !== \"undefined\" ? /Mac|iPhone|iPad|iPod/.test(navigator.userAgent) : false;\n\n const modKey = isMac ? \"⌘\" : \"Ctrl\";\n const altKey = isMac ? \"⌥\" : \"Alt\";\n\n const onOpenChange = React.useCallback((isOpen: boolean) => {\n setOpen(isOpen);\n if (!isOpen) {\n setInput(\"\");\n }\n }, []);\n\n const onOpenAutoFocus = React.useCallback((event: Event) => {\n event.preventDefault();\n inputRef.current?.focus();\n }, []);\n\n const onInputChange = React.useCallback((event: React.ChangeEvent<HTMLInputElement>) => {\n setInput(event.target.value);\n }, []);\n\n const shortcutGroups: ShortcutGroup[] = React.useMemo(\n () => [\n {\n title: msg.shortcuts.groups.navigation,\n shortcuts: [\n { keys: [\"↑\", \"↓\", \"←\", \"→\"], description: msg.shortcuts.navigation.move },\n { keys: [\"Tab\"], description: msg.shortcuts.navigation.nextCell },\n { keys: [\"Shift\", \"Tab\"], description: msg.shortcuts.navigation.prevCell },\n { keys: [\"Home\"], description: msg.shortcuts.navigation.firstColumn },\n { keys: [\"End\"], description: msg.shortcuts.navigation.lastColumn },\n { keys: [modKey, \"↑\"], description: msg.shortcuts.navigation.firstRowSameColumn },\n { keys: [modKey, \"↓\"], description: msg.shortcuts.navigation.lastRowSameColumn },\n { keys: [modKey, \"←\"], description: msg.shortcuts.navigation.firstColumnSameRow },\n { keys: [modKey, \"→\"], description: msg.shortcuts.navigation.lastColumnSameRow },\n { keys: [modKey, \"Home\"], description: msg.shortcuts.navigation.firstCell },\n { keys: [modKey, \"End\"], description: msg.shortcuts.navigation.lastCell },\n { keys: [\"PgUp\"], description: msg.shortcuts.navigation.pageUp },\n { keys: [\"PgDn\"], description: msg.shortcuts.navigation.pageDown },\n { keys: [altKey, \"↑\"], description: msg.shortcuts.navigation.scrollUp },\n { keys: [altKey, \"↓\"], description: msg.shortcuts.navigation.scrollDown },\n { keys: [altKey, \"PgUp\"], description: msg.shortcuts.navigation.scrollLeft },\n { keys: [altKey, \"PgDn\"], description: msg.shortcuts.navigation.scrollRight }\n ]\n },\n {\n title: msg.shortcuts.groups.selection,\n shortcuts: [\n { keys: [\"Shift\", \"↑↓←→\"], description: msg.shortcuts.selection.extend },\n { keys: [modKey, \"Shift\", \"↑\"], description: msg.shortcuts.selection.toTop },\n { keys: [modKey, \"Shift\", \"↓\"], description: msg.shortcuts.selection.toBottom },\n { keys: [modKey, \"Shift\", \"←\"], description: msg.shortcuts.selection.toFirstColumn },\n { keys: [modKey, \"Shift\", \"→\"], description: msg.shortcuts.selection.toLastColumn },\n { keys: [modKey, \"A\"], description: msg.shortcuts.selection.all },\n { keys: [modKey, msg.shortcuts.keys.click], description: msg.shortcuts.selection.toggle },\n { keys: [\"Shift\", msg.shortcuts.keys.click], description: msg.shortcuts.selection.range },\n { keys: [\"Esc\"], description: msg.shortcuts.selection.clear }\n ]\n },\n {\n title: msg.shortcuts.groups.editing,\n shortcuts: [\n { keys: [\"Enter\"], description: msg.shortcuts.editing.start },\n { keys: [\"F2\"], description: msg.shortcuts.editing.start },\n { keys: [msg.shortcuts.keys.doubleClick], description: msg.shortcuts.editing.start },\n ...(enableRowAdd ? [{ keys: [\"Shift\", \"Enter\"], description: msg.shortcuts.editing.insertRow }] : []),\n { keys: [modKey, \"C\"], description: msg.shortcuts.editing.copy },\n { keys: [modKey, \"X\"], description: msg.shortcuts.editing.cut },\n ...(enablePaste ? [{ keys: [modKey, \"V\"], description: msg.shortcuts.editing.paste }] : []),\n { keys: [\"Delete\"], description: msg.shortcuts.editing.clear },\n { keys: [\"Backspace\"], description: msg.shortcuts.editing.clear },\n ...(enableRowsDelete\n ? [\n { keys: [modKey, \"Backspace\"], description: msg.shortcuts.editing.deleteRows },\n { keys: [modKey, \"Delete\"], description: msg.shortcuts.editing.deleteRows }\n ]\n : []),\n ...(enableUndoRedo\n ? [\n { keys: [modKey, \"Z\"], description: msg.shortcuts.editing.undo },\n { keys: [modKey, \"Shift\", \"Z\"], description: msg.shortcuts.editing.redo }\n ]\n : [])\n ]\n },\n ...(enableSearch\n ? [\n {\n title: msg.shortcuts.groups.search,\n shortcuts: [\n { keys: [modKey, \"F\"], description: msg.shortcuts.search.open },\n { keys: [\"Enter\"], description: msg.shortcuts.search.next },\n { keys: [\"Shift\", \"Enter\"], description: msg.shortcuts.search.prev },\n { keys: [\"Esc\"], description: msg.shortcuts.search.close }\n ]\n }\n ]\n : []),\n {\n title: msg.shortcuts.groups.filtering,\n shortcuts: [\n { keys: [modKey, \"Shift\", \"F\"], description: msg.shortcuts.filtering.toggle },\n { keys: [\"Backspace\"], description: msg.shortcuts.filtering.remove },\n { keys: [\"Delete\"], description: msg.shortcuts.filtering.remove }\n ]\n },\n {\n title: msg.shortcuts.groups.sorting,\n shortcuts: [\n { keys: [modKey, \"Shift\", \"S\"], description: msg.shortcuts.sorting.toggle },\n { keys: [\"Backspace\"], description: msg.shortcuts.sorting.remove },\n { keys: [\"Delete\"], description: msg.shortcuts.sorting.remove }\n ]\n },\n {\n title: msg.shortcuts.groups.general,\n shortcuts: [{ keys: [modKey, \"/\"], description: msg.shortcuts.general.shortcuts }]\n }\n ],\n [modKey, altKey, enableSearch, enableUndoRedo, enablePaste, enableRowAdd, enableRowsDelete]\n );\n\n const filteredGroups = React.useMemo(() => {\n if (!input.trim()) return shortcutGroups;\n\n const query = input.toLowerCase();\n return shortcutGroups\n .map((group) => ({\n ...group,\n shortcuts: group.shortcuts.filter(\n (shortcut) =>\n shortcut.description.toLowerCase().includes(query) ||\n shortcut.keys.some((key) => key.toLowerCase().includes(query))\n )\n }))\n .filter((group) => group.shortcuts.length > 0);\n }, [shortcutGroups, input]);\n\n React.useEffect(() => {\n function onKeyDown(event: KeyboardEvent) {\n if ((event.ctrlKey || event.metaKey) && event.key === SHORTCUT_KEY) {\n event.preventDefault();\n setOpen(true);\n }\n }\n\n window.addEventListener(\"keydown\", onKeyDown);\n return () => {\n window.removeEventListener(\"keydown\", onKeyDown);\n };\n }, []);\n\n return (\n <Dialog open={open} onOpenChange={onOpenChange}>\n {!hideTrigger && (\n <DialogTrigger asChild>\n <Button aria-label={msg.shortcuts.trigger} variant=\"outline\" size=\"icon\" className=\"h-8 w-8\">\n <Keyboard aria-hidden=\"true\" className=\"h-4 w-4 text-muted-foreground\" />\n </Button>\n </DialogTrigger>\n )}\n <DialogContent dir={dir} className=\"max-w-2xl px-0\" onOpenAutoFocus={onOpenAutoFocus}>\n <DialogHeader className=\"px-6\">\n <DialogTitle>{msg.shortcuts.title}</DialogTitle>\n <DialogDescription className=\"sr-only\">{msg.shortcuts.description}</DialogDescription>\n </DialogHeader>\n <div className=\"px-6\">\n <div className=\"relative\">\n <SearchIcon\n aria-hidden=\"true\"\n className=\"absolute start-3 top-1/2 size-3.5 -translate-y-1/2 text-muted-foreground\"\n />\n <Input\n ref={inputRef}\n placeholder={msg.shortcuts.searchPlaceholder}\n aria-label={msg.shortcuts.searchPlaceholder}\n className=\"h-8 ps-8\"\n value={input}\n onChange={onInputChange}\n />\n </div>\n </div>\n <Separator className=\"mx-auto w-[calc(100%-3rem)]\" />\n <div className=\"h-[40vh] overflow-y-auto px-6\">\n {filteredGroups.length === 0 ? (\n <div className=\"flex h-full flex-col items-center justify-center gap-3 text-center\">\n <div className=\"flex size-10 shrink-0 items-center justify-center rounded-lg bg-muted text-foreground\">\n <SearchIcon aria-hidden=\"true\" className=\"pointer-events-none size-6\" />\n </div>\n <div className=\"flex flex-col gap-1\">\n <div className=\"font-medium text-lg tracking-tight\">{msg.shortcuts.emptyTitle}</div>\n <p className=\"text-muted-foreground text-sm\">{msg.shortcuts.emptyDescription}</p>\n </div>\n </div>\n ) : (\n <div className=\"flex flex-col gap-6\">\n {filteredGroups.map((shortcutGroup) => (\n <div key={shortcutGroup.title} className=\"flex flex-col gap-2\">\n <h3 className=\"font-semibold text-foreground text-sm\">{shortcutGroup.title}</h3>\n <div className=\"divide-y divide-border rounded-md border\">\n {shortcutGroup.shortcuts.map((shortcut) => (\n <ShortcutCard\n key={`${shortcut.description}-${shortcut.keys.join(\"+\")}`}\n keys={shortcut.keys}\n description={shortcut.description}\n />\n ))}\n </div>\n </div>\n ))}\n </div>\n )}\n </div>\n </DialogContent>\n </Dialog>\n );\n}\n\nfunction ShortcutCard({ keys, description }: ShortcutGroup[\"shortcuts\"][number]) {\n return (\n <div className=\"flex items-center gap-4 px-3 py-2\">\n <span className=\"flex-1 text-sm\">{description}</span>\n <KbdGroup className=\"shrink-0\">\n {keys.map((key, index) => (\n <React.Fragment key={key}>\n {index > 0 && <span className=\"text-muted-foreground text-xs\">+</span>}\n <Kbd>{key}</Kbd>\n </React.Fragment>\n ))}\n </KbdGroup>\n </div>\n );\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/data-grid/data-grid-keyboard-shortcuts.tsx"],"sourcesContent":["\"use client\";\n\nimport { useDirection } from \"@radix-ui/react-direction\";\nimport { Keyboard, SearchIcon } from \"lucide-react\";\nimport * as React from \"react\";\nimport { Button } from \"../components/ui/button.js\";\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogHeader,\n DialogTitle,\n DialogTrigger\n} from \"../components/ui/dialog.js\";\nimport { Input } from \"../components/ui/input.js\";\nimport { Kbd, KbdGroup } from \"../components/ui/kbd.js\";\nimport { Separator } from \"../components/ui/separator.js\";\nimport { useResolvedDataGridMessages } from \"./data-grid-locale.js\";\nimport type { DataGridLocale, DataGridMessages } from \"./messages.js\";\n\nconst SHORTCUT_KEY = \"/\";\n\ninterface ShortcutGroup {\n title: string;\n shortcuts: Array<{\n keys: string[];\n description: string;\n }>;\n}\n\ninterface DataGridKeyboardShortcutsProps {\n /** Hiện phím tắt của ô tìm kiếm (bật cùng `enableSearch` của lưới) */\n enableSearch?: boolean;\n enableUndoRedo?: boolean;\n enablePaste?: boolean;\n enableRowAdd?: boolean;\n enableRowsDelete?: boolean;\n /** Ẩn nút mở trên thanh công cụ — vẫn mở được bằng Ctrl+/ */\n hideTrigger?: 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\n/**\n * Hộp thoại liệt kê phím tắt của lưới (mở bằng Ctrl/⌘ + `/`, hoặc nút trên thanh công cụ).\n * Danh sách hiển thị theo đúng những tính năng đang bật, nên truyền các cờ giống lưới.\n */\nexport const DataGridKeyboardShortcuts = React.memo(DataGridKeyboardShortcutsImpl, (prev, next) => {\n return (\n prev.enableSearch === next.enableSearch &&\n prev.enableUndoRedo === next.enableUndoRedo &&\n prev.enablePaste === next.enablePaste &&\n prev.enableRowAdd === next.enableRowAdd &&\n prev.enableRowsDelete === next.enableRowsDelete &&\n prev.hideTrigger === next.hideTrigger &&\n prev.locale === next.locale\n );\n});\n\nfunction DataGridKeyboardShortcutsImpl({\n enableSearch = false,\n enableUndoRedo = false,\n enablePaste = false,\n enableRowAdd = false,\n enableRowsDelete = false,\n hideTrigger = false,\n locale\n}: DataGridKeyboardShortcutsProps) {\n const msg = useResolvedDataGridMessages(locale);\n const dir = useDirection();\n const [open, setOpen] = React.useState(false);\n const [input, setInput] = React.useState(\"\");\n const inputRef = React.useRef<HTMLInputElement>(null);\n\n const isMac = typeof navigator !== \"undefined\" ? /Mac|iPhone|iPad|iPod/.test(navigator.userAgent) : false;\n\n const modKey = isMac ? \"⌘\" : \"Ctrl\";\n const altKey = isMac ? \"⌥\" : \"Alt\";\n\n const onOpenChange = React.useCallback((isOpen: boolean) => {\n setOpen(isOpen);\n if (!isOpen) {\n setInput(\"\");\n }\n }, []);\n\n const onOpenAutoFocus = React.useCallback((event: Event) => {\n event.preventDefault();\n inputRef.current?.focus();\n }, []);\n\n const onInputChange = React.useCallback((event: React.ChangeEvent<HTMLInputElement>) => {\n setInput(event.target.value);\n }, []);\n\n const shortcutGroups: ShortcutGroup[] = React.useMemo(\n () => [\n {\n title: msg.shortcuts.groups.navigation,\n shortcuts: [\n { keys: [\"↑\", \"↓\", \"←\", \"→\"], description: msg.shortcuts.navigation.move },\n { keys: [\"Tab\"], description: msg.shortcuts.navigation.nextCell },\n { keys: [\"Shift\", \"Tab\"], description: msg.shortcuts.navigation.prevCell },\n { keys: [\"Home\"], description: msg.shortcuts.navigation.firstColumn },\n { keys: [\"End\"], description: msg.shortcuts.navigation.lastColumn },\n { keys: [modKey, \"↑\"], description: msg.shortcuts.navigation.firstRowSameColumn },\n { keys: [modKey, \"↓\"], description: msg.shortcuts.navigation.lastRowSameColumn },\n { keys: [modKey, \"←\"], description: msg.shortcuts.navigation.firstColumnSameRow },\n { keys: [modKey, \"→\"], description: msg.shortcuts.navigation.lastColumnSameRow },\n { keys: [modKey, \"Home\"], description: msg.shortcuts.navigation.firstCell },\n { keys: [modKey, \"End\"], description: msg.shortcuts.navigation.lastCell },\n { keys: [\"PgUp\"], description: msg.shortcuts.navigation.pageUp },\n { keys: [\"PgDn\"], description: msg.shortcuts.navigation.pageDown },\n { keys: [altKey, \"↑\"], description: msg.shortcuts.navigation.scrollUp },\n { keys: [altKey, \"↓\"], description: msg.shortcuts.navigation.scrollDown },\n { keys: [altKey, \"PgUp\"], description: msg.shortcuts.navigation.scrollLeft },\n { keys: [altKey, \"PgDn\"], description: msg.shortcuts.navigation.scrollRight }\n ]\n },\n {\n title: msg.shortcuts.groups.selection,\n shortcuts: [\n { keys: [\"Shift\", \"↑↓←→\"], description: msg.shortcuts.selection.extend },\n { keys: [modKey, \"Shift\", \"↑\"], description: msg.shortcuts.selection.toTop },\n { keys: [modKey, \"Shift\", \"↓\"], description: msg.shortcuts.selection.toBottom },\n { keys: [modKey, \"Shift\", \"←\"], description: msg.shortcuts.selection.toFirstColumn },\n { keys: [modKey, \"Shift\", \"→\"], description: msg.shortcuts.selection.toLastColumn },\n { keys: [modKey, \"A\"], description: msg.shortcuts.selection.all },\n { keys: [modKey, msg.shortcuts.keys.click], description: msg.shortcuts.selection.toggle },\n { keys: [\"Shift\", msg.shortcuts.keys.click], description: msg.shortcuts.selection.range },\n { keys: [\"Esc\"], description: msg.shortcuts.selection.clear }\n ]\n },\n {\n title: msg.shortcuts.groups.editing,\n shortcuts: [\n { keys: [\"Enter\"], description: msg.shortcuts.editing.start },\n { keys: [\"F2\"], description: msg.shortcuts.editing.start },\n { keys: [msg.shortcuts.keys.doubleClick], description: msg.shortcuts.editing.start },\n ...(enableRowAdd ? [{ keys: [\"Shift\", \"Enter\"], description: msg.shortcuts.editing.insertRow }] : []),\n { keys: [modKey, \"C\"], description: msg.shortcuts.editing.copy },\n { keys: [modKey, \"X\"], description: msg.shortcuts.editing.cut },\n ...(enablePaste ? [{ keys: [modKey, \"V\"], description: msg.shortcuts.editing.paste }] : []),\n { keys: [\"Delete\"], description: msg.shortcuts.editing.clear },\n { keys: [\"Backspace\"], description: msg.shortcuts.editing.clear },\n ...(enableRowsDelete\n ? [\n { keys: [modKey, \"Backspace\"], description: msg.shortcuts.editing.deleteRows },\n { keys: [modKey, \"Delete\"], description: msg.shortcuts.editing.deleteRows }\n ]\n : []),\n ...(enableUndoRedo\n ? [\n { keys: [modKey, \"Z\"], description: msg.shortcuts.editing.undo },\n { keys: [modKey, \"Shift\", \"Z\"], description: msg.shortcuts.editing.redo }\n ]\n : [])\n ]\n },\n ...(enableSearch\n ? [\n {\n title: msg.shortcuts.groups.search,\n shortcuts: [\n { keys: [modKey, \"F\"], description: msg.shortcuts.search.open },\n { keys: [\"Enter\"], description: msg.shortcuts.search.next },\n { keys: [\"Shift\", \"Enter\"], description: msg.shortcuts.search.prev },\n { keys: [\"Esc\"], description: msg.shortcuts.search.close }\n ]\n }\n ]\n : []),\n {\n title: msg.shortcuts.groups.filtering,\n shortcuts: [\n { keys: [modKey, \"Shift\", \"F\"], description: msg.shortcuts.filtering.toggle },\n { keys: [\"Backspace\"], description: msg.shortcuts.filtering.remove },\n { keys: [\"Delete\"], description: msg.shortcuts.filtering.remove }\n ]\n },\n {\n title: msg.shortcuts.groups.sorting,\n shortcuts: [\n { keys: [modKey, \"Shift\", \"S\"], description: msg.shortcuts.sorting.toggle },\n { keys: [\"Backspace\"], description: msg.shortcuts.sorting.remove },\n { keys: [\"Delete\"], description: msg.shortcuts.sorting.remove }\n ]\n },\n {\n title: msg.shortcuts.groups.general,\n shortcuts: [{ keys: [modKey, \"/\"], description: msg.shortcuts.general.shortcuts }]\n }\n ],\n [msg, modKey, altKey, enableSearch, enableUndoRedo, enablePaste, enableRowAdd, enableRowsDelete]\n );\n\n const filteredGroups = React.useMemo(() => {\n if (!input.trim()) return shortcutGroups;\n\n const query = input.toLowerCase();\n return shortcutGroups\n .map((group) => ({\n ...group,\n shortcuts: group.shortcuts.filter(\n (shortcut) =>\n shortcut.description.toLowerCase().includes(query) ||\n shortcut.keys.some((key) => key.toLowerCase().includes(query))\n )\n }))\n .filter((group) => group.shortcuts.length > 0);\n }, [shortcutGroups, input]);\n\n React.useEffect(() => {\n function onKeyDown(event: KeyboardEvent) {\n if ((event.ctrlKey || event.metaKey) && event.key === SHORTCUT_KEY) {\n event.preventDefault();\n setOpen(true);\n }\n }\n\n window.addEventListener(\"keydown\", onKeyDown);\n return () => {\n window.removeEventListener(\"keydown\", onKeyDown);\n };\n }, []);\n\n return (\n <Dialog open={open} onOpenChange={onOpenChange}>\n {!hideTrigger && (\n <DialogTrigger asChild>\n <Button aria-label={msg.shortcuts.trigger} variant=\"outline\" size=\"icon-sm\">\n <Keyboard aria-hidden=\"true\" className=\"size-3.5 text-muted-foreground\" />\n </Button>\n </DialogTrigger>\n )}\n <DialogContent dir={dir} className=\"max-w-2xl px-0\" onOpenAutoFocus={onOpenAutoFocus}>\n <DialogHeader className=\"px-6\">\n <DialogTitle>{msg.shortcuts.title}</DialogTitle>\n <DialogDescription className=\"sr-only\">{msg.shortcuts.description}</DialogDescription>\n </DialogHeader>\n <div className=\"px-6\">\n <div className=\"relative\">\n <SearchIcon\n aria-hidden=\"true\"\n className=\"absolute start-3 top-1/2 size-3.5 -translate-y-1/2 text-muted-foreground\"\n />\n <Input\n ref={inputRef}\n placeholder={msg.shortcuts.searchPlaceholder}\n aria-label={msg.shortcuts.searchPlaceholder}\n className=\"h-8 ps-8\"\n value={input}\n onChange={onInputChange}\n />\n </div>\n </div>\n <Separator className=\"mx-auto w-[calc(100%-3rem)]\" />\n <div className=\"h-[40vh] overflow-y-auto px-6\">\n {filteredGroups.length === 0 ? (\n <div className=\"flex h-full flex-col items-center justify-center gap-3 text-center\">\n <div className=\"flex size-10 shrink-0 items-center justify-center rounded-lg bg-muted text-foreground\">\n <SearchIcon aria-hidden=\"true\" className=\"pointer-events-none size-6\" />\n </div>\n <div className=\"flex flex-col gap-1\">\n <div className=\"font-medium text-lg tracking-tight\">{msg.shortcuts.emptyTitle}</div>\n <p className=\"text-muted-foreground text-sm\">{msg.shortcuts.emptyDescription}</p>\n </div>\n </div>\n ) : (\n <div className=\"flex flex-col gap-6\">\n {filteredGroups.map((shortcutGroup) => (\n <div key={shortcutGroup.title} className=\"flex flex-col gap-2\">\n <h3 className=\"font-semibold text-foreground text-sm\">{shortcutGroup.title}</h3>\n <div className=\"divide-y divide-border rounded-md border\">\n {shortcutGroup.shortcuts.map((shortcut) => (\n <ShortcutCard\n key={`${shortcut.description}-${shortcut.keys.join(\"+\")}`}\n keys={shortcut.keys}\n description={shortcut.description}\n />\n ))}\n </div>\n </div>\n ))}\n </div>\n )}\n </div>\n </DialogContent>\n </Dialog>\n );\n}\n\nfunction ShortcutCard({ keys, description }: ShortcutGroup[\"shortcuts\"][number]) {\n return (\n <div className=\"flex items-center gap-4 px-3 py-2\">\n <span className=\"flex-1 text-sm\">{description}</span>\n <KbdGroup className=\"shrink-0\">\n {keys.map((key, index) => (\n <React.Fragment key={key}>\n {index > 0 && <span className=\"text-muted-foreground text-xs\">+</span>}\n <Kbd>{key}</Kbd>\n </React.Fragment>\n ))}\n </KbdGroup>\n </div>\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { DataGridLocale } from './messages.js';
|
|
3
|
+
import { DataGridMessages } from './messages-en.js';
|
|
4
|
+
import './messages-vi.js';
|
|
5
|
+
|
|
6
|
+
interface DataGridLocaleProviderProps {
|
|
7
|
+
/** Mã ngôn ngữ (`"en"` · `"vi"`) hoặc cả một bảng chuỗi tự soạn. */
|
|
8
|
+
locale?: DataGridLocale | DataGridMessages;
|
|
9
|
+
children: React.ReactNode;
|
|
10
|
+
}
|
|
11
|
+
declare function DataGridLocaleProvider({ locale, children }: DataGridLocaleProviderProps): React.JSX.Element;
|
|
12
|
+
/**
|
|
13
|
+
* Bảng chuỗi đang có hiệu lực. KHÔNG ném lỗi khi thiếu provider — lưới phải dùng được ở dạng
|
|
14
|
+
* trần (`<DataGrid>` một mình, không bọc gì), và khi ấy mặc định tiếng Anh là câu trả lời đúng.
|
|
15
|
+
*/
|
|
16
|
+
declare function useDataGridMessages(): DataGridMessages;
|
|
17
|
+
/**
|
|
18
|
+
* Dành cho component nhận prop `locale` của riêng nó: prop thắng, không có prop thì theo provider.
|
|
19
|
+
* Tách ra thành hook riêng để năm component thanh công cụ không mỗi cái viết lại luật ưu tiên một
|
|
20
|
+
* kiểu.
|
|
21
|
+
*/
|
|
22
|
+
declare function useResolvedDataGridMessages(locale?: DataGridLocale | DataGridMessages): DataGridMessages;
|
|
23
|
+
|
|
24
|
+
export { DataGridLocaleProvider, type DataGridLocaleProviderProps, useDataGridMessages, useResolvedDataGridMessages };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { getDataGridMessages } from "./messages.js";
|
|
5
|
+
const DataGridLocaleContext = React.createContext(null);
|
|
6
|
+
function DataGridLocaleProvider({ locale, children }) {
|
|
7
|
+
const messages = React.useMemo(() => getDataGridMessages(locale), [locale]);
|
|
8
|
+
return /* @__PURE__ */ jsx(DataGridLocaleContext.Provider, { value: messages, children });
|
|
9
|
+
}
|
|
10
|
+
function useDataGridMessages() {
|
|
11
|
+
return React.useContext(DataGridLocaleContext) ?? getDataGridMessages();
|
|
12
|
+
}
|
|
13
|
+
function useResolvedDataGridMessages(locale) {
|
|
14
|
+
const fromContext = React.useContext(DataGridLocaleContext);
|
|
15
|
+
return React.useMemo(() => {
|
|
16
|
+
if (locale) return getDataGridMessages(locale);
|
|
17
|
+
return fromContext ?? getDataGridMessages();
|
|
18
|
+
}, [locale, fromContext]);
|
|
19
|
+
}
|
|
20
|
+
export {
|
|
21
|
+
DataGridLocaleProvider,
|
|
22
|
+
useDataGridMessages,
|
|
23
|
+
useResolvedDataGridMessages
|
|
24
|
+
};
|
|
25
|
+
//# sourceMappingURL=data-grid-locale.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/data-grid/data-grid-locale.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { type DataGridLocale, type DataGridMessages, getDataGridMessages } from \"./messages.js\";\n\n/**\n * Ngôn ngữ của DataGrid, đi xuống cây bằng context.\n *\n * ─ VÌ SAO CẦN PROVIDER CHỨ KHÔNG CHỈ MỘT PROP ─\n * Thanh công cụ (`DataGridFilterMenu`, `DataGridSortMenu`, `DataGridViewMenu`,\n * `DataGridRowHeightMenu`, `DataGridKeyboardShortcuts`) nằm NGOÀI `<DataGrid>` — app tự đặt chúng\n * ở đâu tuỳ ý. Vậy nên một prop trên `<DataGrid>` không với tới chúng được, và bắt mỗi cái tự\n * nhận `locale` thì năm chỗ phải nhớ truyền, quên một chỗ là màn hình lẫn hai thứ tiếng.\n *\n * Nên có HAI đường, và thứ tự ưu tiên là: prop `locale` của chính component → provider gần nhất →\n * mặc định `\"en\"`. App bọc một lần quanh cả màn là xong; chỗ nào cần khác thì đè bằng prop.\n *\n * `useDataGrid({ locale })` cũng nhận cùng giá trị ấy, vì hook bắn toast và toast không có cây DOM\n * nào để đọc context — nó phải giữ bảng chuỗi của riêng nó.\n */\n\nconst DataGridLocaleContext = React.createContext<DataGridMessages | null>(null);\n\nexport interface DataGridLocaleProviderProps {\n /** Mã ngôn ngữ (`\"en\"` · `\"vi\"`) hoặc cả một bảng chuỗi tự soạn. */\n locale?: DataGridLocale | DataGridMessages;\n children: React.ReactNode;\n}\n\nexport function DataGridLocaleProvider({ locale, children }: DataGridLocaleProviderProps) {\n const messages = React.useMemo(() => getDataGridMessages(locale), [locale]);\n return <DataGridLocaleContext.Provider value={messages}>{children}</DataGridLocaleContext.Provider>;\n}\n\n/**\n * Bảng chuỗi đang có hiệu lực. KHÔNG ném lỗi khi thiếu provider — lưới phải dùng được ở dạng\n * trần (`<DataGrid>` một mình, không bọc gì), và khi ấy mặc định tiếng Anh là câu trả lời đúng.\n */\nexport function useDataGridMessages(): DataGridMessages {\n return React.useContext(DataGridLocaleContext) ?? getDataGridMessages();\n}\n\n/**\n * Dành cho component nhận prop `locale` của riêng nó: prop thắng, không có prop thì theo provider.\n * Tách ra thành hook riêng để năm component thanh công cụ không mỗi cái viết lại luật ưu tiên một\n * kiểu.\n */\nexport function useResolvedDataGridMessages(locale?: DataGridLocale | DataGridMessages): DataGridMessages {\n const fromContext = React.useContext(DataGridLocaleContext);\n return React.useMemo(() => {\n if (locale) return getDataGridMessages(locale);\n return fromContext ?? getDataGridMessages();\n }, [locale, fromContext]);\n}\n"],"mappings":";AA+BS;AA7BT,YAAY,WAAW;AACvB,SAAqD,2BAA2B;AAkBhF,MAAM,wBAAwB,MAAM,cAAuC,IAAI;AAQxE,SAAS,uBAAuB,EAAE,QAAQ,SAAS,GAAgC;AACxF,QAAM,WAAW,MAAM,QAAQ,MAAM,oBAAoB,MAAM,GAAG,CAAC,MAAM,CAAC;AAC1E,SAAO,oBAAC,sBAAsB,UAAtB,EAA+B,OAAO,UAAW,UAAS;AACpE;AAMO,SAAS,sBAAwC;AACtD,SAAO,MAAM,WAAW,qBAAqB,KAAK,oBAAoB;AACxE;AAOO,SAAS,4BAA4B,QAA8D;AACxG,QAAM,cAAc,MAAM,WAAW,qBAAqB;AAC1D,SAAO,MAAM,QAAQ,MAAM;AACzB,QAAI,OAAQ,QAAO,oBAAoB,MAAM;AAC7C,WAAO,eAAe,oBAAoB;AAAA,EAC5C,GAAG,CAAC,QAAQ,WAAW,CAAC;AAC1B;","names":[]}
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
DialogTitle
|
|
12
12
|
} from "../components/ui/dialog.js";
|
|
13
13
|
import { cn } from "../lib/cn.js";
|
|
14
|
-
import {
|
|
14
|
+
import { useDataGridMessages } from "./data-grid-locale.js";
|
|
15
15
|
import { useAsRef } from "./use-as-ref.js";
|
|
16
16
|
function DataGridPasteDialog({ tableMeta, pasteDialog }) {
|
|
17
17
|
const onPasteDialogOpenChange = tableMeta?.onPasteDialogOpenChange;
|
|
@@ -33,6 +33,7 @@ const PasteDialog = React.memo(PasteDialogImpl, (prev, next) => {
|
|
|
33
33
|
return true;
|
|
34
34
|
});
|
|
35
35
|
function PasteDialogImpl({ pasteDialog, onPasteDialogOpenChange, onCellsPaste }) {
|
|
36
|
+
const msg = useDataGridMessages();
|
|
36
37
|
const propsRef = useAsRef({
|
|
37
38
|
onPasteDialogOpenChange,
|
|
38
39
|
onCellsPaste
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/data-grid/data-grid-paste-dialog.tsx"],"sourcesContent":["\"use client\";\n\nimport type { TableMeta } from \"@tanstack/react-table\";\nimport * as React from \"react\";\nimport { Button } from \"../components/ui/button.js\";\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle\n} from \"../components/ui/dialog.js\";\nimport { cn } from \"../lib/cn.js\";\nimport {
|
|
1
|
+
{"version":3,"sources":["../../src/data-grid/data-grid-paste-dialog.tsx"],"sourcesContent":["\"use client\";\n\nimport type { TableMeta } from \"@tanstack/react-table\";\nimport * as React from \"react\";\nimport { Button } from \"../components/ui/button.js\";\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle\n} from \"../components/ui/dialog.js\";\nimport { cn } from \"../lib/cn.js\";\nimport { useDataGridMessages } from \"./data-grid-locale.js\";\nimport type { PasteDialogState } from \"./types.js\";\nimport { useAsRef } from \"./use-as-ref.js\";\n\ninterface DataGridPasteDialogProps<TData> {\n tableMeta: TableMeta<TData>;\n pasteDialog: PasteDialogState;\n}\n\nexport function DataGridPasteDialog<TData>({ tableMeta, pasteDialog }: DataGridPasteDialogProps<TData>) {\n const onPasteDialogOpenChange = tableMeta?.onPasteDialogOpenChange;\n const onCellsPaste = tableMeta?.onCellsPaste;\n\n if (!pasteDialog.open) return null;\n\n return (\n <PasteDialog\n pasteDialog={pasteDialog}\n onPasteDialogOpenChange={onPasteDialogOpenChange}\n onCellsPaste={onCellsPaste}\n />\n );\n}\n\ninterface PasteDialogProps\n extends Pick<TableMeta<unknown>, \"onPasteDialogOpenChange\" | \"onCellsPaste\">,\n Required<Pick<TableMeta<unknown>, \"pasteDialog\">> {}\n\nconst PasteDialog = React.memo(PasteDialogImpl, (prev, next) => {\n if (prev.pasteDialog.open !== next.pasteDialog.open) return false;\n if (!next.pasteDialog.open) return true;\n if (prev.pasteDialog.rowsNeeded !== next.pasteDialog.rowsNeeded) return false;\n\n return true;\n});\n\nfunction PasteDialogImpl({ pasteDialog, onPasteDialogOpenChange, onCellsPaste }: PasteDialogProps) {\n const msg = useDataGridMessages();\n\n const propsRef = useAsRef({\n onPasteDialogOpenChange,\n onCellsPaste\n });\n\n const expandRadioRef = React.useRef<HTMLInputElement | null>(null);\n\n const onOpenChange = React.useCallback(\n (open: boolean) => {\n propsRef.current.onPasteDialogOpenChange?.(open);\n },\n [propsRef]\n );\n\n const onCancel = React.useCallback(() => {\n propsRef.current.onPasteDialogOpenChange?.(false);\n }, [propsRef]);\n\n const onContinue = React.useCallback(() => {\n propsRef.current.onCellsPaste?.(expandRadioRef.current?.checked ?? false);\n }, [propsRef]);\n\n return (\n <Dialog open={pasteDialog.open} onOpenChange={onOpenChange}>\n <DialogContent data-grid-popover=\"\">\n <DialogHeader>\n <DialogTitle>{msg.pasteDialog.title}</DialogTitle>\n <DialogDescription>{msg.pasteDialog.description(pasteDialog.rowsNeeded)}</DialogDescription>\n </DialogHeader>\n <div className=\"flex flex-col gap-3 py-1\">\n {/* biome-ignore lint/a11y/noLabelWithoutControl: <RadioItem> bọc sẵn <input type=\"radio\"> bên trong */}\n <label className=\"flex cursor-pointer items-start gap-3\">\n <RadioItem ref={expandRadioRef} name=\"expand-option\" value=\"expand\" defaultChecked />\n <div className=\"flex flex-col gap-1\">\n <span className=\"font-medium text-sm leading-none\">{msg.pasteDialog.expandTitle}</span>\n <span className=\"text-muted-foreground text-sm\">\n {msg.pasteDialog.expandDescription(pasteDialog.rowsNeeded)}\n </span>\n </div>\n </label>\n {/* biome-ignore lint/a11y/noLabelWithoutControl: <RadioItem> bọc sẵn <input type=\"radio\"> bên trong */}\n <label className=\"flex cursor-pointer items-start gap-3\">\n <RadioItem name=\"expand-option\" value=\"no-expand\" />\n <div className=\"flex flex-col gap-1\">\n <span className=\"font-medium text-sm leading-none\">{msg.pasteDialog.keepTitle}</span>\n <span className=\"text-muted-foreground text-sm\">{msg.pasteDialog.keepDescription}</span>\n </div>\n </label>\n </div>\n <DialogFooter className=\"gap-2\">\n <Button variant=\"outline\" onClick={onCancel}>\n {msg.pasteDialog.cancel}\n </Button>\n <Button onClick={onContinue}>{msg.pasteDialog.confirm}</Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n );\n}\n\n/**\n * Radio thuần HTML (không dùng RadioGroup của Radix) để bấm vào cả khối `<label>`\n * là chọn được, và để đọc trạng thái qua ref lúc bấm \"Tiếp tục\".\n */\nfunction RadioItem({ className, ...props }: React.ComponentProps<\"input\">) {\n return (\n <input\n type=\"radio\"\n className={cn(\n // Cùng bộ token với `RadioGroupItem` của gói (`--choice-edge` cho viền nghỉ,\n // `--control-on` cho viền + chấm khi chọn) — đừng quay lại `--primary`/`--ring`: đó là\n // bậc tô NỀN, đem vẽ NÉT thì ở light chỉ 1,73:1.\n \"relative mt-0.5 size-4 shrink-0 appearance-none rounded-full border border-choice-edge outline-none transition-colors dark:bg-input-fill\",\n \"hover:border-choice-edge-strong checked:border-control-on\",\n \"focus-visible:ring-2 focus-visible:ring-ring/50 focus-visible:ring-offset-2 focus-visible:ring-offset-background\",\n \"disabled:cursor-not-allowed disabled:opacity-50\",\n \"checked:before:absolute checked:before:start-1/2 checked:before:top-1/2 checked:before:size-2 checked:before:-translate-x-1/2 checked:before:-translate-y-1/2 checked:before:rounded-full checked:before:bg-control-on checked:before:content-['']\",\n className\n )}\n {...props}\n />\n );\n}\n"],"mappings":";AA8BI,cAgDI,YAhDJ;AA3BJ,YAAY,WAAW;AACvB,SAAS,cAAc;AACvB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,UAAU;AACnB,SAAS,2BAA2B;AAEpC,SAAS,gBAAgB;AAOlB,SAAS,oBAA2B,EAAE,WAAW,YAAY,GAAoC;AACtG,QAAM,0BAA0B,WAAW;AAC3C,QAAM,eAAe,WAAW;AAEhC,MAAI,CAAC,YAAY,KAAM,QAAO;AAE9B,SACE;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA;AAAA,MACA;AAAA;AAAA,EACF;AAEJ;AAMA,MAAM,cAAc,MAAM,KAAK,iBAAiB,CAAC,MAAM,SAAS;AAC9D,MAAI,KAAK,YAAY,SAAS,KAAK,YAAY,KAAM,QAAO;AAC5D,MAAI,CAAC,KAAK,YAAY,KAAM,QAAO;AACnC,MAAI,KAAK,YAAY,eAAe,KAAK,YAAY,WAAY,QAAO;AAExE,SAAO;AACT,CAAC;AAED,SAAS,gBAAgB,EAAE,aAAa,yBAAyB,aAAa,GAAqB;AACjG,QAAM,MAAM,oBAAoB;AAEhC,QAAM,WAAW,SAAS;AAAA,IACxB;AAAA,IACA;AAAA,EACF,CAAC;AAED,QAAM,iBAAiB,MAAM,OAAgC,IAAI;AAEjE,QAAM,eAAe,MAAM;AAAA,IACzB,CAAC,SAAkB;AACjB,eAAS,QAAQ,0BAA0B,IAAI;AAAA,IACjD;AAAA,IACA,CAAC,QAAQ;AAAA,EACX;AAEA,QAAM,WAAW,MAAM,YAAY,MAAM;AACvC,aAAS,QAAQ,0BAA0B,KAAK;AAAA,EAClD,GAAG,CAAC,QAAQ,CAAC;AAEb,QAAM,aAAa,MAAM,YAAY,MAAM;AACzC,aAAS,QAAQ,eAAe,eAAe,SAAS,WAAW,KAAK;AAAA,EAC1E,GAAG,CAAC,QAAQ,CAAC;AAEb,SACE,oBAAC,UAAO,MAAM,YAAY,MAAM,cAC9B,+BAAC,iBAAc,qBAAkB,IAC/B;AAAA,yBAAC,gBACC;AAAA,0BAAC,eAAa,cAAI,YAAY,OAAM;AAAA,MACpC,oBAAC,qBAAmB,cAAI,YAAY,YAAY,YAAY,UAAU,GAAE;AAAA,OAC1E;AAAA,IACA,qBAAC,SAAI,WAAU,4BAEb;AAAA,2BAAC,WAAM,WAAU,yCACf;AAAA,4BAAC,aAAU,KAAK,gBAAgB,MAAK,iBAAgB,OAAM,UAAS,gBAAc,MAAC;AAAA,QACnF,qBAAC,SAAI,WAAU,uBACb;AAAA,8BAAC,UAAK,WAAU,oCAAoC,cAAI,YAAY,aAAY;AAAA,UAChF,oBAAC,UAAK,WAAU,iCACb,cAAI,YAAY,kBAAkB,YAAY,UAAU,GAC3D;AAAA,WACF;AAAA,SACF;AAAA,MAEA,qBAAC,WAAM,WAAU,yCACf;AAAA,4BAAC,aAAU,MAAK,iBAAgB,OAAM,aAAY;AAAA,QAClD,qBAAC,SAAI,WAAU,uBACb;AAAA,8BAAC,UAAK,WAAU,oCAAoC,cAAI,YAAY,WAAU;AAAA,UAC9E,oBAAC,UAAK,WAAU,iCAAiC,cAAI,YAAY,iBAAgB;AAAA,WACnF;AAAA,SACF;AAAA,OACF;AAAA,IACA,qBAAC,gBAAa,WAAU,SACtB;AAAA,0BAAC,UAAO,SAAQ,WAAU,SAAS,UAChC,cAAI,YAAY,QACnB;AAAA,MACA,oBAAC,UAAO,SAAS,YAAa,cAAI,YAAY,SAAQ;AAAA,OACxD;AAAA,KACF,GACF;AAEJ;AAMA,SAAS,UAAU,EAAE,WAAW,GAAG,MAAM,GAAkC;AACzE,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,WAAW;AAAA;AAAA;AAAA;AAAA,QAIT;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,MACC,GAAG;AAAA;AAAA,EACN;AAEJ;","names":[]}
|
|
@@ -1,15 +1,25 @@
|
|
|
1
1
|
import { Table } from '@tanstack/react-table';
|
|
2
2
|
import * as React from 'react';
|
|
3
3
|
import { SelectContent } from '../components/ui/select.js';
|
|
4
|
+
import { DataGridLocale } from './messages.js';
|
|
5
|
+
import { DataGridMessages } from './messages-en.js';
|
|
4
6
|
import '@radix-ui/react-select';
|
|
7
|
+
import './messages-vi.js';
|
|
5
8
|
|
|
6
9
|
interface DataGridRowHeightMenuProps<TData> extends React.ComponentProps<typeof SelectContent> {
|
|
7
10
|
table: Table<TData>;
|
|
8
11
|
disabled?: boolean;
|
|
9
12
|
/** className cho nút mở menu (mặc định cao 8 như các nút khác trên thanh công cụ) */
|
|
10
13
|
triggerClassName?: string;
|
|
14
|
+
/**
|
|
15
|
+
* Ngôn ngữ của menu: `"en"` (mặc định) · `"vi"`, hoặc cả một bảng chuỗi tự soạn.
|
|
16
|
+
*
|
|
17
|
+
* ⚠ 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
|
|
18
|
+
* cả màn bằng `DataGridLocaleProvider`, hoặc truyền prop này cho từng menu. Prop thắng provider.
|
|
19
|
+
*/
|
|
20
|
+
locale?: DataGridLocale | DataGridMessages;
|
|
11
21
|
}
|
|
12
22
|
/** 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ụ. */
|
|
13
|
-
declare function DataGridRowHeightMenu<TData>({ table, disabled, triggerClassName, ...props }: DataGridRowHeightMenuProps<TData>): React.JSX.Element;
|
|
23
|
+
declare function DataGridRowHeightMenu<TData>({ table, disabled, triggerClassName, locale, ...props }: DataGridRowHeightMenuProps<TData>): React.JSX.Element;
|
|
14
24
|
|
|
15
25
|
export { DataGridRowHeightMenu };
|
|
@@ -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":[]}
|
|
@@ -4,7 +4,7 @@ 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 {
|
|
7
|
+
import { useDataGridMessages } from "./data-grid-locale.js";
|
|
8
8
|
import { useAsRef } from "./use-as-ref.js";
|
|
9
9
|
import { useDebouncedCallback } from "./use-debounced-callback.js";
|
|
10
10
|
function onTriggerPointerDown(event) {
|
|
@@ -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 { useDataGridMessages } from \"./data-grid-locale.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 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 };
|