@postxl/generators 1.1.0 → 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.
Files changed (169) hide show
  1. package/dist/backend-core/template/apps/api/src/e2e.ts +13 -4
  2. package/dist/e2e/e2e.generator.js +2 -14
  3. package/dist/e2e/e2e.generator.js.map +1 -1
  4. package/dist/e2e/generators/docker-sh.generator.d.ts +2 -0
  5. package/dist/e2e/generators/docker-sh.generator.js +25 -0
  6. package/dist/e2e/generators/docker-sh.generator.js.map +1 -0
  7. package/dist/frontend-core/frontend.generator.d.ts +0 -58
  8. package/dist/frontend-core/frontend.generator.js +6 -172
  9. package/dist/frontend-core/frontend.generator.js.map +1 -1
  10. package/dist/frontend-core/template/README.md +1 -1
  11. package/dist/frontend-core/template/src/components/admin/table-filter.tsx +1 -5
  12. package/dist/frontend-core/template/src/components/ui/color-mode-toggle/color-mode-toggle.tsx +10 -4
  13. package/dist/frontend-core/template/src/context-providers/auth-context-provider.tsx +2 -5
  14. package/dist/frontend-core/template/src/pages/dashboard/dashboard.page.tsx +2 -3
  15. package/dist/frontend-core/template/src/pages/error/default-error.page.tsx +1 -1
  16. package/dist/frontend-core/template/src/pages/error/not-found-error.page.tsx +1 -1
  17. package/dist/frontend-core/template/src/styles/styles.css +13 -1
  18. package/dist/frontend-core/template/tsconfig.json +2 -0
  19. package/dist/frontend-core/types/component.d.ts +1 -1
  20. package/dist/frontend-forms/generators/discriminated-union/fields.generator.js +4 -6
  21. package/dist/frontend-forms/generators/discriminated-union/fields.generator.js.map +1 -1
  22. package/dist/frontend-forms/generators/discriminated-union/inputs.generator.js +1 -1
  23. package/dist/frontend-forms/generators/discriminated-union/inputs.generator.js.map +1 -1
  24. package/dist/frontend-forms/generators/enum/inputs.generator.js +1 -1
  25. package/dist/frontend-forms/generators/enum/inputs.generator.js.map +1 -1
  26. package/dist/frontend-forms/generators/model/forms.generator.js +8 -12
  27. package/dist/frontend-forms/generators/model/forms.generator.js.map +1 -1
  28. package/dist/frontend-forms/generators/model/inputs.generator.js +2 -6
  29. package/dist/frontend-forms/generators/model/inputs.generator.js.map +1 -1
  30. package/dist/frontend-forms/template/src/components/ui/field/field.tsx +1 -4
  31. package/dist/frontend-tables/generators/model-table.generator.js +1 -5
  32. package/dist/frontend-tables/generators/model-table.generator.js.map +1 -1
  33. package/package.json +3 -2
  34. package/dist/e2e/template/scripts/docker.sh +0 -17
  35. package/dist/frontend-core/template/src/components/ui/accordion/accordion.stories.tsx +0 -47
  36. package/dist/frontend-core/template/src/components/ui/accordion/accordion.tsx +0 -52
  37. package/dist/frontend-core/template/src/components/ui/admin-sidebar/admin-sidebar.tsx +0 -195
  38. package/dist/frontend-core/template/src/components/ui/alert/alert.stories.tsx +0 -61
  39. package/dist/frontend-core/template/src/components/ui/alert/alert.tsx +0 -45
  40. package/dist/frontend-core/template/src/components/ui/alert-dialog/alert-dialog.stories.tsx +0 -52
  41. package/dist/frontend-core/template/src/components/ui/alert-dialog/alert-dialog.tsx +0 -105
  42. package/dist/frontend-core/template/src/components/ui/avatar/avatar.stories.tsx +0 -30
  43. package/dist/frontend-core/template/src/components/ui/avatar/avatar.tsx +0 -39
  44. package/dist/frontend-core/template/src/components/ui/badge/badge.stories.tsx +0 -78
  45. package/dist/frontend-core/template/src/components/ui/badge/badge.tsx +0 -48
  46. package/dist/frontend-core/template/src/components/ui/breadcrumb/breadcrumb.stories.tsx +0 -67
  47. package/dist/frontend-core/template/src/components/ui/breadcrumb/breadcrumb.tsx +0 -85
  48. package/dist/frontend-core/template/src/components/ui/button/button.stories.tsx +0 -150
  49. package/dist/frontend-core/template/src/components/ui/button/button.tsx +0 -68
  50. package/dist/frontend-core/template/src/components/ui/calendar/calendar.stories.tsx +0 -160
  51. package/dist/frontend-core/template/src/components/ui/calendar/calendar.tsx +0 -293
  52. package/dist/frontend-core/template/src/components/ui/card/card.stories.tsx +0 -77
  53. package/dist/frontend-core/template/src/components/ui/card/card.tsx +0 -45
  54. package/dist/frontend-core/template/src/components/ui/card-hover/card-hover.stories.tsx +0 -29
  55. package/dist/frontend-core/template/src/components/ui/card-hover/card-hover.tsx +0 -28
  56. package/dist/frontend-core/template/src/components/ui/carousel/carousel.stories.tsx +0 -154
  57. package/dist/frontend-core/template/src/components/ui/carousel/carousel.tsx +0 -227
  58. package/dist/frontend-core/template/src/components/ui/checkbox/checkbox.stories.tsx +0 -106
  59. package/dist/frontend-core/template/src/components/ui/checkbox/checkbox.tsx +0 -88
  60. package/dist/frontend-core/template/src/components/ui/checkbox/shadcn-checkbox.stories.tsx +0 -90
  61. package/dist/frontend-core/template/src/components/ui/checkbox/shadcn-checkbox.tsx +0 -54
  62. package/dist/frontend-core/template/src/components/ui/collapse/collapse.stories.tsx +0 -52
  63. package/dist/frontend-core/template/src/components/ui/collapse/collapse.tsx +0 -9
  64. package/dist/frontend-core/template/src/components/ui/combobox/combobox.stories.tsx +0 -207
  65. package/dist/frontend-core/template/src/components/ui/combobox/combobox.tsx +0 -79
  66. package/dist/frontend-core/template/src/components/ui/command/command.stories.tsx +0 -186
  67. package/dist/frontend-core/template/src/components/ui/command/command.tsx +0 -165
  68. package/dist/frontend-core/template/src/components/ui/command-palette/command-palette.stories.tsx +0 -160
  69. package/dist/frontend-core/template/src/components/ui/command-palette/command-palette.tsx +0 -134
  70. package/dist/frontend-core/template/src/components/ui/content-frame/content-frame.stories.tsx +0 -198
  71. package/dist/frontend-core/template/src/components/ui/content-frame/content-frame.tsx +0 -100
  72. package/dist/frontend-core/template/src/components/ui/context-menu/context-menu.stories.tsx +0 -78
  73. package/dist/frontend-core/template/src/components/ui/context-menu/context-menu.tsx +0 -179
  74. package/dist/frontend-core/template/src/components/ui/data-grid/cell-variants/cell-variant-types.ts +0 -11
  75. package/dist/frontend-core/template/src/components/ui/data-grid/cell-variants/checkbox-cell.tsx +0 -116
  76. package/dist/frontend-core/template/src/components/ui/data-grid/cell-variants/date-cell.tsx +0 -157
  77. package/dist/frontend-core/template/src/components/ui/data-grid/cell-variants/gantt-cell.tsx +0 -82
  78. package/dist/frontend-core/template/src/components/ui/data-grid/cell-variants/long-text-cell.tsx +0 -180
  79. package/dist/frontend-core/template/src/components/ui/data-grid/cell-variants/multi-select-cell.tsx +0 -280
  80. package/dist/frontend-core/template/src/components/ui/data-grid/cell-variants/number-cell.tsx +0 -169
  81. package/dist/frontend-core/template/src/components/ui/data-grid/cell-variants/react-node-cell.tsx +0 -33
  82. package/dist/frontend-core/template/src/components/ui/data-grid/cell-variants/select-cell.tsx +0 -175
  83. package/dist/frontend-core/template/src/components/ui/data-grid/cell-variants/short-text-cell.tsx +0 -138
  84. package/dist/frontend-core/template/src/components/ui/data-grid/cell-variants/utils/gantt-timeline.tsx +0 -92
  85. package/dist/frontend-core/template/src/components/ui/data-grid/cell-variants/utils/gantt-timerange-picker.tsx +0 -330
  86. package/dist/frontend-core/template/src/components/ui/data-grid/data-grid-cell-wrapper.tsx +0 -212
  87. package/dist/frontend-core/template/src/components/ui/data-grid/data-grid-cell.tsx +0 -157
  88. package/dist/frontend-core/template/src/components/ui/data-grid/data-grid-column-header.tsx +0 -340
  89. package/dist/frontend-core/template/src/components/ui/data-grid/data-grid-context-menu.tsx +0 -271
  90. package/dist/frontend-core/template/src/components/ui/data-grid/data-grid-row.tsx +0 -123
  91. package/dist/frontend-core/template/src/components/ui/data-grid/data-grid-search.tsx +0 -211
  92. package/dist/frontend-core/template/src/components/ui/data-grid/data-grid-types.ts +0 -159
  93. package/dist/frontend-core/template/src/components/ui/data-grid/data-grid-utils.ts +0 -67
  94. package/dist/frontend-core/template/src/components/ui/data-grid/data-grid-view-menu.tsx +0 -360
  95. package/dist/frontend-core/template/src/components/ui/data-grid/data-grid.stories.tsx +0 -780
  96. package/dist/frontend-core/template/src/components/ui/data-grid/data-grid.tsx +0 -217
  97. package/dist/frontend-core/template/src/components/ui/data-grid/hooks/use-callback-ref.ts +0 -22
  98. package/dist/frontend-core/template/src/components/ui/data-grid/hooks/use-data-grid.tsx +0 -1892
  99. package/dist/frontend-core/template/src/components/ui/data-grid/hooks/use-debounced-callback.ts +0 -19
  100. package/dist/frontend-core/template/src/components/ui/data-grid/styles.css +0 -3
  101. package/dist/frontend-core/template/src/components/ui/data-table/context-menu-simple.tsx +0 -141
  102. package/dist/frontend-core/template/src/components/ui/data-table/data-table.stories.tsx +0 -146
  103. package/dist/frontend-core/template/src/components/ui/data-table/data-table.tsx +0 -447
  104. package/dist/frontend-core/template/src/components/ui/data-table/renderers/country-array-cell-renderer.tsx +0 -77
  105. package/dist/frontend-core/template/src/components/ui/data-table/renderers/country-cell-renderer.tsx +0 -56
  106. package/dist/frontend-core/template/src/components/ui/data-table/renderers/favorite-cell-renderer.tsx +0 -68
  107. package/dist/frontend-core/template/src/components/ui/data-table/renderers/links-cell-renderer.tsx +0 -205
  108. package/dist/frontend-core/template/src/components/ui/data-table/utils/columns.ts +0 -351
  109. package/dist/frontend-core/template/src/components/ui/data-table/utils/data-table.utils.ts +0 -49
  110. package/dist/frontend-core/template/src/components/ui/date-picker/date-picker.stories.tsx +0 -149
  111. package/dist/frontend-core/template/src/components/ui/date-picker/date-picker.tsx +0 -30
  112. package/dist/frontend-core/template/src/components/ui/dialog/dialog.stories.tsx +0 -80
  113. package/dist/frontend-core/template/src/components/ui/dialog/dialog.tsx +0 -134
  114. package/dist/frontend-core/template/src/components/ui/drawer/drawer.stories.tsx +0 -104
  115. package/dist/frontend-core/template/src/components/ui/drawer/drawer.tsx +0 -87
  116. package/dist/frontend-core/template/src/components/ui/dropdown-menu/dropdown-menu.stories.tsx +0 -168
  117. package/dist/frontend-core/template/src/components/ui/dropdown-menu/dropdown-menu.tsx +0 -225
  118. package/dist/frontend-core/template/src/components/ui/input/input.stories.tsx +0 -141
  119. package/dist/frontend-core/template/src/components/ui/input/input.tsx +0 -47
  120. package/dist/frontend-core/template/src/components/ui/label/label.stories.tsx +0 -41
  121. package/dist/frontend-core/template/src/components/ui/label/label.tsx +0 -20
  122. package/dist/frontend-core/template/src/components/ui/loader/loader.stories.tsx +0 -45
  123. package/dist/frontend-core/template/src/components/ui/loader/loader.tsx +0 -17
  124. package/dist/frontend-core/template/src/components/ui/mark-value-renderer/mark-value-renderer.stories.tsx +0 -114
  125. package/dist/frontend-core/template/src/components/ui/mark-value-renderer/mark-value-renderer.tsx +0 -48
  126. package/dist/frontend-core/template/src/components/ui/menubar/menu.stories.tsx +0 -134
  127. package/dist/frontend-core/template/src/components/ui/menubar/menubar.tsx +0 -208
  128. package/dist/frontend-core/template/src/components/ui/modal/modal.stories.tsx +0 -297
  129. package/dist/frontend-core/template/src/components/ui/modal/modal.tsx +0 -80
  130. package/dist/frontend-core/template/src/components/ui/navigation-menu/navigation-menu.stories.tsx +0 -213
  131. package/dist/frontend-core/template/src/components/ui/navigation-menu/navigation-menu.tsx +0 -142
  132. package/dist/frontend-core/template/src/components/ui/pagination/pagination.stories.tsx +0 -49
  133. package/dist/frontend-core/template/src/components/ui/pagination/pagination.tsx +0 -84
  134. package/dist/frontend-core/template/src/components/ui/popover/popover.stories.tsx +0 -82
  135. package/dist/frontend-core/template/src/components/ui/popover/popover.tsx +0 -55
  136. package/dist/frontend-core/template/src/components/ui/progress/progress.stories.tsx +0 -80
  137. package/dist/frontend-core/template/src/components/ui/progress/progress.tsx +0 -17
  138. package/dist/frontend-core/template/src/components/ui/radio-group/radio-group.stories.tsx +0 -154
  139. package/dist/frontend-core/template/src/components/ui/radio-group/radio-group.tsx +0 -68
  140. package/dist/frontend-core/template/src/components/ui/resizable/resizable.stories.tsx +0 -73
  141. package/dist/frontend-core/template/src/components/ui/resizable/resizeable.tsx +0 -38
  142. package/dist/frontend-core/template/src/components/ui/scroll-area/scroll-area.stories.tsx +0 -55
  143. package/dist/frontend-core/template/src/components/ui/scroll-area/scroll-area.tsx +0 -39
  144. package/dist/frontend-core/template/src/components/ui/select/select.stories.tsx +0 -297
  145. package/dist/frontend-core/template/src/components/ui/select/select.tsx +0 -227
  146. package/dist/frontend-core/template/src/components/ui/separator/separator.tsx +0 -21
  147. package/dist/frontend-core/template/src/components/ui/separator/seperator.stories.tsx +0 -25
  148. package/dist/frontend-core/template/src/components/ui/sheet/sheet.stories.tsx +0 -45
  149. package/dist/frontend-core/template/src/components/ui/sheet/sheet.tsx +0 -107
  150. package/dist/frontend-core/template/src/components/ui/skeleton/skeleton.stories.tsx +0 -26
  151. package/dist/frontend-core/template/src/components/ui/skeleton/skeleton.tsx +0 -7
  152. package/dist/frontend-core/template/src/components/ui/slider/slider.stories.tsx +0 -101
  153. package/dist/frontend-core/template/src/components/ui/slider/slider.tsx +0 -98
  154. package/dist/frontend-core/template/src/components/ui/spinner/spinner.stories.tsx +0 -19
  155. package/dist/frontend-core/template/src/components/ui/spinner/spinner.tsx +0 -21
  156. package/dist/frontend-core/template/src/components/ui/switch/switch.stories.tsx +0 -33
  157. package/dist/frontend-core/template/src/components/ui/switch/switch.tsx +0 -28
  158. package/dist/frontend-core/template/src/components/ui/tabs/tabs.stories.tsx +0 -215
  159. package/dist/frontend-core/template/src/components/ui/tabs/tabs.tsx +0 -70
  160. package/dist/frontend-core/template/src/components/ui/textarea/textarea.stories.tsx +0 -138
  161. package/dist/frontend-core/template/src/components/ui/textarea/textarea.tsx +0 -40
  162. package/dist/frontend-core/template/src/components/ui/toast/toast.mdx +0 -31
  163. package/dist/frontend-core/template/src/components/ui/toast/toast.stories.tsx +0 -89
  164. package/dist/frontend-core/template/src/components/ui/toggle/toggle.stories.tsx +0 -65
  165. package/dist/frontend-core/template/src/components/ui/toggle/toggle.tsx +0 -38
  166. package/dist/frontend-core/template/src/components/ui/toggle-group/toggle-group.stories.tsx +0 -85
  167. package/dist/frontend-core/template/src/components/ui/toggle-group/toggle-group.tsx +0 -54
  168. package/dist/frontend-core/template/src/components/ui/tooltip/tooltip.stories.tsx +0 -29
  169. package/dist/frontend-core/template/src/components/ui/tooltip/tooltip.tsx +0 -29
