@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,168 +0,0 @@
1
- import type { Meta, StoryObj } from '@storybook/react-vite'
2
- import { SunIcon, ChevronUpIcon, ChevronDownIcon } from '@radix-ui/react-icons'
3
- import { expect, userEvent, screen, waitFor } from 'storybook/test'
4
- import { useState } from 'react'
5
- import {
6
- DropdownMenu,
7
- DropdownMenuPortal,
8
- DropdownMenuTrigger,
9
- DropdownMenuContent,
10
- DropdownMenuGroup,
11
- DropdownMenuLabel,
12
- DropdownMenuItem,
13
- DropdownMenuSeparator,
14
- DropdownMenuShortcut,
15
- DropdownMenuSub,
16
- DropdownMenuSubTrigger,
17
- DropdownMenuSubContent,
18
- } from './dropdown-menu'
19
- import { Button } from '@components/ui/button/button'
20
- import { Label } from '@components/ui/label/label'
21
- import { Checkbox } from '@components/ui/checkbox/checkbox'
22
- import { Input } from '@components/ui/input/input'
23
-
24
- const meta = {
25
- title: 'DropdownMenu',
26
- component: DropdownMenu,
27
- tags: ['autodocs'],
28
- parameters: {
29
- layout: 'centered',
30
- },
31
- argTypes: {},
32
- } satisfies Meta<typeof DropdownMenu>
33
- export default meta
34
-
35
- type Story = StoryObj<typeof meta>
36
-
37
- export const Default: Story = {
38
- render: () => (
39
- <div data-testid="outside-click-for-test" className="pointer-events-auto">
40
- <DropdownMenu>
41
- <DropdownMenuTrigger asChild>
42
- <Button variant="outline">Open dropdown</Button>
43
- </DropdownMenuTrigger>
44
- <DropdownMenuContent className="w-[250px]" align="start">
45
- <DropdownMenuLabel>Category 1</DropdownMenuLabel>
46
- <DropdownMenuGroup>
47
- <DropdownMenuItem>Item 1</DropdownMenuItem>
48
- <DropdownMenuItem>
49
- Item 2<DropdownMenuShortcut>⌘P (only visually)</DropdownMenuShortcut>
50
- </DropdownMenuItem>
51
- </DropdownMenuGroup>
52
- <DropdownMenuSeparator />
53
- <DropdownMenuGroup>
54
- <DropdownMenuSub>
55
- <DropdownMenuSubTrigger>Sub menu trigger</DropdownMenuSubTrigger>
56
- <DropdownMenuPortal>
57
- <DropdownMenuSubContent>
58
- <DropdownMenuItem>Sub Item 1</DropdownMenuItem>
59
- <DropdownMenuSeparator />
60
- <DropdownMenuItem>More... (just another item)</DropdownMenuItem>
61
- </DropdownMenuSubContent>
62
- </DropdownMenuPortal>
63
- </DropdownMenuSub>
64
- <DropdownMenuItem disabled>Disabled</DropdownMenuItem>
65
- <div className="flex items-center justify-center gap-3 mt-5">
66
- <span>or just use custom content instead of the DropdownMenuItems</span>
67
- <SunIcon className="size-15 text-yellow-500" />
68
- </div>
69
- </DropdownMenuGroup>
70
- </DropdownMenuContent>
71
- </DropdownMenu>
72
- </div>
73
- ),
74
- play: async () => {
75
- await userEvent.click(screen.getByText('Open dropdown'))
76
- const item1 = await screen.findByText('Item 1')
77
- await waitFor(() => {
78
- const style = window.getComputedStyle(item1)
79
- expect(style.visibility).toBe('visible')
80
- expect(Number(style.opacity)).toBeGreaterThan(0)
81
- })
82
- await userEvent.click(screen.getByTestId('outside-click-for-test'))
83
- await waitFor(() => {
84
- expect(screen.queryByText('Item 1')).toBeNull()
85
- })
86
- await userEvent.keyboard('{Escape}')
87
- await waitFor(() => {
88
- expect(screen.queryByText('Item 1')).toBeNull()
89
- })
90
- },
91
- }
92
-
93
- export const ExampleDropdownSearchableSelection: Story = {
94
- render: () => {
95
- const dummyUsers = [
96
- { id: '1', name: 'alice@wonderland.net' },
97
- { id: '2', name: 'bob.builder@kika.de' },
98
- { id: '3', name: 'charlie.bucket@chocolate-factory.com' },
99
- ]
100
- const [menuOpen, setMenuOpen] = useState(false)
101
- const [userFilterValue, setUserFilterValue] = useState('')
102
- const [selectedUserIds, setSelectedUserIds] = useState<string[]>([])
103
-
104
- const filteredUserData = dummyUsers.filter((user) =>
105
- user.name.toLowerCase().includes(userFilterValue.toLowerCase()),
106
- )
107
-
108
- const handleCheckboxChange = (userId: string) => {
109
- setSelectedUserIds((prev) => (prev.includes(userId) ? prev.filter((id) => id !== userId) : [...prev, userId]))
110
- }
111
-
112
- return (
113
- <div className="w-[180px]">
114
- <DropdownMenu open={menuOpen} onOpenChange={setMenuOpen}>
115
- <DropdownMenuTrigger asChild>
116
- <Button
117
- variant="outline"
118
- size="sm"
119
- className="group w-full flex items-center justify-between disabled:text-muted-foreground border-input hover:bg-muted-foreground hover:text-background"
120
- >
121
- <span className="mx-auto">
122
- {selectedUserIds.length === 0
123
- ? 'Select specific users'
124
- : `${selectedUserIds.length} user${selectedUserIds.length > 1 ? 's' : ''} selected`}
125
- </span>
126
- {menuOpen ? (
127
- <ChevronUpIcon className="size-4 opacity-50 text-muted-foreground group-hover:text-background" />
128
- ) : (
129
- <ChevronDownIcon className="size-4 opacity-50 group-hover:opacity-100 text-muted-foreground group-hover:text-background" />
130
- )}
131
- </Button>
132
- </DropdownMenuTrigger>
133
- <DropdownMenuContent align="start" className="w-[280px] flex flex-col p-0 border-(--discreet-border)">
134
- <Input
135
- className=" rounded-none border-0 border-b-1"
136
- variant="simple"
137
- placeholder="Search users"
138
- value={userFilterValue}
139
- onChange={(e) => setUserFilterValue(e.target.value)}
140
- />
141
- <div className="p-1">
142
- {filteredUserData.length > 0 ? (
143
- filteredUserData.map((user) => (
144
- <div key={user.id} className="flex hover:bg-accent py-1 px-2 rounded items-center gap-2">
145
- <Checkbox
146
- checked={selectedUserIds.includes(user.id)}
147
- onChange={() => handleCheckboxChange(user.id)}
148
- id={`user-${user.id}`}
149
- variant="iconSolo"
150
- checkboxSize="lg"
151
- checkIcon="check"
152
- iconStyle="solo"
153
- />
154
- <Label htmlFor={`user-${user.id}`} className="cursor-pointer">
155
- {user.name}
156
- </Label>
157
- </div>
158
- ))
159
- ) : (
160
- <p className="text-center text-muted-foreground py-3">no results found</p>
161
- )}
162
- </div>
163
- </DropdownMenuContent>
164
- </DropdownMenu>
165
- </div>
166
- )
167
- },
168
- }
@@ -1,225 +0,0 @@
1
- import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu'
2
- import { CheckIcon, ChevronRightIcon, CircleIcon } from '@radix-ui/react-icons'
3
-
4
- import * as React from 'react'
5
-
6
- import { cn } from '@lib/utils'
7
-
8
- function DropdownMenu({ ...props }: Readonly<React.ComponentProps<typeof DropdownMenuPrimitive.Root>>) {
9
- return <DropdownMenuPrimitive.Root data-slot="dropdown-menu" {...props} />
10
- }
11
-
12
- function DropdownMenuPortal({ ...props }: Readonly<React.ComponentProps<typeof DropdownMenuPrimitive.Portal>>) {
13
- return <DropdownMenuPrimitive.Portal data-slot="dropdown-menu-portal" {...props} />
14
- }
15
-
16
- function DropdownMenuTrigger({ ...props }: Readonly<React.ComponentProps<typeof DropdownMenuPrimitive.Trigger>>) {
17
- return <DropdownMenuPrimitive.Trigger data-slot="dropdown-menu-trigger" {...props} />
18
- }
19
-
20
- function DropdownMenuContent({
21
- className,
22
- sideOffset = 4,
23
- ...props
24
- }: Readonly<React.ComponentProps<typeof DropdownMenuPrimitive.Content>>) {
25
- return (
26
- <DropdownMenuPrimitive.Portal>
27
- <DropdownMenuPrimitive.Content
28
- data-slot="dropdown-menu-content"
29
- sideOffset={sideOffset}
30
- className={cn(
31
- 'bg-popover text-popover-foreground 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 z-50 max-h-(--radix-dropdown-menu-content-available-height) min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border p-1 shadow-md',
32
- className,
33
- )}
34
- {...props}
35
- />
36
- </DropdownMenuPrimitive.Portal>
37
- )
38
- }
39
-
40
- function DropdownMenuGroup({ ...props }: Readonly<React.ComponentProps<typeof DropdownMenuPrimitive.Group>>) {
41
- return <DropdownMenuPrimitive.Group data-slot="dropdown-menu-group" {...props} />
42
- }
43
-
44
- function DropdownMenuItem({
45
- className,
46
- inset,
47
- variant = 'default',
48
- ...props
49
- }: React.ComponentProps<typeof DropdownMenuPrimitive.Item> & {
50
- inset?: boolean
51
- variant?: 'default' | 'destructive'
52
- }) {
53
- return (
54
- <DropdownMenuPrimitive.Item
55
- data-slot="dropdown-menu-item"
56
- data-inset={inset}
57
- data-variant={variant}
58
- className={cn(
59
- "focus:bg-accent focus:text-accent-foreground data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 dark:data-[variant=destructive]:focus:bg-destructive/20 data-[variant=destructive]:focus:text-destructive data-[variant=destructive]:*:[svg]:!text-destructive [&_svg:not([class*='text-'])]:text-muted-foreground relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
60
- className,
61
- )}
62
- {...props}
63
- />
64
- )
65
- }
66
-
67
- function DropdownMenuCheckboxItem({
68
- className,
69
- children,
70
- checked,
71
- ...props
72
- }: Readonly<React.ComponentProps<typeof DropdownMenuPrimitive.CheckboxItem>>) {
73
- return (
74
- <DropdownMenuPrimitive.CheckboxItem
75
- data-slot="dropdown-menu-checkbox-item"
76
- className={cn(
77
- "focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
78
- className,
79
- )}
80
- checked={checked}
81
- {...props}
82
- >
83
- <span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
84
- <DropdownMenuPrimitive.ItemIndicator>
85
- <CheckIcon className="size-4" />
86
- </DropdownMenuPrimitive.ItemIndicator>
87
- </span>
88
- {children}
89
- </DropdownMenuPrimitive.CheckboxItem>
90
- )
91
- }
92
-
93
- function DropdownMenuRadioGroup({ ...props }: Readonly<React.ComponentProps<typeof DropdownMenuPrimitive.RadioGroup>>) {
94
- return <DropdownMenuPrimitive.RadioGroup data-slot="dropdown-menu-radio-group" {...props} />
95
- }
96
-
97
- function DropdownMenuRadioItem({
98
- className,
99
- children,
100
- ...props
101
- }: Readonly<React.ComponentProps<typeof DropdownMenuPrimitive.RadioItem>>) {
102
- return (
103
- <DropdownMenuPrimitive.RadioItem
104
- data-slot="dropdown-menu-radio-item"
105
- className={cn(
106
- "focus:bg-accent focus:text-accent-foreground relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
107
- className,
108
- )}
109
- {...props}
110
- >
111
- <span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center">
112
- <DropdownMenuPrimitive.ItemIndicator>
113
- <CircleIcon className="size-2 fill-current" />
114
- </DropdownMenuPrimitive.ItemIndicator>
115
- </span>
116
- {children}
117
- </DropdownMenuPrimitive.RadioItem>
118
- )
119
- }
120
-
121
- function DropdownMenuLabel({
122
- className,
123
- inset,
124
- ...props
125
- }: Readonly<
126
- React.ComponentProps<typeof DropdownMenuPrimitive.Label> & {
127
- inset?: boolean
128
- }
129
- >) {
130
- return (
131
- <DropdownMenuPrimitive.Label
132
- data-slot="dropdown-menu-label"
133
- data-inset={inset}
134
- className={cn('px-2 py-1.5 text-sm font-medium data-[inset]:pl-8', className)}
135
- {...props}
136
- />
137
- )
138
- }
139
-
140
- function DropdownMenuSeparator({
141
- className,
142
- ...props
143
- }: Readonly<React.ComponentProps<typeof DropdownMenuPrimitive.Separator>>) {
144
- return (
145
- <DropdownMenuPrimitive.Separator
146
- data-slot="dropdown-menu-separator"
147
- className={cn('bg-border -mx-1 my-1 h-px', className)}
148
- {...props}
149
- />
150
- )
151
- }
152
-
153
- function DropdownMenuShortcut({ className, ...props }: React.ComponentProps<'span'>) {
154
- return (
155
- <span
156
- data-slot="dropdown-menu-shortcut"
157
- className={cn('text-muted-foreground ml-auto text-xs tracking-widest', className)}
158
- {...props}
159
- />
160
- )
161
- }
162
-
163
- function DropdownMenuSub({ ...props }: Readonly<React.ComponentProps<typeof DropdownMenuPrimitive.Sub>>) {
164
- return <DropdownMenuPrimitive.Sub data-slot="dropdown-menu-sub" {...props} />
165
- }
166
-
167
- function DropdownMenuSubTrigger({
168
- className,
169
- inset,
170
- children,
171
- ...props
172
- }: Readonly<
173
- React.ComponentProps<typeof DropdownMenuPrimitive.SubTrigger> & {
174
- inset?: boolean
175
- }
176
- >) {
177
- return (
178
- <DropdownMenuPrimitive.SubTrigger
179
- data-slot="dropdown-menu-sub-trigger"
180
- data-inset={inset}
181
- className={cn(
182
- 'focus:bg-accent focus:text-accent-foreground data-[state=open]:bg-accent data-[state=open]:text-accent-foreground flex cursor-default items-center rounded-sm px-2 py-1.5 text-sm outline-hidden select-none data-[inset]:pl-8',
183
- className,
184
- )}
185
- {...props}
186
- >
187
- {children}
188
- <ChevronRightIcon className="ml-auto size-4" />
189
- </DropdownMenuPrimitive.SubTrigger>
190
- )
191
- }
192
-
193
- function DropdownMenuSubContent({
194
- className,
195
- ...props
196
- }: Readonly<React.ComponentProps<typeof DropdownMenuPrimitive.SubContent>>) {
197
- return (
198
- <DropdownMenuPrimitive.SubContent
199
- data-slot="dropdown-menu-sub-content"
200
- className={cn(
201
- 'bg-popover text-popover-foreground 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 z-50 min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-hidden rounded-md border p-1 shadow-lg',
202
- className,
203
- )}
204
- {...props}
205
- />
206
- )
207
- }
208
-
209
- export {
210
- DropdownMenu,
211
- DropdownMenuPortal,
212
- DropdownMenuTrigger,
213
- DropdownMenuContent,
214
- DropdownMenuGroup,
215
- DropdownMenuLabel,
216
- DropdownMenuItem,
217
- DropdownMenuCheckboxItem,
218
- DropdownMenuRadioGroup,
219
- DropdownMenuRadioItem,
220
- DropdownMenuSeparator,
221
- DropdownMenuShortcut,
222
- DropdownMenuSub,
223
- DropdownMenuSubTrigger,
224
- DropdownMenuSubContent,
225
- }
@@ -1,141 +0,0 @@
1
- import type { Meta, StoryObj } from '@storybook/react-vite'
2
- import { useState } from 'react'
3
-
4
- import { Input } from './input'
5
- import { expect, userEvent, screen } from 'storybook/test'
6
- import { Button } from '@components/ui/button/button'
7
-
8
- const meta = {
9
- title: 'Input',
10
- component: Input,
11
- tags: ['autodocs'],
12
- parameters: {
13
- layout: 'centered',
14
- },
15
- argTypes: {
16
- variant: {
17
- control: 'select',
18
- options: ['default', 'simple'],
19
- },
20
- },
21
- } satisfies Meta<typeof Input>
22
- export default meta
23
-
24
- type Story = StoryObj<typeof meta>
25
-
26
- export const Default: Story = {
27
- args: { variant: 'default' },
28
- render: (args) => {
29
- const [value, setValue] = useState('')
30
- return (
31
- <div className="flex items-center gap-2">
32
- <Input
33
- placeholder="Enter text..."
34
- {...args}
35
- value={value}
36
- onChange={(e) => setValue(e.target.value)}
37
- className="w-[200px]"
38
- />
39
- <span data-testid="input-value">
40
- {value ? 'value: ' : ''}
41
- {value}
42
- </span>
43
- </div>
44
- )
45
- },
46
- play: async () => {
47
- const input = screen.getByPlaceholderText('Enter text...')
48
- await userEvent.type(input, 'test')
49
- const valueSpan = screen.getByTestId('input-value')
50
- expect(valueSpan).toHaveTextContent('test')
51
- },
52
- }
53
-
54
- export const Variants: Story = {
55
- render: () => (
56
- <div className="flex flex-wrap gap-2 items-center">
57
- <Input placeholder="default" variant="default" className="w-48" />
58
- <Input placeholder="simple" variant="simple" className="w-48" />
59
- </div>
60
- ),
61
- }
62
-
63
- export const Disabled: Story = {
64
- render: (args) => (
65
- <div className="flex flex-wrap gap-4 items-center">
66
- <Input disabled {...args} className="w-[200px]" placeholder="Disabled" />
67
- </div>
68
- ),
69
- }
70
-
71
- export const EmailForm: Story = {
72
- render: () => {
73
- const [value, setValue] = useState('')
74
- const [error, setError] = useState<string | null>(null)
75
- const [submitted, setSubmitted] = useState(false)
76
- const [touched, setTouched] = useState(false)
77
-
78
- function validateEmail(email: string) {
79
- return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)
80
- }
81
-
82
- function validate(value: string) {
83
- if (!value) return 'Field is required.'
84
- if (!validateEmail(value)) return 'Not a valid email.'
85
- return null
86
- }
87
-
88
- const handleSubmit = (e: React.FormEvent) => {
89
- e.preventDefault()
90
- setSubmitted(true)
91
- setError(validate(value))
92
- }
93
-
94
- const handleBlur = () => {
95
- setTouched(true)
96
- setError(validate(value))
97
- }
98
-
99
- return (
100
- <form className="flex flex-col gap-2 items-center w-[350px]" onSubmit={handleSubmit} noValidate>
101
- <Input
102
- className="w-full"
103
- placeholder="Enter an email..."
104
- value={value}
105
- onChange={(e) => {
106
- setValue(e.target.value)
107
- if (submitted || touched) setError(validate(e.target.value))
108
- }}
109
- onBlur={handleBlur}
110
- aria-invalid={!!error}
111
- />
112
- {error && (touched || submitted) && (
113
- <span className="text-destructive mt-1" role="alert">
114
- {error}
115
- </span>
116
- )}
117
- <Button type="submit" size="smLow">
118
- Submit
119
- </Button>
120
- </form>
121
- )
122
- },
123
- play: async () => {
124
- const input = screen.getByPlaceholderText('Enter an email...')
125
- const submitButton = screen.getByRole('button', { name: /submit/i })
126
-
127
- // Submit with empty input
128
- await userEvent.clear(input)
129
- await userEvent.click(submitButton)
130
- await expect(await screen.findByRole('alert')).toHaveTextContent('Field is required.')
131
- // Enter invalid email and submit
132
- await userEvent.type(input, 'not-an-email')
133
- await userEvent.click(submitButton)
134
- await expect(await screen.findByRole('alert')).toHaveTextContent('Not a valid email.')
135
- // Enter valid email and submit
136
- await userEvent.clear(input)
137
- await userEvent.type(input, 'test@example.com')
138
- await userEvent.click(submitButton)
139
- await expect(screen.queryByRole('alert')).toBeNull()
140
- },
141
- }
@@ -1,47 +0,0 @@
1
- import { cva, type VariantProps } from 'class-variance-authority'
2
- import * as React from 'react'
3
-
4
- import { cn } from '@lib/utils'
5
-
6
- const inputVariants = cva(
7
- 'file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground dark:bg-input/30 border-input flex w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive',
8
- {
9
- variants: {
10
- variant: {
11
- default: 'h-9 md:text-sm focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]',
12
- simple: 'h-8',
13
- },
14
- },
15
- defaultVariants: {
16
- variant: 'default',
17
- },
18
- },
19
- )
20
-
21
- type InputProps = React.ComponentProps<'input'> &
22
- VariantProps<typeof inputVariants> & {
23
- /**
24
- * E2E test_id to identify the input.
25
- */
26
- __e2e_test_id__?: string
27
- onEnter?: () => void
28
- }
29
- function Input({ className, type, variant, __e2e_test_id__, onEnter, ...props }: InputProps) {
30
- return (
31
- <input
32
- type={type}
33
- data-slot="input"
34
- className={cn(inputVariants({ variant, className }))}
35
- data-test-id={__e2e_test_id__}
36
- onKeyDown={(e) => {
37
- props.onKeyDown?.(e)
38
- if (e.key === 'Enter') {
39
- onEnter?.()
40
- }
41
- }}
42
- {...props}
43
- />
44
- )
45
- }
46
-
47
- export { Input }
@@ -1,41 +0,0 @@
1
- import type { Meta, StoryObj } from '@storybook/react-vite'
2
- import { expect, userEvent, screen } from 'storybook/test'
3
-
4
- import { Label } from './label'
5
- import { Checkbox } from '@components/ui/checkbox/shadcn-checkbox'
6
-
7
- const meta = {
8
- title: 'Label',
9
- component: Label,
10
- tags: ['autodocs'],
11
- parameters: {
12
- layout: 'centered',
13
- },
14
- } satisfies Meta<typeof Label>
15
- export default meta
16
-
17
- type Story = StoryObj<typeof meta>
18
-
19
- export const Default: Story = {
20
- render: () => <Label>Label</Label>,
21
- }
22
-
23
- export const Usage: Story = {
24
- render: () => (
25
- <div className="flex flex-wrap gap-2 items-center">
26
- <Checkbox id="label-1" />
27
- <Label htmlFor="label-1" className="cursor-pointer">
28
- Label for usage demonstration (click label to toggle checkbox)
29
- </Label>
30
- </div>
31
- ),
32
- play: async () => {
33
- const label = screen.getByText(/Label for usage demonstration/)
34
- const checkbox = screen.getByRole('checkbox')
35
- await expect(checkbox).not.toBeChecked()
36
- await userEvent.click(label)
37
- await expect(checkbox).toBeChecked()
38
- await userEvent.click(label)
39
- await expect(checkbox).not.toBeChecked()
40
- },
41
- }
@@ -1,20 +0,0 @@
1
- import * as LabelPrimitive from '@radix-ui/react-label'
2
-
3
- import * as React from 'react'
4
-
5
- import { cn } from '@lib/utils'
6
-
7
- function Label({ className, ...props }: React.ComponentProps<typeof LabelPrimitive.Root>) {
8
- return (
9
- <LabelPrimitive.Root
10
- data-slot="label"
11
- className={cn(
12
- 'flex items-center gap-2 text-base leading-none font-medium select-none group-data-[disabled=true]:pointer-events-none group-data-[disabled=true]:opacity-50 peer-disabled:cursor-not-allowed peer-disabled:opacity-50',
13
- className,
14
- )}
15
- {...props}
16
- />
17
- )
18
- }
19
-
20
- export { Label }
@@ -1,45 +0,0 @@
1
- import type { Meta, StoryObj } from '@storybook/react-vite'
2
-
3
- import { Loader } from './loader'
4
-
5
- const meta = {
6
- title: 'Loader',
7
- component: Loader,
8
- tags: ['autodocs'],
9
- parameters: {
10
- layout: 'centered',
11
- },
12
- argTypes: {
13
- label: {
14
- control: 'text',
15
- },
16
- },
17
- } satisfies Meta<typeof Loader>
18
- export default meta
19
-
20
- type Story = StoryObj<typeof meta>
21
-
22
- export const Default: Story = {
23
- args: { label: 'Loading...' },
24
- render: (args) => (
25
- <div className="relative w-[350px] h-[150px] border">
26
- <span>Background, loader is applied on, which gets dimmed</span>
27
- <br />
28
- <span>needs position relative for correct loader placement</span>
29
- <Loader {...args} />
30
- </div>
31
- ),
32
- // play: async () => {
33
- // // Check that the loader label is visible
34
- // expect(screen.getByText('Loading...')).toBeVisible()
35
- // const loaderLabel = screen.getByText('Loading...')
36
- // // Find the SVG spinner within the loader
37
- // const svg = loaderLabel.closest('div')?.querySelector('svg')
38
- // expect(svg).toBeTruthy()
39
- // expect(svg).toBeVisible()
40
- // // Check that the SVG size is greater than 0
41
- // const rect = svg?.getBoundingClientRect()
42
- // expect(rect?.width).toBeGreaterThan(0)
43
- // expect(rect?.height).toBeGreaterThan(0)
44
- // },
45
- }