@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.
Files changed (59) hide show
  1. package/README.md +10 -2
  2. package/dist/data-grid/data-grid-cell-variants.js +10 -6
  3. package/dist/data-grid/data-grid-cell-variants.js.map +1 -1
  4. package/dist/data-grid/data-grid-column-header.js +4 -2
  5. package/dist/data-grid/data-grid-column-header.js.map +1 -1
  6. package/dist/data-grid/data-grid-context-menu.js +4 -3
  7. package/dist/data-grid/data-grid-context-menu.js.map +1 -1
  8. package/dist/data-grid/data-grid-filter-menu.d.ts +12 -1
  9. package/dist/data-grid/data-grid-filter-menu.js +28 -17
  10. package/dist/data-grid/data-grid-filter-menu.js.map +1 -1
  11. package/dist/data-grid/data-grid-keyboard-shortcuts.d.ts +12 -1
  12. package/dist/data-grid/data-grid-keyboard-shortcuts.js +7 -5
  13. package/dist/data-grid/data-grid-keyboard-shortcuts.js.map +1 -1
  14. package/dist/data-grid/data-grid-locale.d.ts +24 -0
  15. package/dist/data-grid/data-grid-locale.js +25 -0
  16. package/dist/data-grid/data-grid-locale.js.map +1 -0
  17. package/dist/data-grid/data-grid-paste-dialog.js +2 -1
  18. package/dist/data-grid/data-grid-paste-dialog.js.map +1 -1
  19. package/dist/data-grid/data-grid-row-height-menu.d.ts +11 -1
  20. package/dist/data-grid/data-grid-row-height-menu.js +25 -28
  21. package/dist/data-grid/data-grid-row-height-menu.js.map +1 -1
  22. package/dist/data-grid/data-grid-search.js +5 -4
  23. package/dist/data-grid/data-grid-search.js.map +1 -1
  24. package/dist/data-grid/data-grid-select-column.js +3 -1
  25. package/dist/data-grid/data-grid-select-column.js.map +1 -1
  26. package/dist/data-grid/data-grid-sort-menu.d.ts +12 -1
  27. package/dist/data-grid/data-grid-sort-menu.js +25 -13
  28. package/dist/data-grid/data-grid-sort-menu.js.map +1 -1
  29. package/dist/data-grid/data-grid-view-menu.d.ts +12 -1
  30. package/dist/data-grid/data-grid-view-menu.js +12 -4
  31. package/dist/data-grid/data-grid-view-menu.js.map +1 -1
  32. package/dist/data-grid/data-grid.d.ts +14 -2
  33. package/dist/data-grid/data-grid.js +6 -3
  34. package/dist/data-grid/data-grid.js.map +1 -1
  35. package/dist/data-grid/filters.d.ts +17 -21
  36. package/dist/data-grid/filters.js +73 -52
  37. package/dist/data-grid/filters.js.map +1 -1
  38. package/dist/data-grid/index.d.ts +4 -1
  39. package/dist/data-grid/index.js +20 -2
  40. package/dist/data-grid/index.js.map +1 -1
  41. package/dist/data-grid/messages-en.d.ts +294 -0
  42. package/dist/data-grid/messages-en.js +279 -0
  43. package/dist/data-grid/messages-en.js.map +1 -0
  44. package/dist/data-grid/messages-vi.d.ts +12 -0
  45. package/dist/data-grid/messages-vi.js +279 -0
  46. package/dist/data-grid/messages-vi.js.map +1 -0
  47. package/dist/data-grid/messages.d.ts +549 -262
  48. package/dist/data-grid/messages.js +16 -275
  49. package/dist/data-grid/messages.js.map +1 -1
  50. package/dist/data-grid/use-data-grid-undo-redo.d.ts +13 -1
  51. package/dist/data-grid/use-data-grid-undo-redo.js +11 -8
  52. package/dist/data-grid/use-data-grid-undo-redo.js.map +1 -1
  53. package/dist/data-grid/use-data-grid.d.ts +281 -1
  54. package/dist/data-grid/use-data-grid.js +21 -16
  55. package/dist/data-grid/use-data-grid.js.map +1 -1
  56. package/dist/data-grid/utils.d.ts +9 -1
  57. package/dist/data-grid/utils.js +3 -2
  58. package/dist/data-grid/utils.js.map +1 -1
  59. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/data-grid/data-grid-column-header.tsx"],"sourcesContent":["\"use client\";\n\nimport type { ColumnSort, Header, SortDirection, SortingState, Table } from \"@tanstack/react-table\";\nimport { ChevronDownIcon, ChevronUpIcon, EyeOffIcon, PinIcon, PinOffIcon, XIcon } from \"lucide-react\";\nimport * as React from \"react\";\n\nimport {\n DropdownMenu,\n DropdownMenuCheckboxItem,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuSeparator,\n DropdownMenuTrigger\n} from \"../components/ui/dropdown-menu.js\";\nimport { Tooltip, TooltipContent, TooltipTrigger } from \"../components/ui/tooltip.js\";\nimport { cn } from \"../lib/cn.js\";\nimport { msg } from \"./messages.js\";\nimport { getColumnVariant } from \"./utils.js\";\n\ninterface DataGridColumnHeaderProps<TData, TValue> extends React.ComponentProps<typeof DropdownMenuTrigger> {\n header: Header<TData, TValue>;\n table: Table<TData>;\n}\n\nexport function DataGridColumnHeader<TData, TValue>({\n header,\n table,\n className,\n onPointerDown,\n ...props\n}: DataGridColumnHeaderProps<TData, TValue>) {\n const column = header.column;\n const label = column.columnDef.meta?.label\n ? column.columnDef.meta.label\n : typeof column.columnDef.header === \"string\"\n ? column.columnDef.header\n : column.id;\n\n const isAnyColumnResizing = table.getState().columnSizingInfo.isResizingColumn;\n\n const cellVariant = column.columnDef.meta?.cell;\n const columnVariant = getColumnVariant(cellVariant?.variant);\n\n const pinnedPosition = column.getIsPinned();\n const isPinnedLeft = pinnedPosition === \"left\";\n const isPinnedRight = pinnedPosition === \"right\";\n\n const onSortingChange = React.useCallback(\n (direction: SortDirection) => {\n table.setSorting((prev: SortingState) => {\n const existingSortIndex = prev.findIndex((sort) => sort.id === column.id);\n const newSort: ColumnSort = {\n id: column.id,\n desc: direction === \"desc\"\n };\n\n if (existingSortIndex >= 0) {\n const updated = [...prev];\n updated[existingSortIndex] = newSort;\n return updated;\n } else {\n return [...prev, newSort];\n }\n });\n },\n [column.id, table]\n );\n\n const onSortRemove = React.useCallback(() => {\n table.setSorting((prev: SortingState) => prev.filter((sort) => sort.id !== column.id));\n }, [column.id, table]);\n\n const onLeftPin = React.useCallback(() => {\n column.pin(\"left\");\n }, [column]);\n\n const onRightPin = React.useCallback(() => {\n column.pin(\"right\");\n }, [column]);\n\n const onUnpin = React.useCallback(() => {\n column.pin(false);\n }, [column]);\n\n const onTriggerPointerDown = React.useCallback(\n (event: React.PointerEvent<HTMLButtonElement>) => {\n onPointerDown?.(event);\n if (event.defaultPrevented) return;\n\n if (event.button !== 0) {\n return;\n }\n table.options.meta?.onColumnClick?.(column.id);\n },\n [table.options.meta, column.id, onPointerDown]\n );\n\n return (\n <>\n <DropdownMenu modal={false}>\n <DropdownMenuTrigger\n className={cn(\n \"flex size-full items-center justify-between gap-2 p-2 text-sm hover:bg-accent/40 data-[state=open]:bg-accent/40 [&_svg]:size-4\",\n isAnyColumnResizing && \"pointer-events-none\",\n className\n )}\n onPointerDown={onTriggerPointerDown}\n {...props}\n >\n <div className=\"flex min-w-0 flex-1 items-center gap-1.5\">\n {columnVariant && (\n <Tooltip delayDuration={100}>\n <TooltipTrigger asChild>\n <columnVariant.icon className=\"size-3.5 shrink-0 text-muted-foreground\" />\n </TooltipTrigger>\n {/* `TooltipContent` của gói TỰ portal ra ngoài — cần thiết vì hộp lưới\n có overflow-auto, không portal thì tooltip bị cắt. */}\n <TooltipContent side=\"top\">{columnVariant.label}</TooltipContent>\n </Tooltip>\n )}\n <span className=\"truncate\">{label}</span>\n </div>\n <ChevronDownIcon className=\"shrink-0 text-muted-foreground\" />\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"start\" sideOffset={0} className=\"w-60\">\n {column.getCanSort() && (\n <>\n <DropdownMenuCheckboxItem\n className=\"gap-2 [&>svg]:size-4 [&>svg]:shrink-0 [&>svg]:text-muted-foreground\"\n checked={column.getIsSorted() === \"asc\"}\n onSelect={() => onSortingChange(\"asc\")}\n >\n <ChevronUpIcon />\n {msg.column.sortAsc}\n </DropdownMenuCheckboxItem>\n <DropdownMenuCheckboxItem\n className=\"gap-2 [&>svg]:size-4 [&>svg]:shrink-0 [&>svg]:text-muted-foreground\"\n checked={column.getIsSorted() === \"desc\"}\n onSelect={() => onSortingChange(\"desc\")}\n >\n <ChevronDownIcon />\n {msg.column.sortDesc}\n </DropdownMenuCheckboxItem>\n {column.getIsSorted() && (\n <DropdownMenuItem onSelect={onSortRemove}>\n <XIcon />\n {msg.column.removeSort}\n </DropdownMenuItem>\n )}\n </>\n )}\n {column.getCanPin() && (\n <>\n {column.getCanSort() && <DropdownMenuSeparator />}\n\n {isPinnedLeft ? (\n <DropdownMenuItem className=\"[&_svg]:text-muted-foreground\" onSelect={onUnpin}>\n <PinOffIcon />\n {msg.column.unpinLeft}\n </DropdownMenuItem>\n ) : (\n <DropdownMenuItem className=\"[&_svg]:text-muted-foreground\" onSelect={onLeftPin}>\n <PinIcon />\n {msg.column.pinLeft}\n </DropdownMenuItem>\n )}\n {isPinnedRight ? (\n <DropdownMenuItem className=\"[&_svg]:text-muted-foreground\" onSelect={onUnpin}>\n <PinOffIcon />\n {msg.column.unpinRight}\n </DropdownMenuItem>\n ) : (\n <DropdownMenuItem className=\"[&_svg]:text-muted-foreground\" onSelect={onRightPin}>\n <PinIcon />\n {msg.column.pinRight}\n </DropdownMenuItem>\n )}\n </>\n )}\n {column.getCanHide() && (\n <>\n <DropdownMenuSeparator />\n <DropdownMenuItem\n className=\"[&_svg]:text-muted-foreground\"\n onSelect={() => column.toggleVisibility(false)}\n >\n <EyeOffIcon />\n {msg.column.hide}\n </DropdownMenuItem>\n </>\n )}\n </DropdownMenuContent>\n </DropdownMenu>\n {header.column.getCanResize() && <DataGridColumnResizer header={header} table={table} label={label} />}\n </>\n );\n}\n\nconst DataGridColumnResizer = React.memo(DataGridColumnResizerImpl, (prev, next) => {\n const prevColumn = prev.header.column;\n const nextColumn = next.header.column;\n\n if (prevColumn.getIsResizing() !== nextColumn.getIsResizing() || prevColumn.getSize() !== nextColumn.getSize()) {\n return false;\n }\n\n if (prev.label !== next.label) return false;\n\n return true;\n}) as typeof DataGridColumnResizerImpl;\n\ninterface DataGridColumnResizerProps<TData, TValue> extends DataGridColumnHeaderProps<TData, TValue> {\n label: string;\n}\n\nfunction DataGridColumnResizerImpl<TData, TValue>({ header, table, label }: DataGridColumnResizerProps<TData, TValue>) {\n const defaultColumnDef = table._getDefaultColumnDef();\n\n const onDoubleClick = React.useCallback(() => {\n header.column.resetSize();\n }, [header.column]);\n\n return (\n <div\n role=\"separator\"\n aria-orientation=\"vertical\"\n aria-label={msg.column.resize(label)}\n aria-valuenow={header.column.getSize()}\n aria-valuemin={defaultColumnDef.minSize}\n aria-valuemax={defaultColumnDef.maxSize}\n tabIndex={0}\n className={cn(\n // Tay kéo chỉ hiện khi rê/focus/đang kéo, nên nó CHỈ mang đúng một màu — `--primary-ink`\n // (bậc NÉT). `--primary` trần là bậc tô NỀN: gold #E8B824 chỉ 1,73:1 với nền trang ở\n // light, tức một tay kéo nhìn thấy được ở dark mà gần như vô hình ở light.\n \"absolute -end-px top-0 z-50 h-full w-0.5 cursor-ew-resize touch-none select-none bg-primary-ink transition-opacity after:absolute after:inset-y-0 after:start-1/2 after:h-full after:w-[18px] after:-translate-x-1/2 after:content-[''] focus:outline-none\",\n header.column.getIsResizing() ? \"opacity-100\" : \"opacity-0 hover:opacity-100 focus:opacity-100\"\n )}\n onDoubleClick={onDoubleClick}\n onMouseDown={header.getResizeHandler()}\n onTouchStart={header.getResizeHandler()}\n />\n );\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/data-grid/data-grid-column-header.tsx"],"sourcesContent":["\"use client\";\n\nimport type { ColumnSort, Header, SortDirection, SortingState, Table } from \"@tanstack/react-table\";\nimport { ChevronDownIcon, ChevronUpIcon, EyeOffIcon, PinIcon, PinOffIcon, XIcon } from \"lucide-react\";\nimport * as React from \"react\";\n\nimport {\n DropdownMenu,\n DropdownMenuCheckboxItem,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuSeparator,\n DropdownMenuTrigger\n} from \"../components/ui/dropdown-menu.js\";\nimport { Tooltip, TooltipContent, TooltipTrigger } from \"../components/ui/tooltip.js\";\nimport { cn } from \"../lib/cn.js\";\nimport { useDataGridMessages } from \"./data-grid-locale.js\";\nimport { getColumnVariant } from \"./utils.js\";\n\ninterface DataGridColumnHeaderProps<TData, TValue> extends React.ComponentProps<typeof DropdownMenuTrigger> {\n header: Header<TData, TValue>;\n table: Table<TData>;\n}\n\nexport function DataGridColumnHeader<TData, TValue>({\n header,\n table,\n className,\n onPointerDown,\n ...props\n}: DataGridColumnHeaderProps<TData, TValue>) {\n const msg = useDataGridMessages();\n\n const column = header.column;\n const label = column.columnDef.meta?.label\n ? column.columnDef.meta.label\n : typeof column.columnDef.header === \"string\"\n ? column.columnDef.header\n : column.id;\n\n const isAnyColumnResizing = table.getState().columnSizingInfo.isResizingColumn;\n\n const cellVariant = column.columnDef.meta?.cell;\n const columnVariant = getColumnVariant(cellVariant?.variant);\n\n const pinnedPosition = column.getIsPinned();\n const isPinnedLeft = pinnedPosition === \"left\";\n const isPinnedRight = pinnedPosition === \"right\";\n\n const onSortingChange = React.useCallback(\n (direction: SortDirection) => {\n table.setSorting((prev: SortingState) => {\n const existingSortIndex = prev.findIndex((sort) => sort.id === column.id);\n const newSort: ColumnSort = {\n id: column.id,\n desc: direction === \"desc\"\n };\n\n if (existingSortIndex >= 0) {\n const updated = [...prev];\n updated[existingSortIndex] = newSort;\n return updated;\n } else {\n return [...prev, newSort];\n }\n });\n },\n [column.id, table]\n );\n\n const onSortRemove = React.useCallback(() => {\n table.setSorting((prev: SortingState) => prev.filter((sort) => sort.id !== column.id));\n }, [column.id, table]);\n\n const onLeftPin = React.useCallback(() => {\n column.pin(\"left\");\n }, [column]);\n\n const onRightPin = React.useCallback(() => {\n column.pin(\"right\");\n }, [column]);\n\n const onUnpin = React.useCallback(() => {\n column.pin(false);\n }, [column]);\n\n const onTriggerPointerDown = React.useCallback(\n (event: React.PointerEvent<HTMLButtonElement>) => {\n onPointerDown?.(event);\n if (event.defaultPrevented) return;\n\n if (event.button !== 0) {\n return;\n }\n table.options.meta?.onColumnClick?.(column.id);\n },\n [table.options.meta, column.id, onPointerDown]\n );\n\n return (\n <>\n <DropdownMenu modal={false}>\n <DropdownMenuTrigger\n className={cn(\n \"flex size-full items-center justify-between gap-2 p-2 text-sm hover:bg-accent/40 data-[state=open]:bg-accent/40 [&_svg]:size-4\",\n isAnyColumnResizing && \"pointer-events-none\",\n className\n )}\n onPointerDown={onTriggerPointerDown}\n {...props}\n >\n <div className=\"flex min-w-0 flex-1 items-center gap-1.5\">\n {columnVariant && (\n <Tooltip delayDuration={100}>\n <TooltipTrigger asChild>\n <columnVariant.icon className=\"size-3.5 shrink-0 text-muted-foreground\" />\n </TooltipTrigger>\n {/* `TooltipContent` của gói TỰ portal ra ngoài — cần thiết vì hộp lưới\n có overflow-auto, không portal thì tooltip bị cắt. */}\n <TooltipContent side=\"top\">{columnVariant.label}</TooltipContent>\n </Tooltip>\n )}\n <span className=\"truncate\">{label}</span>\n </div>\n <ChevronDownIcon className=\"size-3.5 shrink-0 text-muted-foreground\" />\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"start\" sideOffset={0} className=\"w-60\">\n {column.getCanSort() && (\n <>\n <DropdownMenuCheckboxItem\n className=\"gap-2 [&>svg]:size-4 [&>svg]:shrink-0 [&>svg]:text-muted-foreground\"\n checked={column.getIsSorted() === \"asc\"}\n onSelect={() => onSortingChange(\"asc\")}\n >\n <ChevronUpIcon />\n {msg.column.sortAsc}\n </DropdownMenuCheckboxItem>\n <DropdownMenuCheckboxItem\n className=\"gap-2 [&>svg]:size-4 [&>svg]:shrink-0 [&>svg]:text-muted-foreground\"\n checked={column.getIsSorted() === \"desc\"}\n onSelect={() => onSortingChange(\"desc\")}\n >\n <ChevronDownIcon />\n {msg.column.sortDesc}\n </DropdownMenuCheckboxItem>\n {column.getIsSorted() && (\n <DropdownMenuItem onSelect={onSortRemove}>\n <XIcon />\n {msg.column.removeSort}\n </DropdownMenuItem>\n )}\n </>\n )}\n {column.getCanPin() && (\n <>\n {column.getCanSort() && <DropdownMenuSeparator />}\n\n {isPinnedLeft ? (\n <DropdownMenuItem className=\"[&_svg]:text-muted-foreground\" onSelect={onUnpin}>\n <PinOffIcon />\n {msg.column.unpinLeft}\n </DropdownMenuItem>\n ) : (\n <DropdownMenuItem className=\"[&_svg]:text-muted-foreground\" onSelect={onLeftPin}>\n <PinIcon />\n {msg.column.pinLeft}\n </DropdownMenuItem>\n )}\n {isPinnedRight ? (\n <DropdownMenuItem className=\"[&_svg]:text-muted-foreground\" onSelect={onUnpin}>\n <PinOffIcon />\n {msg.column.unpinRight}\n </DropdownMenuItem>\n ) : (\n <DropdownMenuItem className=\"[&_svg]:text-muted-foreground\" onSelect={onRightPin}>\n <PinIcon />\n {msg.column.pinRight}\n </DropdownMenuItem>\n )}\n </>\n )}\n {column.getCanHide() && (\n <>\n <DropdownMenuSeparator />\n <DropdownMenuItem\n className=\"[&_svg]:text-muted-foreground\"\n onSelect={() => column.toggleVisibility(false)}\n >\n <EyeOffIcon />\n {msg.column.hide}\n </DropdownMenuItem>\n </>\n )}\n </DropdownMenuContent>\n </DropdownMenu>\n {header.column.getCanResize() && <DataGridColumnResizer header={header} table={table} label={label} />}\n </>\n );\n}\n\nconst DataGridColumnResizer = React.memo(DataGridColumnResizerImpl, (prev, next) => {\n const prevColumn = prev.header.column;\n const nextColumn = next.header.column;\n\n if (prevColumn.getIsResizing() !== nextColumn.getIsResizing() || prevColumn.getSize() !== nextColumn.getSize()) {\n return false;\n }\n\n if (prev.label !== next.label) return false;\n\n return true;\n}) as typeof DataGridColumnResizerImpl;\n\ninterface DataGridColumnResizerProps<TData, TValue> extends DataGridColumnHeaderProps<TData, TValue> {\n label: string;\n}\n\nfunction DataGridColumnResizerImpl<TData, TValue>({ header, table, label }: DataGridColumnResizerProps<TData, TValue>) {\n const msg = useDataGridMessages();\n const defaultColumnDef = table._getDefaultColumnDef();\n\n const onDoubleClick = React.useCallback(() => {\n header.column.resetSize();\n }, [header.column]);\n\n return (\n <div\n role=\"separator\"\n aria-orientation=\"vertical\"\n aria-label={msg.column.resize(label)}\n aria-valuenow={header.column.getSize()}\n aria-valuemin={defaultColumnDef.minSize}\n aria-valuemax={defaultColumnDef.maxSize}\n tabIndex={0}\n className={cn(\n // Tay kéo chỉ hiện khi rê/focus/đang kéo, nên nó CHỈ mang đúng một màu — `--primary-ink`\n // (bậc NÉT). `--primary` trần là bậc tô NỀN: gold #E8B824 chỉ 1,73:1 với nền trang ở\n // light, tức một tay kéo nhìn thấy được ở dark mà gần như vô hình ở light.\n \"absolute -end-px top-0 z-50 h-full w-0.5 cursor-ew-resize touch-none select-none bg-primary-ink transition-opacity after:absolute after:inset-y-0 after:start-1/2 after:h-full after:w-[18px] after:-translate-x-1/2 after:content-[''] focus:outline-none\",\n header.column.getIsResizing() ? \"opacity-100\" : \"opacity-0 hover:opacity-100 focus:opacity-100\"\n )}\n onDoubleClick={onDoubleClick}\n onMouseDown={header.getResizeHandler()}\n onTouchStart={header.getResizeHandler()}\n />\n );\n}\n"],"mappings":";AAiHc,SAeF,UAbM,KAFJ;AA9Gd,SAAS,iBAAiB,eAAe,YAAY,SAAS,YAAY,aAAa;AACvF,YAAY,WAAW;AAEvB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,SAAS,gBAAgB,sBAAsB;AACxD,SAAS,UAAU;AACnB,SAAS,2BAA2B;AACpC,SAAS,wBAAwB;AAO1B,SAAS,qBAAoC;AAAA,EAClD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,GAAG;AACL,GAA6C;AAC3C,QAAM,MAAM,oBAAoB;AAEhC,QAAM,SAAS,OAAO;AACtB,QAAM,QAAQ,OAAO,UAAU,MAAM,QACjC,OAAO,UAAU,KAAK,QACtB,OAAO,OAAO,UAAU,WAAW,WACjC,OAAO,UAAU,SACjB,OAAO;AAEb,QAAM,sBAAsB,MAAM,SAAS,EAAE,iBAAiB;AAE9D,QAAM,cAAc,OAAO,UAAU,MAAM;AAC3C,QAAM,gBAAgB,iBAAiB,aAAa,OAAO;AAE3D,QAAM,iBAAiB,OAAO,YAAY;AAC1C,QAAM,eAAe,mBAAmB;AACxC,QAAM,gBAAgB,mBAAmB;AAEzC,QAAM,kBAAkB,MAAM;AAAA,IAC5B,CAAC,cAA6B;AAC5B,YAAM,WAAW,CAAC,SAAuB;AACvC,cAAM,oBAAoB,KAAK,UAAU,CAAC,SAAS,KAAK,OAAO,OAAO,EAAE;AACxE,cAAM,UAAsB;AAAA,UAC1B,IAAI,OAAO;AAAA,UACX,MAAM,cAAc;AAAA,QACtB;AAEA,YAAI,qBAAqB,GAAG;AAC1B,gBAAM,UAAU,CAAC,GAAG,IAAI;AACxB,kBAAQ,iBAAiB,IAAI;AAC7B,iBAAO;AAAA,QACT,OAAO;AACL,iBAAO,CAAC,GAAG,MAAM,OAAO;AAAA,QAC1B;AAAA,MACF,CAAC;AAAA,IACH;AAAA,IACA,CAAC,OAAO,IAAI,KAAK;AAAA,EACnB;AAEA,QAAM,eAAe,MAAM,YAAY,MAAM;AAC3C,UAAM,WAAW,CAAC,SAAuB,KAAK,OAAO,CAAC,SAAS,KAAK,OAAO,OAAO,EAAE,CAAC;AAAA,EACvF,GAAG,CAAC,OAAO,IAAI,KAAK,CAAC;AAErB,QAAM,YAAY,MAAM,YAAY,MAAM;AACxC,WAAO,IAAI,MAAM;AAAA,EACnB,GAAG,CAAC,MAAM,CAAC;AAEX,QAAM,aAAa,MAAM,YAAY,MAAM;AACzC,WAAO,IAAI,OAAO;AAAA,EACpB,GAAG,CAAC,MAAM,CAAC;AAEX,QAAM,UAAU,MAAM,YAAY,MAAM;AACtC,WAAO,IAAI,KAAK;AAAA,EAClB,GAAG,CAAC,MAAM,CAAC;AAEX,QAAM,uBAAuB,MAAM;AAAA,IACjC,CAAC,UAAiD;AAChD,sBAAgB,KAAK;AACrB,UAAI,MAAM,iBAAkB;AAE5B,UAAI,MAAM,WAAW,GAAG;AACtB;AAAA,MACF;AACA,YAAM,QAAQ,MAAM,gBAAgB,OAAO,EAAE;AAAA,IAC/C;AAAA,IACA,CAAC,MAAM,QAAQ,MAAM,OAAO,IAAI,aAAa;AAAA,EAC/C;AAEA,SACE,iCACE;AAAA,yBAAC,gBAAa,OAAO,OACnB;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,WAAW;AAAA,YACT;AAAA,YACA,uBAAuB;AAAA,YACvB;AAAA,UACF;AAAA,UACA,eAAe;AAAA,UACd,GAAG;AAAA,UAEJ;AAAA,iCAAC,SAAI,WAAU,4CACZ;AAAA,+BACC,qBAAC,WAAQ,eAAe,KACtB;AAAA,oCAAC,kBAAe,SAAO,MACrB,8BAAC,cAAc,MAAd,EAAmB,WAAU,2CAA0C,GAC1E;AAAA,gBAGA,oBAAC,kBAAe,MAAK,OAAO,wBAAc,OAAM;AAAA,iBAClD;AAAA,cAEF,oBAAC,UAAK,WAAU,YAAY,iBAAM;AAAA,eACpC;AAAA,YACA,oBAAC,mBAAgB,WAAU,2CAA0C;AAAA;AAAA;AAAA,MACvE;AAAA,MACA,qBAAC,uBAAoB,OAAM,SAAQ,YAAY,GAAG,WAAU,QACzD;AAAA,eAAO,WAAW,KACjB,iCACE;AAAA;AAAA,YAAC;AAAA;AAAA,cACC,WAAU;AAAA,cACV,SAAS,OAAO,YAAY,MAAM;AAAA,cAClC,UAAU,MAAM,gBAAgB,KAAK;AAAA,cAErC;AAAA,oCAAC,iBAAc;AAAA,gBACd,IAAI,OAAO;AAAA;AAAA;AAAA,UACd;AAAA,UACA;AAAA,YAAC;AAAA;AAAA,cACC,WAAU;AAAA,cACV,SAAS,OAAO,YAAY,MAAM;AAAA,cAClC,UAAU,MAAM,gBAAgB,MAAM;AAAA,cAEtC;AAAA,oCAAC,mBAAgB;AAAA,gBAChB,IAAI,OAAO;AAAA;AAAA;AAAA,UACd;AAAA,UACC,OAAO,YAAY,KAClB,qBAAC,oBAAiB,UAAU,cAC1B;AAAA,gCAAC,SAAM;AAAA,YACN,IAAI,OAAO;AAAA,aACd;AAAA,WAEJ;AAAA,QAED,OAAO,UAAU,KAChB,iCACG;AAAA,iBAAO,WAAW,KAAK,oBAAC,yBAAsB;AAAA,UAE9C,eACC,qBAAC,oBAAiB,WAAU,iCAAgC,UAAU,SACpE;AAAA,gCAAC,cAAW;AAAA,YACX,IAAI,OAAO;AAAA,aACd,IAEA,qBAAC,oBAAiB,WAAU,iCAAgC,UAAU,WACpE;AAAA,gCAAC,WAAQ;AAAA,YACR,IAAI,OAAO;AAAA,aACd;AAAA,UAED,gBACC,qBAAC,oBAAiB,WAAU,iCAAgC,UAAU,SACpE;AAAA,gCAAC,cAAW;AAAA,YACX,IAAI,OAAO;AAAA,aACd,IAEA,qBAAC,oBAAiB,WAAU,iCAAgC,UAAU,YACpE;AAAA,gCAAC,WAAQ;AAAA,YACR,IAAI,OAAO;AAAA,aACd;AAAA,WAEJ;AAAA,QAED,OAAO,WAAW,KACjB,iCACE;AAAA,8BAAC,yBAAsB;AAAA,UACvB;AAAA,YAAC;AAAA;AAAA,cACC,WAAU;AAAA,cACV,UAAU,MAAM,OAAO,iBAAiB,KAAK;AAAA,cAE7C;AAAA,oCAAC,cAAW;AAAA,gBACX,IAAI,OAAO;AAAA;AAAA;AAAA,UACd;AAAA,WACF;AAAA,SAEJ;AAAA,OACF;AAAA,IACC,OAAO,OAAO,aAAa,KAAK,oBAAC,yBAAsB,QAAgB,OAAc,OAAc;AAAA,KACtG;AAEJ;AAEA,MAAM,wBAAwB,MAAM,KAAK,2BAA2B,CAAC,MAAM,SAAS;AAClF,QAAM,aAAa,KAAK,OAAO;AAC/B,QAAM,aAAa,KAAK,OAAO;AAE/B,MAAI,WAAW,cAAc,MAAM,WAAW,cAAc,KAAK,WAAW,QAAQ,MAAM,WAAW,QAAQ,GAAG;AAC9G,WAAO;AAAA,EACT;AAEA,MAAI,KAAK,UAAU,KAAK,MAAO,QAAO;AAEtC,SAAO;AACT,CAAC;AAMD,SAAS,0BAAyC,EAAE,QAAQ,OAAO,MAAM,GAA8C;AACrH,QAAM,MAAM,oBAAoB;AAChC,QAAM,mBAAmB,MAAM,qBAAqB;AAEpD,QAAM,gBAAgB,MAAM,YAAY,MAAM;AAC5C,WAAO,OAAO,UAAU;AAAA,EAC1B,GAAG,CAAC,OAAO,MAAM,CAAC;AAElB,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,oBAAiB;AAAA,MACjB,cAAY,IAAI,OAAO,OAAO,KAAK;AAAA,MACnC,iBAAe,OAAO,OAAO,QAAQ;AAAA,MACrC,iBAAe,iBAAiB;AAAA,MAChC,iBAAe,iBAAiB;AAAA,MAChC,UAAU;AAAA,MACV,WAAW;AAAA;AAAA;AAAA;AAAA,QAIT;AAAA,QACA,OAAO,OAAO,cAAc,IAAI,gBAAgB;AAAA,MAClD;AAAA,MACA;AAAA,MACA,aAAa,OAAO,iBAAiB;AAAA,MACrC,cAAc,OAAO,iBAAiB;AAAA;AAAA,EACxC;AAEJ;","names":[]}
