@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,160 +0,0 @@
1
- import type { Meta, StoryObj } from '@storybook/react-vite'
2
-
3
- import { Calendar } from './calendar'
4
- import { expect, userEvent, screen } from 'storybook/test'
5
- import { useState } from 'react'
6
-
7
- const meta = {
8
- title: 'Calendar',
9
- component: Calendar,
10
- tags: ['autodocs'],
11
- parameters: {
12
- layout: 'centered',
13
- },
14
- argTypes: {
15
- buttonVariant: {
16
- control: 'select',
17
- options: [
18
- undefined,
19
- 'default',
20
- 'secondary',
21
- 'destructive',
22
- 'outline',
23
- 'ghost',
24
- 'link',
25
- 'outlineInvert',
26
- 'extraGhost',
27
- 'extraGhost2',
28
- 'neutral',
29
- ],
30
- },
31
- showYearNavigation: {
32
- control: 'boolean',
33
- },
34
- mode: {
35
- control: 'select',
36
- options: ['single', 'multiple', 'range'],
37
- },
38
- showOutsideDays: {
39
- control: 'boolean',
40
- defaultValue: true,
41
- },
42
- captionLayout: {
43
- control: 'select',
44
- options: ['label', 'dropdown', 'dropdown-months', 'dropdown-years'],
45
- defaultValue: 'label',
46
- },
47
- formatters: {
48
- control: 'object',
49
- },
50
- components: {
51
- control: 'object',
52
- },
53
- disabled: {
54
- control: 'object',
55
- },
56
- fromYear: {
57
- control: 'number',
58
- },
59
- toYear: {
60
- control: 'number',
61
- },
62
- },
63
- } satisfies Meta<typeof Calendar>
64
- export default meta
65
-
66
- type Story = StoryObj<typeof meta>
67
-
68
- type DateRange = {
69
- from?: Date
70
- to?: Date
71
- }
72
-
73
- export const Default: Story = {
74
- args: {
75
- mode: 'single',
76
- showOutsideDays: true,
77
- captionLayout: 'label',
78
- formatters: {
79
- // used by this Calendar (and merged with the built-in formatMonthDropdown)
80
- formatMonthDropdown: (date: Date) => date.toLocaleString('en-US', { month: 'long' }), // "January", "February", ...
81
-
82
- // typical DayPicker formatter names you can override:
83
- formatWeekdayName: (date: Date) => date.toLocaleDateString('en-US', { weekday: 'short' }), // "Mon", "Tue", ...
84
-
85
- formatDay: (date: Date) => date.toLocaleDateString('en-US', { day: 'numeric' }), // "01"
86
- },
87
- },
88
- render: (args) => <Calendar {...args} data-testid="default-calendar" />,
89
- play: async () => {
90
- const calendar = screen.getByTestId('default-calendar')
91
- const dayButton = calendar.querySelector('button[aria-label*="13"]') as HTMLElement
92
- await userEvent.click(dayButton)
93
- expect(dayButton).toHaveAttribute('data-selected-single', 'true')
94
- },
95
- }
96
-
97
- export const Multiple: Story = {
98
- args: {
99
- mode: 'multiple',
100
- },
101
- render: (args) => <Calendar {...args} data-testid="default-calendar" />,
102
- }
103
-
104
- function RangeCalendarStory(args: any) {
105
- const [range, setRange] = useState<DateRange | undefined>(undefined)
106
- return (
107
- <Calendar
108
- mode="range"
109
- buttonVariant={args.buttonVariant}
110
- data-testid="default-calendar"
111
- selected={range?.from && range?.to ? { from: range.from, to: range.to } : undefined}
112
- onSelect={(value: { from?: Date; to?: Date } | undefined) => {
113
- if (value?.from == null) {
114
- setRange(undefined)
115
- } else {
116
- const newRange = { from: value.from, to: value.to ?? value.from }
117
- setRange(newRange)
118
- }
119
- }}
120
- />
121
- )
122
- }
123
- export const RangeWithAlternatingSelection: Story = {
124
- render: (args) => <RangeCalendarStory {...args} />,
125
- }
126
-
127
- export const WithDisabledRange: Story = {
128
- render: () => {
129
- return (
130
- <Calendar
131
- disabled={(date) => date > new Date() || date < new Date(new Date().setMonth(new Date().getMonth() - 3))}
132
- data-testid="default-calendar"
133
- />
134
- )
135
- },
136
- play: async () => {
137
- const calendar = screen.getByTestId('default-calendar')
138
- const today = new Date()
139
- const future = new Date(today)
140
- future.setDate(today.getDate() + 2)
141
- const futureDate = future.toLocaleDateString()
142
- // Use data-day attribute to find the specific button for the future date
143
- // This is more reliable than using aria-label with partial string matching
144
- const disabledDayButton = calendar.querySelector(`button[data-day="${futureDate}"]`) as HTMLElement
145
-
146
- // Previous approach had a bug: aria-label*="${dayNumber}" would match any date containing that number
147
- // For example, dayNumber=25 would incorrectly match "September 28th 2025" because it contains "25"
148
- // const dayNumber = future.getDate()
149
- // const disabledDayButton = calendar.querySelector(`button[aria-label*="${dayNumber}"]`) as HTMLElement
150
- await expect(disabledDayButton).toHaveAttribute('disabled')
151
- await userEvent.click(disabledDayButton, { pointerEventsCheck: 0 })
152
- await expect(disabledDayButton).toHaveAttribute('disabled') // still disabled after click
153
- },
154
- }
155
-
156
- export const WithDropdowns: Story = {
157
- render: () => {
158
- return <Calendar data-testid="default-calendar" captionLayout="dropdown" />
159
- },
160
- }
@@ -1,293 +0,0 @@
1
- import {
2
- ChevronDownIcon,
3
- ChevronLeftIcon,
4
- ChevronRightIcon,
5
- DoubleArrowLeftIcon,
6
- DoubleArrowRightIcon,
7
- } from '@radix-ui/react-icons'
8
-
9
- import * as React from 'react'
10
- import { DayButton, DayPicker, getDefaultClassNames } from 'react-day-picker'
11
-
12
- import { Button, buttonVariants } from '@components/ui/button/button'
13
- import { cn } from '@lib/utils'
14
-
15
- function Calendar({
16
- className,
17
- classNames,
18
- showOutsideDays = true,
19
- captionLayout = 'label',
20
- buttonVariant = 'ghost',
21
- showYearNavigation = false,
22
- formatters,
23
- components,
24
- ...props
25
- }: React.ComponentProps<typeof DayPicker> & {
26
- buttonVariant?: React.ComponentProps<typeof Button>['variant']
27
- showYearNavigation?: boolean
28
- }) {
29
- const defaultClassNames = getDefaultClassNames()
30
-
31
- // Track last selected field for range mode
32
- const [rangeSelectionStep, setRangeSelectionStep] = React.useState<'from' | 'to'>('from')
33
- // Custom onDayClick for range mode to make sure 'from' and 'to' are always set alternatingly
34
- const handleDayClick = React.useCallback(
35
- (day: Date, modifiers: any, e: React.MouseEvent<Element>) => {
36
- if (props.mode === 'range') {
37
- const range = props.selected as { from?: Date; to?: Date } | undefined
38
-
39
- // Always start a new range when selecting 'from'
40
- if (rangeSelectionStep === 'from') {
41
- props.onSelect?.({ from: day, to: undefined }, day, modifiers, e)
42
- setRangeSelectionStep('to')
43
- return
44
- }
45
-
46
- // Only set 'to' if 'from' is set and not the same day
47
- if (rangeSelectionStep === 'to') {
48
- if (range?.from && day.getTime() !== range.from.getTime()) {
49
- props.onSelect?.({ from: range.from, to: day }, day, modifiers, e)
50
- setRangeSelectionStep('from')
51
- }
52
- return
53
- }
54
- } else {
55
- props.onDayClick?.(day, modifiers, e)
56
- }
57
- },
58
- [props, rangeSelectionStep],
59
- )
60
-
61
- // default year range if caption layout has year dropdown: 100 years past and 100 years future unless user overrides
62
- // with the dropdown a range is required. if we don't set it manually it will be -100 years until now which is impractical for future events
63
- let fromMonth: Date | undefined
64
- let toMonth: Date | undefined
65
- if (captionLayout === 'dropdown-years' || captionLayout === 'dropdown') {
66
- const nowYear = new Date().getFullYear()
67
- fromMonth = props.startMonth ?? new Date(nowYear - 100, 0)
68
- toMonth = props.endMonth ?? new Date(nowYear + 100, 11)
69
- }
70
-
71
- // controlled month state so we can programmatically change months (and years)
72
- const [currentMonth, setCurrentMonth] = React.useState<Date>(props.defaultMonth ?? props.month ?? new Date())
73
- React.useEffect(() => {
74
- if (props.month) {
75
- setCurrentMonth(props.month)
76
- }
77
- }, [props.month])
78
-
79
- const addMonths = (date: Date, months: number) => {
80
- const d = new Date(date)
81
- d.setMonth(d.getMonth() + months)
82
- if (fromMonth && d < fromMonth) {
83
- return fromMonth
84
- }
85
- if (toMonth && d > toMonth) {
86
- return toMonth
87
- }
88
- return d
89
- }
90
-
91
- return (
92
- <DayPicker
93
- month={currentMonth}
94
- onMonthChange={(m) => {
95
- setCurrentMonth(m)
96
- props.onMonthChange?.(m)
97
- }}
98
- showOutsideDays={showOutsideDays}
99
- className={cn(
100
- 'bg-background group/calendar p-3 [--cell-size:--spacing(8)] [[data-slot=card-content]_&]:bg-transparent [[data-slot=popover-content]_&]:bg-transparent',
101
- String.raw`rtl:**:[.rdp-button\_next>svg]:rotate-180`,
102
- String.raw`rtl:**:[.rdp-button\_previous>svg]:rotate-180`,
103
- className,
104
- )}
105
- captionLayout={captionLayout}
106
- formatters={{
107
- formatMonthDropdown: (date) => date.toLocaleString('default', { month: 'short' }),
108
- ...formatters,
109
- }}
110
- classNames={{
111
- root: cn('w-fit', defaultClassNames.root),
112
- months: cn('flex gap-4 flex-col md:flex-row relative', defaultClassNames.months),
113
- month: cn('flex flex-col w-full gap-4', defaultClassNames.month),
114
- nav: cn('flex items-center gap-1 w-full absolute top-0 inset-x-0 justify-between', defaultClassNames.nav),
115
- button_previous: cn(
116
- buttonVariants({ variant: buttonVariant }),
117
- 'size-(--cell-size) aria-disabled:opacity-50 p-0 select-none',
118
- defaultClassNames.button_previous,
119
- ),
120
- button_next: cn(
121
- buttonVariants({ variant: buttonVariant }),
122
- 'size-(--cell-size) aria-disabled:opacity-50 p-0 select-none',
123
- defaultClassNames.button_next,
124
- ),
125
- month_caption: cn(
126
- 'flex items-center justify-center h-(--cell-size) w-full px-(--cell-size)',
127
- defaultClassNames.month_caption,
128
- ),
129
- dropdowns: cn(
130
- 'w-full flex items-center text-sm font-medium justify-center h-(--cell-size) gap-1.5',
131
- defaultClassNames.dropdowns,
132
- ),
133
- dropdown_root: cn(
134
- 'relative has-focus:border-ring border border-input shadow-xs has-focus:ring-ring/50 has-focus:ring-[3px] rounded-md',
135
- defaultClassNames.dropdown_root,
136
- ),
137
- dropdown: cn('absolute bg-popover inset-0 opacity-0', defaultClassNames.dropdown),
138
- caption_label: cn(
139
- 'select-none font-medium',
140
- captionLayout === 'label'
141
- ? 'text-sm'
142
- : 'rounded-md pl-2 pr-1 flex items-center gap-1 text-sm h-8 [&>svg]:text-muted-foreground [&>svg]:size-3.5',
143
- defaultClassNames.caption_label,
144
- ),
145
- table: 'w-full border-collapse',
146
- weekdays: cn('flex', defaultClassNames.weekdays),
147
- weekday: cn(
148
- 'text-muted-foreground rounded-md flex-1 font-normal text-[0.8rem] select-none',
149
- defaultClassNames.weekday,
150
- ),
151
- week: cn('flex w-full mt-2', defaultClassNames.week),
152
- week_number_header: cn('select-none w-(--cell-size)', defaultClassNames.week_number_header),
153
- week_number: cn('text-[0.8rem] select-none text-muted-foreground', defaultClassNames.week_number),
154
- day: cn(
155
- 'relative w-full h-full p-0 text-center [&:first-child[data-selected=true]_button]:rounded-l-md [&:last-child[data-selected=true]_button]:rounded-r-md group/day aspect-square select-none',
156
- defaultClassNames.day,
157
- ),
158
- range_start: cn('rounded-l-md bg-accent', defaultClassNames.range_start),
159
- range_middle: cn('rounded-none', defaultClassNames.range_middle),
160
- range_end: cn('rounded-r-md bg-accent', defaultClassNames.range_end),
161
- today: cn(
162
- 'bg-accent text-accent-foreground rounded-md data-[selected=true]:rounded-none',
163
- defaultClassNames.today,
164
- ),
165
- outside: cn('text-muted-foreground aria-selected:text-muted-foreground', defaultClassNames.outside),
166
- disabled: cn('text-muted-foreground opacity-50', defaultClassNames.disabled),
167
- hidden: cn('invisible', defaultClassNames.hidden),
168
- ...classNames,
169
- }}
170
- // prefer startMonth/toMonth instead of deprecated fromYear/toYear
171
- startMonth={fromMonth}
172
- endMonth={toMonth}
173
- components={{
174
- // custom navigation: to add double-chevron year skip buttons
175
- Nav: ({ className }) => (
176
- <div className={cn('mt-0.5', className)}>
177
- <div className="flex items-center">
178
- {showYearNavigation && (
179
- <Button
180
- aria-label="previous year"
181
- variant={buttonVariant}
182
- size="iconSm"
183
- disabled={fromMonth && currentMonth <= fromMonth}
184
- className={captionLayout === 'dropdown' ? 'size-6.5' : ''}
185
- onClick={() => setCurrentMonth((m) => addMonths(m ?? new Date(), -12))}
186
- >
187
- <DoubleArrowLeftIcon className="" />
188
- </Button>
189
- )}
190
- <Button
191
- aria-label="previous month"
192
- variant={buttonVariant}
193
- size="iconSm"
194
- disabled={fromMonth && currentMonth <= fromMonth}
195
- className={captionLayout === 'dropdown' ? 'size-6.5' : ''}
196
- onClick={() => setCurrentMonth((m) => addMonths(m ?? new Date(), -1))}
197
- >
198
- <ChevronLeftIcon />
199
- </Button>
200
- </div>
201
-
202
- <div className="flex items-center">
203
- <Button
204
- aria-label="next month"
205
- variant={buttonVariant}
206
- size="iconSm"
207
- disabled={toMonth && currentMonth >= toMonth}
208
- className={captionLayout === 'dropdown' ? 'size-6.5' : ''}
209
- onClick={() => setCurrentMonth((m) => addMonths(m ?? new Date(), 1))}
210
- >
211
- <ChevronRightIcon />
212
- </Button>
213
- {showYearNavigation && (
214
- <Button
215
- aria-label="next year"
216
- variant={buttonVariant}
217
- size="iconSm"
218
- disabled={toMonth && currentMonth >= toMonth}
219
- className={captionLayout === 'dropdown' ? 'size-6.5' : ''}
220
- onClick={() => setCurrentMonth((m) => addMonths(m ?? new Date(), 12))}
221
- >
222
- <DoubleArrowRightIcon />
223
- </Button>
224
- )}
225
- </div>
226
- </div>
227
- ),
228
- // prettier-ignore
229
- Root: ({ className, rootRef, ...props }) => { //NOSONAR - default shadeCn
230
- return <div data-slot="calendar" ref={rootRef} className={cn(className)} {...props} />
231
- },
232
- // prettier-ignore
233
- Chevron: ({ className, orientation, ...props }) => { //NOSONAR - default shadeCn
234
- if (orientation === 'left') {
235
- return <ChevronLeftIcon className={cn('size-4', className)} {...props} />
236
- }
237
-
238
- if (orientation === 'right') {
239
- return <ChevronRightIcon className={cn('size-4', className)} {...props} />
240
- }
241
-
242
- return <ChevronDownIcon className={cn('size-4', className)} {...props} />
243
- },
244
- DayButton: CalendarDayButton,
245
- // prettier-ignore
246
- WeekNumber: ({ children, ...props }) => { //NOSONAR - default shadeCn
247
- return (
248
- <td {...props}>
249
- <div className="flex size-(--cell-size) items-center justify-center text-center">{children}</div>
250
- </td>
251
- )
252
- },
253
- ...components,
254
- }}
255
- onDayClick={handleDayClick}
256
- {...props}
257
- />
258
- )
259
- }
260
-
261
- function CalendarDayButton({ className, day, modifiers, ...props }: React.ComponentProps<typeof DayButton>) {
262
- const defaultClassNames = getDefaultClassNames()
263
-
264
- const ref = React.useRef<HTMLButtonElement>(null)
265
- React.useEffect(() => {
266
- if (modifiers.focused) {
267
- ref.current?.focus()
268
- }
269
- }, [modifiers.focused])
270
-
271
- return (
272
- <Button
273
- ref={ref}
274
- variant="ghost"
275
- size="icon"
276
- data-day={day.date.toLocaleDateString()}
277
- data-selected-single={
278
- modifiers.selected && !modifiers.range_start && !modifiers.range_end && !modifiers.range_middle
279
- }
280
- data-range-start={modifiers.range_start}
281
- data-range-end={modifiers.range_end}
282
- data-range-middle={modifiers.range_middle}
283
- className={cn(
284
- 'data-[selected-single=true]:bg-primary data-[selected-single=true]:text-primary-foreground data-[range-middle=true]:bg-accent data-[range-middle=true]:text-accent-foreground data-[range-start=true]:bg-primary data-[range-start=true]:text-primary-foreground data-[range-end=true]:bg-primary data-[range-end=true]:text-primary-foreground group-data-[focused=true]/day:border-ring group-data-[focused=true]/day:ring-ring/50 dark:hover:text-accent-foreground flex aspect-square size-auto w-full min-w-(--cell-size) flex-col gap-1 leading-none font-normal group-data-[focused=true]/day:relative group-data-[focused=true]/day:z-10 group-data-[focused=true]/day:ring-[3px] data-[range-end=true]:rounded-md data-[range-end=true]:rounded-r-md data-[range-middle=true]:rounded-none data-[range-start=true]:rounded-md data-[range-start=true]:rounded-l-md [&>span]:text-xs [&>span]:opacity-70',
285
- defaultClassNames.day,
286
- className,
287
- )}
288
- {...props}
289
- />
290
- )
291
- }
292
-
293
- export { Calendar, CalendarDayButton }
@@ -1,77 +0,0 @@
1
- import { Meta, StoryObj } from '@storybook/react-vite'
2
-
3
- import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from './card'
4
- import { BellIcon, CheckIcon } from '@radix-ui/react-icons'
5
- import { cn } from '@lib/utils'
6
- import { Button } from '@components/ui/button/button'
7
-
8
- const meta = {
9
- title: 'Card',
10
- component: Card,
11
- tags: ['autodocs'],
12
- } satisfies Meta<typeof Card>
13
-
14
- export default meta
15
-
16
- export const Default: StoryObj<typeof meta> = {
17
- parameters: {
18
- docs: {
19
- description: {
20
- story:
21
- 'The Card component is used to group related information in a single container.This means any other component can be placed inside the Card component.',
22
- },
23
- },
24
- },
25
- render: () => (
26
- <div className="flex items-center justify-center border rounded p-4">
27
- <Card className={cn('w-[380px]')}>
28
- <CardHeader>
29
- <CardTitle>Card Title</CardTitle>
30
- <CardDescription>You have 3 unread messages.</CardDescription>
31
- </CardHeader>
32
- <CardContent className="grid gap-4">
33
- <div className=" flex items-center space-x-4 rounded-md border p-4">
34
- <BellIcon />
35
- <div className="flex-1 space-y-1">
36
- <p className="text-sm font-medium leading-none">Push Notifications</p>
37
- <p className="text-sm text-muted-foreground">Send notifications to device.</p>
38
- </div>
39
- </div>
40
- <div>
41
- {notifications.map((notification, index) => (
42
- <div key={index} className="mb-4 grid grid-cols-[25px_1fr] items-start pb-4 last:mb-0 last:pb-0">
43
- <span className="flex h-2 w-2 translate-y-1 rounded-full bg-sky-500" />
44
- <div className="space-y-1">
45
- <p className="text-sm font-medium leading-none">{notification.title}</p>
46
- <p className="text-sm text-muted-foreground">{notification.description}</p>
47
- </div>
48
- </div>
49
- ))}
50
- </div>
51
- </CardContent>
52
- <CardFooter>
53
- <Button className="w-full">
54
- <CheckIcon className="mr-2 h-4 w-4" /> Mark all as read
55
- </Button>
56
- </CardFooter>
57
- </Card>
58
- </div>
59
- ),
60
- }
61
-
62
- // DATA ------------------------------------------------------------------------
63
-
64
- const notifications = [
65
- {
66
- title: 'Your call has been confirmed.',
67
- description: '1 hour ago',
68
- },
69
- {
70
- title: 'You have a new message!',
71
- description: '1 hour ago',
72
- },
73
- {
74
- title: 'Your subscription is expiring soon!',
75
- description: '2 hours ago',
76
- },
77
- ]
@@ -1,45 +0,0 @@
1
- import * as React from 'react'
2
-
3
- import { cn } from '@lib/utils'
4
-
5
- const Card = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(({ className, ...props }, ref) => (
6
- <div ref={ref} className={cn('rounded-xl border bg-card text-card-foreground shadow', className)} {...props} />
7
- ))
8
- Card.displayName = 'Card'
9
-
10
- const CardHeader = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
11
- ({ className, ...props }, ref) => (
12
- <div ref={ref} className={cn('flex flex-col space-y-1.5 p-6', className)} {...props} />
13
- ),
14
- )
15
- CardHeader.displayName = 'CardHeader'
16
-
17
- const CardTitle = React.forwardRef<HTMLParagraphElement, React.HTMLAttributes<HTMLHeadingElement>>(
18
- ({ className, children, ...props }, ref) => (
19
- <h3 ref={ref} className={cn('font-semibold leading-none tracking-tight', className)} {...props}>
20
- {children}
21
- </h3>
22
- ),
23
- )
24
- CardTitle.displayName = 'CardTitle'
25
-
26
- const CardDescription = React.forwardRef<HTMLParagraphElement, React.HTMLAttributes<HTMLParagraphElement>>(
27
- ({ className, ...props }, ref) => (
28
- <p ref={ref} className={cn('text-sm text-muted-foreground', className)} {...props} />
29
- ),
30
- )
31
- CardDescription.displayName = 'CardDescription'
32
-
33
- const CardContent = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
34
- ({ className, ...props }, ref) => <div ref={ref} className={cn('p-6 pt-0', className)} {...props} />,
35
- )
36
- CardContent.displayName = 'CardContent'
37
-
38
- const CardFooter = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(
39
- ({ className, ...props }, ref) => (
40
- <div ref={ref} className={cn('flex items-center p-6 pt-0', className)} {...props} />
41
- ),
42
- )
43
- CardFooter.displayName = 'CardFooter'
44
-
45
- export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent }
@@ -1,29 +0,0 @@
1
- import { Meta, StoryObj } from '@storybook/react-vite'
2
-
3
- import { HoverCard, HoverCardContent, HoverCardTrigger } from './card-hover'
4
-
5
- const meta = {
6
- title: 'Hover Card',
7
- component: HoverCard,
8
- tags: ['autodocs'],
9
- } satisfies Meta<typeof HoverCard>
10
-
11
- export default meta
12
-
13
- export const Default: StoryObj<typeof meta> = {
14
- parameters: {
15
- docs: {
16
- description: {
17
- story: 'The Hover Card component displays additional information when hovering over an element.',
18
- },
19
- },
20
- },
21
- render: () => (
22
- <div className="flex items-center justify-center">
23
- <HoverCard>
24
- <HoverCardTrigger>Hover</HoverCardTrigger>
25
- <HoverCardContent>The React Framework – created and maintained by @vercel.</HoverCardContent>
26
- </HoverCard>
27
- </div>
28
- ),
29
- }
@@ -1,28 +0,0 @@
1
- import * as HoverCardPrimitive from '@radix-ui/react-hover-card'
2
-
3
- import * as React from 'react'
4
-
5
- import { cn } from '@lib/utils'
6
-
7
- const HoverCard = HoverCardPrimitive.Root
8
-
9
- const HoverCardTrigger = HoverCardPrimitive.Trigger
10
-
11
- const HoverCardContent = React.forwardRef<
12
- React.ElementRef<typeof HoverCardPrimitive.Content>,
13
- React.ComponentPropsWithoutRef<typeof HoverCardPrimitive.Content>
14
- >(({ className, align = 'center', sideOffset = 4, ...props }, ref) => (
15
- <HoverCardPrimitive.Content
16
- ref={ref}
17
- align={align}
18
- sideOffset={sideOffset}
19
- className={cn(
20
- 'z-50 w-64 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',
21
- className,
22
- )}
23
- {...props}
24
- />
25
- ))
26
- HoverCardContent.displayName = HoverCardPrimitive.Content.displayName
27
-
28
- export { HoverCard, HoverCardTrigger, HoverCardContent }