@postxl/generators 1.1.1 → 1.2.1

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 (181) hide show
  1. package/dist/backend-core/backend.generator.js +4 -1
  2. package/dist/backend-core/backend.generator.js.map +1 -1
  3. package/dist/backend-core/generators/jest.config.generator.d.ts +2 -0
  4. package/dist/backend-core/{template/jest.config.ts → generators/jest.config.generator.js} +12 -8
  5. package/dist/backend-core/generators/jest.config.generator.js.map +1 -0
  6. package/dist/backend-core/generators/tsconfig.generator.d.ts +1 -1
  7. package/dist/backend-core/generators/tsconfig.generator.js +1 -9
  8. package/dist/backend-core/generators/tsconfig.generator.js.map +1 -1
  9. package/dist/backend-core/types.d.ts +2 -0
  10. package/dist/base/base.generator.js +12 -8
  11. package/dist/base/base.generator.js.map +1 -1
  12. package/dist/e2e/template/e2e/package.json +1 -1
  13. package/dist/e2e/template/e2e/specs/example.spec.ts +1 -1
  14. package/dist/e2e/template/e2e/specs/example.spec.ts-snapshots/Navigate-to-homepage-and-take-snapshot-1-chromium-linux.png +0 -0
  15. package/dist/frontend-core/frontend.generator.d.ts +0 -58
  16. package/dist/frontend-core/frontend.generator.js +9 -173
  17. package/dist/frontend-core/frontend.generator.js.map +1 -1
  18. package/dist/frontend-core/generators/tsconfig.generator.js +2 -0
  19. package/dist/frontend-core/generators/tsconfig.generator.js.map +1 -1
  20. package/dist/frontend-core/template/README.md +1 -1
  21. package/dist/frontend-core/template/src/components/admin/table-filter.tsx +1 -5
  22. package/dist/frontend-core/template/src/components/ui/color-mode-toggle/color-mode-toggle.tsx +10 -4
  23. package/dist/frontend-core/template/src/lib/query-client.ts +45 -4
  24. package/dist/frontend-core/template/src/pages/dashboard/dashboard.page.tsx +2 -3
  25. package/dist/frontend-core/template/src/pages/error/default-error.page.tsx +45 -12
  26. package/dist/frontend-core/template/src/pages/error/not-found-error.page.tsx +1 -1
  27. package/dist/frontend-core/template/src/styles/styles.css +13 -1
  28. package/dist/frontend-core/template/tsconfig.json +2 -0
  29. package/dist/frontend-core/types/component.d.ts +1 -1
  30. package/dist/frontend-forms/generators/discriminated-union/fields.generator.js +4 -6
  31. package/dist/frontend-forms/generators/discriminated-union/fields.generator.js.map +1 -1
  32. package/dist/frontend-forms/generators/discriminated-union/inputs.generator.js +1 -1
  33. package/dist/frontend-forms/generators/discriminated-union/inputs.generator.js.map +1 -1
  34. package/dist/frontend-forms/generators/enum/inputs.generator.js +1 -1
  35. package/dist/frontend-forms/generators/enum/inputs.generator.js.map +1 -1
  36. package/dist/frontend-forms/generators/model/forms.generator.js +8 -12
  37. package/dist/frontend-forms/generators/model/forms.generator.js.map +1 -1
  38. package/dist/frontend-forms/generators/model/inputs.generator.js +2 -6
  39. package/dist/frontend-forms/generators/model/inputs.generator.js.map +1 -1
  40. package/dist/frontend-forms/template/src/components/ui/field/field.tsx +1 -4
  41. package/dist/frontend-tables/generators/model-table.generator.js +1 -5
  42. package/dist/frontend-tables/generators/model-table.generator.js.map +1 -1
  43. package/package.json +4 -3
  44. package/dist/e2e/generators/package-json.generator.d.ts +0 -2
  45. package/dist/e2e/generators/package-json.generator.js +0 -29
  46. package/dist/e2e/generators/package-json.generator.js.map +0 -1
  47. package/dist/frontend-core/template/src/components/ui/accordion/accordion.stories.tsx +0 -47
  48. package/dist/frontend-core/template/src/components/ui/accordion/accordion.tsx +0 -52
  49. package/dist/frontend-core/template/src/components/ui/admin-sidebar/admin-sidebar.tsx +0 -195
  50. package/dist/frontend-core/template/src/components/ui/alert/alert.stories.tsx +0 -61
  51. package/dist/frontend-core/template/src/components/ui/alert/alert.tsx +0 -45
  52. package/dist/frontend-core/template/src/components/ui/alert-dialog/alert-dialog.stories.tsx +0 -52
  53. package/dist/frontend-core/template/src/components/ui/alert-dialog/alert-dialog.tsx +0 -105
  54. package/dist/frontend-core/template/src/components/ui/avatar/avatar.stories.tsx +0 -30
  55. package/dist/frontend-core/template/src/components/ui/avatar/avatar.tsx +0 -39
  56. package/dist/frontend-core/template/src/components/ui/badge/badge.stories.tsx +0 -78
  57. package/dist/frontend-core/template/src/components/ui/badge/badge.tsx +0 -48
  58. package/dist/frontend-core/template/src/components/ui/breadcrumb/breadcrumb.stories.tsx +0 -67
  59. package/dist/frontend-core/template/src/components/ui/breadcrumb/breadcrumb.tsx +0 -85
  60. package/dist/frontend-core/template/src/components/ui/button/button.stories.tsx +0 -150
  61. package/dist/frontend-core/template/src/components/ui/button/button.tsx +0 -68
  62. package/dist/frontend-core/template/src/components/ui/calendar/calendar.stories.tsx +0 -160
  63. package/dist/frontend-core/template/src/components/ui/calendar/calendar.tsx +0 -293
  64. package/dist/frontend-core/template/src/components/ui/card/card.stories.tsx +0 -77
  65. package/dist/frontend-core/template/src/components/ui/card/card.tsx +0 -45
  66. package/dist/frontend-core/template/src/components/ui/card-hover/card-hover.stories.tsx +0 -29
  67. package/dist/frontend-core/template/src/components/ui/card-hover/card-hover.tsx +0 -28
  68. package/dist/frontend-core/template/src/components/ui/carousel/carousel.stories.tsx +0 -154
  69. package/dist/frontend-core/template/src/components/ui/carousel/carousel.tsx +0 -227
  70. package/dist/frontend-core/template/src/components/ui/checkbox/checkbox.stories.tsx +0 -106
  71. package/dist/frontend-core/template/src/components/ui/checkbox/checkbox.tsx +0 -88
  72. package/dist/frontend-core/template/src/components/ui/checkbox/shadcn-checkbox.stories.tsx +0 -90
  73. package/dist/frontend-core/template/src/components/ui/checkbox/shadcn-checkbox.tsx +0 -54
  74. package/dist/frontend-core/template/src/components/ui/collapse/collapse.stories.tsx +0 -52
  75. package/dist/frontend-core/template/src/components/ui/collapse/collapse.tsx +0 -9
  76. package/dist/frontend-core/template/src/components/ui/combobox/combobox.stories.tsx +0 -207
  77. package/dist/frontend-core/template/src/components/ui/combobox/combobox.tsx +0 -79
  78. package/dist/frontend-core/template/src/components/ui/command/command.stories.tsx +0 -186
  79. package/dist/frontend-core/template/src/components/ui/command/command.tsx +0 -165
  80. package/dist/frontend-core/template/src/components/ui/command-palette/command-palette.stories.tsx +0 -160
  81. package/dist/frontend-core/template/src/components/ui/command-palette/command-palette.tsx +0 -134
  82. package/dist/frontend-core/template/src/components/ui/content-frame/content-frame.stories.tsx +0 -198
  83. package/dist/frontend-core/template/src/components/ui/content-frame/content-frame.tsx +0 -100
  84. package/dist/frontend-core/template/src/components/ui/context-menu/context-menu.stories.tsx +0 -78
  85. package/dist/frontend-core/template/src/components/ui/context-menu/context-menu.tsx +0 -179
  86. package/dist/frontend-core/template/src/components/ui/data-grid/cell-variants/cell-variant-types.ts +0 -11
  87. package/dist/frontend-core/template/src/components/ui/data-grid/cell-variants/checkbox-cell.tsx +0 -116
  88. package/dist/frontend-core/template/src/components/ui/data-grid/cell-variants/date-cell.tsx +0 -157
  89. package/dist/frontend-core/template/src/components/ui/data-grid/cell-variants/gantt-cell.tsx +0 -82
  90. package/dist/frontend-core/template/src/components/ui/data-grid/cell-variants/long-text-cell.tsx +0 -180
  91. package/dist/frontend-core/template/src/components/ui/data-grid/cell-variants/multi-select-cell.tsx +0 -280
  92. package/dist/frontend-core/template/src/components/ui/data-grid/cell-variants/number-cell.tsx +0 -169
  93. package/dist/frontend-core/template/src/components/ui/data-grid/cell-variants/react-node-cell.tsx +0 -33
  94. package/dist/frontend-core/template/src/components/ui/data-grid/cell-variants/select-cell.tsx +0 -175
  95. package/dist/frontend-core/template/src/components/ui/data-grid/cell-variants/short-text-cell.tsx +0 -138
  96. package/dist/frontend-core/template/src/components/ui/data-grid/cell-variants/utils/gantt-timeline.tsx +0 -92
  97. package/dist/frontend-core/template/src/components/ui/data-grid/cell-variants/utils/gantt-timerange-picker.tsx +0 -330
  98. package/dist/frontend-core/template/src/components/ui/data-grid/data-grid-cell-wrapper.tsx +0 -212
  99. package/dist/frontend-core/template/src/components/ui/data-grid/data-grid-cell.tsx +0 -157
  100. package/dist/frontend-core/template/src/components/ui/data-grid/data-grid-column-header.tsx +0 -340
  101. package/dist/frontend-core/template/src/components/ui/data-grid/data-grid-context-menu.tsx +0 -271
  102. package/dist/frontend-core/template/src/components/ui/data-grid/data-grid-row.tsx +0 -123
  103. package/dist/frontend-core/template/src/components/ui/data-grid/data-grid-search.tsx +0 -211
  104. package/dist/frontend-core/template/src/components/ui/data-grid/data-grid-types.ts +0 -159
  105. package/dist/frontend-core/template/src/components/ui/data-grid/data-grid-utils.ts +0 -67
  106. package/dist/frontend-core/template/src/components/ui/data-grid/data-grid-view-menu.tsx +0 -360
  107. package/dist/frontend-core/template/src/components/ui/data-grid/data-grid.stories.tsx +0 -780
  108. package/dist/frontend-core/template/src/components/ui/data-grid/data-grid.tsx +0 -217
  109. package/dist/frontend-core/template/src/components/ui/data-grid/hooks/use-callback-ref.ts +0 -22
  110. package/dist/frontend-core/template/src/components/ui/data-grid/hooks/use-data-grid.tsx +0 -1892
  111. package/dist/frontend-core/template/src/components/ui/data-grid/hooks/use-debounced-callback.ts +0 -19
  112. package/dist/frontend-core/template/src/components/ui/data-grid/styles.css +0 -3
  113. package/dist/frontend-core/template/src/components/ui/data-table/context-menu-simple.tsx +0 -141
  114. package/dist/frontend-core/template/src/components/ui/data-table/data-table.stories.tsx +0 -146
  115. package/dist/frontend-core/template/src/components/ui/data-table/data-table.tsx +0 -447
  116. package/dist/frontend-core/template/src/components/ui/data-table/renderers/country-array-cell-renderer.tsx +0 -77
  117. package/dist/frontend-core/template/src/components/ui/data-table/renderers/country-cell-renderer.tsx +0 -56
  118. package/dist/frontend-core/template/src/components/ui/data-table/renderers/favorite-cell-renderer.tsx +0 -68
  119. package/dist/frontend-core/template/src/components/ui/data-table/renderers/links-cell-renderer.tsx +0 -205
  120. package/dist/frontend-core/template/src/components/ui/data-table/utils/columns.ts +0 -351
  121. package/dist/frontend-core/template/src/components/ui/data-table/utils/data-table.utils.ts +0 -49
  122. package/dist/frontend-core/template/src/components/ui/date-picker/date-picker.stories.tsx +0 -149
  123. package/dist/frontend-core/template/src/components/ui/date-picker/date-picker.tsx +0 -30
  124. package/dist/frontend-core/template/src/components/ui/dialog/dialog.stories.tsx +0 -80
  125. package/dist/frontend-core/template/src/components/ui/dialog/dialog.tsx +0 -134
  126. package/dist/frontend-core/template/src/components/ui/drawer/drawer.stories.tsx +0 -104
  127. package/dist/frontend-core/template/src/components/ui/drawer/drawer.tsx +0 -87
  128. package/dist/frontend-core/template/src/components/ui/dropdown-menu/dropdown-menu.stories.tsx +0 -168
  129. package/dist/frontend-core/template/src/components/ui/dropdown-menu/dropdown-menu.tsx +0 -225
  130. package/dist/frontend-core/template/src/components/ui/input/input.stories.tsx +0 -141
  131. package/dist/frontend-core/template/src/components/ui/input/input.tsx +0 -47
  132. package/dist/frontend-core/template/src/components/ui/label/label.stories.tsx +0 -41
  133. package/dist/frontend-core/template/src/components/ui/label/label.tsx +0 -20
  134. package/dist/frontend-core/template/src/components/ui/loader/loader.stories.tsx +0 -45
  135. package/dist/frontend-core/template/src/components/ui/loader/loader.tsx +0 -17
  136. package/dist/frontend-core/template/src/components/ui/mark-value-renderer/mark-value-renderer.stories.tsx +0 -114
  137. package/dist/frontend-core/template/src/components/ui/mark-value-renderer/mark-value-renderer.tsx +0 -48
  138. package/dist/frontend-core/template/src/components/ui/menubar/menu.stories.tsx +0 -134
  139. package/dist/frontend-core/template/src/components/ui/menubar/menubar.tsx +0 -208
  140. package/dist/frontend-core/template/src/components/ui/modal/modal.stories.tsx +0 -297
  141. package/dist/frontend-core/template/src/components/ui/modal/modal.tsx +0 -80
  142. package/dist/frontend-core/template/src/components/ui/navigation-menu/navigation-menu.stories.tsx +0 -213
  143. package/dist/frontend-core/template/src/components/ui/navigation-menu/navigation-menu.tsx +0 -142
  144. package/dist/frontend-core/template/src/components/ui/pagination/pagination.stories.tsx +0 -49
  145. package/dist/frontend-core/template/src/components/ui/pagination/pagination.tsx +0 -84
  146. package/dist/frontend-core/template/src/components/ui/popover/popover.stories.tsx +0 -82
  147. package/dist/frontend-core/template/src/components/ui/popover/popover.tsx +0 -55
  148. package/dist/frontend-core/template/src/components/ui/progress/progress.stories.tsx +0 -80
  149. package/dist/frontend-core/template/src/components/ui/progress/progress.tsx +0 -17
  150. package/dist/frontend-core/template/src/components/ui/radio-group/radio-group.stories.tsx +0 -154
  151. package/dist/frontend-core/template/src/components/ui/radio-group/radio-group.tsx +0 -68
  152. package/dist/frontend-core/template/src/components/ui/resizable/resizable.stories.tsx +0 -73
  153. package/dist/frontend-core/template/src/components/ui/resizable/resizeable.tsx +0 -38
  154. package/dist/frontend-core/template/src/components/ui/scroll-area/scroll-area.stories.tsx +0 -55
  155. package/dist/frontend-core/template/src/components/ui/scroll-area/scroll-area.tsx +0 -39
  156. package/dist/frontend-core/template/src/components/ui/select/select.stories.tsx +0 -297
  157. package/dist/frontend-core/template/src/components/ui/select/select.tsx +0 -227
  158. package/dist/frontend-core/template/src/components/ui/separator/separator.tsx +0 -21
  159. package/dist/frontend-core/template/src/components/ui/separator/seperator.stories.tsx +0 -25
  160. package/dist/frontend-core/template/src/components/ui/sheet/sheet.stories.tsx +0 -45
  161. package/dist/frontend-core/template/src/components/ui/sheet/sheet.tsx +0 -107
  162. package/dist/frontend-core/template/src/components/ui/skeleton/skeleton.stories.tsx +0 -26
  163. package/dist/frontend-core/template/src/components/ui/skeleton/skeleton.tsx +0 -7
  164. package/dist/frontend-core/template/src/components/ui/slider/slider.stories.tsx +0 -101
  165. package/dist/frontend-core/template/src/components/ui/slider/slider.tsx +0 -98
  166. package/dist/frontend-core/template/src/components/ui/spinner/spinner.stories.tsx +0 -19
  167. package/dist/frontend-core/template/src/components/ui/spinner/spinner.tsx +0 -21
  168. package/dist/frontend-core/template/src/components/ui/switch/switch.stories.tsx +0 -33
  169. package/dist/frontend-core/template/src/components/ui/switch/switch.tsx +0 -28
  170. package/dist/frontend-core/template/src/components/ui/tabs/tabs.stories.tsx +0 -215
  171. package/dist/frontend-core/template/src/components/ui/tabs/tabs.tsx +0 -70
  172. package/dist/frontend-core/template/src/components/ui/textarea/textarea.stories.tsx +0 -138
  173. package/dist/frontend-core/template/src/components/ui/textarea/textarea.tsx +0 -40
  174. package/dist/frontend-core/template/src/components/ui/toast/toast.mdx +0 -31
  175. package/dist/frontend-core/template/src/components/ui/toast/toast.stories.tsx +0 -89
  176. package/dist/frontend-core/template/src/components/ui/toggle/toggle.stories.tsx +0 -65
  177. package/dist/frontend-core/template/src/components/ui/toggle/toggle.tsx +0 -38
  178. package/dist/frontend-core/template/src/components/ui/toggle-group/toggle-group.stories.tsx +0 -85
  179. package/dist/frontend-core/template/src/components/ui/toggle-group/toggle-group.tsx +0 -54
  180. package/dist/frontend-core/template/src/components/ui/tooltip/tooltip.stories.tsx +0 -29
  181. 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
- }