@@ -9,7 +9,7 @@ import {
9
9
  DropdownMenuSeparator,
10
10
  DropdownMenuTrigger
11
11
  } from "../components/ui/dropdown-menu.js";
12
- import { msg } from "./messages.js";
12
+ import { useDataGridMessages } from "./data-grid-locale.js";
13
13
  import { toastSuccess } from "./toast.js";
14
14
  import { useAsRef } from "./use-as-ref.js";
15
15
  import { getEmptyCellValue, parseCellKey } from "./utils.js";
@@ -60,6 +60,7 @@ function ContextMenuImpl({
60
60
  onCellsCopy,
61
61
  onCellsCut
62
62
  }) {
63
+ const msg = useDataGridMessages();
63
64
  const propsRef = useAsRef({
64
65
  dataGridRef,
65
66
  selectionState,
@@ -115,7 +116,7 @@ function ContextMenuImpl({
115
116
  }
116
117
  onDataUpdate2?.(updates);
117
118
  toastSuccess(msg.toast.cellsCleared(updates.length));
118
- }, [propsRef]);
119
+ }, [propsRef, msg]);
119
120
  const onDelete = React.useCallback(async () => {
120
121
  const { selectionState: selectionState2, onRowsDelete: onRowsDelete2 } = propsRef.current;
121
122
  if (!selectionState2?.selectedCells || selectionState2.selectedCells.size === 0) return;
@@ -128,7 +129,7 @@ function ContextMenuImpl({
128
129
  const rowCount = rowIndicesArray.length;
129
130
  await onRowsDelete2?.(rowIndicesArray);
130
131
  toastSuccess(msg.toast.rowsDeleted(rowCount));
131
- }, [propsRef]);
132
+ }, [propsRef, msg]);
132
133
  return /* @__PURE__ */ jsxs(DropdownMenu, { open: contextMenu.open, onOpenChange: onContextMenuOpenChange, children: [
133
134
  /* @__PURE__ */ jsx(DropdownMenuTrigger, { style: triggerStyle }),
134
135
  /* @__PURE__ */ jsxs(DropdownMenuContent, { "data-grid-popover": "", align: "start", className: "w-48", onCloseAutoFocus, children: [
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/data-grid/data-grid-context-menu.tsx"],"sourcesContent":["\"use client\";\n\nimport type { ColumnDef, TableMeta } from \"@tanstack/react-table\";\nimport { CopyIcon, EraserIcon, ScissorsIcon, Trash2Icon } from \"lucide-react\";\nimport * as React from \"react\";\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuSeparator,\n DropdownMenuTrigger\n} from \"../components/ui/dropdown-menu.js\";\nimport { msg } from \"./messages.js\";\nimport { toastSuccess } from \"./toast.js\";\nimport type { CellUpdate, ContextMenuState } from \"./types.js\";\nimport { useAsRef } from \"./use-as-ref.js\";\nimport { getEmptyCellValue, parseCellKey } from \"./utils.js\";\n\ninterface DataGridContextMenuProps<TData> {\n tableMeta: TableMeta<TData>;\n columns: Array<ColumnDef<TData>>;\n contextMenu: ContextMenuState;\n}\n\nexport function DataGridContextMenu<TData>({ tableMeta, columns, contextMenu }: DataGridContextMenuProps<TData>) {\n const onContextMenuOpenChange = tableMeta?.onContextMenuOpenChange;\n const selectionState = tableMeta?.selectionState;\n const dataGridRef = tableMeta?.dataGridRef;\n const onDataUpdate = tableMeta?.onDataUpdate;\n const onRowsDelete = tableMeta?.onRowsDelete;\n const onCellsCopy = tableMeta?.onCellsCopy;\n const onCellsCut = tableMeta?.onCellsCut;\n\n if (!contextMenu.open) return null;\n\n return (\n <ContextMenu\n tableMeta={tableMeta}\n columns={columns}\n dataGridRef={dataGridRef}\n contextMenu={contextMenu}\n onContextMenuOpenChange={onContextMenuOpenChange}\n selectionState={selectionState}\n onDataUpdate={onDataUpdate}\n onRowsDelete={onRowsDelete}\n onCellsCopy={onCellsCopy}\n onCellsCut={onCellsCut}\n />\n );\n}\n\ninterface ContextMenuProps<TData>\n extends Pick<\n TableMeta<TData>,\n | \"dataGridRef\"\n | \"onContextMenuOpenChange\"\n | \"selectionState\"\n | \"onDataUpdate\"\n | \"onRowsDelete\"\n | \"onCellsCopy\"\n | \"onCellsCut\"\n | \"readOnly\"\n >,\n Required<Pick<TableMeta<TData>, \"contextMenu\">> {\n tableMeta: TableMeta<TData>;\n columns: Array<ColumnDef<TData>>;\n}\n\nconst ContextMenu = React.memo(ContextMenuImpl, (prev, next) => {\n if (prev.contextMenu.open !== next.contextMenu.open) return false;\n if (!next.contextMenu.open) return true;\n if (prev.contextMenu.x !== next.contextMenu.x) return false;\n if (prev.contextMenu.y !== next.contextMenu.y) return false;\n\n const prevSize = prev.selectionState?.selectedCells?.size ?? 0;\n const nextSize = next.selectionState?.selectedCells?.size ?? 0;\n if (prevSize !== nextSize) return false;\n\n return true;\n}) as typeof ContextMenuImpl;\n\nfunction ContextMenuImpl<TData>({\n tableMeta,\n columns,\n dataGridRef,\n contextMenu,\n onContextMenuOpenChange,\n selectionState,\n onDataUpdate,\n onRowsDelete,\n onCellsCopy,\n onCellsCut\n}: ContextMenuProps<TData>) {\n const propsRef = useAsRef({\n dataGridRef,\n selectionState,\n onDataUpdate,\n onRowsDelete,\n onCellsCopy,\n onCellsCut,\n columns\n });\n\n const triggerStyle = React.useMemo<React.CSSProperties>(\n () => ({\n position: \"fixed\",\n left: `${contextMenu.x}px`,\n top: `${contextMenu.y}px`,\n width: \"1px\",\n height: \"1px\",\n padding: 0,\n margin: 0,\n border: \"none\",\n background: \"transparent\",\n pointerEvents: \"none\",\n opacity: 0\n }),\n [contextMenu.x, contextMenu.y]\n );\n\n const onCloseAutoFocus: NonNullable<React.ComponentProps<typeof DropdownMenuContent>[\"onCloseAutoFocus\"]> =\n React.useCallback(\n (event) => {\n event.preventDefault();\n propsRef.current.dataGridRef?.current?.focus();\n },\n [propsRef]\n );\n\n const onCopy = React.useCallback(() => {\n propsRef.current.onCellsCopy?.();\n }, [propsRef]);\n\n const onCut = React.useCallback(() => {\n propsRef.current.onCellsCut?.();\n }, [propsRef]);\n\n const onClear = React.useCallback(() => {\n const { selectionState, columns, onDataUpdate } = propsRef.current;\n\n if (!selectionState?.selectedCells || selectionState.selectedCells.size === 0) return;\n\n const updates: Array<CellUpdate> = [];\n\n for (const cellKey of selectionState.selectedCells) {\n const { rowIndex, columnId } = parseCellKey(cellKey);\n\n // Get column from columns array\n const column = columns.find((col) => {\n if (col.id) return col.id === columnId;\n if (\"accessorKey\" in col) return col.accessorKey === columnId;\n return false;\n });\n const cellVariant = column?.meta?.cell?.variant;\n\n const emptyValue = getEmptyCellValue(cellVariant);\n\n updates.push({ rowIndex, columnId, value: emptyValue });\n }\n\n onDataUpdate?.(updates);\n\n toastSuccess(msg.toast.cellsCleared(updates.length));\n }, [propsRef]);\n\n const onDelete = React.useCallback(async () => {\n const { selectionState, onRowsDelete } = propsRef.current;\n\n if (!selectionState?.selectedCells || selectionState.selectedCells.size === 0) return;\n\n const rowIndices = new Set<number>();\n for (const cellKey of selectionState.selectedCells) {\n const { rowIndex } = parseCellKey(cellKey);\n rowIndices.add(rowIndex);\n }\n\n const rowIndicesArray = Array.from(rowIndices).sort((a, b) => a - b);\n const rowCount = rowIndicesArray.length;\n\n await onRowsDelete?.(rowIndicesArray);\n\n toastSuccess(msg.toast.rowsDeleted(rowCount));\n }, [propsRef]);\n\n return (\n <DropdownMenu open={contextMenu.open} onOpenChange={onContextMenuOpenChange}>\n <DropdownMenuTrigger style={triggerStyle} />\n <DropdownMenuContent data-grid-popover=\"\" align=\"start\" className=\"w-48\" onCloseAutoFocus={onCloseAutoFocus}>\n <DropdownMenuItem onSelect={onCopy}>\n <CopyIcon />\n {msg.contextMenu.copy}\n </DropdownMenuItem>\n <DropdownMenuItem onSelect={onCut} disabled={tableMeta?.readOnly}>\n <ScissorsIcon />\n {msg.contextMenu.cut}\n </DropdownMenuItem>\n <DropdownMenuItem onSelect={onClear} disabled={tableMeta?.readOnly}>\n <EraserIcon />\n {msg.contextMenu.clear}\n </DropdownMenuItem>\n {onRowsDelete && (\n <>\n <DropdownMenuSeparator />\n {/* `variant=\"destructive\"` của gói đã đi qua `--destructive-ink` (bậc CHỮ) cho cả\n chữ, icon và nền focus — đừng tự viết lại bằng `text-destructive` (bậc TÔ NỀN). */}\n <DropdownMenuItem variant=\"destructive\" onSelect={onDelete}>\n <Trash2Icon />\n {msg.contextMenu.deleteRows}\n </DropdownMenuItem>\n </>\n )}\n </DropdownMenuContent>\n </DropdownMenu>\n );\n}\n"],"mappings":"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","names":["selectionState","columns","onDataUpdate","onRowsDelete"]}
1
+ {"version":3,"sources":["../../src/data-grid/data-grid-context-menu.tsx"],"sourcesContent":["\"use client\";\n\nimport type { ColumnDef, TableMeta } from \"@tanstack/react-table\";\nimport { CopyIcon, EraserIcon, ScissorsIcon, Trash2Icon } from \"lucide-react\";\nimport * as React from \"react\";\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuSeparator,\n DropdownMenuTrigger\n} from \"../components/ui/dropdown-menu.js\";\nimport { useDataGridMessages } from \"./data-grid-locale.js\";\nimport { toastSuccess } from \"./toast.js\";\nimport type { CellUpdate, ContextMenuState } from \"./types.js\";\nimport { useAsRef } from \"./use-as-ref.js\";\nimport { getEmptyCellValue, parseCellKey } from \"./utils.js\";\n\ninterface DataGridContextMenuProps<TData> {\n tableMeta: TableMeta<TData>;\n columns: Array<ColumnDef<TData>>;\n contextMenu: ContextMenuState;\n}\n\nexport function DataGridContextMenu<TData>({ tableMeta, columns, contextMenu }: DataGridContextMenuProps<TData>) {\n const onContextMenuOpenChange = tableMeta?.onContextMenuOpenChange;\n const selectionState = tableMeta?.selectionState;\n const dataGridRef = tableMeta?.dataGridRef;\n const onDataUpdate = tableMeta?.onDataUpdate;\n const onRowsDelete = tableMeta?.onRowsDelete;\n const onCellsCopy = tableMeta?.onCellsCopy;\n const onCellsCut = tableMeta?.onCellsCut;\n\n if (!contextMenu.open) return null;\n\n return (\n <ContextMenu\n tableMeta={tableMeta}\n columns={columns}\n dataGridRef={dataGridRef}\n contextMenu={contextMenu}\n onContextMenuOpenChange={onContextMenuOpenChange}\n selectionState={selectionState}\n onDataUpdate={onDataUpdate}\n onRowsDelete={onRowsDelete}\n onCellsCopy={onCellsCopy}\n onCellsCut={onCellsCut}\n />\n );\n}\n\ninterface ContextMenuProps<TData>\n extends Pick<\n TableMeta<TData>,\n | \"dataGridRef\"\n | \"onContextMenuOpenChange\"\n | \"selectionState\"\n | \"onDataUpdate\"\n | \"onRowsDelete\"\n | \"onCellsCopy\"\n | \"onCellsCut\"\n | \"readOnly\"\n >,\n Required<Pick<TableMeta<TData>, \"contextMenu\">> {\n tableMeta: TableMeta<TData>;\n columns: Array<ColumnDef<TData>>;\n}\n\nconst ContextMenu = React.memo(ContextMenuImpl, (prev, next) => {\n if (prev.contextMenu.open !== next.contextMenu.open) return false;\n if (!next.contextMenu.open) return true;\n if (prev.contextMenu.x !== next.contextMenu.x) return false;\n if (prev.contextMenu.y !== next.contextMenu.y) return false;\n\n const prevSize = prev.selectionState?.selectedCells?.size ?? 0;\n const nextSize = next.selectionState?.selectedCells?.size ?? 0;\n if (prevSize !== nextSize) return false;\n\n return true;\n}) as typeof ContextMenuImpl;\n\nfunction ContextMenuImpl<TData>({\n tableMeta,\n columns,\n dataGridRef,\n contextMenu,\n onContextMenuOpenChange,\n selectionState,\n onDataUpdate,\n onRowsDelete,\n onCellsCopy,\n onCellsCut\n}: ContextMenuProps<TData>) {\n const msg = useDataGridMessages();\n\n const propsRef = useAsRef({\n dataGridRef,\n selectionState,\n onDataUpdate,\n onRowsDelete,\n onCellsCopy,\n onCellsCut,\n columns\n });\n\n const triggerStyle = React.useMemo<React.CSSProperties>(\n () => ({\n position: \"fixed\",\n left: `${contextMenu.x}px`,\n top: `${contextMenu.y}px`,\n width: \"1px\",\n height: \"1px\",\n padding: 0,\n margin: 0,\n border: \"none\",\n background: \"transparent\",\n pointerEvents: \"none\",\n opacity: 0\n }),\n [contextMenu.x, contextMenu.y]\n );\n\n const onCloseAutoFocus: NonNullable<React.ComponentProps<typeof DropdownMenuContent>[\"onCloseAutoFocus\"]> =\n React.useCallback(\n (event) => {\n event.preventDefault();\n propsRef.current.dataGridRef?.current?.focus();\n },\n [propsRef]\n );\n\n const onCopy = React.useCallback(() => {\n propsRef.current.onCellsCopy?.();\n }, [propsRef]);\n\n const onCut = React.useCallback(() => {\n propsRef.current.onCellsCut?.();\n }, [propsRef]);\n\n const onClear = React.useCallback(() => {\n const { selectionState, columns, onDataUpdate } = propsRef.current;\n\n if (!selectionState?.selectedCells || selectionState.selectedCells.size === 0) return;\n\n const updates: Array<CellUpdate> = [];\n\n for (const cellKey of selectionState.selectedCells) {\n const { rowIndex, columnId } = parseCellKey(cellKey);\n\n // Get column from columns array\n const column = columns.find((col) => {\n if (col.id) return col.id === columnId;\n if (\"accessorKey\" in col) return col.accessorKey === columnId;\n return false;\n });\n const cellVariant = column?.meta?.cell?.variant;\n\n const emptyValue = getEmptyCellValue(cellVariant);\n\n updates.push({ rowIndex, columnId, value: emptyValue });\n }\n\n onDataUpdate?.(updates);\n\n toastSuccess(msg.toast.cellsCleared(updates.length));\n }, [propsRef, msg]);\n\n const onDelete = React.useCallback(async () => {\n const { selectionState, onRowsDelete } = propsRef.current;\n\n if (!selectionState?.selectedCells || selectionState.selectedCells.size === 0) return;\n\n const rowIndices = new Set<number>();\n for (const cellKey of selectionState.selectedCells) {\n const { rowIndex } = parseCellKey(cellKey);\n rowIndices.add(rowIndex);\n }\n\n const rowIndicesArray = Array.from(rowIndices).sort((a, b) => a - b);\n const rowCount = rowIndicesArray.length;\n\n await onRowsDelete?.(rowIndicesArray);\n\n toastSuccess(msg.toast.rowsDeleted(rowCount));\n }, [propsRef, msg]);\n\n return (\n <DropdownMenu open={contextMenu.open} onOpenChange={onContextMenuOpenChange}>\n <DropdownMenuTrigger style={triggerStyle} />\n <DropdownMenuContent data-grid-popover=\"\" align=\"start\" className=\"w-48\" onCloseAutoFocus={onCloseAutoFocus}>\n <DropdownMenuItem onSelect={onCopy}>\n <CopyIcon />\n {msg.contextMenu.copy}\n </DropdownMenuItem>\n <DropdownMenuItem onSelect={onCut} disabled={tableMeta?.readOnly}>\n <ScissorsIcon />\n {msg.contextMenu.cut}\n </DropdownMenuItem>\n <DropdownMenuItem onSelect={onClear} disabled={tableMeta?.readOnly}>\n <EraserIcon />\n {msg.contextMenu.clear}\n </DropdownMenuItem>\n {onRowsDelete && (\n <>\n <DropdownMenuSeparator />\n {/* `variant=\"destructive\"` của gói đã đi qua `--destructive-ink` (bậc CHỮ) cho cả\n chữ, icon và nền focus — đừng tự viết lại bằng `text-destructive` (bậc TÔ NỀN). */}\n <DropdownMenuItem variant=\"destructive\" onSelect={onDelete}>\n <Trash2Icon />\n {msg.contextMenu.deleteRows}\n </DropdownMenuItem>\n </>\n )}\n </DropdownMenuContent>\n </DropdownMenu>\n );\n}\n"],"mappings":"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","names":["selectionState","columns","onDataUpdate","onRowsDelete"]}
@@ -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 DataGridFilterMenuProps<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 DataGridFilterMenu<TData>({ table, disabled, className, ...props }: DataGridFilterMenuProps<TData>): React.JSX.Element;
21
+ declare function DataGridFilterMenu<TData>({ table, disabled, className, locale, ...props }: DataGridFilterMenuProps<TData>): React.JSX.Element;
11
22
 
12
23
  export { DataGridFilterMenu };
@@ -19,8 +19,8 @@ import { Input } from "../components/ui/input.js";
19
19
  import { Popover, PopoverContent, PopoverTrigger } from "../components/ui/popover.js";
20
20
  import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from "../components/ui/select.js";
21
21
  import { cn } from "../lib/cn.js";
22
+ import { DataGridLocaleProvider, useDataGridMessages, useResolvedDataGridMessages } from "./data-grid-locale.js";
22
23
  import { getDefaultOperator, getOperatorsForVariant } from "./filters.js";
23
- import { msg } from "./messages.js";
24
24
  import { Sortable, SortableContent, SortableItem, SortableItemHandle, SortableOverlay } from "./sortable.js";
25
25
  import { useDebouncedCallback } from "./use-debounced-callback.js";
26
26
  import { formatDate } from "./utils.js";
@@ -28,7 +28,14 @@ const FILTER_SHORTCUT_KEY = "f";
28
28
  const REMOVE_FILTER_SHORTCUTS = /* @__PURE__ */ new Set(["backspace", "delete"]);
29
29
  const FILTER_DEBOUNCE_MS = 300;
30
30
  const OPERATORS_WITHOUT_VALUE = /* @__PURE__ */ new Set(["isEmpty", "isNotEmpty", "isTrue", "isFalse"]);
31
- function DataGridFilterMenu({ table, disabled, className, ...props }) {
31
+ function DataGridFilterMenu({
32
+ table,
33
+ disabled,
34
+ className,
35
+ locale,
36
+ ...props
37
+ }) {
38
+ const msg = useResolvedDataGridMessages(locale);
32
39
  const dir = useDirection();
33
40
  const id = React.useId();
34
41
  const labelId = React.useId();
@@ -113,18 +120,19 @@ function DataGridFilterMenu({ table, disabled, className, ...props }) {
113
120
  },
114
121
  [columnFilters.length, onFiltersReset]
115
122
  );
116
- return /* @__PURE__ */ jsxs(Sortable, { value: columnFilters, onValueChange: table.setColumnFilters, getItemValue: (item) => item.id, children: [
123
+ return /* @__PURE__ */ jsx(DataGridLocaleProvider, { locale: msg, children: /* @__PURE__ */ jsxs(Sortable, { value: columnFilters, onValueChange: table.setColumnFilters, getItemValue: (item) => item.id, children: [
117
124
  /* @__PURE__ */ jsxs(Popover, { open, onOpenChange: setOpen, children: [
118
125
  /* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
119
126
  Button,
120
127
  {
121
128
  dir,
122
129
  variant: "outline",
123
- className: "h-8 gap-2 font-normal",
130
+ size: "sm",
131
+ className: "font-normal",
124
132
  onKeyDown: onTriggerKeyDown,
125
133
  disabled,
126
134
  children: [
127
- /* @__PURE__ */ jsx(ListFilter, { "aria-hidden": "true", className: "text-muted-foreground" }),
135
+ /* @__PURE__ */ jsx(ListFilter, { "aria-hidden": "true", className: "size-3.5 text-muted-foreground" }),
128
136
  msg.filter.trigger,
129
137
  columnFilters.length > 0 && /* @__PURE__ */ jsx(
130
138
  "span",
@@ -204,7 +212,7 @@ function DataGridFilterMenu({ table, disabled, className, ...props }) {
204
212
  /* @__PURE__ */ jsx("div", { className: "size-8 shrink-0 rounded-sm bg-muted" }),
205
213
  /* @__PURE__ */ jsx("div", { className: "size-8 shrink-0 rounded-sm bg-muted" })
206
214
  ] }) })
207
- ] });
215
+ ] }) });
208
216
  }
209
217
  function DataGridFilterItem({
210
218
  filter,
@@ -218,6 +226,7 @@ function DataGridFilterItem({
218
226
  onFilterUpdate,
219
227
  onFilterRemove
220
228
  }) {
229
+ const msg = useDataGridMessages();
221
230
  const fieldListboxId = `${filterItemId}-field-listbox`;
222
231
  const fieldTriggerId = `${filterItemId}-field-trigger`;
223
232
  const operatorListboxId = `${filterItemId}-operator-listbox`;
@@ -386,10 +395,10 @@ function DataGridFilterItem({
386
395
  size: "icon",
387
396
  className: "size-8 rounded",
388
397
  onClick: () => onFilterRemove(filter.id),
389
- children: /* @__PURE__ */ jsx(Trash2, { "aria-hidden": "true" })
398
+ children: /* @__PURE__ */ jsx(Trash2, { "aria-hidden": "true", className: "size-3.5" })
390
399
  }
391
400
  ),
392
- /* @__PURE__ */ jsx(SortableItemHandle, { asChild: true, children: /* @__PURE__ */ jsx(Button, { "aria-label": msg.filter.drag, variant: "outline", size: "icon", className: "size-8 rounded", children: /* @__PURE__ */ jsx(GripVertical, { "aria-hidden": "true" }) }) })
401
+ /* @__PURE__ */ jsx(SortableItemHandle, { asChild: true, children: /* @__PURE__ */ jsx(Button, { "aria-label": msg.filter.drag, variant: "outline", size: "icon", className: "size-8 rounded", children: /* @__PURE__ */ jsx(GripVertical, { "aria-hidden": "true", className: "size-3.5" }) }) })
393
402
  ]
394
403
  }
395
404
  ) });
@@ -398,7 +407,7 @@ function DataGridFilterInput({
398
407
  variant,
399
408
  operator,
400
409
  dir,
401
- placeholder = msg.filter.valuePlaceholder,
410
+ placeholder,
402
411
  value,
403
412
  endValue,
404
413
  column,
@@ -406,6 +415,8 @@ function DataGridFilterInput({
406
415
  onValueChange,
407
416
  onEndValueChange
408
417
  }) {
418
+ const msg = useDataGridMessages();
419
+ const inputPlaceholder = placeholder ?? msg.filter.valuePlaceholder;
409
420
  const [showValueSelector, setShowValueSelector] = React.useState(false);
410
421
  const [localValue, setLocalValue] = React.useState(value);
411
422
  const [localEndValue, setLocalEndValue] = React.useState(endValue);
@@ -467,8 +478,8 @@ function DataGridFilterInput({
467
478
  id: inputId,
468
479
  type: "number",
469
480
  inputMode: "numeric",
470
- placeholder,
471
- "aria-label": placeholder,
481
+ placeholder: inputPlaceholder,
482
+ "aria-label": inputPlaceholder,
472
483
  value: localValue ?? "",
473
484
  onChange: (event) => {
474
485
  const val = event.target.value;
@@ -500,7 +511,7 @@ function DataGridFilterInput({
500
511
  !startDate && "text-muted-foreground"
501
512
  ),
502
513
  children: [
503
- /* @__PURE__ */ jsx(CalendarIcon, { "aria-hidden": "true" }),
514
+ /* @__PURE__ */ jsx(CalendarIcon, { "aria-hidden": "true", className: "size-3.5" }),
504
515
  /* @__PURE__ */ jsx("span", { className: "truncate", children: displayValue })
505
516
  ]
506
517
  }
@@ -535,7 +546,7 @@ function DataGridFilterInput({
535
546
  variant: "outline",
536
547
  className: cn("h-8 w-full justify-start gap-2 rounded font-normal", !dateValue && "text-muted-foreground"),
537
548
  children: [
538
- /* @__PURE__ */ jsx(CalendarIcon, { "aria-hidden": "true" }),
549
+ /* @__PURE__ */ jsx(CalendarIcon, { "aria-hidden": "true", className: "size-3.5" }),
539
550
  /* @__PURE__ */ jsx("span", { className: "truncate", children: dateValue ? formatDate(dateValue) : msg.filter.pickDate })
540
551
  ]
541
552
  }
@@ -575,7 +586,7 @@ function DataGridFilterInput({
575
586
  dir,
576
587
  variant: "outline",
577
588
  className: "h-8 w-full justify-start rounded font-normal",
578
- children: selectedOptions.length === 0 ? /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: placeholder }) : /* @__PURE__ */ jsxs(Fragment, { children: [
589
+ children: selectedOptions.length === 0 ? /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: inputPlaceholder }) : /* @__PURE__ */ jsxs(Fragment, { children: [
579
590
  selectedOptionsWithIcons.length > 0 && /* @__PURE__ */ jsx("div", { className: "flex items-center -space-x-2 rtl:space-x-reverse", children: selectedOptionsWithIcons.map(
580
591
  (selectedOption2) => selectedOption2.icon && /* @__PURE__ */ jsx("div", { className: "rounded-full border bg-background p-0.5", children: /* @__PURE__ */ jsx(selectedOption2.icon, { className: "size-3.5" }) }, selectedOption2.value)
581
592
  ) }),
@@ -624,7 +635,7 @@ function DataGridFilterInput({
624
635
  children: selectedOption ? /* @__PURE__ */ jsxs(Fragment, { children: [
625
636
  selectedOption.icon && /* @__PURE__ */ jsx(selectedOption.icon, {}),
626
637
  /* @__PURE__ */ jsx("span", { className: "truncate", children: selectedOption.label })
627
- ] }) : /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: placeholder })
638
+ ] }) : /* @__PURE__ */ jsx("span", { className: "text-muted-foreground", children: inputPlaceholder })
628
639
  }
629
640
  ) }),
630
641
  /* @__PURE__ */ jsx(PopoverContent, { id: inputListboxId, dir, align: "start", className: "w-[200px] p-0", children: /* @__PURE__ */ jsxs(Command, { children: [
@@ -695,8 +706,8 @@ function DataGridFilterInput({
695
706
  {
696
707
  id: inputId,
697
708
  type: "text",
698
- placeholder,
699
- "aria-label": placeholder,
709
+ placeholder: inputPlaceholder,
710
+ "aria-label": inputPlaceholder,
700
711
  className: "h-8 w-full rounded",
701
712
  value: localValue ?? "",
702
713
  onChange: (event) => {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/data-grid/data-grid-filter-menu.tsx"],"sourcesContent":["\"use client\";\n\nimport { useDirection } from \"@radix-ui/react-direction\";\nimport type { Column, ColumnFilter, Table } from \"@tanstack/react-table\";\nimport { vi } from \"date-fns/locale\";\nimport { CalendarIcon, Check, ChevronsUpDown, GripVertical, ListFilter, Trash2 } from \"lucide-react\";\nimport * as React from \"react\";\nimport { badgeVariants } from \"../components/ui/badge.js\";\nimport { Button } from \"../components/ui/button.js\";\nimport { Calendar } from \"../components/ui/calendar.js\";\nimport {\n Command,\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n CommandList\n} from \"../components/ui/command.js\";\nimport { Input } from \"../components/ui/input.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 { getDefaultOperator, getOperatorsForVariant } from \"./filters.js\";\nimport { msg } from \"./messages.js\";\nimport { Sortable, SortableContent, SortableItem, SortableItemHandle, SortableOverlay } from \"./sortable.js\";\nimport type { FilterOperator, FilterValue } from \"./types.js\";\nimport { useDebouncedCallback } from \"./use-debounced-callback.js\";\nimport { formatDate } from \"./utils.js\";\n\nconst FILTER_SHORTCUT_KEY = \"f\";\nconst REMOVE_FILTER_SHORTCUTS = new Set([\"backspace\", \"delete\"]);\nconst FILTER_DEBOUNCE_MS = 300;\nconst OPERATORS_WITHOUT_VALUE = new Set([\"isEmpty\", \"isNotEmpty\", \"isTrue\", \"isFalse\"]);\n\ninterface DataGridFilterMenuProps<TData> extends React.ComponentProps<typeof PopoverContent> {\n table: Table<TData>;\n disabled?: boolean;\n}\n\nexport function DataGridFilterMenu<TData>({ table, disabled, className, ...props }: DataGridFilterMenuProps<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 columnFilters = table.getState().columnFilters;\n\n const { columnLabels, columns, columnVariants } = React.useMemo(() => {\n const labels = new Map<string, string>();\n const variants = new Map<string, string>();\n const filteringIds = new Set(columnFilters.map((f) => f.id));\n const availableColumns: { id: string; label: string }[] = [];\n\n for (const column of table.getAllColumns()) {\n if (!column.getCanFilter()) continue;\n\n const label = column.columnDef.meta?.label ?? column.id;\n const variant = column.columnDef.meta?.cell?.variant ?? \"short-text\";\n\n labels.set(column.id, label);\n variants.set(column.id, variant);\n\n if (!filteringIds.has(column.id)) {\n availableColumns.push({ id: column.id, label });\n }\n }\n\n return {\n columnLabels: labels,\n columns: availableColumns,\n columnVariants: variants\n };\n }, [columnFilters, table]);\n\n const onFilterAdd = React.useCallback(() => {\n const firstColumn = columns[0];\n if (!firstColumn) return;\n\n const variant = columnVariants.get(firstColumn.id) ?? \"short-text\";\n const defaultOperator = getDefaultOperator(variant);\n\n table.setColumnFilters((prevFilters) => [\n ...prevFilters,\n {\n id: firstColumn.id,\n value: {\n operator: defaultOperator,\n value: \"\"\n }\n }\n ]);\n }, [columns, columnVariants, table]);\n\n const onFilterUpdate = React.useCallback(\n (filterId: string, updates: Partial<ColumnFilter>) => {\n table.setColumnFilters((prevFilters) => {\n if (!prevFilters) return prevFilters;\n return prevFilters.map((filter) => (filter.id === filterId ? { ...filter, ...updates } : filter));\n });\n },\n [table]\n );\n\n const onFilterRemove = React.useCallback(\n (filterId: string) => {\n table.setColumnFilters((prevFilters) => prevFilters.filter((item) => item.id !== filterId));\n },\n [table]\n );\n\n const onFiltersReset = React.useCallback(() => {\n table.setColumnFilters(table.initialState.columnFilters ?? []);\n }, [table]);\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() === FILTER_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_FILTER_SHORTCUTS.has(event.key.toLowerCase()) && columnFilters.length > 0) {\n event.preventDefault();\n onFiltersReset();\n }\n },\n [columnFilters.length, onFiltersReset]\n );\n\n return (\n <Sortable value={columnFilters} onValueChange={table.setColumnFilters} 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 <ListFilter aria-hidden=\"true\" className=\"text-muted-foreground\" />\n {msg.filter.trigger}\n {columnFilters.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 {columnFilters.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-[480px]\",\n className\n )}\n {...props}\n >\n <div className=\"flex flex-col gap-1\">\n <h4 id={labelId} className=\"font-medium leading-none\">\n {columnFilters.length > 0 ? msg.filter.title : msg.filter.emptyTitle}\n </h4>\n <p\n id={descriptionId}\n className={cn(\"text-muted-foreground text-sm\", columnFilters.length > 0 && \"sr-only\")}\n >\n {columnFilters.length > 0 ? msg.filter.description : msg.filter.emptyDescription}\n </p>\n </div>\n {columnFilters.length > 0 && (\n <SortableContent asChild>\n <div role=\"list\" className=\"flex max-h-[400px] flex-col gap-2 overflow-y-auto p-1\">\n {columnFilters.map((filter, index) => (\n <DataGridFilterItem\n key={filter.id}\n filter={filter}\n index={index}\n filterItemId={`${id}-filter-${filter.id}`}\n dir={dir}\n columns={columns}\n columnLabels={columnLabels}\n columnVariants={columnVariants}\n table={table}\n onFilterUpdate={onFilterUpdate}\n onFilterRemove={onFilterRemove}\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={onFilterAdd}\n disabled={columns.length === 0}\n >\n {msg.filter.add}\n </Button>\n {columnFilters.length > 0 && (\n <Button variant=\"outline\" size=\"sm\" className=\"rounded\" onClick={onFiltersReset}>\n {msg.filter.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 min-w-[72px] rounded-sm bg-muted\" />\n <div className=\"h-8 w-32 rounded-sm bg-muted\" />\n <div className=\"h-8 w-32 rounded-sm bg-muted\" />\n <div className=\"h-8 w-36 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 DataGridFilterItemProps<TData> {\n filter: ColumnFilter;\n index: number;\n filterItemId: string;\n dir: \"ltr\" | \"rtl\";\n columns: { id: string; label: string }[];\n columnLabels: Map<string, string>;\n columnVariants: Map<string, string>;\n table: Table<TData>;\n onFilterUpdate: (filterId: string, updates: Partial<ColumnFilter>) => void;\n onFilterRemove: (filterId: string) => void;\n}\n\nfunction DataGridFilterItem<TData>({\n filter,\n index,\n filterItemId,\n dir,\n columns,\n columnLabels,\n columnVariants,\n table,\n onFilterUpdate,\n onFilterRemove\n}: DataGridFilterItemProps<TData>) {\n const fieldListboxId = `${filterItemId}-field-listbox`;\n const fieldTriggerId = `${filterItemId}-field-trigger`;\n const operatorListboxId = `${filterItemId}-operator-listbox`;\n const inputId = `${filterItemId}-input`;\n\n const [showFieldSelector, setShowFieldSelector] = React.useState(false);\n const [showOperatorSelector, setShowOperatorSelector] = React.useState(false);\n\n const variant = columnVariants.get(filter.id) ?? \"short-text\";\n const filterValue = filter.value as FilterValue | undefined;\n const operator = filterValue?.operator ?? getDefaultOperator(variant);\n\n const operators = getOperatorsForVariant(variant);\n const needsValue = !OPERATORS_WITHOUT_VALUE.has(operator);\n\n const column = table.getColumn(filter.id);\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 || showOperatorSelector) {\n return;\n }\n\n if (REMOVE_FILTER_SHORTCUTS.has(event.key.toLowerCase())) {\n event.preventDefault();\n onFilterRemove(filter.id);\n }\n },\n [filter.id, showFieldSelector, showOperatorSelector, onFilterRemove]\n );\n\n const onOperatorChange = React.useCallback(\n (newOperator: FilterOperator) => {\n onFilterUpdate(filter.id, {\n value: {\n operator: newOperator,\n value: filterValue?.value,\n endValue: filterValue?.endValue\n }\n });\n },\n [filter.id, filterValue?.value, filterValue?.endValue, onFilterUpdate]\n );\n\n const onValueChange = React.useCallback(\n (newValue: string | number | string[] | undefined) => {\n onFilterUpdate(filter.id, {\n value: {\n operator,\n value: newValue,\n endValue: filterValue?.endValue\n }\n });\n },\n [filter.id, operator, filterValue?.endValue, onFilterUpdate]\n );\n\n const onEndValueChange = React.useCallback(\n (newValue: string | number | string[] | undefined) => {\n onFilterUpdate(filter.id, {\n value: {\n operator,\n value: filterValue?.value,\n endValue: newValue as string | number | undefined\n }\n });\n },\n [filter.id, operator, filterValue?.value, onFilterUpdate]\n );\n\n return (\n <SortableItem value={filter.id} asChild>\n <div\n role=\"listitem\"\n id={filterItemId}\n tabIndex={-1}\n className=\"flex items-center gap-2\"\n onKeyDown={onItemKeyDown}\n >\n <div className=\"min-w-[72px] text-center\">\n <span className=\"text-muted-foreground text-sm\">{index === 0 ? msg.filter.where : msg.filter.and}</span>\n </div>\n <Popover open={showFieldSelector} onOpenChange={setShowFieldSelector}>\n <PopoverTrigger asChild>\n <Button\n id={fieldTriggerId}\n aria-controls={fieldListboxId}\n dir={dir}\n variant=\"outline\"\n className=\"h-8 w-32 justify-between rounded font-normal\"\n >\n <span className=\"truncate\">{columnLabels.get(filter.id)}</span>\n <ChevronsUpDown aria-hidden=\"true\" className=\"opacity-50\" />\n </Button>\n </PopoverTrigger>\n <PopoverContent id={fieldListboxId} dir={dir} align=\"start\" className=\"w-40 p-0\">\n <Command>\n <CommandInput placeholder={msg.filter.fieldPlaceholder} aria-label={msg.filter.fieldPlaceholder} />\n <CommandList>\n <CommandEmpty>{msg.filter.fieldEmpty}</CommandEmpty>\n <CommandGroup>\n {columns.map((column) => (\n <CommandItem\n key={column.id}\n value={column.id}\n onSelect={(value) => {\n const newVariant = columnVariants.get(value) ?? \"short-text\";\n const newOperator = getDefaultOperator(newVariant);\n\n table.setColumnFilters((prevFilters) =>\n prevFilters.map((f) =>\n f.id === filter.id\n ? {\n id: value,\n value: {\n operator: newOperator,\n value: \"\"\n }\n }\n : f\n )\n );\n setShowFieldSelector(false);\n }}\n >\n <span className=\"truncate\">{column.label}</span>\n <Check className={cn(\"ms-auto\", column.id === filter.id ? \"opacity-100\" : \"opacity-0\")} />\n </CommandItem>\n ))}\n </CommandGroup>\n </CommandList>\n </Command>\n </PopoverContent>\n </Popover>\n <Select\n open={showOperatorSelector}\n onOpenChange={setShowOperatorSelector}\n value={operator}\n onValueChange={onOperatorChange}\n >\n <SelectTrigger aria-controls={operatorListboxId} aria-label={msg.filter.title} className=\"h-8 w-36 rounded\">\n <div className=\"truncate\">\n <SelectValue />\n </div>\n </SelectTrigger>\n <SelectContent id={operatorListboxId}>\n <SelectGroup>\n {operators.map((op) => (\n <SelectItem key={op.value} value={op.value}>\n {op.label}\n </SelectItem>\n ))}\n </SelectGroup>\n </SelectContent>\n </Select>\n <div className=\"min-w-36 max-w-60 flex-1\">\n {needsValue && column ? (\n <DataGridFilterInput\n key={filter.id}\n variant={variant}\n operator={operator}\n column={column}\n inputId={inputId}\n dir={dir}\n value={filterValue?.value}\n endValue={filterValue?.endValue}\n onValueChange={onValueChange}\n onEndValueChange={onEndValueChange}\n />\n ) : (\n <div\n id={inputId}\n role=\"status\"\n aria-label={msg.filter.emptyValue(columnLabels.get(filter.id) ?? filter.id)}\n aria-live=\"polite\"\n className=\"h-8 w-full rounded border bg-transparent\"\n />\n )}\n </div>\n <Button\n aria-controls={filterItemId}\n aria-label={msg.filter.remove}\n variant=\"outline\"\n size=\"icon\"\n className=\"size-8 rounded\"\n onClick={() => onFilterRemove(filter.id)}\n >\n <Trash2 aria-hidden=\"true\" />\n </Button>\n <SortableItemHandle asChild>\n <Button aria-label={msg.filter.drag} variant=\"outline\" size=\"icon\" className=\"size-8 rounded\">\n <GripVertical aria-hidden=\"true\" />\n </Button>\n </SortableItemHandle>\n </div>\n </SortableItem>\n );\n}\n\ninterface DataGridFilterInputProps<TData> {\n variant: string;\n operator: FilterOperator;\n dir: \"ltr\" | \"rtl\";\n placeholder?: string;\n value: string | number | string[] | undefined;\n endValue?: string | number;\n column: Column<TData>;\n inputId: string;\n onValueChange: (value: string | number | string[] | undefined) => void;\n onEndValueChange?: (value: string | number | string[] | undefined) => void;\n}\n\nfunction DataGridFilterInput<TData>({\n variant,\n operator,\n dir,\n placeholder = msg.filter.valuePlaceholder,\n value,\n endValue,\n column,\n inputId,\n onValueChange,\n onEndValueChange\n}: DataGridFilterInputProps<TData>) {\n const [showValueSelector, setShowValueSelector] = React.useState(false);\n const [localValue, setLocalValue] = React.useState(value);\n const [localEndValue, setLocalEndValue] = React.useState(endValue);\n\n const debouncedOnChange = useDebouncedCallback((newValue: string | number | string[] | undefined) => {\n onValueChange(newValue);\n }, FILTER_DEBOUNCE_MS);\n\n const debouncedOnEndValueChange = useDebouncedCallback((newValue: string | number | string[] | undefined) => {\n onEndValueChange?.(newValue);\n }, FILTER_DEBOUNCE_MS);\n\n const cellVariant = column.columnDef.meta?.cell;\n\n const selectOptions = React.useMemo(() => {\n return cellVariant?.variant === \"select\" || cellVariant?.variant === \"multi-select\" ? cellVariant.options : [];\n }, [cellVariant]);\n\n const isBetween = operator === \"isBetween\";\n\n if (variant === \"number\") {\n if (isBetween) {\n return (\n <div className=\"flex gap-2\">\n <Input\n id={inputId}\n type=\"number\"\n inputMode=\"numeric\"\n placeholder={msg.filter.rangeStart}\n aria-label={msg.filter.rangeStart}\n value={(localValue as number | undefined) ?? \"\"}\n onChange={(event) => {\n const val = event.target.value;\n const newValue = val === \"\" ? undefined : Number(val);\n setLocalValue(newValue);\n debouncedOnChange(newValue);\n }}\n className=\"h-8 w-full flex-1 rounded\"\n />\n <Input\n id={`${inputId}-end`}\n type=\"number\"\n inputMode=\"numeric\"\n placeholder={msg.filter.rangeEnd}\n aria-label={msg.filter.rangeEnd}\n value={(localEndValue as number | undefined) ?? \"\"}\n onChange={(event) => {\n const val = event.target.value;\n const newValue = val === \"\" ? undefined : Number(val);\n setLocalEndValue(newValue);\n debouncedOnEndValueChange(newValue);\n }}\n className=\"h-8 w-full flex-1 rounded\"\n />\n </div>\n );\n }\n\n return (\n <Input\n id={inputId}\n type=\"number\"\n inputMode=\"numeric\"\n placeholder={placeholder}\n aria-label={placeholder}\n value={(localValue as number | undefined) ?? \"\"}\n onChange={(event) => {\n const val = event.target.value;\n const newValue = val === \"\" ? undefined : Number(val);\n setLocalValue(newValue);\n debouncedOnChange(newValue);\n }}\n className=\"h-8 w-full rounded\"\n />\n );\n }\n\n if (variant === \"date\") {\n const inputListboxId = `${inputId}-listbox`;\n\n if (isBetween) {\n const startDate = localValue && typeof localValue === \"string\" ? new Date(localValue) : undefined;\n const endDate = localEndValue && typeof localEndValue === \"string\" ? new Date(localEndValue) : undefined;\n\n const isSameDate = startDate && endDate && startDate.toDateString() === endDate.toDateString();\n\n const displayValue =\n startDate && endDate && !isSameDate\n ? `${formatDate(startDate)} - ${formatDate(endDate)}`\n : startDate\n ? formatDate(startDate)\n : msg.filter.pickRange;\n\n return (\n <Popover open={showValueSelector} onOpenChange={setShowValueSelector}>\n <PopoverTrigger asChild>\n <Button\n id={inputId}\n aria-controls={inputListboxId}\n dir={dir}\n variant=\"outline\"\n className={cn(\n \"h-8 w-full justify-start gap-2 rounded font-normal\",\n !startDate && \"text-muted-foreground\"\n )}\n >\n <CalendarIcon aria-hidden=\"true\" />\n <span className=\"truncate\">{displayValue}</span>\n </Button>\n </PopoverTrigger>\n <PopoverContent id={inputListboxId} dir={dir} align=\"start\" className=\"w-auto p-0\">\n <Calendar\n mode=\"range\"\n locale={vi}\n autoFocus\n selected={startDate ? { from: startDate, to: endDate } : undefined}\n onSelect={(range) => {\n const fromValue = range?.from ? range.from.toISOString() : undefined;\n const toValue = range?.to ? range.to.toISOString() : undefined;\n setLocalValue(fromValue);\n setLocalEndValue(toValue);\n onValueChange(fromValue);\n onEndValueChange?.(toValue);\n }}\n />\n </PopoverContent>\n </Popover>\n );\n }\n\n const dateValue = localValue && typeof localValue === \"string\" ? new Date(localValue) : undefined;\n\n return (\n <Popover open={showValueSelector} onOpenChange={setShowValueSelector}>\n <PopoverTrigger asChild>\n <Button\n id={inputId}\n aria-controls={inputListboxId}\n dir={dir}\n variant=\"outline\"\n className={cn(\"h-8 w-full justify-start gap-2 rounded font-normal\", !dateValue && \"text-muted-foreground\")}\n >\n <CalendarIcon aria-hidden=\"true\" />\n <span className=\"truncate\">{dateValue ? formatDate(dateValue) : msg.filter.pickDate}</span>\n </Button>\n </PopoverTrigger>\n <PopoverContent id={inputListboxId} dir={dir} align=\"start\" className=\"w-auto p-0\">\n <Calendar\n mode=\"single\"\n locale={vi}\n autoFocus\n selected={dateValue}\n onSelect={(date) => {\n if (!date) return;\n const newValue = date.toISOString();\n setLocalValue(newValue);\n onValueChange(newValue);\n setShowValueSelector(false);\n }}\n />\n </PopoverContent>\n </Popover>\n );\n }\n\n const isSelectVariant = variant === \"select\" || variant === \"multi-select\";\n const isMultiValueOperator = operator === \"isAnyOf\" || operator === \"isNoneOf\";\n\n if (isSelectVariant && selectOptions.length > 0) {\n const inputListboxId = `${inputId}-listbox`;\n\n if (isMultiValueOperator) {\n const selectedValues = Array.isArray(value) ? value : [];\n const selectedOptions = selectOptions.filter((option) => selectedValues.includes(option.value));\n\n const selectedOptionsWithIcons = selectedOptions.filter((selectedOption) => selectedOption.icon);\n\n return (\n <Popover open={showValueSelector} onOpenChange={setShowValueSelector}>\n <PopoverTrigger asChild>\n <Button\n id={inputId}\n aria-controls={inputListboxId}\n dir={dir}\n variant=\"outline\"\n className=\"h-8 w-full justify-start rounded font-normal\"\n >\n {selectedOptions.length === 0 ? (\n <span className=\"text-muted-foreground\">{placeholder}</span>\n ) : (\n <>\n {selectedOptionsWithIcons.length > 0 && (\n <div className=\"flex items-center -space-x-2 rtl:space-x-reverse\">\n {selectedOptionsWithIcons.map(\n (selectedOption) =>\n selectedOption.icon && (\n <div key={selectedOption.value} className=\"rounded-full border bg-background p-0.5\">\n <selectedOption.icon className=\"size-3.5\" />\n </div>\n )\n )}\n </div>\n )}\n <span className=\"truncate\">\n {selectedOptions.length > 1\n ? msg.filter.selectedCount(selectedOptions.length)\n : selectedOptions[0]?.label}\n </span>\n </>\n )}\n </Button>\n </PopoverTrigger>\n <PopoverContent id={inputListboxId} dir={dir} align=\"start\" className=\"w-48 p-0\">\n <Command>\n <CommandInput placeholder={msg.filter.optionPlaceholder} aria-label={msg.filter.optionPlaceholder} />\n <CommandList>\n <CommandEmpty>{msg.filter.optionEmpty}</CommandEmpty>\n <CommandGroup>\n {selectOptions.map((option) => {\n const isSelected = selectedValues.includes(option.value);\n return (\n <CommandItem\n key={option.value}\n value={option.value}\n onSelect={() => {\n const newValues = isSelected\n ? selectedValues.filter((v) => v !== option.value)\n : [...selectedValues, option.value];\n onValueChange(newValues.length > 0 ? newValues : undefined);\n }}\n >\n {option.icon && <option.icon />}\n <span className=\"truncate\">{option.label}</span>\n {option.count && <span className=\"ms-auto font-mono text-xs\">{option.count}</span>}\n <Check className={cn(\"ms-auto\", isSelected ? \"opacity-100\" : \"opacity-0\")} />\n </CommandItem>\n );\n })}\n </CommandGroup>\n </CommandList>\n </Command>\n </PopoverContent>\n </Popover>\n );\n }\n\n const selectedOption = selectOptions.find((opt) => opt.value === (value as string));\n\n return (\n <Popover open={showValueSelector} onOpenChange={setShowValueSelector}>\n <PopoverTrigger asChild>\n <Button\n id={inputId}\n aria-controls={inputListboxId}\n dir={dir}\n variant=\"outline\"\n className=\"h-8 w-full justify-start rounded font-normal\"\n >\n {selectedOption ? (\n <>\n {selectedOption.icon && <selectedOption.icon />}\n <span className=\"truncate\">{selectedOption.label}</span>\n </>\n ) : (\n <span className=\"text-muted-foreground\">{placeholder}</span>\n )}\n </Button>\n </PopoverTrigger>\n <PopoverContent id={inputListboxId} dir={dir} align=\"start\" className=\"w-[200px] p-0\">\n <Command>\n <CommandInput placeholder={msg.filter.optionPlaceholder} aria-label={msg.filter.optionPlaceholder} />\n <CommandList>\n <CommandEmpty>{msg.filter.optionEmpty}</CommandEmpty>\n <CommandGroup>\n {selectOptions.map((option) => (\n <CommandItem\n key={option.value}\n value={option.value}\n onSelect={() => {\n onValueChange(option.value);\n setShowValueSelector(false);\n }}\n >\n {option.icon && <option.icon />}\n <span className=\"truncate\">{option.label}</span>\n {option.count && <span className=\"ms-auto font-mono text-xs\">{option.count}</span>}\n <Check className={cn(\"ms-auto\", value === option.value ? \"opacity-100\" : \"opacity-0\")} />\n </CommandItem>\n ))}\n </CommandGroup>\n </CommandList>\n </Command>\n </PopoverContent>\n </Popover>\n );\n }\n\n if (isBetween) {\n return (\n <div className=\"flex gap-2\">\n <Input\n id={inputId}\n type=\"text\"\n placeholder={msg.filter.rangeStart}\n aria-label={msg.filter.rangeStart}\n className=\"h-8 w-full flex-1 rounded\"\n value={(localValue as string | undefined) ?? \"\"}\n onChange={(event) => {\n const val = event.target.value;\n const newValue = val === \"\" ? undefined : val;\n setLocalValue(newValue);\n debouncedOnChange(newValue);\n }}\n />\n <Input\n id={`${inputId}-end`}\n type=\"text\"\n placeholder={msg.filter.rangeEnd}\n aria-label={msg.filter.rangeEnd}\n className=\"h-8 w-full flex-1 rounded\"\n value={(localEndValue as string | undefined) ?? \"\"}\n onChange={(event) => {\n const val = event.target.value;\n const newValue = val === \"\" ? undefined : val;\n setLocalEndValue(newValue);\n debouncedOnEndValueChange(newValue);\n }}\n />\n </div>\n );\n }\n\n return (\n <Input\n id={inputId}\n type=\"text\"\n placeholder={placeholder}\n aria-label={placeholder}\n className=\"h-8 w-full rounded\"\n value={(localValue as string | undefined) ?? \"\"}\n onChange={(event) => {\n const val = event.target.value;\n const newValue = val === \"\" ? undefined : val;\n setLocalValue(newValue);\n debouncedOnChange(newValue);\n }}\n />\n );\n}\n"],"mappings":"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","names":["column","selectedOption"]}
1
+ {"version":3,"sources":["../../src/data-grid/data-grid-filter-menu.tsx"],"sourcesContent":["\"use client\";\n\nimport { useDirection } from \"@radix-ui/react-direction\";\nimport type { Column, ColumnFilter, Table } from \"@tanstack/react-table\";\nimport { vi } from \"date-fns/locale\";\nimport { CalendarIcon, Check, ChevronsUpDown, GripVertical, ListFilter, Trash2 } from \"lucide-react\";\nimport * as React from \"react\";\nimport { badgeVariants } from \"../components/ui/badge.js\";\nimport { Button } from \"../components/ui/button.js\";\nimport { Calendar } from \"../components/ui/calendar.js\";\nimport {\n Command,\n CommandEmpty,\n CommandGroup,\n CommandInput,\n CommandItem,\n CommandList\n} from \"../components/ui/command.js\";\nimport { Input } from \"../components/ui/input.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 { getDefaultOperator, getOperatorsForVariant } from \"./filters.js\";\nimport type { DataGridLocale, DataGridMessages } from \"./messages.js\";\nimport { Sortable, SortableContent, SortableItem, SortableItemHandle, SortableOverlay } from \"./sortable.js\";\nimport type { FilterOperator, FilterValue } from \"./types.js\";\nimport { useDebouncedCallback } from \"./use-debounced-callback.js\";\nimport { formatDate } from \"./utils.js\";\n\nconst FILTER_SHORTCUT_KEY = \"f\";\nconst REMOVE_FILTER_SHORTCUTS = new Set([\"backspace\", \"delete\"]);\nconst FILTER_DEBOUNCE_MS = 300;\nconst OPERATORS_WITHOUT_VALUE = new Set([\"isEmpty\", \"isNotEmpty\", \"isTrue\", \"isFalse\"]);\n\ninterface DataGridFilterMenuProps<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 DataGridFilterMenu<TData>({\n table,\n disabled,\n className,\n locale,\n ...props\n}: DataGridFilterMenuProps<TData>) {\n // Menu giữ bảng chuỗi rồi PHÁT xuống `DataGridFilterItem` / `DataGridFilterInput`.\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 columnFilters = table.getState().columnFilters;\n\n const { columnLabels, columns, columnVariants } = React.useMemo(() => {\n const labels = new Map<string, string>();\n const variants = new Map<string, string>();\n const filteringIds = new Set(columnFilters.map((f) => f.id));\n const availableColumns: { id: string; label: string }[] = [];\n\n for (const column of table.getAllColumns()) {\n if (!column.getCanFilter()) continue;\n\n const label = column.columnDef.meta?.label ?? column.id;\n const variant = column.columnDef.meta?.cell?.variant ?? \"short-text\";\n\n labels.set(column.id, label);\n variants.set(column.id, variant);\n\n if (!filteringIds.has(column.id)) {\n availableColumns.push({ id: column.id, label });\n }\n }\n\n return {\n columnLabels: labels,\n columns: availableColumns,\n columnVariants: variants\n };\n }, [columnFilters, table]);\n\n const onFilterAdd = React.useCallback(() => {\n const firstColumn = columns[0];\n if (!firstColumn) return;\n\n const variant = columnVariants.get(firstColumn.id) ?? \"short-text\";\n const defaultOperator = getDefaultOperator(variant);\n\n table.setColumnFilters((prevFilters) => [\n ...prevFilters,\n {\n id: firstColumn.id,\n value: {\n operator: defaultOperator,\n value: \"\"\n }\n }\n ]);\n }, [columns, columnVariants, table]);\n\n const onFilterUpdate = React.useCallback(\n (filterId: string, updates: Partial<ColumnFilter>) => {\n table.setColumnFilters((prevFilters) => {\n if (!prevFilters) return prevFilters;\n return prevFilters.map((filter) => (filter.id === filterId ? { ...filter, ...updates } : filter));\n });\n },\n [table]\n );\n\n const onFilterRemove = React.useCallback(\n (filterId: string) => {\n table.setColumnFilters((prevFilters) => prevFilters.filter((item) => item.id !== filterId));\n },\n [table]\n );\n\n const onFiltersReset = React.useCallback(() => {\n table.setColumnFilters(table.initialState.columnFilters ?? []);\n }, [table]);\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() === FILTER_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_FILTER_SHORTCUTS.has(event.key.toLowerCase()) && columnFilters.length > 0) {\n event.preventDefault();\n onFiltersReset();\n }\n },\n [columnFilters.length, onFiltersReset]\n );\n\n return (\n <DataGridLocaleProvider locale={msg}>\n <Sortable value={columnFilters} onValueChange={table.setColumnFilters} 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 <ListFilter aria-hidden=\"true\" className=\"size-3.5 text-muted-foreground\" />\n {msg.filter.trigger}\n {columnFilters.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 {columnFilters.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-[480px]\",\n className\n )}\n {...props}\n >\n <div className=\"flex flex-col gap-1\">\n <h4 id={labelId} className=\"font-medium leading-none\">\n {columnFilters.length > 0 ? msg.filter.title : msg.filter.emptyTitle}\n </h4>\n <p\n id={descriptionId}\n className={cn(\"text-muted-foreground text-sm\", columnFilters.length > 0 && \"sr-only\")}\n >\n {columnFilters.length > 0 ? msg.filter.description : msg.filter.emptyDescription}\n </p>\n </div>\n {columnFilters.length > 0 && (\n <SortableContent asChild>\n <div role=\"list\" className=\"flex max-h-[400px] flex-col gap-2 overflow-y-auto p-1\">\n {columnFilters.map((filter, index) => (\n <DataGridFilterItem\n key={filter.id}\n filter={filter}\n index={index}\n filterItemId={`${id}-filter-${filter.id}`}\n dir={dir}\n columns={columns}\n columnLabels={columnLabels}\n columnVariants={columnVariants}\n table={table}\n onFilterUpdate={onFilterUpdate}\n onFilterRemove={onFilterRemove}\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={onFilterAdd}\n disabled={columns.length === 0}\n >\n {msg.filter.add}\n </Button>\n {columnFilters.length > 0 && (\n <Button variant=\"outline\" size=\"sm\" className=\"rounded\" onClick={onFiltersReset}>\n {msg.filter.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 min-w-[72px] rounded-sm bg-muted\" />\n <div className=\"h-8 w-32 rounded-sm bg-muted\" />\n <div className=\"h-8 w-32 rounded-sm bg-muted\" />\n <div className=\"h-8 w-36 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 DataGridFilterItemProps<TData> {\n filter: ColumnFilter;\n index: number;\n filterItemId: string;\n dir: \"ltr\" | \"rtl\";\n columns: { id: string; label: string }[];\n columnLabels: Map<string, string>;\n columnVariants: Map<string, string>;\n table: Table<TData>;\n onFilterUpdate: (filterId: string, updates: Partial<ColumnFilter>) => void;\n onFilterRemove: (filterId: string) => void;\n}\n\nfunction DataGridFilterItem<TData>({\n filter,\n index,\n filterItemId,\n dir,\n columns,\n columnLabels,\n columnVariants,\n table,\n onFilterUpdate,\n onFilterRemove\n}: DataGridFilterItemProps<TData>) {\n const msg = useDataGridMessages();\n const fieldListboxId = `${filterItemId}-field-listbox`;\n const fieldTriggerId = `${filterItemId}-field-trigger`;\n const operatorListboxId = `${filterItemId}-operator-listbox`;\n const inputId = `${filterItemId}-input`;\n\n const [showFieldSelector, setShowFieldSelector] = React.useState(false);\n const [showOperatorSelector, setShowOperatorSelector] = React.useState(false);\n\n const variant = columnVariants.get(filter.id) ?? \"short-text\";\n const filterValue = filter.value as FilterValue | undefined;\n const operator = filterValue?.operator ?? getDefaultOperator(variant);\n\n const operators = getOperatorsForVariant(variant);\n const needsValue = !OPERATORS_WITHOUT_VALUE.has(operator);\n\n const column = table.getColumn(filter.id);\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 || showOperatorSelector) {\n return;\n }\n\n if (REMOVE_FILTER_SHORTCUTS.has(event.key.toLowerCase())) {\n event.preventDefault();\n onFilterRemove(filter.id);\n }\n },\n [filter.id, showFieldSelector, showOperatorSelector, onFilterRemove]\n );\n\n const onOperatorChange = React.useCallback(\n (newOperator: FilterOperator) => {\n onFilterUpdate(filter.id, {\n value: {\n operator: newOperator,\n value: filterValue?.value,\n endValue: filterValue?.endValue\n }\n });\n },\n [filter.id, filterValue?.value, filterValue?.endValue, onFilterUpdate]\n );\n\n const onValueChange = React.useCallback(\n (newValue: string | number | string[] | undefined) => {\n onFilterUpdate(filter.id, {\n value: {\n operator,\n value: newValue,\n endValue: filterValue?.endValue\n }\n });\n },\n [filter.id, operator, filterValue?.endValue, onFilterUpdate]\n );\n\n const onEndValueChange = React.useCallback(\n (newValue: string | number | string[] | undefined) => {\n onFilterUpdate(filter.id, {\n value: {\n operator,\n value: filterValue?.value,\n endValue: newValue as string | number | undefined\n }\n });\n },\n [filter.id, operator, filterValue?.value, onFilterUpdate]\n );\n\n return (\n <SortableItem value={filter.id} asChild>\n <div\n role=\"listitem\"\n id={filterItemId}\n tabIndex={-1}\n className=\"flex items-center gap-2\"\n onKeyDown={onItemKeyDown}\n >\n <div className=\"min-w-[72px] text-center\">\n <span className=\"text-muted-foreground text-sm\">{index === 0 ? msg.filter.where : msg.filter.and}</span>\n </div>\n <Popover open={showFieldSelector} onOpenChange={setShowFieldSelector}>\n <PopoverTrigger asChild>\n <Button\n id={fieldTriggerId}\n aria-controls={fieldListboxId}\n dir={dir}\n variant=\"outline\"\n className=\"h-8 w-32 justify-between rounded font-normal\"\n >\n <span className=\"truncate\">{columnLabels.get(filter.id)}</span>\n <ChevronsUpDown aria-hidden=\"true\" className=\"opacity-50\" />\n </Button>\n </PopoverTrigger>\n <PopoverContent id={fieldListboxId} dir={dir} align=\"start\" className=\"w-40 p-0\">\n <Command>\n <CommandInput placeholder={msg.filter.fieldPlaceholder} aria-label={msg.filter.fieldPlaceholder} />\n <CommandList>\n <CommandEmpty>{msg.filter.fieldEmpty}</CommandEmpty>\n <CommandGroup>\n {columns.map((column) => (\n <CommandItem\n key={column.id}\n value={column.id}\n onSelect={(value) => {\n const newVariant = columnVariants.get(value) ?? \"short-text\";\n const newOperator = getDefaultOperator(newVariant);\n\n table.setColumnFilters((prevFilters) =>\n prevFilters.map((f) =>\n f.id === filter.id\n ? {\n id: value,\n value: {\n operator: newOperator,\n value: \"\"\n }\n }\n : f\n )\n );\n setShowFieldSelector(false);\n }}\n >\n <span className=\"truncate\">{column.label}</span>\n <Check className={cn(\"ms-auto\", column.id === filter.id ? \"opacity-100\" : \"opacity-0\")} />\n </CommandItem>\n ))}\n </CommandGroup>\n </CommandList>\n </Command>\n </PopoverContent>\n </Popover>\n <Select\n open={showOperatorSelector}\n onOpenChange={setShowOperatorSelector}\n value={operator}\n onValueChange={onOperatorChange}\n >\n <SelectTrigger aria-controls={operatorListboxId} aria-label={msg.filter.title} className=\"h-8 w-36 rounded\">\n <div className=\"truncate\">\n <SelectValue />\n </div>\n </SelectTrigger>\n <SelectContent id={operatorListboxId}>\n <SelectGroup>\n {operators.map((op) => (\n <SelectItem key={op.value} value={op.value}>\n {op.label}\n </SelectItem>\n ))}\n </SelectGroup>\n </SelectContent>\n </Select>\n <div className=\"min-w-36 max-w-60 flex-1\">\n {needsValue && column ? (\n <DataGridFilterInput\n key={filter.id}\n variant={variant}\n operator={operator}\n column={column}\n inputId={inputId}\n dir={dir}\n value={filterValue?.value}\n endValue={filterValue?.endValue}\n onValueChange={onValueChange}\n onEndValueChange={onEndValueChange}\n />\n ) : (\n <div\n id={inputId}\n role=\"status\"\n aria-label={msg.filter.emptyValue(columnLabels.get(filter.id) ?? filter.id)}\n aria-live=\"polite\"\n className=\"h-8 w-full rounded border bg-transparent\"\n />\n )}\n </div>\n <Button\n aria-controls={filterItemId}\n aria-label={msg.filter.remove}\n variant=\"outline\"\n size=\"icon\"\n className=\"size-8 rounded\"\n onClick={() => onFilterRemove(filter.id)}\n >\n <Trash2 aria-hidden=\"true\" className=\"size-3.5\" />\n </Button>\n <SortableItemHandle asChild>\n <Button aria-label={msg.filter.drag} variant=\"outline\" size=\"icon\" className=\"size-8 rounded\">\n <GripVertical aria-hidden=\"true\" className=\"size-3.5\" />\n </Button>\n </SortableItemHandle>\n </div>\n </SortableItem>\n );\n}\n\ninterface DataGridFilterInputProps<TData> {\n variant: string;\n operator: FilterOperator;\n dir: \"ltr\" | \"rtl\";\n placeholder?: string;\n value: string | number | string[] | undefined;\n endValue?: string | number;\n column: Column<TData>;\n inputId: string;\n onValueChange: (value: string | number | string[] | undefined) => void;\n onEndValueChange?: (value: string | number | string[] | undefined) => void;\n}\n\nfunction DataGridFilterInput<TData>({\n variant,\n operator,\n dir,\n placeholder,\n value,\n endValue,\n column,\n inputId,\n onValueChange,\n onEndValueChange\n}: DataGridFilterInputProps<TData>) {\n const msg = useDataGridMessages();\n // Mặc định không đặt được ở tham số vì nó phụ thuộc bảng chuỗi, mà bảng chuỗi đến từ hook.\n const inputPlaceholder = placeholder ?? msg.filter.valuePlaceholder;\n const [showValueSelector, setShowValueSelector] = React.useState(false);\n const [localValue, setLocalValue] = React.useState(value);\n const [localEndValue, setLocalEndValue] = React.useState(endValue);\n\n const debouncedOnChange = useDebouncedCallback((newValue: string | number | string[] | undefined) => {\n onValueChange(newValue);\n }, FILTER_DEBOUNCE_MS);\n\n const debouncedOnEndValueChange = useDebouncedCallback((newValue: string | number | string[] | undefined) => {\n onEndValueChange?.(newValue);\n }, FILTER_DEBOUNCE_MS);\n\n const cellVariant = column.columnDef.meta?.cell;\n\n const selectOptions = React.useMemo(() => {\n return cellVariant?.variant === \"select\" || cellVariant?.variant === \"multi-select\" ? cellVariant.options : [];\n }, [cellVariant]);\n\n const isBetween = operator === \"isBetween\";\n\n if (variant === \"number\") {\n if (isBetween) {\n return (\n <div className=\"flex gap-2\">\n <Input\n id={inputId}\n type=\"number\"\n inputMode=\"numeric\"\n placeholder={msg.filter.rangeStart}\n aria-label={msg.filter.rangeStart}\n value={(localValue as number | undefined) ?? \"\"}\n onChange={(event) => {\n const val = event.target.value;\n const newValue = val === \"\" ? undefined : Number(val);\n setLocalValue(newValue);\n debouncedOnChange(newValue);\n }}\n className=\"h-8 w-full flex-1 rounded\"\n />\n <Input\n id={`${inputId}-end`}\n type=\"number\"\n inputMode=\"numeric\"\n placeholder={msg.filter.rangeEnd}\n aria-label={msg.filter.rangeEnd}\n value={(localEndValue as number | undefined) ?? \"\"}\n onChange={(event) => {\n const val = event.target.value;\n const newValue = val === \"\" ? undefined : Number(val);\n setLocalEndValue(newValue);\n debouncedOnEndValueChange(newValue);\n }}\n className=\"h-8 w-full flex-1 rounded\"\n />\n </div>\n );\n }\n\n return (\n <Input\n id={inputId}\n type=\"number\"\n inputMode=\"numeric\"\n placeholder={inputPlaceholder}\n aria-label={inputPlaceholder}\n value={(localValue as number | undefined) ?? \"\"}\n onChange={(event) => {\n const val = event.target.value;\n const newValue = val === \"\" ? undefined : Number(val);\n setLocalValue(newValue);\n debouncedOnChange(newValue);\n }}\n className=\"h-8 w-full rounded\"\n />\n );\n }\n\n if (variant === \"date\") {\n const inputListboxId = `${inputId}-listbox`;\n\n if (isBetween) {\n const startDate = localValue && typeof localValue === \"string\" ? new Date(localValue) : undefined;\n const endDate = localEndValue && typeof localEndValue === \"string\" ? new Date(localEndValue) : undefined;\n\n const isSameDate = startDate && endDate && startDate.toDateString() === endDate.toDateString();\n\n const displayValue =\n startDate && endDate && !isSameDate\n ? `${formatDate(startDate)} - ${formatDate(endDate)}`\n : startDate\n ? formatDate(startDate)\n : msg.filter.pickRange;\n\n return (\n <Popover open={showValueSelector} onOpenChange={setShowValueSelector}>\n <PopoverTrigger asChild>\n <Button\n id={inputId}\n aria-controls={inputListboxId}\n dir={dir}\n variant=\"outline\"\n className={cn(\n \"h-8 w-full justify-start gap-2 rounded font-normal\",\n !startDate && \"text-muted-foreground\"\n )}\n >\n <CalendarIcon aria-hidden=\"true\" className=\"size-3.5\" />\n <span className=\"truncate\">{displayValue}</span>\n </Button>\n </PopoverTrigger>\n <PopoverContent id={inputListboxId} dir={dir} align=\"start\" className=\"w-auto p-0\">\n <Calendar\n mode=\"range\"\n locale={vi}\n autoFocus\n selected={startDate ? { from: startDate, to: endDate } : undefined}\n onSelect={(range) => {\n const fromValue = range?.from ? range.from.toISOString() : undefined;\n const toValue = range?.to ? range.to.toISOString() : undefined;\n setLocalValue(fromValue);\n setLocalEndValue(toValue);\n onValueChange(fromValue);\n onEndValueChange?.(toValue);\n }}\n />\n </PopoverContent>\n </Popover>\n );\n }\n\n const dateValue = localValue && typeof localValue === \"string\" ? new Date(localValue) : undefined;\n\n return (\n <Popover open={showValueSelector} onOpenChange={setShowValueSelector}>\n <PopoverTrigger asChild>\n <Button\n id={inputId}\n aria-controls={inputListboxId}\n dir={dir}\n variant=\"outline\"\n className={cn(\"h-8 w-full justify-start gap-2 rounded font-normal\", !dateValue && \"text-muted-foreground\")}\n >\n <CalendarIcon aria-hidden=\"true\" className=\"size-3.5\" />\n <span className=\"truncate\">{dateValue ? formatDate(dateValue) : msg.filter.pickDate}</span>\n </Button>\n </PopoverTrigger>\n <PopoverContent id={inputListboxId} dir={dir} align=\"start\" className=\"w-auto p-0\">\n <Calendar\n mode=\"single\"\n locale={vi}\n autoFocus\n selected={dateValue}\n onSelect={(date) => {\n if (!date) return;\n const newValue = date.toISOString();\n setLocalValue(newValue);\n onValueChange(newValue);\n setShowValueSelector(false);\n }}\n />\n </PopoverContent>\n </Popover>\n );\n }\n\n const isSelectVariant = variant === \"select\" || variant === \"multi-select\";\n const isMultiValueOperator = operator === \"isAnyOf\" || operator === \"isNoneOf\";\n\n if (isSelectVariant && selectOptions.length > 0) {\n const inputListboxId = `${inputId}-listbox`;\n\n if (isMultiValueOperator) {\n const selectedValues = Array.isArray(value) ? value : [];\n const selectedOptions = selectOptions.filter((option) => selectedValues.includes(option.value));\n\n const selectedOptionsWithIcons = selectedOptions.filter((selectedOption) => selectedOption.icon);\n\n return (\n <Popover open={showValueSelector} onOpenChange={setShowValueSelector}>\n <PopoverTrigger asChild>\n <Button\n id={inputId}\n aria-controls={inputListboxId}\n dir={dir}\n variant=\"outline\"\n className=\"h-8 w-full justify-start rounded font-normal\"\n >\n {selectedOptions.length === 0 ? (\n <span className=\"text-muted-foreground\">{inputPlaceholder}</span>\n ) : (\n <>\n {selectedOptionsWithIcons.length > 0 && (\n <div className=\"flex items-center -space-x-2 rtl:space-x-reverse\">\n {selectedOptionsWithIcons.map(\n (selectedOption) =>\n selectedOption.icon && (\n <div key={selectedOption.value} className=\"rounded-full border bg-background p-0.5\">\n <selectedOption.icon className=\"size-3.5\" />\n </div>\n )\n )}\n </div>\n )}\n <span className=\"truncate\">\n {selectedOptions.length > 1\n ? msg.filter.selectedCount(selectedOptions.length)\n : selectedOptions[0]?.label}\n </span>\n </>\n )}\n </Button>\n </PopoverTrigger>\n <PopoverContent id={inputListboxId} dir={dir} align=\"start\" className=\"w-48 p-0\">\n <Command>\n <CommandInput placeholder={msg.filter.optionPlaceholder} aria-label={msg.filter.optionPlaceholder} />\n <CommandList>\n <CommandEmpty>{msg.filter.optionEmpty}</CommandEmpty>\n <CommandGroup>\n {selectOptions.map((option) => {\n const isSelected = selectedValues.includes(option.value);\n return (\n <CommandItem\n key={option.value}\n value={option.value}\n onSelect={() => {\n const newValues = isSelected\n ? selectedValues.filter((v) => v !== option.value)\n : [...selectedValues, option.value];\n onValueChange(newValues.length > 0 ? newValues : undefined);\n }}\n >\n {option.icon && <option.icon />}\n <span className=\"truncate\">{option.label}</span>\n {option.count && <span className=\"ms-auto font-mono text-xs\">{option.count}</span>}\n <Check className={cn(\"ms-auto\", isSelected ? \"opacity-100\" : \"opacity-0\")} />\n </CommandItem>\n );\n })}\n </CommandGroup>\n </CommandList>\n </Command>\n </PopoverContent>\n </Popover>\n );\n }\n\n const selectedOption = selectOptions.find((opt) => opt.value === (value as string));\n\n return (\n <Popover open={showValueSelector} onOpenChange={setShowValueSelector}>\n <PopoverTrigger asChild>\n <Button\n id={inputId}\n aria-controls={inputListboxId}\n dir={dir}\n variant=\"outline\"\n className=\"h-8 w-full justify-start rounded font-normal\"\n >\n {selectedOption ? (\n <>\n {selectedOption.icon && <selectedOption.icon />}\n <span className=\"truncate\">{selectedOption.label}</span>\n </>\n ) : (\n <span className=\"text-muted-foreground\">{inputPlaceholder}</span>\n )}\n </Button>\n </PopoverTrigger>\n <PopoverContent id={inputListboxId} dir={dir} align=\"start\" className=\"w-[200px] p-0\">\n <Command>\n <CommandInput placeholder={msg.filter.optionPlaceholder} aria-label={msg.filter.optionPlaceholder} />\n <CommandList>\n <CommandEmpty>{msg.filter.optionEmpty}</CommandEmpty>\n <CommandGroup>\n {selectOptions.map((option) => (\n <CommandItem\n key={option.value}\n value={option.value}\n onSelect={() => {\n onValueChange(option.value);\n setShowValueSelector(false);\n }}\n >\n {option.icon && <option.icon />}\n <span className=\"truncate\">{option.label}</span>\n {option.count && <span className=\"ms-auto font-mono text-xs\">{option.count}</span>}\n <Check className={cn(\"ms-auto\", value === option.value ? \"opacity-100\" : \"opacity-0\")} />\n </CommandItem>\n ))}\n </CommandGroup>\n </CommandList>\n </Command>\n </PopoverContent>\n </Popover>\n );\n }\n\n if (isBetween) {\n return (\n <div className=\"flex gap-2\">\n <Input\n id={inputId}\n type=\"text\"\n placeholder={msg.filter.rangeStart}\n aria-label={msg.filter.rangeStart}\n className=\"h-8 w-full flex-1 rounded\"\n value={(localValue as string | undefined) ?? \"\"}\n onChange={(event) => {\n const val = event.target.value;\n const newValue = val === \"\" ? undefined : val;\n setLocalValue(newValue);\n debouncedOnChange(newValue);\n }}\n />\n <Input\n id={`${inputId}-end`}\n type=\"text\"\n placeholder={msg.filter.rangeEnd}\n aria-label={msg.filter.rangeEnd}\n className=\"h-8 w-full flex-1 rounded\"\n value={(localEndValue as string | undefined) ?? \"\"}\n onChange={(event) => {\n const val = event.target.value;\n const newValue = val === \"\" ? undefined : val;\n setLocalEndValue(newValue);\n debouncedOnEndValueChange(newValue);\n }}\n />\n </div>\n );\n }\n\n return (\n <Input\n id={inputId}\n type=\"text\"\n placeholder={inputPlaceholder}\n aria-label={inputPlaceholder}\n className=\"h-8 w-full rounded\"\n value={(localValue as string | undefined) ?? \"\"}\n onChange={(event) => {\n const val = event.target.value;\n const newValue = val === \"\" ? undefined : val;\n setLocalValue(newValue);\n debouncedOnChange(newValue);\n }}\n />\n );\n}\n"],"mappings":"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","names":["column","selectedOption"]}
@@ -1,4 +1,7 @@
1
1
  import * as React from 'react';
2
+ import { DataGridLocale } from './messages.js';
3
+ import { DataGridMessages } from './messages-en.js';
4
+ import './messages-vi.js';
2
5
 
3
6
  interface DataGridKeyboardShortcutsProps {
4
7
  /** Hiện phím tắt của ô tìm kiếm (bật cùng `enableSearch` của lưới) */
@@ -9,12 +12,20 @@ interface DataGridKeyboardShortcutsProps {
9
12
  enableRowsDelete?: boolean;
10
13
  /** Ẩn nút mở trên thanh công cụ — vẫn mở được bằng Ctrl+/ */
11
14
  hideTrigger?: boolean;
15
+ /**
16
+ * Ngôn ngữ của menu: `"en"` (mặc định) · `"vi"`, hoặc cả một bảng chuỗi tự soạn.
17
+ *
18
+ * ⚠ 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
19
+ * cả màn bằng `DataGridLocaleProvider` (một lần, đúng cho mọi mảnh), hoặc truyền prop này cho
20
+ * từng menu. Prop thắng provider.
21
+ */
22
+ locale?: DataGridLocale | DataGridMessages;
12
23
  }
13
24
  /**
14
25
  * 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ụ).
15
26
  * 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.
16
27
  */
17
28
  declare const DataGridKeyboardShortcuts: React.MemoExoticComponent<typeof DataGridKeyboardShortcutsImpl>;
18
- declare function DataGridKeyboardShortcutsImpl({ enableSearch, enableUndoRedo, enablePaste, enableRowAdd, enableRowsDelete, hideTrigger }: DataGridKeyboardShortcutsProps): React.JSX.Element;
29
+ declare function DataGridKeyboardShortcutsImpl({ enableSearch, enableUndoRedo, enablePaste, enableRowAdd, enableRowsDelete, hideTrigger, locale }: DataGridKeyboardShortcutsProps): React.JSX.Element;
19
30
 
20
31
  export { DataGridKeyboardShortcuts };