@postxl/generators 1.1.1 → 1.2.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/dist/frontend-core/frontend.generator.d.ts +0 -58
- package/dist/frontend-core/frontend.generator.js +6 -172
- package/dist/frontend-core/frontend.generator.js.map +1 -1
- package/dist/frontend-core/template/README.md +1 -1
- package/dist/frontend-core/template/src/components/admin/table-filter.tsx +1 -5
- package/dist/frontend-core/template/src/components/ui/color-mode-toggle/color-mode-toggle.tsx +10 -4
- package/dist/frontend-core/template/src/pages/dashboard/dashboard.page.tsx +2 -3
- package/dist/frontend-core/template/src/pages/error/default-error.page.tsx +1 -1
- package/dist/frontend-core/template/src/pages/error/not-found-error.page.tsx +1 -1
- package/dist/frontend-core/template/src/styles/styles.css +13 -1
- package/dist/frontend-core/template/tsconfig.json +2 -0
- package/dist/frontend-core/types/component.d.ts +1 -1
- package/dist/frontend-forms/generators/discriminated-union/fields.generator.js +4 -6
- package/dist/frontend-forms/generators/discriminated-union/fields.generator.js.map +1 -1
- package/dist/frontend-forms/generators/discriminated-union/inputs.generator.js +1 -1
- package/dist/frontend-forms/generators/discriminated-union/inputs.generator.js.map +1 -1
- package/dist/frontend-forms/generators/enum/inputs.generator.js +1 -1
- package/dist/frontend-forms/generators/enum/inputs.generator.js.map +1 -1
- package/dist/frontend-forms/generators/model/forms.generator.js +8 -12
- package/dist/frontend-forms/generators/model/forms.generator.js.map +1 -1
- package/dist/frontend-forms/generators/model/inputs.generator.js +2 -6
- package/dist/frontend-forms/generators/model/inputs.generator.js.map +1 -1
- package/dist/frontend-forms/template/src/components/ui/field/field.tsx +1 -4
- package/dist/frontend-tables/generators/model-table.generator.js +1 -5
- package/dist/frontend-tables/generators/model-table.generator.js.map +1 -1
- package/package.json +3 -2
- package/dist/frontend-core/template/src/components/ui/accordion/accordion.stories.tsx +0 -47
- package/dist/frontend-core/template/src/components/ui/accordion/accordion.tsx +0 -52
- package/dist/frontend-core/template/src/components/ui/admin-sidebar/admin-sidebar.tsx +0 -195
- package/dist/frontend-core/template/src/components/ui/alert/alert.stories.tsx +0 -61
- package/dist/frontend-core/template/src/components/ui/alert/alert.tsx +0 -45
- package/dist/frontend-core/template/src/components/ui/alert-dialog/alert-dialog.stories.tsx +0 -52
- package/dist/frontend-core/template/src/components/ui/alert-dialog/alert-dialog.tsx +0 -105
- package/dist/frontend-core/template/src/components/ui/avatar/avatar.stories.tsx +0 -30
- package/dist/frontend-core/template/src/components/ui/avatar/avatar.tsx +0 -39
- package/dist/frontend-core/template/src/components/ui/badge/badge.stories.tsx +0 -78
- package/dist/frontend-core/template/src/components/ui/badge/badge.tsx +0 -48
- package/dist/frontend-core/template/src/components/ui/breadcrumb/breadcrumb.stories.tsx +0 -67
- package/dist/frontend-core/template/src/components/ui/breadcrumb/breadcrumb.tsx +0 -85
- package/dist/frontend-core/template/src/components/ui/button/button.stories.tsx +0 -150
- package/dist/frontend-core/template/src/components/ui/button/button.tsx +0 -68
- package/dist/frontend-core/template/src/components/ui/calendar/calendar.stories.tsx +0 -160
- package/dist/frontend-core/template/src/components/ui/calendar/calendar.tsx +0 -293
- package/dist/frontend-core/template/src/components/ui/card/card.stories.tsx +0 -77
- package/dist/frontend-core/template/src/components/ui/card/card.tsx +0 -45
- package/dist/frontend-core/template/src/components/ui/card-hover/card-hover.stories.tsx +0 -29
- package/dist/frontend-core/template/src/components/ui/card-hover/card-hover.tsx +0 -28
- package/dist/frontend-core/template/src/components/ui/carousel/carousel.stories.tsx +0 -154
- package/dist/frontend-core/template/src/components/ui/carousel/carousel.tsx +0 -227
- package/dist/frontend-core/template/src/components/ui/checkbox/checkbox.stories.tsx +0 -106
- package/dist/frontend-core/template/src/components/ui/checkbox/checkbox.tsx +0 -88
- package/dist/frontend-core/template/src/components/ui/checkbox/shadcn-checkbox.stories.tsx +0 -90
- package/dist/frontend-core/template/src/components/ui/checkbox/shadcn-checkbox.tsx +0 -54
- package/dist/frontend-core/template/src/components/ui/collapse/collapse.stories.tsx +0 -52
- package/dist/frontend-core/template/src/components/ui/collapse/collapse.tsx +0 -9
- package/dist/frontend-core/template/src/components/ui/combobox/combobox.stories.tsx +0 -207
- package/dist/frontend-core/template/src/components/ui/combobox/combobox.tsx +0 -79
- package/dist/frontend-core/template/src/components/ui/command/command.stories.tsx +0 -186
- package/dist/frontend-core/template/src/components/ui/command/command.tsx +0 -165
- package/dist/frontend-core/template/src/components/ui/command-palette/command-palette.stories.tsx +0 -160
- package/dist/frontend-core/template/src/components/ui/command-palette/command-palette.tsx +0 -134
- package/dist/frontend-core/template/src/components/ui/content-frame/content-frame.stories.tsx +0 -198
- package/dist/frontend-core/template/src/components/ui/content-frame/content-frame.tsx +0 -100
- package/dist/frontend-core/template/src/components/ui/context-menu/context-menu.stories.tsx +0 -78
- package/dist/frontend-core/template/src/components/ui/context-menu/context-menu.tsx +0 -179
- package/dist/frontend-core/template/src/components/ui/data-grid/cell-variants/cell-variant-types.ts +0 -11
- package/dist/frontend-core/template/src/components/ui/data-grid/cell-variants/checkbox-cell.tsx +0 -116
- package/dist/frontend-core/template/src/components/ui/data-grid/cell-variants/date-cell.tsx +0 -157
- package/dist/frontend-core/template/src/components/ui/data-grid/cell-variants/gantt-cell.tsx +0 -82
- package/dist/frontend-core/template/src/components/ui/data-grid/cell-variants/long-text-cell.tsx +0 -180
- package/dist/frontend-core/template/src/components/ui/data-grid/cell-variants/multi-select-cell.tsx +0 -280
- package/dist/frontend-core/template/src/components/ui/data-grid/cell-variants/number-cell.tsx +0 -169
- package/dist/frontend-core/template/src/components/ui/data-grid/cell-variants/react-node-cell.tsx +0 -33
- package/dist/frontend-core/template/src/components/ui/data-grid/cell-variants/select-cell.tsx +0 -175
- package/dist/frontend-core/template/src/components/ui/data-grid/cell-variants/short-text-cell.tsx +0 -138
- package/dist/frontend-core/template/src/components/ui/data-grid/cell-variants/utils/gantt-timeline.tsx +0 -92
- package/dist/frontend-core/template/src/components/ui/data-grid/cell-variants/utils/gantt-timerange-picker.tsx +0 -330
- package/dist/frontend-core/template/src/components/ui/data-grid/data-grid-cell-wrapper.tsx +0 -212
- package/dist/frontend-core/template/src/components/ui/data-grid/data-grid-cell.tsx +0 -157
- package/dist/frontend-core/template/src/components/ui/data-grid/data-grid-column-header.tsx +0 -340
- package/dist/frontend-core/template/src/components/ui/data-grid/data-grid-context-menu.tsx +0 -271
- package/dist/frontend-core/template/src/components/ui/data-grid/data-grid-row.tsx +0 -123
- package/dist/frontend-core/template/src/components/ui/data-grid/data-grid-search.tsx +0 -211
- package/dist/frontend-core/template/src/components/ui/data-grid/data-grid-types.ts +0 -159
- package/dist/frontend-core/template/src/components/ui/data-grid/data-grid-utils.ts +0 -67
- package/dist/frontend-core/template/src/components/ui/data-grid/data-grid-view-menu.tsx +0 -360
- package/dist/frontend-core/template/src/components/ui/data-grid/data-grid.stories.tsx +0 -780
- package/dist/frontend-core/template/src/components/ui/data-grid/data-grid.tsx +0 -217
- package/dist/frontend-core/template/src/components/ui/data-grid/hooks/use-callback-ref.ts +0 -22
- package/dist/frontend-core/template/src/components/ui/data-grid/hooks/use-data-grid.tsx +0 -1892
- package/dist/frontend-core/template/src/components/ui/data-grid/hooks/use-debounced-callback.ts +0 -19
- package/dist/frontend-core/template/src/components/ui/data-grid/styles.css +0 -3
- package/dist/frontend-core/template/src/components/ui/data-table/context-menu-simple.tsx +0 -141
- package/dist/frontend-core/template/src/components/ui/data-table/data-table.stories.tsx +0 -146
- package/dist/frontend-core/template/src/components/ui/data-table/data-table.tsx +0 -447
- package/dist/frontend-core/template/src/components/ui/data-table/renderers/country-array-cell-renderer.tsx +0 -77
- package/dist/frontend-core/template/src/components/ui/data-table/renderers/country-cell-renderer.tsx +0 -56
- package/dist/frontend-core/template/src/components/ui/data-table/renderers/favorite-cell-renderer.tsx +0 -68
- package/dist/frontend-core/template/src/components/ui/data-table/renderers/links-cell-renderer.tsx +0 -205
- package/dist/frontend-core/template/src/components/ui/data-table/utils/columns.ts +0 -351
- package/dist/frontend-core/template/src/components/ui/data-table/utils/data-table.utils.ts +0 -49
- package/dist/frontend-core/template/src/components/ui/date-picker/date-picker.stories.tsx +0 -149
- package/dist/frontend-core/template/src/components/ui/date-picker/date-picker.tsx +0 -30
- package/dist/frontend-core/template/src/components/ui/dialog/dialog.stories.tsx +0 -80
- package/dist/frontend-core/template/src/components/ui/dialog/dialog.tsx +0 -134
- package/dist/frontend-core/template/src/components/ui/drawer/drawer.stories.tsx +0 -104
- package/dist/frontend-core/template/src/components/ui/drawer/drawer.tsx +0 -87
- package/dist/frontend-core/template/src/components/ui/dropdown-menu/dropdown-menu.stories.tsx +0 -168
- package/dist/frontend-core/template/src/components/ui/dropdown-menu/dropdown-menu.tsx +0 -225
- package/dist/frontend-core/template/src/components/ui/input/input.stories.tsx +0 -141
- package/dist/frontend-core/template/src/components/ui/input/input.tsx +0 -47
- package/dist/frontend-core/template/src/components/ui/label/label.stories.tsx +0 -41
- package/dist/frontend-core/template/src/components/ui/label/label.tsx +0 -20
- package/dist/frontend-core/template/src/components/ui/loader/loader.stories.tsx +0 -45
- package/dist/frontend-core/template/src/components/ui/loader/loader.tsx +0 -17
- package/dist/frontend-core/template/src/components/ui/mark-value-renderer/mark-value-renderer.stories.tsx +0 -114
- package/dist/frontend-core/template/src/components/ui/mark-value-renderer/mark-value-renderer.tsx +0 -48
- package/dist/frontend-core/template/src/components/ui/menubar/menu.stories.tsx +0 -134
- package/dist/frontend-core/template/src/components/ui/menubar/menubar.tsx +0 -208
- package/dist/frontend-core/template/src/components/ui/modal/modal.stories.tsx +0 -297
- package/dist/frontend-core/template/src/components/ui/modal/modal.tsx +0 -80
- package/dist/frontend-core/template/src/components/ui/navigation-menu/navigation-menu.stories.tsx +0 -213
- package/dist/frontend-core/template/src/components/ui/navigation-menu/navigation-menu.tsx +0 -142
- package/dist/frontend-core/template/src/components/ui/pagination/pagination.stories.tsx +0 -49
- package/dist/frontend-core/template/src/components/ui/pagination/pagination.tsx +0 -84
- package/dist/frontend-core/template/src/components/ui/popover/popover.stories.tsx +0 -82
- package/dist/frontend-core/template/src/components/ui/popover/popover.tsx +0 -55
- package/dist/frontend-core/template/src/components/ui/progress/progress.stories.tsx +0 -80
- package/dist/frontend-core/template/src/components/ui/progress/progress.tsx +0 -17
- package/dist/frontend-core/template/src/components/ui/radio-group/radio-group.stories.tsx +0 -154
- package/dist/frontend-core/template/src/components/ui/radio-group/radio-group.tsx +0 -68
- package/dist/frontend-core/template/src/components/ui/resizable/resizable.stories.tsx +0 -73
- package/dist/frontend-core/template/src/components/ui/resizable/resizeable.tsx +0 -38
- package/dist/frontend-core/template/src/components/ui/scroll-area/scroll-area.stories.tsx +0 -55
- package/dist/frontend-core/template/src/components/ui/scroll-area/scroll-area.tsx +0 -39
- package/dist/frontend-core/template/src/components/ui/select/select.stories.tsx +0 -297
- package/dist/frontend-core/template/src/components/ui/select/select.tsx +0 -227
- package/dist/frontend-core/template/src/components/ui/separator/separator.tsx +0 -21
- package/dist/frontend-core/template/src/components/ui/separator/seperator.stories.tsx +0 -25
- package/dist/frontend-core/template/src/components/ui/sheet/sheet.stories.tsx +0 -45
- package/dist/frontend-core/template/src/components/ui/sheet/sheet.tsx +0 -107
- package/dist/frontend-core/template/src/components/ui/skeleton/skeleton.stories.tsx +0 -26
- package/dist/frontend-core/template/src/components/ui/skeleton/skeleton.tsx +0 -7
- package/dist/frontend-core/template/src/components/ui/slider/slider.stories.tsx +0 -101
- package/dist/frontend-core/template/src/components/ui/slider/slider.tsx +0 -98
- package/dist/frontend-core/template/src/components/ui/spinner/spinner.stories.tsx +0 -19
- package/dist/frontend-core/template/src/components/ui/spinner/spinner.tsx +0 -21
- package/dist/frontend-core/template/src/components/ui/switch/switch.stories.tsx +0 -33
- package/dist/frontend-core/template/src/components/ui/switch/switch.tsx +0 -28
- package/dist/frontend-core/template/src/components/ui/tabs/tabs.stories.tsx +0 -215
- package/dist/frontend-core/template/src/components/ui/tabs/tabs.tsx +0 -70
- package/dist/frontend-core/template/src/components/ui/textarea/textarea.stories.tsx +0 -138
- package/dist/frontend-core/template/src/components/ui/textarea/textarea.tsx +0 -40
- package/dist/frontend-core/template/src/components/ui/toast/toast.mdx +0 -31
- package/dist/frontend-core/template/src/components/ui/toast/toast.stories.tsx +0 -89
- package/dist/frontend-core/template/src/components/ui/toggle/toggle.stories.tsx +0 -65
- package/dist/frontend-core/template/src/components/ui/toggle/toggle.tsx +0 -38
- package/dist/frontend-core/template/src/components/ui/toggle-group/toggle-group.stories.tsx +0 -85
- package/dist/frontend-core/template/src/components/ui/toggle-group/toggle-group.tsx +0 -54
- package/dist/frontend-core/template/src/components/ui/tooltip/tooltip.stories.tsx +0 -29
- package/dist/frontend-core/template/src/components/ui/tooltip/tooltip.tsx +0 -29
|
@@ -1,340 +0,0 @@
|
|
|
1
|
-
import type { ColumnSort, Header, SortDirection, SortingState, Table } from '@tanstack/react-table'
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
BaselineIcon,
|
|
5
|
-
CalendarIcon,
|
|
6
|
-
CheckSquareIcon,
|
|
7
|
-
ChevronDownIcon,
|
|
8
|
-
ChevronUpIcon,
|
|
9
|
-
EyeOffIcon,
|
|
10
|
-
HashIcon,
|
|
11
|
-
ListChecksIcon,
|
|
12
|
-
ListIcon,
|
|
13
|
-
PinIcon,
|
|
14
|
-
PinOffIcon,
|
|
15
|
-
TextInitialIcon,
|
|
16
|
-
XIcon,
|
|
17
|
-
} from 'lucide-react'
|
|
18
|
-
import * as React from 'react'
|
|
19
|
-
|
|
20
|
-
import type { Cell, ColumnMenuRendererFunction } from '@components/ui/data-grid/data-grid-types'
|
|
21
|
-
import {
|
|
22
|
-
DropdownMenu,
|
|
23
|
-
DropdownMenuCheckboxItem,
|
|
24
|
-
DropdownMenuContent,
|
|
25
|
-
DropdownMenuItem,
|
|
26
|
-
DropdownMenuSeparator,
|
|
27
|
-
DropdownMenuTrigger,
|
|
28
|
-
} from '@components/ui/dropdown-menu/dropdown-menu'
|
|
29
|
-
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@components/ui/tooltip/tooltip'
|
|
30
|
-
import { cn } from '@lib/utils'
|
|
31
|
-
|
|
32
|
-
import { GanttTimeline } from './cell-variants/utils/gantt-timeline'
|
|
33
|
-
|
|
34
|
-
function getColumnVariant(variant?: Cell['variant']): {
|
|
35
|
-
icon: React.ComponentType<React.SVGProps<SVGSVGElement>>
|
|
36
|
-
label: string
|
|
37
|
-
} | null {
|
|
38
|
-
switch (variant) {
|
|
39
|
-
case 'short-text':
|
|
40
|
-
return { icon: BaselineIcon, label: 'Short text' }
|
|
41
|
-
case 'long-text':
|
|
42
|
-
return { icon: TextInitialIcon, label: 'Long text' }
|
|
43
|
-
case 'number':
|
|
44
|
-
return { icon: HashIcon, label: 'Number' }
|
|
45
|
-
case 'select':
|
|
46
|
-
return { icon: ListIcon, label: 'Select' }
|
|
47
|
-
case 'multi-select':
|
|
48
|
-
return { icon: ListChecksIcon, label: 'Multi-select' }
|
|
49
|
-
case 'checkbox':
|
|
50
|
-
return { icon: CheckSquareIcon, label: 'Checkbox' }
|
|
51
|
-
case 'date':
|
|
52
|
-
return { icon: CalendarIcon, label: 'Date' }
|
|
53
|
-
default:
|
|
54
|
-
return null
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
type DataGridColumnHeaderProps<TData, TValue> = {
|
|
59
|
-
header: Header<TData, TValue>
|
|
60
|
-
table: Table<TData>
|
|
61
|
-
} & React.ComponentProps<typeof DropdownMenuTrigger>
|
|
62
|
-
|
|
63
|
-
export function DataGridColumnHeader<TData, TValue>({
|
|
64
|
-
header,
|
|
65
|
-
table,
|
|
66
|
-
className,
|
|
67
|
-
onPointerDown,
|
|
68
|
-
...props
|
|
69
|
-
}: DataGridColumnHeaderProps<TData, TValue>) {
|
|
70
|
-
const [open, setOpen] = React.useState(false)
|
|
71
|
-
|
|
72
|
-
const column = header.column
|
|
73
|
-
const label = column.columnDef.meta?.label
|
|
74
|
-
? column.columnDef.meta.label
|
|
75
|
-
: typeof column.columnDef.header === 'string'
|
|
76
|
-
? column.columnDef.header
|
|
77
|
-
: column.id
|
|
78
|
-
|
|
79
|
-
const isAnyColumnResizing = table.getState().columnSizingInfo.isResizingColumn
|
|
80
|
-
|
|
81
|
-
const cellVariant = column.columnDef.meta?.cell
|
|
82
|
-
const columnVariant = getColumnVariant(cellVariant?.variant)
|
|
83
|
-
|
|
84
|
-
const pinnedPosition = column.getIsPinned()
|
|
85
|
-
const isPinnedLeft = pinnedPosition === 'left'
|
|
86
|
-
const isPinnedRight = pinnedPosition === 'right'
|
|
87
|
-
|
|
88
|
-
const onSortingChange = React.useCallback(
|
|
89
|
-
(direction: SortDirection) => {
|
|
90
|
-
table.setSorting((prev: SortingState) => {
|
|
91
|
-
const existingSortIndex = prev.findIndex((sort) => sort.id === column.id)
|
|
92
|
-
const newSort: ColumnSort = {
|
|
93
|
-
id: column.id,
|
|
94
|
-
desc: direction === 'desc',
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
if (existingSortIndex >= 0) {
|
|
98
|
-
const updated = [...prev]
|
|
99
|
-
updated[existingSortIndex] = newSort
|
|
100
|
-
return updated
|
|
101
|
-
} else {
|
|
102
|
-
return [...prev, newSort]
|
|
103
|
-
}
|
|
104
|
-
})
|
|
105
|
-
},
|
|
106
|
-
[column.id, table],
|
|
107
|
-
)
|
|
108
|
-
|
|
109
|
-
const onSortRemove = React.useCallback(() => {
|
|
110
|
-
table.setSorting((prev: SortingState) => prev.filter((sort) => sort.id !== column.id))
|
|
111
|
-
}, [column.id, table])
|
|
112
|
-
|
|
113
|
-
const onLeftPin = React.useCallback(() => {
|
|
114
|
-
column.pin('left')
|
|
115
|
-
}, [column])
|
|
116
|
-
|
|
117
|
-
const onRightPin = React.useCallback(() => {
|
|
118
|
-
column.pin('right')
|
|
119
|
-
}, [column])
|
|
120
|
-
|
|
121
|
-
const onUnpin = React.useCallback(() => {
|
|
122
|
-
column.pin(false)
|
|
123
|
-
}, [column])
|
|
124
|
-
|
|
125
|
-
const onTriggerPointerDown = React.useCallback(
|
|
126
|
-
(event: React.PointerEvent<HTMLButtonElement>) => {
|
|
127
|
-
onPointerDown?.(event)
|
|
128
|
-
if (event.defaultPrevented) {
|
|
129
|
-
return
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
if (event.button !== 0) {
|
|
133
|
-
return
|
|
134
|
-
}
|
|
135
|
-
table.options.meta?.onColumnClick?.(column.id)
|
|
136
|
-
},
|
|
137
|
-
[table.options.meta, column.id, onPointerDown],
|
|
138
|
-
)
|
|
139
|
-
|
|
140
|
-
return (
|
|
141
|
-
<>
|
|
142
|
-
<DropdownMenu open={open} onOpenChange={setOpen}>
|
|
143
|
-
<DropdownMenuTrigger
|
|
144
|
-
className={cn(
|
|
145
|
-
'flex size-full items-center justify-between gap-2 p-2 text-sm bg-sidebar-accent/80 font-bold hover:bg-secondary/40 data-[state=open]:bg-secondary/40 [&_svg]:size-4',
|
|
146
|
-
isAnyColumnResizing && 'pointer-events-none',
|
|
147
|
-
className,
|
|
148
|
-
)}
|
|
149
|
-
onPointerDown={onTriggerPointerDown}
|
|
150
|
-
{...props}
|
|
151
|
-
>
|
|
152
|
-
<div className="flex min-w-0 flex-1 items-center gap-1.5">
|
|
153
|
-
{columnVariant && (
|
|
154
|
-
<TooltipProvider>
|
|
155
|
-
<Tooltip delayDuration={100}>
|
|
156
|
-
<TooltipTrigger asChild>
|
|
157
|
-
<columnVariant.icon className="size-3.5 shrink-0 text-muted-foreground" />
|
|
158
|
-
</TooltipTrigger>
|
|
159
|
-
<TooltipContent side="top">
|
|
160
|
-
<p>{columnVariant.label}</p>
|
|
161
|
-
</TooltipContent>
|
|
162
|
-
</Tooltip>
|
|
163
|
-
</TooltipProvider>
|
|
164
|
-
)}
|
|
165
|
-
<span className="truncate">{label}</span>
|
|
166
|
-
</div>
|
|
167
|
-
<ChevronDownIcon className="shrink-0 text-muted-foreground" />
|
|
168
|
-
</DropdownMenuTrigger>
|
|
169
|
-
<DropdownMenuContent align="start" sideOffset={0} className="w-60">
|
|
170
|
-
{column.getCanSort() && (
|
|
171
|
-
<>
|
|
172
|
-
<DropdownMenuCheckboxItem
|
|
173
|
-
className="relative pr-8 pl-2 [&>span:first-child]:right-2 [&>span:first-child]:left-auto [&_svg]:text-muted-foreground"
|
|
174
|
-
checked={column.getIsSorted() === 'asc'}
|
|
175
|
-
onClick={() => onSortingChange('asc')}
|
|
176
|
-
>
|
|
177
|
-
<ChevronUpIcon />
|
|
178
|
-
Sort asc
|
|
179
|
-
</DropdownMenuCheckboxItem>
|
|
180
|
-
<DropdownMenuCheckboxItem
|
|
181
|
-
className="relative pr-8 pl-2 [&>span:first-child]:right-2 [&>span:first-child]:left-auto [&_svg]:text-muted-foreground"
|
|
182
|
-
checked={column.getIsSorted() === 'desc'}
|
|
183
|
-
onClick={() => onSortingChange('desc')}
|
|
184
|
-
>
|
|
185
|
-
<ChevronDownIcon />
|
|
186
|
-
Sort desc
|
|
187
|
-
</DropdownMenuCheckboxItem>
|
|
188
|
-
{column.getIsSorted() && (
|
|
189
|
-
<DropdownMenuItem onClick={onSortRemove}>
|
|
190
|
-
<XIcon />
|
|
191
|
-
Remove sort
|
|
192
|
-
</DropdownMenuItem>
|
|
193
|
-
)}
|
|
194
|
-
</>
|
|
195
|
-
)}
|
|
196
|
-
{column.getCanPin() && (
|
|
197
|
-
<>
|
|
198
|
-
{column.getCanSort() && <DropdownMenuSeparator />}
|
|
199
|
-
|
|
200
|
-
{isPinnedLeft ? (
|
|
201
|
-
<DropdownMenuItem className="[&_svg]:text-muted-foreground" onClick={onUnpin}>
|
|
202
|
-
<PinOffIcon />
|
|
203
|
-
Unpin from left
|
|
204
|
-
</DropdownMenuItem>
|
|
205
|
-
) : (
|
|
206
|
-
<DropdownMenuItem className="[&_svg]:text-muted-foreground" onClick={onLeftPin}>
|
|
207
|
-
<PinIcon />
|
|
208
|
-
Pin to left
|
|
209
|
-
</DropdownMenuItem>
|
|
210
|
-
)}
|
|
211
|
-
{isPinnedRight ? (
|
|
212
|
-
<DropdownMenuItem className="[&_svg]:text-muted-foreground" onClick={onUnpin}>
|
|
213
|
-
<PinOffIcon />
|
|
214
|
-
Unpin from right
|
|
215
|
-
</DropdownMenuItem>
|
|
216
|
-
) : (
|
|
217
|
-
<DropdownMenuItem className="[&_svg]:text-muted-foreground" onClick={onRightPin}>
|
|
218
|
-
<PinIcon />
|
|
219
|
-
Pin to right
|
|
220
|
-
</DropdownMenuItem>
|
|
221
|
-
)}
|
|
222
|
-
</>
|
|
223
|
-
)}
|
|
224
|
-
{column.getCanHide() && (
|
|
225
|
-
<>
|
|
226
|
-
<DropdownMenuSeparator />
|
|
227
|
-
<DropdownMenuCheckboxItem
|
|
228
|
-
className="relative pr-8 pl-2 [&>span:first-child]:right-2 [&>span:first-child]:left-auto [&_svg]:text-muted-foreground"
|
|
229
|
-
checked={!column.getIsVisible()}
|
|
230
|
-
onClick={() => column.toggleVisibility(false)}
|
|
231
|
-
>
|
|
232
|
-
<EyeOffIcon />
|
|
233
|
-
Hide column
|
|
234
|
-
</DropdownMenuCheckboxItem>
|
|
235
|
-
</>
|
|
236
|
-
)}
|
|
237
|
-
|
|
238
|
-
{/* Render header menu footer (custom optional component) */}
|
|
239
|
-
{column.columnDef.meta?.headerMenuFooter && (
|
|
240
|
-
<>
|
|
241
|
-
<DropdownMenuSeparator />
|
|
242
|
-
<div className="dropdown-footer">
|
|
243
|
-
{isMenuRendererFunction(column.columnDef.meta.headerMenuFooter)
|
|
244
|
-
? column.columnDef.meta.headerMenuFooter({ column, open, onOpenChange: setOpen })
|
|
245
|
-
: column.columnDef.meta.headerMenuFooter}
|
|
246
|
-
</div>
|
|
247
|
-
</>
|
|
248
|
-
)}
|
|
249
|
-
</DropdownMenuContent>
|
|
250
|
-
</DropdownMenu>
|
|
251
|
-
{/* Render any variant-provided header component from HeaderComponents. */}
|
|
252
|
-
{(() => {
|
|
253
|
-
const variant = column.columnDef.meta?.cell?.variant
|
|
254
|
-
const variantHeader = variant ? HeaderComponents[variant] : undefined
|
|
255
|
-
if (variantHeader) {
|
|
256
|
-
return variantHeader({ header, table })
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
return null
|
|
260
|
-
})()}
|
|
261
|
-
|
|
262
|
-
{/* Render custom column header component (optional columnDef.meta) */}
|
|
263
|
-
{column.columnDef.meta?.headerCustomComponent && (
|
|
264
|
-
<>
|
|
265
|
-
{isMenuRendererFunction(column.columnDef.meta.headerCustomComponent)
|
|
266
|
-
? column.columnDef.meta.headerCustomComponent({ column })
|
|
267
|
-
: column.columnDef.meta.headerCustomComponent}
|
|
268
|
-
</>
|
|
269
|
-
)}
|
|
270
|
-
|
|
271
|
-
{header.column.getCanResize() && <DataGridColumnResizer header={header} table={table} label={label} />}
|
|
272
|
-
</>
|
|
273
|
-
)
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
const DataGridColumnResizer = React.memo(DataGridColumnResizerImpl, (prev, next) => {
|
|
277
|
-
const prevColumn = prev.header.column
|
|
278
|
-
const nextColumn = next.header.column
|
|
279
|
-
|
|
280
|
-
if (prevColumn.getIsResizing() !== nextColumn.getIsResizing() || prevColumn.getSize() !== nextColumn.getSize()) {
|
|
281
|
-
return false
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
if (prev.label !== next.label) {
|
|
285
|
-
return false
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
return true
|
|
289
|
-
}) as typeof DataGridColumnResizerImpl
|
|
290
|
-
|
|
291
|
-
type DataGridColumnResizerProps<TData, TValue> = {
|
|
292
|
-
label: string
|
|
293
|
-
} & DataGridColumnHeaderProps<TData, TValue>
|
|
294
|
-
|
|
295
|
-
function DataGridColumnResizerImpl<TData, TValue>({ header, table, label }: DataGridColumnResizerProps<TData, TValue>) {
|
|
296
|
-
const defaultColumnDef = table._getDefaultColumnDef()
|
|
297
|
-
|
|
298
|
-
const onDoubleClick = React.useCallback(() => {
|
|
299
|
-
header.column.resetSize()
|
|
300
|
-
}, [header.column])
|
|
301
|
-
|
|
302
|
-
return (
|
|
303
|
-
<div
|
|
304
|
-
role="separator"
|
|
305
|
-
aria-orientation="vertical"
|
|
306
|
-
aria-label={`Resize ${label} column`}
|
|
307
|
-
aria-valuenow={header.column.getSize()}
|
|
308
|
-
aria-valuemin={defaultColumnDef.minSize}
|
|
309
|
-
aria-valuemax={defaultColumnDef.maxSize}
|
|
310
|
-
tabIndex={0}
|
|
311
|
-
className={cn(
|
|
312
|
-
'right-0 absolute top-0 z-50 h-full w-0 touch-none select-none cursor-ew-resize focus:outline-none',
|
|
313
|
-
// visible thin line (use right positioning and a stable 1px width)
|
|
314
|
-
"before:content-[''] before:absolute before:inset-y-0 before:right-0 before:translate-x-1/2 before:w-px before:h-full before:bg-accent-foreground/70 before:opacity-0 before:transition-opacity before:duration-150",
|
|
315
|
-
// large invisible hit area
|
|
316
|
-
"after:content-[''] after:absolute after:inset-y-0 after:right-0 after:translate-x-1/2 after:w-[18px] after:h-full after:bg-transparent",
|
|
317
|
-
header.column.getIsResizing() ? 'before:opacity-100 before:bg-accent-foreground' : 'hover:before:opacity-100',
|
|
318
|
-
)}
|
|
319
|
-
style={{ willChange: 'transform, opacity', transform: 'translateZ(0)' }}
|
|
320
|
-
onDoubleClick={onDoubleClick}
|
|
321
|
-
onMouseDown={header.getResizeHandler()}
|
|
322
|
-
onTouchStart={header.getResizeHandler()}
|
|
323
|
-
/>
|
|
324
|
-
)
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
function isMenuRendererFunction<TData, TValue>(
|
|
328
|
-
value: React.ReactNode | ColumnMenuRendererFunction<TData, TValue>,
|
|
329
|
-
): value is ColumnMenuRendererFunction<TData, TValue> {
|
|
330
|
-
return typeof value === 'function'
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
/**
|
|
334
|
-
* Optional header components keyed by cell variant. Components receive { header, table } and
|
|
335
|
-
* should return a React node (or null). This allows the column header to render variant-specific
|
|
336
|
-
* header visuals without coupling the header implementation to variants.
|
|
337
|
-
*/
|
|
338
|
-
export const HeaderComponents: Record<string, (props: any) => React.ReactNode | null> = {
|
|
339
|
-
gantt: (props) => <GanttTimeline {...props} />,
|
|
340
|
-
}
|
|
@@ -1,271 +0,0 @@
|
|
|
1
|
-
import { CopyIcon, EraserIcon, TrashIcon } from '@radix-ui/react-icons'
|
|
2
|
-
import type { Table, TableMeta } from '@tanstack/react-table'
|
|
3
|
-
|
|
4
|
-
import * as React from 'react'
|
|
5
|
-
import { toast } from 'sonner'
|
|
6
|
-
|
|
7
|
-
import type { UpdateCell } from '@components/ui/data-grid/data-grid-types'
|
|
8
|
-
import { parseCellKey } from '@components/ui/data-grid/data-grid-utils'
|
|
9
|
-
import {
|
|
10
|
-
DropdownMenu,
|
|
11
|
-
DropdownMenuContent,
|
|
12
|
-
DropdownMenuItem,
|
|
13
|
-
DropdownMenuSeparator,
|
|
14
|
-
DropdownMenuTrigger,
|
|
15
|
-
} from '@components/ui/dropdown-menu/dropdown-menu'
|
|
16
|
-
|
|
17
|
-
type DataGridContextMenuProps<TData> = {
|
|
18
|
-
table: Table<TData>
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export function DataGridContextMenu<TData>({ table }: DataGridContextMenuProps<TData>) {
|
|
22
|
-
const meta = table.options.meta
|
|
23
|
-
const contextMenu = meta?.contextMenu
|
|
24
|
-
const onContextMenuOpenChange = meta?.onContextMenuOpenChange
|
|
25
|
-
const selectionState = meta?.selectionState
|
|
26
|
-
const dataGridRef = meta?.dataGridRef
|
|
27
|
-
const onDataUpdate = meta?.onDataUpdate
|
|
28
|
-
const onRowsDelete = meta?.onRowsDelete
|
|
29
|
-
|
|
30
|
-
if (!contextMenu) {
|
|
31
|
-
return null
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
return (
|
|
35
|
-
<ContextMenu
|
|
36
|
-
table={table}
|
|
37
|
-
dataGridRef={dataGridRef}
|
|
38
|
-
contextMenu={contextMenu}
|
|
39
|
-
onContextMenuOpenChange={onContextMenuOpenChange}
|
|
40
|
-
selectionState={selectionState}
|
|
41
|
-
onDataUpdate={onDataUpdate}
|
|
42
|
-
onRowsDelete={onRowsDelete}
|
|
43
|
-
/>
|
|
44
|
-
)
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
type ContextMenuProps<TData> = {
|
|
48
|
-
table: Table<TData>
|
|
49
|
-
} & Pick<
|
|
50
|
-
TableMeta<TData>,
|
|
51
|
-
'dataGridRef' | 'onContextMenuOpenChange' | 'selectionState' | 'onDataUpdate' | 'onRowsDelete'
|
|
52
|
-
> &
|
|
53
|
-
Required<Pick<TableMeta<TData>, 'contextMenu'>>
|
|
54
|
-
|
|
55
|
-
const ContextMenu = React.memo(ContextMenuImpl, (prev, next) => {
|
|
56
|
-
if (prev.contextMenu.open !== next.contextMenu.open) {
|
|
57
|
-
return false
|
|
58
|
-
}
|
|
59
|
-
if (!next.contextMenu.open) {
|
|
60
|
-
return true
|
|
61
|
-
}
|
|
62
|
-
if (prev.contextMenu.x !== next.contextMenu.x) {
|
|
63
|
-
return false
|
|
64
|
-
}
|
|
65
|
-
if (prev.contextMenu.y !== next.contextMenu.y) {
|
|
66
|
-
return false
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
const prevSize = prev.selectionState?.selectedCells?.size ?? 0
|
|
70
|
-
const nextSize = next.selectionState?.selectedCells?.size ?? 0
|
|
71
|
-
if (prevSize !== nextSize) {
|
|
72
|
-
return false
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
return true
|
|
76
|
-
}) as typeof ContextMenuImpl
|
|
77
|
-
|
|
78
|
-
function ContextMenuImpl<TData>({
|
|
79
|
-
table,
|
|
80
|
-
dataGridRef,
|
|
81
|
-
contextMenu,
|
|
82
|
-
onContextMenuOpenChange,
|
|
83
|
-
selectionState,
|
|
84
|
-
onDataUpdate,
|
|
85
|
-
onRowsDelete,
|
|
86
|
-
}: ContextMenuProps<TData>) {
|
|
87
|
-
const triggerStyle = React.useMemo<React.CSSProperties>(
|
|
88
|
-
() => ({
|
|
89
|
-
position: 'fixed',
|
|
90
|
-
left: `${contextMenu.x}px`,
|
|
91
|
-
top: `${contextMenu.y}px`,
|
|
92
|
-
width: '1px',
|
|
93
|
-
height: '1px',
|
|
94
|
-
padding: 0,
|
|
95
|
-
margin: 0,
|
|
96
|
-
border: 'none',
|
|
97
|
-
background: 'transparent',
|
|
98
|
-
pointerEvents: 'none',
|
|
99
|
-
opacity: 0,
|
|
100
|
-
}),
|
|
101
|
-
[contextMenu.x, contextMenu.y],
|
|
102
|
-
)
|
|
103
|
-
|
|
104
|
-
const onCloseAutoFocus: NonNullable<React.ComponentProps<typeof DropdownMenuContent>['onCloseAutoFocus']> =
|
|
105
|
-
React.useCallback(
|
|
106
|
-
(event) => {
|
|
107
|
-
event.preventDefault()
|
|
108
|
-
dataGridRef?.current?.focus()
|
|
109
|
-
},
|
|
110
|
-
[dataGridRef],
|
|
111
|
-
)
|
|
112
|
-
|
|
113
|
-
const onCopy = React.useCallback(async () => {
|
|
114
|
-
if (!selectionState?.selectedCells || selectionState.selectedCells.size === 0) {
|
|
115
|
-
return
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
const rows = table.getRowModel().rows
|
|
119
|
-
const columnIds: string[] = []
|
|
120
|
-
|
|
121
|
-
const selectedCellsArray = Array.from(selectionState.selectedCells)
|
|
122
|
-
for (const cellKey of selectedCellsArray) {
|
|
123
|
-
const { columnId } = parseCellKey(cellKey)
|
|
124
|
-
if (columnId && !columnIds.includes(columnId)) {
|
|
125
|
-
columnIds.push(columnId)
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
const cellData = new Map<string, string>()
|
|
130
|
-
for (const cellKey of selectedCellsArray) {
|
|
131
|
-
const { rowIndex, columnId } = parseCellKey(cellKey)
|
|
132
|
-
const row = rows[rowIndex]
|
|
133
|
-
if (row) {
|
|
134
|
-
const cell = row.getVisibleCells().find((c) => c.column.id === columnId)
|
|
135
|
-
if (cell) {
|
|
136
|
-
const value = cell.getValue()
|
|
137
|
-
cellData.set(cellKey, String(value ?? ''))
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
const rowIndices = new Set<number>()
|
|
143
|
-
const colIndices = new Set<number>()
|
|
144
|
-
|
|
145
|
-
for (const cellKey of selectedCellsArray) {
|
|
146
|
-
const { rowIndex, columnId } = parseCellKey(cellKey)
|
|
147
|
-
rowIndices.add(rowIndex)
|
|
148
|
-
const colIndex = columnIds.indexOf(columnId)
|
|
149
|
-
if (colIndex >= 0) {
|
|
150
|
-
colIndices.add(colIndex)
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
const sortedRowIndices = Array.from(rowIndices).sort((a, b) => a - b)
|
|
155
|
-
const sortedColIndices = Array.from(colIndices).sort((a, b) => a - b)
|
|
156
|
-
const sortedColumnIds = sortedColIndices.map((i) => columnIds[i])
|
|
157
|
-
|
|
158
|
-
const tsvData = sortedRowIndices
|
|
159
|
-
.map((rowIndex) =>
|
|
160
|
-
sortedColumnIds
|
|
161
|
-
.map((columnId) => {
|
|
162
|
-
const cellKey = `${rowIndex}:${columnId}`
|
|
163
|
-
return cellData.get(cellKey) ?? ''
|
|
164
|
-
})
|
|
165
|
-
.join('\t'),
|
|
166
|
-
)
|
|
167
|
-
.join('\n')
|
|
168
|
-
|
|
169
|
-
await navigator.clipboard.writeText(tsvData)
|
|
170
|
-
toast.success(
|
|
171
|
-
`${selectionState.selectedCells.size} cell${selectionState.selectedCells.size !== 1 ? 's' : ''} copied`,
|
|
172
|
-
)
|
|
173
|
-
}, [table, selectionState])
|
|
174
|
-
|
|
175
|
-
// Determine whether the selected cells are all editable. If any selected cell belongs to a non-editable column (meta.editable === false), disable the Clear action.
|
|
176
|
-
const canClear = React.useMemo(() => {
|
|
177
|
-
if (!selectionState?.selectedCells || selectionState.selectedCells.size === 0) {
|
|
178
|
-
return false
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
const visibleCols = table.getVisibleLeafColumns()
|
|
182
|
-
const rows = table.getRowModel().rows
|
|
183
|
-
|
|
184
|
-
for (const cellKey of selectionState.selectedCells) {
|
|
185
|
-
const { rowIndex, columnId } = parseCellKey(cellKey)
|
|
186
|
-
if (!columnId) {
|
|
187
|
-
continue
|
|
188
|
-
}
|
|
189
|
-
const col = visibleCols.find((c) => c.id === columnId)
|
|
190
|
-
const editable = col?.columnDef?.meta?.editable
|
|
191
|
-
|
|
192
|
-
if (editable === false) {
|
|
193
|
-
return false
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
if (typeof editable === 'function') {
|
|
197
|
-
const row = rows[rowIndex]
|
|
198
|
-
if (row && !editable(row.original)) {
|
|
199
|
-
return false
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
return true
|
|
205
|
-
}, [selectionState, table])
|
|
206
|
-
|
|
207
|
-
const onClear = React.useCallback(() => {
|
|
208
|
-
if (!selectionState?.selectedCells || selectionState.selectedCells.size === 0) {
|
|
209
|
-
return
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
if (!canClear) {
|
|
213
|
-
return
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
const updates: UpdateCell[] = []
|
|
217
|
-
|
|
218
|
-
for (const cellKey of selectionState.selectedCells) {
|
|
219
|
-
const { rowIndex, columnId } = parseCellKey(cellKey)
|
|
220
|
-
updates.push({ rowIndex, columnId, value: '' })
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
onDataUpdate?.(updates)
|
|
224
|
-
|
|
225
|
-
toast.success(`${updates.length} cell${updates.length !== 1 ? 's' : ''} cleared`)
|
|
226
|
-
}, [onDataUpdate, selectionState, canClear])
|
|
227
|
-
|
|
228
|
-
const onDelete = React.useCallback(async () => {
|
|
229
|
-
if (!selectionState?.selectedCells || selectionState.selectedCells.size === 0) {
|
|
230
|
-
return
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
const rowIndices = new Set<number>()
|
|
234
|
-
for (const cellKey of selectionState.selectedCells) {
|
|
235
|
-
const { rowIndex } = parseCellKey(cellKey)
|
|
236
|
-
rowIndices.add(rowIndex)
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
const rowIndicesArray = Array.from(rowIndices).sort((a, b) => a - b)
|
|
240
|
-
const rowCount = rowIndicesArray.length
|
|
241
|
-
|
|
242
|
-
await onRowsDelete?.(rowIndicesArray)
|
|
243
|
-
|
|
244
|
-
toast.success(`${rowCount} row${rowCount !== 1 ? 's' : ''} deleted`)
|
|
245
|
-
}, [onRowsDelete, selectionState])
|
|
246
|
-
|
|
247
|
-
return (
|
|
248
|
-
<DropdownMenu open={contextMenu.open} onOpenChange={onContextMenuOpenChange}>
|
|
249
|
-
<DropdownMenuTrigger style={triggerStyle} />
|
|
250
|
-
<DropdownMenuContent data-grid-popover="" align="start" className="w-48" onCloseAutoFocus={onCloseAutoFocus}>
|
|
251
|
-
<DropdownMenuItem onSelect={onCopy}>
|
|
252
|
-
<CopyIcon />
|
|
253
|
-
Copy
|
|
254
|
-
</DropdownMenuItem>
|
|
255
|
-
<DropdownMenuItem onSelect={onClear} disabled={!canClear}>
|
|
256
|
-
<EraserIcon />
|
|
257
|
-
Clear
|
|
258
|
-
</DropdownMenuItem>
|
|
259
|
-
{onRowsDelete && (
|
|
260
|
-
<>
|
|
261
|
-
<DropdownMenuSeparator />
|
|
262
|
-
<DropdownMenuItem variant="destructive" onSelect={onDelete}>
|
|
263
|
-
<TrashIcon />
|
|
264
|
-
Delete rows
|
|
265
|
-
</DropdownMenuItem>
|
|
266
|
-
</>
|
|
267
|
-
)}
|
|
268
|
-
</DropdownMenuContent>
|
|
269
|
-
</DropdownMenu>
|
|
270
|
-
)
|
|
271
|
-
}
|