@comitor/ui 1.10.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -5
- package/dist/data-grid/compose-refs.d.ts +19 -0
- package/dist/data-grid/compose-refs.js +41 -0
- package/dist/data-grid/compose-refs.js.map +1 -0
- package/dist/data-grid/data-grid-cell-variants.d.ts +15 -0
- package/dist/data-grid/data-grid-cell-variants.js +1738 -0
- package/dist/data-grid/data-grid-cell-variants.js.map +1 -0
- package/dist/data-grid/data-grid-cell-wrapper.d.ts +9 -0
- package/dist/data-grid/data-grid-cell-wrapper.js +179 -0
- package/dist/data-grid/data-grid-cell-wrapper.js.map +1 -0
- package/dist/data-grid/data-grid-cell.d.ts +8 -0
- package/dist/data-grid/data-grid-cell.js +101 -0
- package/dist/data-grid/data-grid-cell.js.map +1 -0
- package/dist/data-grid/data-grid-column-header.d.ts +12 -0
- package/dist/data-grid/data-grid-column-header.js +207 -0
- package/dist/data-grid/data-grid-column-header.js.map +1 -0
- package/dist/data-grid/data-grid-context-menu.d.ts +12 -0
- package/dist/data-grid/data-grid-context-menu.js +161 -0
- package/dist/data-grid/data-grid-context-menu.js.map +1 -0
- package/dist/data-grid/data-grid-filter-menu.d.ts +23 -0
- package/dist/data-grid/data-grid-filter-menu.js +725 -0
- package/dist/data-grid/data-grid-filter-menu.js.map +1 -0
- package/dist/data-grid/data-grid-keyboard-shortcuts.d.ts +31 -0
- package/dist/data-grid/data-grid-keyboard-shortcuts.js +229 -0
- package/dist/data-grid/data-grid-keyboard-shortcuts.js.map +1 -0
- package/dist/data-grid/data-grid-locale.d.ts +24 -0
- package/dist/data-grid/data-grid-locale.js +25 -0
- package/dist/data-grid/data-grid-locale.js.map +1 -0
- package/dist/data-grid/data-grid-paste-dialog.d.ts +11 -0
- package/dist/data-grid/data-grid-paste-dialog.js +104 -0
- package/dist/data-grid/data-grid-paste-dialog.js.map +1 -0
- package/dist/data-grid/data-grid-presence.d.ts +14 -0
- package/dist/data-grid/data-grid-presence.js +16 -0
- package/dist/data-grid/data-grid-presence.js.map +1 -0
- package/dist/data-grid/data-grid-row-height-menu.d.ts +25 -0
- package/dist/data-grid/data-grid-row-height-menu.js +53 -0
- package/dist/data-grid/data-grid-row-height-menu.js.map +1 -0
- package/dist/data-grid/data-grid-row.d.ts +28 -0
- package/dist/data-grid/data-grid-row.js +206 -0
- package/dist/data-grid/data-grid-row.js.map +1 -0
- package/dist/data-grid/data-grid-search.d.ts +10 -0
- package/dist/data-grid/data-grid-search.js +184 -0
- package/dist/data-grid/data-grid-search.js.map +1 -0
- package/dist/data-grid/data-grid-select-column.d.ts +12 -0
- package/dist/data-grid/data-grid-select-column.js +179 -0
- package/dist/data-grid/data-grid-select-column.js.map +1 -0
- package/dist/data-grid/data-grid-skeleton.d.ts +13 -0
- package/dist/data-grid/data-grid-skeleton.js +52 -0
- package/dist/data-grid/data-grid-skeleton.js.map +1 -0
- package/dist/data-grid/data-grid-sort-menu.d.ts +23 -0
- package/dist/data-grid/data-grid-sort-menu.js +283 -0
- package/dist/data-grid/data-grid-sort-menu.js.map +1 -0
- package/dist/data-grid/data-grid-view-menu.d.ts +24 -0
- package/dist/data-grid/data-grid-view-menu.js +74 -0
- package/dist/data-grid/data-grid-view-menu.js.map +1 -0
- package/dist/data-grid/data-grid.d.ts +44 -0
- package/dist/data-grid/data-grid.js +238 -0
- package/dist/data-grid/data-grid.js.map +1 -0
- package/dist/data-grid/filters.d.ts +27 -0
- package/dist/data-grid/filters.js +233 -0
- package/dist/data-grid/filters.js.map +1 -0
- package/dist/data-grid/index.d.ts +25 -0
- package/dist/data-grid/index.js +95 -0
- package/dist/data-grid/index.js.map +1 -0
- package/dist/data-grid/messages-en.d.ts +294 -0
- package/dist/data-grid/messages-en.js +279 -0
- package/dist/data-grid/messages-en.js.map +1 -0
- package/dist/data-grid/messages-vi.d.ts +12 -0
- package/dist/data-grid/messages-vi.js +279 -0
- package/dist/data-grid/messages-vi.js.map +1 -0
- package/dist/data-grid/messages.d.ts +567 -0
- package/dist/data-grid/messages.js +20 -0
- package/dist/data-grid/messages.js.map +1 -0
- package/dist/data-grid/sortable.d.ts +50 -0
- package/dist/data-grid/sortable.js +361 -0
- package/dist/data-grid/sortable.js.map +1 -0
- package/dist/data-grid/toast.d.ts +10 -0
- package/dist/data-grid/toast.js +21 -0
- package/dist/data-grid/toast.js.map +1 -0
- package/dist/data-grid/types.d.ts +189 -0
- package/dist/data-grid/types.js +1 -0
- package/dist/data-grid/types.js.map +1 -0
- package/dist/data-grid/use-as-ref.d.ts +5 -0
- package/dist/data-grid/use-as-ref.js +13 -0
- package/dist/data-grid/use-as-ref.js.map +1 -0
- package/dist/data-grid/use-badge-overflow.d.ts +24 -0
- package/dist/data-grid/use-badge-overflow.js +123 -0
- package/dist/data-grid/use-badge-overflow.js.map +1 -0
- package/dist/data-grid/use-callback-ref.d.ts +10 -0
- package/dist/data-grid/use-callback-ref.js +12 -0
- package/dist/data-grid/use-callback-ref.js.map +1 -0
- package/dist/data-grid/use-data-grid-undo-redo.d.ts +45 -0
- package/dist/data-grid/use-data-grid-undo-redo.js +348 -0
- package/dist/data-grid/use-data-grid-undo-redo.js.map +1 -0
- package/dist/data-grid/use-data-grid.d.ts +372 -0
- package/dist/data-grid/use-data-grid.js +2697 -0
- package/dist/data-grid/use-data-grid.js.map +1 -0
- package/dist/data-grid/use-debounced-callback.d.ts +6 -0
- package/dist/data-grid/use-debounced-callback.js +19 -0
- package/dist/data-grid/use-debounced-callback.js.map +1 -0
- package/dist/data-grid/use-isomorphic-layout-effect.d.ts +5 -0
- package/dist/data-grid/use-isomorphic-layout-effect.js +6 -0
- package/dist/data-grid/use-isomorphic-layout-effect.js.map +1 -0
- package/dist/data-grid/use-lazy-ref.d.ts +5 -0
- package/dist/data-grid/use-lazy-ref.js +12 -0
- package/dist/data-grid/use-lazy-ref.js.map +1 -0
- package/dist/data-grid/utils.d.ts +81 -0
- package/dist/data-grid/utils.js +409 -0
- package/dist/data-grid/utils.js.map +1 -0
- package/package.json +33 -15
|
@@ -0,0 +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 { 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"]}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { DataGridLocale } from './messages.js';
|
|
3
|
+
import { DataGridMessages } from './messages-en.js';
|
|
4
|
+
import './messages-vi.js';
|
|
5
|
+
|
|
6
|
+
interface DataGridKeyboardShortcutsProps {
|
|
7
|
+
/** Hiện phím tắt của ô tìm kiếm (bật cùng `enableSearch` của lưới) */
|
|
8
|
+
enableSearch?: boolean;
|
|
9
|
+
enableUndoRedo?: boolean;
|
|
10
|
+
enablePaste?: boolean;
|
|
11
|
+
enableRowAdd?: boolean;
|
|
12
|
+
enableRowsDelete?: boolean;
|
|
13
|
+
/** Ẩn nút mở trên thanh công cụ — vẫn mở được bằng Ctrl+/ */
|
|
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;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
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ụ).
|
|
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.
|
|
27
|
+
*/
|
|
28
|
+
declare const DataGridKeyboardShortcuts: React.MemoExoticComponent<typeof DataGridKeyboardShortcutsImpl>;
|
|
29
|
+
declare function DataGridKeyboardShortcutsImpl({ enableSearch, enableUndoRedo, enablePaste, enableRowAdd, enableRowsDelete, hideTrigger, locale }: DataGridKeyboardShortcutsProps): React.JSX.Element;
|
|
30
|
+
|
|
31
|
+
export { DataGridKeyboardShortcuts };
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useDirection } from "@radix-ui/react-direction";
|
|
4
|
+
import { Keyboard, SearchIcon } from "lucide-react";
|
|
5
|
+
import * as React from "react";
|
|
6
|
+
import { Button } from "../components/ui/button.js";
|
|
7
|
+
import {
|
|
8
|
+
Dialog,
|
|
9
|
+
DialogContent,
|
|
10
|
+
DialogDescription,
|
|
11
|
+
DialogHeader,
|
|
12
|
+
DialogTitle,
|
|
13
|
+
DialogTrigger
|
|
14
|
+
} from "../components/ui/dialog.js";
|
|
15
|
+
import { Input } from "../components/ui/input.js";
|
|
16
|
+
import { Kbd, KbdGroup } from "../components/ui/kbd.js";
|
|
17
|
+
import { Separator } from "../components/ui/separator.js";
|
|
18
|
+
import { useResolvedDataGridMessages } from "./data-grid-locale.js";
|
|
19
|
+
const SHORTCUT_KEY = "/";
|
|
20
|
+
const DataGridKeyboardShortcuts = React.memo(DataGridKeyboardShortcutsImpl, (prev, next) => {
|
|
21
|
+
return prev.enableSearch === next.enableSearch && prev.enableUndoRedo === next.enableUndoRedo && prev.enablePaste === next.enablePaste && prev.enableRowAdd === next.enableRowAdd && prev.enableRowsDelete === next.enableRowsDelete && prev.hideTrigger === next.hideTrigger && prev.locale === next.locale;
|
|
22
|
+
});
|
|
23
|
+
function DataGridKeyboardShortcutsImpl({
|
|
24
|
+
enableSearch = false,
|
|
25
|
+
enableUndoRedo = false,
|
|
26
|
+
enablePaste = false,
|
|
27
|
+
enableRowAdd = false,
|
|
28
|
+
enableRowsDelete = false,
|
|
29
|
+
hideTrigger = false,
|
|
30
|
+
locale
|
|
31
|
+
}) {
|
|
32
|
+
const msg = useResolvedDataGridMessages(locale);
|
|
33
|
+
const dir = useDirection();
|
|
34
|
+
const [open, setOpen] = React.useState(false);
|
|
35
|
+
const [input, setInput] = React.useState("");
|
|
36
|
+
const inputRef = React.useRef(null);
|
|
37
|
+
const isMac = typeof navigator !== "undefined" ? /Mac|iPhone|iPad|iPod/.test(navigator.userAgent) : false;
|
|
38
|
+
const modKey = isMac ? "\u2318" : "Ctrl";
|
|
39
|
+
const altKey = isMac ? "\u2325" : "Alt";
|
|
40
|
+
const onOpenChange = React.useCallback((isOpen) => {
|
|
41
|
+
setOpen(isOpen);
|
|
42
|
+
if (!isOpen) {
|
|
43
|
+
setInput("");
|
|
44
|
+
}
|
|
45
|
+
}, []);
|
|
46
|
+
const onOpenAutoFocus = React.useCallback((event) => {
|
|
47
|
+
event.preventDefault();
|
|
48
|
+
inputRef.current?.focus();
|
|
49
|
+
}, []);
|
|
50
|
+
const onInputChange = React.useCallback((event) => {
|
|
51
|
+
setInput(event.target.value);
|
|
52
|
+
}, []);
|
|
53
|
+
const shortcutGroups = React.useMemo(
|
|
54
|
+
() => [
|
|
55
|
+
{
|
|
56
|
+
title: msg.shortcuts.groups.navigation,
|
|
57
|
+
shortcuts: [
|
|
58
|
+
{ keys: ["\u2191", "\u2193", "\u2190", "\u2192"], description: msg.shortcuts.navigation.move },
|
|
59
|
+
{ keys: ["Tab"], description: msg.shortcuts.navigation.nextCell },
|
|
60
|
+
{ keys: ["Shift", "Tab"], description: msg.shortcuts.navigation.prevCell },
|
|
61
|
+
{ keys: ["Home"], description: msg.shortcuts.navigation.firstColumn },
|
|
62
|
+
{ keys: ["End"], description: msg.shortcuts.navigation.lastColumn },
|
|
63
|
+
{ keys: [modKey, "\u2191"], description: msg.shortcuts.navigation.firstRowSameColumn },
|
|
64
|
+
{ keys: [modKey, "\u2193"], description: msg.shortcuts.navigation.lastRowSameColumn },
|
|
65
|
+
{ keys: [modKey, "\u2190"], description: msg.shortcuts.navigation.firstColumnSameRow },
|
|
66
|
+
{ keys: [modKey, "\u2192"], description: msg.shortcuts.navigation.lastColumnSameRow },
|
|
67
|
+
{ keys: [modKey, "Home"], description: msg.shortcuts.navigation.firstCell },
|
|
68
|
+
{ keys: [modKey, "End"], description: msg.shortcuts.navigation.lastCell },
|
|
69
|
+
{ keys: ["PgUp"], description: msg.shortcuts.navigation.pageUp },
|
|
70
|
+
{ keys: ["PgDn"], description: msg.shortcuts.navigation.pageDown },
|
|
71
|
+
{ keys: [altKey, "\u2191"], description: msg.shortcuts.navigation.scrollUp },
|
|
72
|
+
{ keys: [altKey, "\u2193"], description: msg.shortcuts.navigation.scrollDown },
|
|
73
|
+
{ keys: [altKey, "PgUp"], description: msg.shortcuts.navigation.scrollLeft },
|
|
74
|
+
{ keys: [altKey, "PgDn"], description: msg.shortcuts.navigation.scrollRight }
|
|
75
|
+
]
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
title: msg.shortcuts.groups.selection,
|
|
79
|
+
shortcuts: [
|
|
80
|
+
{ keys: ["Shift", "\u2191\u2193\u2190\u2192"], description: msg.shortcuts.selection.extend },
|
|
81
|
+
{ keys: [modKey, "Shift", "\u2191"], description: msg.shortcuts.selection.toTop },
|
|
82
|
+
{ keys: [modKey, "Shift", "\u2193"], description: msg.shortcuts.selection.toBottom },
|
|
83
|
+
{ keys: [modKey, "Shift", "\u2190"], description: msg.shortcuts.selection.toFirstColumn },
|
|
84
|
+
{ keys: [modKey, "Shift", "\u2192"], description: msg.shortcuts.selection.toLastColumn },
|
|
85
|
+
{ keys: [modKey, "A"], description: msg.shortcuts.selection.all },
|
|
86
|
+
{ keys: [modKey, msg.shortcuts.keys.click], description: msg.shortcuts.selection.toggle },
|
|
87
|
+
{ keys: ["Shift", msg.shortcuts.keys.click], description: msg.shortcuts.selection.range },
|
|
88
|
+
{ keys: ["Esc"], description: msg.shortcuts.selection.clear }
|
|
89
|
+
]
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
title: msg.shortcuts.groups.editing,
|
|
93
|
+
shortcuts: [
|
|
94
|
+
{ keys: ["Enter"], description: msg.shortcuts.editing.start },
|
|
95
|
+
{ keys: ["F2"], description: msg.shortcuts.editing.start },
|
|
96
|
+
{ keys: [msg.shortcuts.keys.doubleClick], description: msg.shortcuts.editing.start },
|
|
97
|
+
...enableRowAdd ? [{ keys: ["Shift", "Enter"], description: msg.shortcuts.editing.insertRow }] : [],
|
|
98
|
+
{ keys: [modKey, "C"], description: msg.shortcuts.editing.copy },
|
|
99
|
+
{ keys: [modKey, "X"], description: msg.shortcuts.editing.cut },
|
|
100
|
+
...enablePaste ? [{ keys: [modKey, "V"], description: msg.shortcuts.editing.paste }] : [],
|
|
101
|
+
{ keys: ["Delete"], description: msg.shortcuts.editing.clear },
|
|
102
|
+
{ keys: ["Backspace"], description: msg.shortcuts.editing.clear },
|
|
103
|
+
...enableRowsDelete ? [
|
|
104
|
+
{ keys: [modKey, "Backspace"], description: msg.shortcuts.editing.deleteRows },
|
|
105
|
+
{ keys: [modKey, "Delete"], description: msg.shortcuts.editing.deleteRows }
|
|
106
|
+
] : [],
|
|
107
|
+
...enableUndoRedo ? [
|
|
108
|
+
{ keys: [modKey, "Z"], description: msg.shortcuts.editing.undo },
|
|
109
|
+
{ keys: [modKey, "Shift", "Z"], description: msg.shortcuts.editing.redo }
|
|
110
|
+
] : []
|
|
111
|
+
]
|
|
112
|
+
},
|
|
113
|
+
...enableSearch ? [
|
|
114
|
+
{
|
|
115
|
+
title: msg.shortcuts.groups.search,
|
|
116
|
+
shortcuts: [
|
|
117
|
+
{ keys: [modKey, "F"], description: msg.shortcuts.search.open },
|
|
118
|
+
{ keys: ["Enter"], description: msg.shortcuts.search.next },
|
|
119
|
+
{ keys: ["Shift", "Enter"], description: msg.shortcuts.search.prev },
|
|
120
|
+
{ keys: ["Esc"], description: msg.shortcuts.search.close }
|
|
121
|
+
]
|
|
122
|
+
}
|
|
123
|
+
] : [],
|
|
124
|
+
{
|
|
125
|
+
title: msg.shortcuts.groups.filtering,
|
|
126
|
+
shortcuts: [
|
|
127
|
+
{ keys: [modKey, "Shift", "F"], description: msg.shortcuts.filtering.toggle },
|
|
128
|
+
{ keys: ["Backspace"], description: msg.shortcuts.filtering.remove },
|
|
129
|
+
{ keys: ["Delete"], description: msg.shortcuts.filtering.remove }
|
|
130
|
+
]
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
title: msg.shortcuts.groups.sorting,
|
|
134
|
+
shortcuts: [
|
|
135
|
+
{ keys: [modKey, "Shift", "S"], description: msg.shortcuts.sorting.toggle },
|
|
136
|
+
{ keys: ["Backspace"], description: msg.shortcuts.sorting.remove },
|
|
137
|
+
{ keys: ["Delete"], description: msg.shortcuts.sorting.remove }
|
|
138
|
+
]
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
title: msg.shortcuts.groups.general,
|
|
142
|
+
shortcuts: [{ keys: [modKey, "/"], description: msg.shortcuts.general.shortcuts }]
|
|
143
|
+
}
|
|
144
|
+
],
|
|
145
|
+
[msg, modKey, altKey, enableSearch, enableUndoRedo, enablePaste, enableRowAdd, enableRowsDelete]
|
|
146
|
+
);
|
|
147
|
+
const filteredGroups = React.useMemo(() => {
|
|
148
|
+
if (!input.trim()) return shortcutGroups;
|
|
149
|
+
const query = input.toLowerCase();
|
|
150
|
+
return shortcutGroups.map((group) => ({
|
|
151
|
+
...group,
|
|
152
|
+
shortcuts: group.shortcuts.filter(
|
|
153
|
+
(shortcut) => shortcut.description.toLowerCase().includes(query) || shortcut.keys.some((key) => key.toLowerCase().includes(query))
|
|
154
|
+
)
|
|
155
|
+
})).filter((group) => group.shortcuts.length > 0);
|
|
156
|
+
}, [shortcutGroups, input]);
|
|
157
|
+
React.useEffect(() => {
|
|
158
|
+
function onKeyDown(event) {
|
|
159
|
+
if ((event.ctrlKey || event.metaKey) && event.key === SHORTCUT_KEY) {
|
|
160
|
+
event.preventDefault();
|
|
161
|
+
setOpen(true);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
window.addEventListener("keydown", onKeyDown);
|
|
165
|
+
return () => {
|
|
166
|
+
window.removeEventListener("keydown", onKeyDown);
|
|
167
|
+
};
|
|
168
|
+
}, []);
|
|
169
|
+
return /* @__PURE__ */ jsxs(Dialog, { open, onOpenChange, children: [
|
|
170
|
+
!hideTrigger && /* @__PURE__ */ jsx(DialogTrigger, { asChild: true, children: /* @__PURE__ */ jsx(Button, { "aria-label": msg.shortcuts.trigger, variant: "outline", size: "icon-sm", children: /* @__PURE__ */ jsx(Keyboard, { "aria-hidden": "true", className: "size-3.5 text-muted-foreground" }) }) }),
|
|
171
|
+
/* @__PURE__ */ jsxs(DialogContent, { dir, className: "max-w-2xl px-0", onOpenAutoFocus, children: [
|
|
172
|
+
/* @__PURE__ */ jsxs(DialogHeader, { className: "px-6", children: [
|
|
173
|
+
/* @__PURE__ */ jsx(DialogTitle, { children: msg.shortcuts.title }),
|
|
174
|
+
/* @__PURE__ */ jsx(DialogDescription, { className: "sr-only", children: msg.shortcuts.description })
|
|
175
|
+
] }),
|
|
176
|
+
/* @__PURE__ */ jsx("div", { className: "px-6", children: /* @__PURE__ */ jsxs("div", { className: "relative", children: [
|
|
177
|
+
/* @__PURE__ */ jsx(
|
|
178
|
+
SearchIcon,
|
|
179
|
+
{
|
|
180
|
+
"aria-hidden": "true",
|
|
181
|
+
className: "absolute start-3 top-1/2 size-3.5 -translate-y-1/2 text-muted-foreground"
|
|
182
|
+
}
|
|
183
|
+
),
|
|
184
|
+
/* @__PURE__ */ jsx(
|
|
185
|
+
Input,
|
|
186
|
+
{
|
|
187
|
+
ref: inputRef,
|
|
188
|
+
placeholder: msg.shortcuts.searchPlaceholder,
|
|
189
|
+
"aria-label": msg.shortcuts.searchPlaceholder,
|
|
190
|
+
className: "h-8 ps-8",
|
|
191
|
+
value: input,
|
|
192
|
+
onChange: onInputChange
|
|
193
|
+
}
|
|
194
|
+
)
|
|
195
|
+
] }) }),
|
|
196
|
+
/* @__PURE__ */ jsx(Separator, { className: "mx-auto w-[calc(100%-3rem)]" }),
|
|
197
|
+
/* @__PURE__ */ jsx("div", { className: "h-[40vh] overflow-y-auto px-6", children: filteredGroups.length === 0 ? /* @__PURE__ */ jsxs("div", { className: "flex h-full flex-col items-center justify-center gap-3 text-center", children: [
|
|
198
|
+
/* @__PURE__ */ jsx("div", { className: "flex size-10 shrink-0 items-center justify-center rounded-lg bg-muted text-foreground", children: /* @__PURE__ */ jsx(SearchIcon, { "aria-hidden": "true", className: "pointer-events-none size-6" }) }),
|
|
199
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
200
|
+
/* @__PURE__ */ jsx("div", { className: "font-medium text-lg tracking-tight", children: msg.shortcuts.emptyTitle }),
|
|
201
|
+
/* @__PURE__ */ jsx("p", { className: "text-muted-foreground text-sm", children: msg.shortcuts.emptyDescription })
|
|
202
|
+
] })
|
|
203
|
+
] }) : /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-6", children: filteredGroups.map((shortcutGroup) => /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
|
|
204
|
+
/* @__PURE__ */ jsx("h3", { className: "font-semibold text-foreground text-sm", children: shortcutGroup.title }),
|
|
205
|
+
/* @__PURE__ */ jsx("div", { className: "divide-y divide-border rounded-md border", children: shortcutGroup.shortcuts.map((shortcut) => /* @__PURE__ */ jsx(
|
|
206
|
+
ShortcutCard,
|
|
207
|
+
{
|
|
208
|
+
keys: shortcut.keys,
|
|
209
|
+
description: shortcut.description
|
|
210
|
+
},
|
|
211
|
+
`${shortcut.description}-${shortcut.keys.join("+")}`
|
|
212
|
+
)) })
|
|
213
|
+
] }, shortcutGroup.title)) }) })
|
|
214
|
+
] })
|
|
215
|
+
] });
|
|
216
|
+
}
|
|
217
|
+
function ShortcutCard({ keys, description }) {
|
|
218
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-4 px-3 py-2", children: [
|
|
219
|
+
/* @__PURE__ */ jsx("span", { className: "flex-1 text-sm", children: description }),
|
|
220
|
+
/* @__PURE__ */ jsx(KbdGroup, { className: "shrink-0", children: keys.map((key, index) => /* @__PURE__ */ jsxs(React.Fragment, { children: [
|
|
221
|
+
index > 0 && /* @__PURE__ */ jsx("span", { className: "text-muted-foreground text-xs", children: "+" }),
|
|
222
|
+
/* @__PURE__ */ jsx(Kbd, { children: key })
|
|
223
|
+
] }, key)) })
|
|
224
|
+
] });
|
|
225
|
+
}
|
|
226
|
+
export {
|
|
227
|
+
DataGridKeyboardShortcuts
|
|
228
|
+
};
|
|
229
|
+
//# sourceMappingURL=data-grid-keyboard-shortcuts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/data-grid/data-grid-keyboard-shortcuts.tsx"],"sourcesContent":["\"use client\";\n\nimport { useDirection } from \"@radix-ui/react-direction\";\nimport { Keyboard, SearchIcon } from \"lucide-react\";\nimport * as React from \"react\";\nimport { Button } from \"../components/ui/button.js\";\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogHeader,\n DialogTitle,\n DialogTrigger\n} from \"../components/ui/dialog.js\";\nimport { Input } from \"../components/ui/input.js\";\nimport { Kbd, KbdGroup } from \"../components/ui/kbd.js\";\nimport { Separator } from \"../components/ui/separator.js\";\nimport { useResolvedDataGridMessages } from \"./data-grid-locale.js\";\nimport type { DataGridLocale, DataGridMessages } from \"./messages.js\";\n\nconst SHORTCUT_KEY = \"/\";\n\ninterface ShortcutGroup {\n title: string;\n shortcuts: Array<{\n keys: string[];\n description: string;\n }>;\n}\n\ninterface DataGridKeyboardShortcutsProps {\n /** Hiện phím tắt của ô tìm kiếm (bật cùng `enableSearch` của lưới) */\n enableSearch?: boolean;\n enableUndoRedo?: boolean;\n enablePaste?: boolean;\n enableRowAdd?: boolean;\n enableRowsDelete?: boolean;\n /** Ẩn nút mở trên thanh công cụ — vẫn mở được bằng Ctrl+/ */\n hideTrigger?: boolean;\n /**\n * Ngôn ngữ của menu: `\"en\"` (mặc định) · `\"vi\"`, hoặc cả một bảng chuỗi tự soạn.\n *\n * ⚠ Thanh công cụ nằm NGOÀI `<DataGrid>`, nên `locale` truyền cho lưới không với tới đây. Bọc\n * cả màn bằng `DataGridLocaleProvider` (một lần, đúng cho mọi mảnh), hoặc truyền prop này cho\n * từng menu. Prop thắng provider.\n */\n locale?: DataGridLocale | DataGridMessages;\n}\n\n/**\n * Hộp thoại liệt kê phím tắt của lưới (mở bằng Ctrl/⌘ + `/`, hoặc nút trên thanh công cụ).\n * Danh sách hiển thị theo đúng những tính năng đang bật, nên truyền các cờ giống lưới.\n */\nexport const DataGridKeyboardShortcuts = React.memo(DataGridKeyboardShortcutsImpl, (prev, next) => {\n return (\n prev.enableSearch === next.enableSearch &&\n prev.enableUndoRedo === next.enableUndoRedo &&\n prev.enablePaste === next.enablePaste &&\n prev.enableRowAdd === next.enableRowAdd &&\n prev.enableRowsDelete === next.enableRowsDelete &&\n prev.hideTrigger === next.hideTrigger &&\n prev.locale === next.locale\n );\n});\n\nfunction DataGridKeyboardShortcutsImpl({\n enableSearch = false,\n enableUndoRedo = false,\n enablePaste = false,\n enableRowAdd = false,\n enableRowsDelete = false,\n hideTrigger = false,\n locale\n}: DataGridKeyboardShortcutsProps) {\n const msg = useResolvedDataGridMessages(locale);\n const dir = useDirection();\n const [open, setOpen] = React.useState(false);\n const [input, setInput] = React.useState(\"\");\n const inputRef = React.useRef<HTMLInputElement>(null);\n\n const isMac = typeof navigator !== \"undefined\" ? /Mac|iPhone|iPad|iPod/.test(navigator.userAgent) : false;\n\n const modKey = isMac ? \"⌘\" : \"Ctrl\";\n const altKey = isMac ? \"⌥\" : \"Alt\";\n\n const onOpenChange = React.useCallback((isOpen: boolean) => {\n setOpen(isOpen);\n if (!isOpen) {\n setInput(\"\");\n }\n }, []);\n\n const onOpenAutoFocus = React.useCallback((event: Event) => {\n event.preventDefault();\n inputRef.current?.focus();\n }, []);\n\n const onInputChange = React.useCallback((event: React.ChangeEvent<HTMLInputElement>) => {\n setInput(event.target.value);\n }, []);\n\n const shortcutGroups: ShortcutGroup[] = React.useMemo(\n () => [\n {\n title: msg.shortcuts.groups.navigation,\n shortcuts: [\n { keys: [\"↑\", \"↓\", \"←\", \"→\"], description: msg.shortcuts.navigation.move },\n { keys: [\"Tab\"], description: msg.shortcuts.navigation.nextCell },\n { keys: [\"Shift\", \"Tab\"], description: msg.shortcuts.navigation.prevCell },\n { keys: [\"Home\"], description: msg.shortcuts.navigation.firstColumn },\n { keys: [\"End\"], description: msg.shortcuts.navigation.lastColumn },\n { keys: [modKey, \"↑\"], description: msg.shortcuts.navigation.firstRowSameColumn },\n { keys: [modKey, \"↓\"], description: msg.shortcuts.navigation.lastRowSameColumn },\n { keys: [modKey, \"←\"], description: msg.shortcuts.navigation.firstColumnSameRow },\n { keys: [modKey, \"→\"], description: msg.shortcuts.navigation.lastColumnSameRow },\n { keys: [modKey, \"Home\"], description: msg.shortcuts.navigation.firstCell },\n { keys: [modKey, \"End\"], description: msg.shortcuts.navigation.lastCell },\n { keys: [\"PgUp\"], description: msg.shortcuts.navigation.pageUp },\n { keys: [\"PgDn\"], description: msg.shortcuts.navigation.pageDown },\n { keys: [altKey, \"↑\"], description: msg.shortcuts.navigation.scrollUp },\n { keys: [altKey, \"↓\"], description: msg.shortcuts.navigation.scrollDown },\n { keys: [altKey, \"PgUp\"], description: msg.shortcuts.navigation.scrollLeft },\n { keys: [altKey, \"PgDn\"], description: msg.shortcuts.navigation.scrollRight }\n ]\n },\n {\n title: msg.shortcuts.groups.selection,\n shortcuts: [\n { keys: [\"Shift\", \"↑↓←→\"], description: msg.shortcuts.selection.extend },\n { keys: [modKey, \"Shift\", \"↑\"], description: msg.shortcuts.selection.toTop },\n { keys: [modKey, \"Shift\", \"↓\"], description: msg.shortcuts.selection.toBottom },\n { keys: [modKey, \"Shift\", \"←\"], description: msg.shortcuts.selection.toFirstColumn },\n { keys: [modKey, \"Shift\", \"→\"], description: msg.shortcuts.selection.toLastColumn },\n { keys: [modKey, \"A\"], description: msg.shortcuts.selection.all },\n { keys: [modKey, msg.shortcuts.keys.click], description: msg.shortcuts.selection.toggle },\n { keys: [\"Shift\", msg.shortcuts.keys.click], description: msg.shortcuts.selection.range },\n { keys: [\"Esc\"], description: msg.shortcuts.selection.clear }\n ]\n },\n {\n title: msg.shortcuts.groups.editing,\n shortcuts: [\n { keys: [\"Enter\"], description: msg.shortcuts.editing.start },\n { keys: [\"F2\"], description: msg.shortcuts.editing.start },\n { keys: [msg.shortcuts.keys.doubleClick], description: msg.shortcuts.editing.start },\n ...(enableRowAdd ? [{ keys: [\"Shift\", \"Enter\"], description: msg.shortcuts.editing.insertRow }] : []),\n { keys: [modKey, \"C\"], description: msg.shortcuts.editing.copy },\n { keys: [modKey, \"X\"], description: msg.shortcuts.editing.cut },\n ...(enablePaste ? [{ keys: [modKey, \"V\"], description: msg.shortcuts.editing.paste }] : []),\n { keys: [\"Delete\"], description: msg.shortcuts.editing.clear },\n { keys: [\"Backspace\"], description: msg.shortcuts.editing.clear },\n ...(enableRowsDelete\n ? [\n { keys: [modKey, \"Backspace\"], description: msg.shortcuts.editing.deleteRows },\n { keys: [modKey, \"Delete\"], description: msg.shortcuts.editing.deleteRows }\n ]\n : []),\n ...(enableUndoRedo\n ? [\n { keys: [modKey, \"Z\"], description: msg.shortcuts.editing.undo },\n { keys: [modKey, \"Shift\", \"Z\"], description: msg.shortcuts.editing.redo }\n ]\n : [])\n ]\n },\n ...(enableSearch\n ? [\n {\n title: msg.shortcuts.groups.search,\n shortcuts: [\n { keys: [modKey, \"F\"], description: msg.shortcuts.search.open },\n { keys: [\"Enter\"], description: msg.shortcuts.search.next },\n { keys: [\"Shift\", \"Enter\"], description: msg.shortcuts.search.prev },\n { keys: [\"Esc\"], description: msg.shortcuts.search.close }\n ]\n }\n ]\n : []),\n {\n title: msg.shortcuts.groups.filtering,\n shortcuts: [\n { keys: [modKey, \"Shift\", \"F\"], description: msg.shortcuts.filtering.toggle },\n { keys: [\"Backspace\"], description: msg.shortcuts.filtering.remove },\n { keys: [\"Delete\"], description: msg.shortcuts.filtering.remove }\n ]\n },\n {\n title: msg.shortcuts.groups.sorting,\n shortcuts: [\n { keys: [modKey, \"Shift\", \"S\"], description: msg.shortcuts.sorting.toggle },\n { keys: [\"Backspace\"], description: msg.shortcuts.sorting.remove },\n { keys: [\"Delete\"], description: msg.shortcuts.sorting.remove }\n ]\n },\n {\n title: msg.shortcuts.groups.general,\n shortcuts: [{ keys: [modKey, \"/\"], description: msg.shortcuts.general.shortcuts }]\n }\n ],\n [msg, modKey, altKey, enableSearch, enableUndoRedo, enablePaste, enableRowAdd, enableRowsDelete]\n );\n\n const filteredGroups = React.useMemo(() => {\n if (!input.trim()) return shortcutGroups;\n\n const query = input.toLowerCase();\n return shortcutGroups\n .map((group) => ({\n ...group,\n shortcuts: group.shortcuts.filter(\n (shortcut) =>\n shortcut.description.toLowerCase().includes(query) ||\n shortcut.keys.some((key) => key.toLowerCase().includes(query))\n )\n }))\n .filter((group) => group.shortcuts.length > 0);\n }, [shortcutGroups, input]);\n\n React.useEffect(() => {\n function onKeyDown(event: KeyboardEvent) {\n if ((event.ctrlKey || event.metaKey) && event.key === SHORTCUT_KEY) {\n event.preventDefault();\n setOpen(true);\n }\n }\n\n window.addEventListener(\"keydown\", onKeyDown);\n return () => {\n window.removeEventListener(\"keydown\", onKeyDown);\n };\n }, []);\n\n return (\n <Dialog open={open} onOpenChange={onOpenChange}>\n {!hideTrigger && (\n <DialogTrigger asChild>\n <Button aria-label={msg.shortcuts.trigger} variant=\"outline\" size=\"icon-sm\">\n <Keyboard aria-hidden=\"true\" className=\"size-3.5 text-muted-foreground\" />\n </Button>\n </DialogTrigger>\n )}\n <DialogContent dir={dir} className=\"max-w-2xl px-0\" onOpenAutoFocus={onOpenAutoFocus}>\n <DialogHeader className=\"px-6\">\n <DialogTitle>{msg.shortcuts.title}</DialogTitle>\n <DialogDescription className=\"sr-only\">{msg.shortcuts.description}</DialogDescription>\n </DialogHeader>\n <div className=\"px-6\">\n <div className=\"relative\">\n <SearchIcon\n aria-hidden=\"true\"\n className=\"absolute start-3 top-1/2 size-3.5 -translate-y-1/2 text-muted-foreground\"\n />\n <Input\n ref={inputRef}\n placeholder={msg.shortcuts.searchPlaceholder}\n aria-label={msg.shortcuts.searchPlaceholder}\n className=\"h-8 ps-8\"\n value={input}\n onChange={onInputChange}\n />\n </div>\n </div>\n <Separator className=\"mx-auto w-[calc(100%-3rem)]\" />\n <div className=\"h-[40vh] overflow-y-auto px-6\">\n {filteredGroups.length === 0 ? (\n <div className=\"flex h-full flex-col items-center justify-center gap-3 text-center\">\n <div className=\"flex size-10 shrink-0 items-center justify-center rounded-lg bg-muted text-foreground\">\n <SearchIcon aria-hidden=\"true\" className=\"pointer-events-none size-6\" />\n </div>\n <div className=\"flex flex-col gap-1\">\n <div className=\"font-medium text-lg tracking-tight\">{msg.shortcuts.emptyTitle}</div>\n <p className=\"text-muted-foreground text-sm\">{msg.shortcuts.emptyDescription}</p>\n </div>\n </div>\n ) : (\n <div className=\"flex flex-col gap-6\">\n {filteredGroups.map((shortcutGroup) => (\n <div key={shortcutGroup.title} className=\"flex flex-col gap-2\">\n <h3 className=\"font-semibold text-foreground text-sm\">{shortcutGroup.title}</h3>\n <div className=\"divide-y divide-border rounded-md border\">\n {shortcutGroup.shortcuts.map((shortcut) => (\n <ShortcutCard\n key={`${shortcut.description}-${shortcut.keys.join(\"+\")}`}\n keys={shortcut.keys}\n description={shortcut.description}\n />\n ))}\n </div>\n </div>\n ))}\n </div>\n )}\n </div>\n </DialogContent>\n </Dialog>\n );\n}\n\nfunction ShortcutCard({ keys, description }: ShortcutGroup[\"shortcuts\"][number]) {\n return (\n <div className=\"flex items-center gap-4 px-3 py-2\">\n <span className=\"flex-1 text-sm\">{description}</span>\n <KbdGroup className=\"shrink-0\">\n {keys.map((key, index) => (\n <React.Fragment key={key}>\n {index > 0 && <span className=\"text-muted-foreground text-xs\">+</span>}\n <Kbd>{key}</Kbd>\n </React.Fragment>\n ))}\n </KbdGroup>\n </div>\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { DataGridLocale } from './messages.js';
|
|
3
|
+
import { DataGridMessages } from './messages-en.js';
|
|
4
|
+
import './messages-vi.js';
|
|
5
|
+
|
|
6
|
+
interface DataGridLocaleProviderProps {
|
|
7
|
+
/** Mã ngôn ngữ (`"en"` · `"vi"`) hoặc cả một bảng chuỗi tự soạn. */
|
|
8
|
+
locale?: DataGridLocale | DataGridMessages;
|
|
9
|
+
children: React.ReactNode;
|
|
10
|
+
}
|
|
11
|
+
declare function DataGridLocaleProvider({ locale, children }: DataGridLocaleProviderProps): React.JSX.Element;
|
|
12
|
+
/**
|
|
13
|
+
* Bảng chuỗi đang có hiệu lực. KHÔNG ném lỗi khi thiếu provider — lưới phải dùng được ở dạng
|
|
14
|
+
* trần (`<DataGrid>` một mình, không bọc gì), và khi ấy mặc định tiếng Anh là câu trả lời đúng.
|
|
15
|
+
*/
|
|
16
|
+
declare function useDataGridMessages(): DataGridMessages;
|
|
17
|
+
/**
|
|
18
|
+
* Dành cho component nhận prop `locale` của riêng nó: prop thắng, không có prop thì theo provider.
|
|
19
|
+
* Tách ra thành hook riêng để năm component thanh công cụ không mỗi cái viết lại luật ưu tiên một
|
|
20
|
+
* kiểu.
|
|
21
|
+
*/
|
|
22
|
+
declare function useResolvedDataGridMessages(locale?: DataGridLocale | DataGridMessages): DataGridMessages;
|
|
23
|
+
|
|
24
|
+
export { DataGridLocaleProvider, type DataGridLocaleProviderProps, useDataGridMessages, useResolvedDataGridMessages };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { getDataGridMessages } from "./messages.js";
|
|
5
|
+
const DataGridLocaleContext = React.createContext(null);
|
|
6
|
+
function DataGridLocaleProvider({ locale, children }) {
|
|
7
|
+
const messages = React.useMemo(() => getDataGridMessages(locale), [locale]);
|
|
8
|
+
return /* @__PURE__ */ jsx(DataGridLocaleContext.Provider, { value: messages, children });
|
|
9
|
+
}
|
|
10
|
+
function useDataGridMessages() {
|
|
11
|
+
return React.useContext(DataGridLocaleContext) ?? getDataGridMessages();
|
|
12
|
+
}
|
|
13
|
+
function useResolvedDataGridMessages(locale) {
|
|
14
|
+
const fromContext = React.useContext(DataGridLocaleContext);
|
|
15
|
+
return React.useMemo(() => {
|
|
16
|
+
if (locale) return getDataGridMessages(locale);
|
|
17
|
+
return fromContext ?? getDataGridMessages();
|
|
18
|
+
}, [locale, fromContext]);
|
|
19
|
+
}
|
|
20
|
+
export {
|
|
21
|
+
DataGridLocaleProvider,
|
|
22
|
+
useDataGridMessages,
|
|
23
|
+
useResolvedDataGridMessages
|
|
24
|
+
};
|
|
25
|
+
//# sourceMappingURL=data-grid-locale.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/data-grid/data-grid-locale.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\nimport { type DataGridLocale, type DataGridMessages, getDataGridMessages } from \"./messages.js\";\n\n/**\n * Ngôn ngữ của DataGrid, đi xuống cây bằng context.\n *\n * ─ VÌ SAO CẦN PROVIDER CHỨ KHÔNG CHỈ MỘT PROP ─\n * Thanh công cụ (`DataGridFilterMenu`, `DataGridSortMenu`, `DataGridViewMenu`,\n * `DataGridRowHeightMenu`, `DataGridKeyboardShortcuts`) nằm NGOÀI `<DataGrid>` — app tự đặt chúng\n * ở đâu tuỳ ý. Vậy nên một prop trên `<DataGrid>` không với tới chúng được, và bắt mỗi cái tự\n * nhận `locale` thì năm chỗ phải nhớ truyền, quên một chỗ là màn hình lẫn hai thứ tiếng.\n *\n * Nên có HAI đường, và thứ tự ưu tiên là: prop `locale` của chính component → provider gần nhất →\n * mặc định `\"en\"`. App bọc một lần quanh cả màn là xong; chỗ nào cần khác thì đè bằng prop.\n *\n * `useDataGrid({ locale })` cũng nhận cùng giá trị ấy, vì hook bắn toast và toast không có cây DOM\n * nào để đọc context — nó phải giữ bảng chuỗi của riêng nó.\n */\n\nconst DataGridLocaleContext = React.createContext<DataGridMessages | null>(null);\n\nexport interface DataGridLocaleProviderProps {\n /** Mã ngôn ngữ (`\"en\"` · `\"vi\"`) hoặc cả một bảng chuỗi tự soạn. */\n locale?: DataGridLocale | DataGridMessages;\n children: React.ReactNode;\n}\n\nexport function DataGridLocaleProvider({ locale, children }: DataGridLocaleProviderProps) {\n const messages = React.useMemo(() => getDataGridMessages(locale), [locale]);\n return <DataGridLocaleContext.Provider value={messages}>{children}</DataGridLocaleContext.Provider>;\n}\n\n/**\n * Bảng chuỗi đang có hiệu lực. KHÔNG ném lỗi khi thiếu provider — lưới phải dùng được ở dạng\n * trần (`<DataGrid>` một mình, không bọc gì), và khi ấy mặc định tiếng Anh là câu trả lời đúng.\n */\nexport function useDataGridMessages(): DataGridMessages {\n return React.useContext(DataGridLocaleContext) ?? getDataGridMessages();\n}\n\n/**\n * Dành cho component nhận prop `locale` của riêng nó: prop thắng, không có prop thì theo provider.\n * Tách ra thành hook riêng để năm component thanh công cụ không mỗi cái viết lại luật ưu tiên một\n * kiểu.\n */\nexport function useResolvedDataGridMessages(locale?: DataGridLocale | DataGridMessages): DataGridMessages {\n const fromContext = React.useContext(DataGridLocaleContext);\n return React.useMemo(() => {\n if (locale) return getDataGridMessages(locale);\n return fromContext ?? getDataGridMessages();\n }, [locale, fromContext]);\n}\n"],"mappings":";AA+BS;AA7BT,YAAY,WAAW;AACvB,SAAqD,2BAA2B;AAkBhF,MAAM,wBAAwB,MAAM,cAAuC,IAAI;AAQxE,SAAS,uBAAuB,EAAE,QAAQ,SAAS,GAAgC;AACxF,QAAM,WAAW,MAAM,QAAQ,MAAM,oBAAoB,MAAM,GAAG,CAAC,MAAM,CAAC;AAC1E,SAAO,oBAAC,sBAAsB,UAAtB,EAA+B,OAAO,UAAW,UAAS;AACpE;AAMO,SAAS,sBAAwC;AACtD,SAAO,MAAM,WAAW,qBAAqB,KAAK,oBAAoB;AACxE;AAOO,SAAS,4BAA4B,QAA8D;AACxG,QAAM,cAAc,MAAM,WAAW,qBAAqB;AAC1D,SAAO,MAAM,QAAQ,MAAM;AACzB,QAAI,OAAQ,QAAO,oBAAoB,MAAM;AAC7C,WAAO,eAAe,oBAAoB;AAAA,EAC5C,GAAG,CAAC,QAAQ,WAAW,CAAC;AAC1B;","names":[]}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { TableMeta } from '@tanstack/react-table';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
import { PasteDialogState } from './types.js';
|
|
4
|
+
|
|
5
|
+
interface DataGridPasteDialogProps<TData> {
|
|
6
|
+
tableMeta: TableMeta<TData>;
|
|
7
|
+
pasteDialog: PasteDialogState;
|
|
8
|
+
}
|
|
9
|
+
declare function DataGridPasteDialog<TData>({ tableMeta, pasteDialog }: DataGridPasteDialogProps<TData>): React.JSX.Element | null;
|
|
10
|
+
|
|
11
|
+
export { DataGridPasteDialog };
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { Button } from "../components/ui/button.js";
|
|
5
|
+
import {
|
|
6
|
+
Dialog,
|
|
7
|
+
DialogContent,
|
|
8
|
+
DialogDescription,
|
|
9
|
+
DialogFooter,
|
|
10
|
+
DialogHeader,
|
|
11
|
+
DialogTitle
|
|
12
|
+
} from "../components/ui/dialog.js";
|
|
13
|
+
import { cn } from "../lib/cn.js";
|
|
14
|
+
import { useDataGridMessages } from "./data-grid-locale.js";
|
|
15
|
+
import { useAsRef } from "./use-as-ref.js";
|
|
16
|
+
function DataGridPasteDialog({ tableMeta, pasteDialog }) {
|
|
17
|
+
const onPasteDialogOpenChange = tableMeta?.onPasteDialogOpenChange;
|
|
18
|
+
const onCellsPaste = tableMeta?.onCellsPaste;
|
|
19
|
+
if (!pasteDialog.open) return null;
|
|
20
|
+
return /* @__PURE__ */ jsx(
|
|
21
|
+
PasteDialog,
|
|
22
|
+
{
|
|
23
|
+
pasteDialog,
|
|
24
|
+
onPasteDialogOpenChange,
|
|
25
|
+
onCellsPaste
|
|
26
|
+
}
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
const PasteDialog = React.memo(PasteDialogImpl, (prev, next) => {
|
|
30
|
+
if (prev.pasteDialog.open !== next.pasteDialog.open) return false;
|
|
31
|
+
if (!next.pasteDialog.open) return true;
|
|
32
|
+
if (prev.pasteDialog.rowsNeeded !== next.pasteDialog.rowsNeeded) return false;
|
|
33
|
+
return true;
|
|
34
|
+
});
|
|
35
|
+
function PasteDialogImpl({ pasteDialog, onPasteDialogOpenChange, onCellsPaste }) {
|
|
36
|
+
const msg = useDataGridMessages();
|
|
37
|
+
const propsRef = useAsRef({
|
|
38
|
+
onPasteDialogOpenChange,
|
|
39
|
+
onCellsPaste
|
|
40
|
+
});
|
|
41
|
+
const expandRadioRef = React.useRef(null);
|
|
42
|
+
const onOpenChange = React.useCallback(
|
|
43
|
+
(open) => {
|
|
44
|
+
propsRef.current.onPasteDialogOpenChange?.(open);
|
|
45
|
+
},
|
|
46
|
+
[propsRef]
|
|
47
|
+
);
|
|
48
|
+
const onCancel = React.useCallback(() => {
|
|
49
|
+
propsRef.current.onPasteDialogOpenChange?.(false);
|
|
50
|
+
}, [propsRef]);
|
|
51
|
+
const onContinue = React.useCallback(() => {
|
|
52
|
+
propsRef.current.onCellsPaste?.(expandRadioRef.current?.checked ?? false);
|
|
53
|
+
}, [propsRef]);
|
|
54
|
+
return /* @__PURE__ */ jsx(Dialog, { open: pasteDialog.open, onOpenChange, children: /* @__PURE__ */ jsxs(DialogContent, { "data-grid-popover": "", children: [
|
|
55
|
+
/* @__PURE__ */ jsxs(DialogHeader, { children: [
|
|
56
|
+
/* @__PURE__ */ jsx(DialogTitle, { children: msg.pasteDialog.title }),
|
|
57
|
+
/* @__PURE__ */ jsx(DialogDescription, { children: msg.pasteDialog.description(pasteDialog.rowsNeeded) })
|
|
58
|
+
] }),
|
|
59
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3 py-1", children: [
|
|
60
|
+
/* @__PURE__ */ jsxs("label", { className: "flex cursor-pointer items-start gap-3", children: [
|
|
61
|
+
/* @__PURE__ */ jsx(RadioItem, { ref: expandRadioRef, name: "expand-option", value: "expand", defaultChecked: true }),
|
|
62
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
63
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium text-sm leading-none", children: msg.pasteDialog.expandTitle }),
|
|
64
|
+
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground text-sm", children: msg.pasteDialog.expandDescription(pasteDialog.rowsNeeded) })
|
|
65
|
+
] })
|
|
66
|
+
] }),
|
|
67
|
+
/* @__PURE__ */ jsxs("label", { className: "flex cursor-pointer items-start gap-3", children: [
|
|
68
|
+
/* @__PURE__ */ jsx(RadioItem, { name: "expand-option", value: "no-expand" }),
|
|
69
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
70
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium text-sm leading-none", children: msg.pasteDialog.keepTitle }),
|
|
71
|
+
/* @__PURE__ */ jsx("span", { className: "text-muted-foreground text-sm", children: msg.pasteDialog.keepDescription })
|
|
72
|
+
] })
|
|
73
|
+
] })
|
|
74
|
+
] }),
|
|
75
|
+
/* @__PURE__ */ jsxs(DialogFooter, { className: "gap-2", children: [
|
|
76
|
+
/* @__PURE__ */ jsx(Button, { variant: "outline", onClick: onCancel, children: msg.pasteDialog.cancel }),
|
|
77
|
+
/* @__PURE__ */ jsx(Button, { onClick: onContinue, children: msg.pasteDialog.confirm })
|
|
78
|
+
] })
|
|
79
|
+
] }) });
|
|
80
|
+
}
|
|
81
|
+
function RadioItem({ className, ...props }) {
|
|
82
|
+
return /* @__PURE__ */ jsx(
|
|
83
|
+
"input",
|
|
84
|
+
{
|
|
85
|
+
type: "radio",
|
|
86
|
+
className: cn(
|
|
87
|
+
// Cùng bộ token với `RadioGroupItem` của gói (`--choice-edge` cho viền nghỉ,
|
|
88
|
+
// `--control-on` cho viền + chấm khi chọn) — đừng quay lại `--primary`/`--ring`: đó là
|
|
89
|
+
// bậc tô NỀN, đem vẽ NÉT thì ở light chỉ 1,73:1.
|
|
90
|
+
"relative mt-0.5 size-4 shrink-0 appearance-none rounded-full border border-choice-edge outline-none transition-colors dark:bg-input-fill",
|
|
91
|
+
"hover:border-choice-edge-strong checked:border-control-on",
|
|
92
|
+
"focus-visible:ring-2 focus-visible:ring-ring/50 focus-visible:ring-offset-2 focus-visible:ring-offset-background",
|
|
93
|
+
"disabled:cursor-not-allowed disabled:opacity-50",
|
|
94
|
+
"checked:before:absolute checked:before:start-1/2 checked:before:top-1/2 checked:before:size-2 checked:before:-translate-x-1/2 checked:before:-translate-y-1/2 checked:before:rounded-full checked:before:bg-control-on checked:before:content-['']",
|
|
95
|
+
className
|
|
96
|
+
),
|
|
97
|
+
...props
|
|
98
|
+
}
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
export {
|
|
102
|
+
DataGridPasteDialog
|
|
103
|
+
};
|
|
104
|
+
//# sourceMappingURL=data-grid-paste-dialog.js.map
|