@@ -1,330 +0,0 @@
1
- /* Modified DateRangePicker based DateRangePicker by John Polacek (https://github.com/johnpolacek/date-range-picker-for-shadcn) (MIT License) */
2
-
3
- import { CalendarIcon, Cross2Icon } from '@radix-ui/react-icons'
4
-
5
- import React, { useEffect, useState } from 'react'
6
-
7
- import { Button } from '@components/ui/button/button'
8
- import { Calendar } from '@components/ui/calendar/calendar'
9
- import { Popover, PopoverContent, PopoverTrigger } from '@components/ui/popover/popover'
10
- import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@components/ui/select/select'
11
- import { cn } from '@lib/utils'
12
-
13
- export type GanttTimerangePickerProps = {
14
- initialDateFrom?: Date
15
- initialDateTo?: Date
16
- // onRangeChange now receives ISO string date range (UTC-normalized) or undefined
17
- onRangeChange?: (values: ISODateRange | undefined) => void
18
- timelineStart?: Date
19
- timelineEnd?: Date
20
- }
21
-
22
- type DateRange = {
23
- from?: Date
24
- to?: Date
25
- }
26
-
27
- // ISODateRange with ISO string dates for UTC-normalized range for querying
28
- export type ISODateRange = {
29
- from?: string
30
- to?: string
31
- }
32
-
33
- // reusable helper: convert an ISO UTC-normalized date string back to a local Date
34
- export const isoToLocalDate = (iso?: string): Date | undefined => {
35
- if (!iso) {
36
- return undefined
37
- }
38
- const d = new Date(iso) // parse ISO instant
39
- // build a local Date that has the same calendar day as the UTC date parts
40
- return new Date(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate())
41
- }
42
-
43
- // helper to convert internal Date range to ISO strings normalized to UTC start/end of day
44
- const convertRangeToISO = (r?: { from?: Date; to?: Date } | undefined): ISODateRange | undefined => {
45
- if (!(r?.from && r?.to)) {
46
- return undefined
47
- }
48
- const from = r.from
49
- const to = r.to
50
-
51
- const fromIso = new Date(
52
- Date.UTC(from.getUTCFullYear(), from.getUTCMonth(), from.getUTCDate(), 0, 0, 0, 0),
53
- ).toISOString()
54
- const toIso = new Date(
55
- Date.UTC(to.getUTCFullYear(), to.getUTCMonth(), to.getUTCDate(), 23, 59, 59, 999),
56
- ).toISOString()
57
-
58
- return { from: fromIso, to: toIso }
59
- }
60
-
61
- type Preset = {
62
- name: string
63
- label: string
64
- }
65
-
66
- const PRESETS: Preset[] = [
67
- { name: 'sinceStart', label: 'Since timeline start' },
68
- { name: 'thisYear', label: 'This year' },
69
- { name: 'nextFullYear', label: 'Next full year' },
70
- { name: 'next1Year', label: 'Next 1 year' },
71
- { name: 'next2Year', label: 'Next 2 years' },
72
- { name: 'next3Year', label: 'Next 3 years' },
73
- { name: 'untilEnd', label: 'Until timeline end' },
74
- ]
75
-
76
- export const GanttTimerangePicker = ({
77
- initialDateFrom,
78
- initialDateTo,
79
- onRangeChange,
80
- timelineStart,
81
- timelineEnd,
82
- }: GanttTimerangePickerProps) => {
83
- const [range, setRange] = useState<DateRange | undefined>(
84
- initialDateFrom || initialDateTo ? { from: initialDateFrom, to: initialDateTo } : undefined,
85
- )
86
- const [isOpen, setIsOpen] = useState(false)
87
- const [selectedPreset, setSelectedPreset] = useState<string | undefined>(undefined)
88
- const [isSmallScreen, setIsSmallScreen] = useState(
89
- globalThis.window === undefined ? false : globalThis.window.innerWidth < 960,
90
- )
91
-
92
- // listen to window resize events to enable a small screen mode
93
- useEffect(() => {
94
- const handleResize = (): void => {
95
- setIsSmallScreen(globalThis.window.innerWidth < 960)
96
- }
97
- globalThis.window.addEventListener('resize', handleResize)
98
- // Clean up event listener on unmount
99
- return () => {
100
- globalThis.window.removeEventListener('resize', handleResize)
101
- }
102
- }, [])
103
-
104
- const getPresetRange = (presetName: string, timelineStart?: Date, timelineEnd?: Date): DateRange => {
105
- const preset = PRESETS.find(({ name }) => name === presetName)
106
- if (!preset) {
107
- throw new Error(`Unknown date range preset: ${presetName}`)
108
- }
109
- const from = new Date()
110
- const to = new Date()
111
-
112
- switch (preset.name) {
113
- case 'sinceStart':
114
- if (timelineStart) {
115
- from.setFullYear(timelineStart.getFullYear(), timelineStart.getMonth(), timelineStart.getDate())
116
- }
117
- from.setHours(0, 0, 0, 0)
118
- to.setHours(23, 59, 59, 999)
119
- break
120
- case 'thisYear':
121
- from.setFullYear(from.getFullYear(), 0, 1)
122
- from.setHours(0, 0, 0, 0)
123
- to.setFullYear(to.getFullYear(), 11, 31)
124
- to.setHours(23, 59, 59, 999)
125
- break
126
- case 'nextFullYear':
127
- from.setFullYear(from.getFullYear() + 1, 0, 1)
128
- from.setHours(0, 0, 0, 0)
129
- to.setFullYear(to.getFullYear() + 1, 11, 31)
130
- to.setHours(23, 59, 59, 999)
131
- break
132
- case 'next1Year':
133
- from.setHours(0, 0, 0, 0)
134
- to.setFullYear(to.getFullYear() + 1)
135
- to.setHours(23, 59, 59, 999)
136
- break
137
- case 'next2Year':
138
- from.setHours(0, 0, 0, 0)
139
- to.setFullYear(to.getFullYear() + 2)
140
- to.setHours(23, 59, 59, 999)
141
- break
142
- case 'next3Year':
143
- from.setHours(0, 0, 0, 0)
144
- to.setFullYear(to.getFullYear() + 3)
145
- to.setHours(23, 59, 59, 999)
146
- break
147
- case 'untilEnd':
148
- from.setHours(0, 0, 0, 0)
149
- if (timelineEnd) {
150
- to.setFullYear(timelineEnd.getFullYear(), timelineEnd.getMonth(), timelineEnd.getDate())
151
- }
152
- to.setHours(23, 59, 59, 999)
153
- break
154
- }
155
-
156
- return { from, to }
157
- }
158
-
159
- // automatically detect selected preset when range changes (internal Date range)
160
- useEffect(() => {
161
- if (!range?.from || !range.to) {
162
- setSelectedPreset(undefined)
163
- return
164
- }
165
- for (const preset of PRESETS) {
166
- const presetRange = getPresetRange(preset.name, timelineStart, timelineEnd)
167
- if (!presetRange.from || !presetRange.to) {
168
- continue
169
- }
170
-
171
- const normalizedRangeFrom = new Date(range.from)
172
- normalizedRangeFrom.setHours(0, 0, 0, 0)
173
- const normalizedPresetFrom = new Date(presetRange.from)
174
- normalizedPresetFrom.setHours(0, 0, 0, 0)
175
-
176
- const normalizedRangeTo = new Date(range.to)
177
- normalizedRangeTo.setHours(0, 0, 0, 0)
178
- const normalizedPresetTo = new Date(presetRange.to)
179
- normalizedPresetTo.setHours(0, 0, 0, 0)
180
-
181
- if (
182
- normalizedRangeFrom.getTime() === normalizedPresetFrom.getTime() &&
183
- normalizedRangeTo.getTime() === normalizedPresetTo.getTime()
184
- ) {
185
- setSelectedPreset(preset.name)
186
- return
187
- }
188
- }
189
- setSelectedPreset(undefined)
190
- }, [range, timelineStart, timelineEnd])
191
-
192
- return (
193
- <Popover
194
- modal={true}
195
- open={isOpen}
196
- onOpenChange={(isOpen) => {
197
- setIsOpen(isOpen)
198
- // on close, emit ISO-normalized range
199
- if (!isOpen) {
200
- onRangeChange?.(convertRangeToISO(range))
201
- }
202
- }}
203
- >
204
- <PopoverTrigger asChild>
205
- <Button size="iconSm" variant="extraGhost2">
206
- <CalendarIcon className="size-3" />
207
- </Button>
208
- </PopoverTrigger>
209
- <PopoverContent align="start" className="w-auto p-2 m-2 relative">
210
- <div className="flex justify-between items-center">
211
- <span className="pl-2">
212
- {range?.from && range?.to
213
- ? `${range.from.toLocaleDateString()} - ${range.to.toLocaleDateString()} selected`
214
- : 'No range selected'}
215
- </span>
216
- <Button
217
- variant="outline"
218
- size="icon"
219
- className="size-6 rounded"
220
- onClick={() => {
221
- setIsOpen(false)
222
- }}
223
- >
224
- <Cross2Icon className="size-5" />
225
- </Button>
226
- </div>
227
- <div className="flex">
228
- <div className="flex">
229
- <div className="flex flex-col">
230
- {isSmallScreen && (
231
- <Select
232
- defaultValue={selectedPreset}
233
- onValueChange={(value) => {
234
- setRange(getPresetRange(value))
235
- }}
236
- >
237
- <SelectTrigger size="xs" className="w-[180px] mx-auto mt-2">
238
- <SelectValue placeholder="Select..." />
239
- </SelectTrigger>
240
- <SelectContent>
241
- {PRESETS.map((preset) => (
242
- <SelectItem key={preset.name} value={preset.name}>
243
- {preset.label}
244
- </SelectItem>
245
- ))}
246
- </SelectContent>
247
- </Select>
248
- )}
249
- <div className={cn('h-[325px]', isSmallScreen && 'mb-8')}>
250
- <Calendar
251
- mode="range"
252
- showYearNavigation={true}
253
- disabled={(date) =>
254
- (timelineStart ? date < timelineStart : false) || (timelineEnd ? date > timelineEnd : false)
255
- }
256
- onSelect={(value: { from?: Date; to?: Date } | undefined) => {
257
- if (value?.from != null) {
258
- const from = value.from
259
- const to = value.to ?? value.from
260
- // Normalize the range so that from <= to
261
- setRange(to < from ? { from: to, to: from } : { from, to })
262
- }
263
- }}
264
- selected={range?.from && range?.to ? { from: range.from, to: range.to } : undefined}
265
- numberOfMonths={isSmallScreen ? 1 : 2}
266
- defaultMonth={new Date(new Date().setMonth(new Date().getMonth() - (isSmallScreen ? 0 : 1)))}
267
- />
268
- </div>
269
- </div>
270
- </div>
271
- {!isSmallScreen && (
272
- <div className="flex flex-col items-start gap-1 pr-2 pl-12 py-3">
273
- {PRESETS.map((preset) => (
274
- <PresetButton
275
- key={preset.name}
276
- preset={preset.name}
277
- label={preset.label}
278
- isSelected={selectedPreset === preset.name}
279
- onSelect={(presetName) => setRange(getPresetRange(presetName))}
280
- />
281
- ))}
282
- </div>
283
- )}
284
- </div>
285
- <div className="flex gap-2 absolute bottom-3 right-3">
286
- <Button
287
- variant="outlineInvert"
288
- size="smLow"
289
- className=""
290
- onClick={() => {
291
- setRange(undefined)
292
- }}
293
- >
294
- Clear Range
295
- </Button>
296
- <Button
297
- size="smLow"
298
- onClick={() => {
299
- setIsOpen(false)
300
- onRangeChange?.(convertRangeToISO(range))
301
- }}
302
- >
303
- Apply
304
- </Button>
305
- </div>
306
- </PopoverContent>
307
- </Popover>
308
- )
309
- }
310
-
311
- const PresetButton = ({
312
- preset,
313
- label,
314
- isSelected,
315
- onSelect,
316
- }: {
317
- preset: string
318
- label: string
319
- isSelected: boolean
320
- onSelect: (preset: string) => void
321
- }): React.ReactNode => (
322
- <Button
323
- className={`w-full justify-start ${isSelected ? 'pointer-events-none bg-accent' : ''}`}
324
- variant="ghost"
325
- size="smLow"
326
- onClick={() => onSelect(preset)}
327
- >
328
- {label}
329
- </Button>
330
- )
@@ -1,212 +0,0 @@
1
- 'use client'
2
-
3
- import type { Cell, Table } from '@tanstack/react-table'
4
-
5
- import * as React from 'react'
6
-
7
- import { cn } from '@lib/utils'
8
-
9
- type DataGridCellWrapperProps<TData> = {
10
- cell: Cell<TData, unknown>
11
- table: Table<TData>
12
- rowIndex: number
13
- columnId: string
14
- isEditing: boolean
15
- isFocused: boolean
16
- isSelected: boolean
17
- } & React.ComponentProps<'div'>
18
-
19
- export function DataGridCellWrapper<TData>({
20
- cell,
21
- table,
22
- rowIndex,
23
- columnId,
24
- isEditing,
25
- isFocused,
26
- isSelected,
27
- className,
28
- onClick: onClickProp,
29
- onKeyDown: onKeyDownProp,
30
- ...props
31
- }: DataGridCellWrapperProps<TData>) {
32
- const meta = table.options.meta
33
-
34
- const rowOriginal = (cell?.row?.original ?? {}) as any
35
- const colCellMeta = cell?.column?.columnDef?.meta as any
36
- const align: 'left' | 'right' | 'center' = colCellMeta?.align ?? 'left'
37
-
38
- // Normalize editable to a resolver function and memoize to avoid typeof checks per cell
39
- const editableResolver = React.useMemo(() => {
40
- const v = colCellMeta?.editable
41
- if (v === undefined) {
42
- return () => true
43
- }
44
- return typeof v === 'function' ? (v as (row: TData) => boolean) : () => Boolean(v)
45
- }, [colCellMeta?.editable])
46
- const isEditable = editableResolver(rowOriginal)
47
-
48
- // Normalize className to a resolver function and memoize to avoid typeof checks per cell
49
- const classNameResolver = React.useMemo(() => {
50
- const v = colCellMeta?.className
51
- return typeof v === 'function' ? (v as (row: any) => string | undefined) : () => v as string | undefined
52
- }, [colCellMeta?.className])
53
- const colCellClassName = classNameResolver(rowOriginal)
54
-
55
- const isSearchMatch = meta?.getIsSearchMatch?.(rowIndex, columnId) ?? false
56
- const isActiveSearchMatch = meta?.getIsActiveSearchMatch?.(rowIndex, columnId) ?? false
57
-
58
- const onClick = React.useCallback(
59
- (event: React.MouseEvent<HTMLDivElement>) => {
60
- if (!isEditing) {
61
- event.preventDefault()
62
- onClickProp?.(event)
63
- if (isFocused) {
64
- if (isEditable) {
65
- meta?.onCellEditingStart?.(rowIndex, columnId)
66
- }
67
- } else {
68
- meta?.onCellClick?.(rowIndex, columnId, event)
69
- }
70
- }
71
- },
72
- [meta, rowIndex, columnId, isEditing, isFocused, onClickProp, isEditable],
73
- )
74
-
75
- const onContextMenu = React.useCallback(
76
- (event: React.MouseEvent) => {
77
- if (!isEditing) {
78
- meta?.onCellContextMenu?.(rowIndex, columnId, event)
79
- }
80
- },
81
- [meta, rowIndex, columnId, isEditing],
82
- )
83
-
84
- const onMouseDown = React.useCallback(
85
- (event: React.MouseEvent) => {
86
- if (!isEditing) {
87
- meta?.onCellMouseDown?.(rowIndex, columnId, event)
88
- }
89
- },
90
- [meta, rowIndex, columnId, isEditing],
91
- )
92
-
93
- const onMouseEnter = React.useCallback(
94
- (event: React.MouseEvent) => {
95
- if (!isEditing) {
96
- meta?.onCellMouseEnter?.(rowIndex, columnId, event)
97
- }
98
- },
99
- [meta, rowIndex, columnId, isEditing],
100
- )
101
-
102
- const onMouseUp = React.useCallback(() => {
103
- if (!isEditing) {
104
- meta?.onCellMouseUp?.()
105
- }
106
- }, [meta, isEditing])
107
-
108
- const onDoubleClick = React.useCallback(
109
- (event: React.MouseEvent) => {
110
- if (!isEditing) {
111
- event.preventDefault()
112
- if (isEditable) {
113
- meta?.onCellDoubleClick?.(rowIndex, columnId)
114
- }
115
- }
116
- },
117
- [meta, rowIndex, columnId, isEditing, isEditable],
118
- )
119
-
120
- const onKeyDown = React.useCallback(
121
- (event: React.KeyboardEvent<HTMLDivElement>) => {
122
- onKeyDownProp?.(event)
123
-
124
- if (event.defaultPrevented) {
125
- return
126
- }
127
-
128
- if (
129
- event.key === 'ArrowUp' ||
130
- event.key === 'ArrowDown' ||
131
- event.key === 'ArrowLeft' ||
132
- event.key === 'ArrowRight' ||
133
- event.key === 'Home' ||
134
- event.key === 'End' ||
135
- event.key === 'PageUp' ||
136
- event.key === 'PageDown' ||
137
- event.key === 'Tab'
138
- ) {
139
- return
140
- }
141
-
142
- if (isFocused && !isEditing) {
143
- if (event.key === 'F2' || event.key === 'Enter') {
144
- event.preventDefault()
145
- event.stopPropagation()
146
- if (isEditable) {
147
- meta?.onCellEditingStart?.(rowIndex, columnId)
148
- }
149
- return
150
- }
151
-
152
- if (event.key === '') {
153
- event.preventDefault()
154
- event.stopPropagation()
155
- meta?.onCellEditingStart?.(rowIndex, columnId)
156
- return
157
- }
158
-
159
- if (event.key.length === 1 && !event.ctrlKey && !event.metaKey) {
160
- event.preventDefault()
161
- event.stopPropagation()
162
- if (isEditable) {
163
- meta?.onCellEditingStart?.(rowIndex, columnId)
164
- }
165
- }
166
- }
167
- },
168
- [onKeyDownProp, isFocused, isEditing, meta, rowIndex, columnId, isEditable],
169
- )
170
-
171
- const rowHeight = meta?.rowHeight ?? 'short'
172
-
173
- return (
174
- <div
175
- role="button"
176
- data-slot="grid-cell-wrapper"
177
- data-editing={isEditing ? '' : undefined}
178
- data-focused={isFocused ? '' : undefined}
179
- data-selected={isSelected ? '' : undefined}
180
- tabIndex={isFocused && !isEditing ? 0 : -1}
181
- className={cn(
182
- 'size-full px-2 py-1.5 text-sm outline-none -has-data-[slot=checkbox]:pt-2.5', // why has-data-[slot=checkbox] ?
183
- {
184
- 'text-left': align === 'left',
185
- 'text-right': align === 'right',
186
- 'text-center': align === 'center',
187
- },
188
- {
189
- 'ring-1 ring-foreground ring-inset dark:ring-secondary-foreground': isFocused,
190
- 'bg-yellow-100 dark:bg-yellow-900/30': isSearchMatch && !isActiveSearchMatch,
191
- 'bg-orange-200 dark:bg-orange-900/50': isActiveSearchMatch,
192
- 'bg-accent-foreground/10': isSelected && !isEditing,
193
- 'cursor-default': !isEditing,
194
- '**:data-[slot=grid-cell-content]:line-clamp-1': !isEditing && rowHeight === 'short',
195
- '**:data-[slot=grid-cell-content]:line-clamp-2': !isEditing && rowHeight === 'medium',
196
- '**:data-[slot=grid-cell-content]:line-clamp-3': !isEditing && rowHeight === 'tall',
197
- '**:data-[slot=grid-cell-content]:line-clamp-4': !isEditing && rowHeight === 'extra-tall',
198
- },
199
- colCellClassName,
200
- className,
201
- )}
202
- onClick={onClick}
203
- onContextMenu={onContextMenu}
204
- onDoubleClick={onDoubleClick}
205
- onMouseDown={onMouseDown}
206
- onMouseEnter={onMouseEnter}
207
- onMouseUp={onMouseUp}
208
- onKeyDown={onKeyDown}
209
- {...props}
210
- />
211
- )
212
- }
@@ -1,157 +0,0 @@
1
- import type { Cell, Table } from '@tanstack/react-table'
2
-
3
- import { CheckboxCell } from './cell-variants/checkbox-cell'
4
- import { DateCell } from './cell-variants/date-cell'
5
- import { GanttCell } from './cell-variants/gantt-cell'
6
- import { LongTextCell } from './cell-variants/long-text-cell'
7
- import { MultiSelectCell } from './cell-variants/multi-select-cell'
8
- import { NumberCell } from './cell-variants/number-cell'
9
- import { ReactNodeCell } from './cell-variants/react-node-cell'
10
- import { SelectCell } from './cell-variants/select-cell'
11
- import { ShortTextCell } from './cell-variants/short-text-cell'
12
-
13
- type DataGridCellProps<TData> = {
14
- cell: Cell<TData, unknown>
15
- table: Table<TData>
16
- }
17
-
18
- export function DataGridCell<TData>({ cell, table }: DataGridCellProps<TData>) {
19
- const meta = table.options.meta
20
- const originalRowIndex = cell.row.index
21
-
22
- const rows = table.getRowModel().rows
23
- const displayRowIndex = rows.findIndex((row) => row.original === cell.row.original)
24
- const rowIndex = displayRowIndex >= 0 ? displayRowIndex : originalRowIndex
25
- const columnId = cell.column.id
26
-
27
- const isFocused = meta?.focusedCell?.rowIndex === rowIndex && meta?.focusedCell?.columnId === columnId
28
- const isEditing = meta?.editingCell?.rowIndex === rowIndex && meta?.editingCell?.columnId === columnId
29
- const isSelected = meta?.getIsCellSelected?.(rowIndex, columnId) ?? false
30
-
31
- const cellOpts = cell.column.columnDef.meta?.cell
32
- const variant = cellOpts?.variant ?? 'text'
33
-
34
- switch (variant) {
35
- case 'short-text':
36
- return (
37
- <ShortTextCell
38
- cell={cell as Cell<TData, string>}
39
- table={table}
40
- rowIndex={rowIndex}
41
- columnId={columnId}
42
- isEditing={isEditing}
43
- isFocused={isFocused}
44
- isSelected={isSelected}
45
- />
46
- )
47
- case 'long-text':
48
- return (
49
- <LongTextCell
50
- cell={cell as Cell<TData, string>}
51
- table={table}
52
- rowIndex={rowIndex}
53
- columnId={columnId}
54
- isEditing={isEditing}
55
- isFocused={isFocused}
56
- isSelected={isSelected}
57
- />
58
- )
59
- case 'number':
60
- return (
61
- <NumberCell
62
- cell={cell as Cell<TData, number>}
63
- table={table}
64
- rowIndex={rowIndex}
65
- columnId={columnId}
66
- isEditing={isEditing}
67
- isFocused={isFocused}
68
- isSelected={isSelected}
69
- />
70
- )
71
- case 'select':
72
- return (
73
- <SelectCell
74
- cell={cell as Cell<TData, string>}
75
- table={table}
76
- rowIndex={rowIndex}
77
- columnId={columnId}
78
- isEditing={isEditing}
79
- isFocused={isFocused}
80
- isSelected={isSelected}
81
- />
82
- )
83
- case 'multi-select':
84
- return (
85
- <MultiSelectCell
86
- cell={cell as Cell<TData, string[]>}
87
- table={table}
88
- rowIndex={rowIndex}
89
- columnId={columnId}
90
- isEditing={isEditing}
91
- isFocused={isFocused}
92
- isSelected={isSelected}
93
- />
94
- )
95
- case 'checkbox':
96
- return (
97
- <CheckboxCell
98
- cell={cell as Cell<TData, boolean>}
99
- table={table}
100
- rowIndex={rowIndex}
101
- columnId={columnId}
102
- isEditing={isEditing}
103
- isFocused={isFocused}
104
- isSelected={isSelected}
105
- />
106
- )
107
- case 'date':
108
- return (
109
- <DateCell
110
- cell={cell as Cell<TData, string>}
111
- table={table}
112
- rowIndex={rowIndex}
113
- columnId={columnId}
114
- isEditing={isEditing}
115
- isFocused={isFocused}
116
- isSelected={isSelected}
117
- />
118
- )
119
- case 'react-node':
120
- return (
121
- <ReactNodeCell
122
- cell={cell as Cell<TData, React.ReactNode>}
123
- table={table}
124
- rowIndex={rowIndex}
125
- columnId={columnId}
126
- isEditing={isEditing}
127
- isFocused={isFocused}
128
- isSelected={isSelected}
129
- />
130
- )
131
- case 'gantt':
132
- return (
133
- <GanttCell
134
- cell={cell as Cell<TData, { start: Date; end: Date } | null>}
135
- table={table}
136
- rowIndex={rowIndex}
137
- columnId={columnId}
138
- isEditing={isEditing}
139
- isFocused={isFocused}
140
- isSelected={isSelected}
141
- />
142
- )
143
-
144
- default:
145
- return (
146
- <ShortTextCell
147
- cell={cell as Cell<TData, string>}
148
- table={table}
149
- rowIndex={rowIndex}
150
- columnId={columnId}
151
- isEditing={isEditing}
152
- isFocused={isFocused}
153
- isSelected={isSelected}
154
- />
155
- )
156
- }
157
- }