@ayasofyazilim/ui 0.0.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 (236) hide show
  1. package/__mocks__/canvas.ts +8 -0
  2. package/components.json +21 -0
  3. package/eslint.config.js +4 -0
  4. package/jest-environment.js +37 -0
  5. package/jest.config.ts +47 -0
  6. package/jest.setup.ts +69 -0
  7. package/package.json +124 -0
  8. package/postcss.config.mjs +6 -0
  9. package/src/aria/index.tsx +1 -0
  10. package/src/aria/number-field.tsx +41 -0
  11. package/src/components/.gitkeep +0 -0
  12. package/src/components/accordion.tsx +66 -0
  13. package/src/components/alert-dialog.tsx +157 -0
  14. package/src/components/alert.tsx +70 -0
  15. package/src/components/aspect-ratio.tsx +11 -0
  16. package/src/components/avatar.tsx +53 -0
  17. package/src/components/badge.tsx +67 -0
  18. package/src/components/breadcrumb.tsx +109 -0
  19. package/src/components/button-group.tsx +83 -0
  20. package/src/components/button.tsx +68 -0
  21. package/src/components/calendar.tsx +219 -0
  22. package/src/components/card.tsx +92 -0
  23. package/src/components/carousel.tsx +241 -0
  24. package/src/components/chart.tsx +363 -0
  25. package/src/components/checkbox.tsx +32 -0
  26. package/src/components/collapsible.tsx +33 -0
  27. package/src/components/command.tsx +184 -0
  28. package/src/components/context-menu.tsx +252 -0
  29. package/src/components/dialog.tsx +144 -0
  30. package/src/components/drawer.tsx +135 -0
  31. package/src/components/dropdown-menu.tsx +258 -0
  32. package/src/components/empty.tsx +100 -0
  33. package/src/components/field.tsx +248 -0
  34. package/src/components/form.tsx +169 -0
  35. package/src/components/hover-card.tsx +44 -0
  36. package/src/components/input-group.tsx +170 -0
  37. package/src/components/input-otp.tsx +77 -0
  38. package/src/components/input.tsx +21 -0
  39. package/src/components/item.tsx +193 -0
  40. package/src/components/kbd.tsx +28 -0
  41. package/src/components/label.tsx +24 -0
  42. package/src/components/menubar.tsx +276 -0
  43. package/src/components/navigation-menu.tsx +168 -0
  44. package/src/components/pagination.tsx +130 -0
  45. package/src/components/popover.tsx +88 -0
  46. package/src/components/progress.tsx +31 -0
  47. package/src/components/radio-group.tsx +45 -0
  48. package/src/components/resizable.tsx +56 -0
  49. package/src/components/scroll-area.tsx +58 -0
  50. package/src/components/select.tsx +189 -0
  51. package/src/components/separator.tsx +28 -0
  52. package/src/components/sheet.tsx +140 -0
  53. package/src/components/sidebar.tsx +862 -0
  54. package/src/components/skeleton.tsx +13 -0
  55. package/src/components/slider.tsx +63 -0
  56. package/src/components/sonner.tsx +40 -0
  57. package/src/components/spinner.tsx +16 -0
  58. package/src/components/stepper.tsx +291 -0
  59. package/src/components/switch.tsx +31 -0
  60. package/src/components/table.tsx +133 -0
  61. package/src/components/tabs.tsx +66 -0
  62. package/src/components/textarea.tsx +18 -0
  63. package/src/components/toggle-group.tsx +83 -0
  64. package/src/components/toggle.tsx +47 -0
  65. package/src/components/tooltip.tsx +66 -0
  66. package/src/custom/action-button.tsx +48 -0
  67. package/src/custom/async-select.tsx +287 -0
  68. package/src/custom/awesome-not-found.tsx +116 -0
  69. package/src/custom/charts/area-chart.tsx +147 -0
  70. package/src/custom/charts/bar-chart.tsx +233 -0
  71. package/src/custom/charts/chart-card.tsx +103 -0
  72. package/src/custom/charts/index.tsx +16 -0
  73. package/src/custom/charts/pie-chart.tsx +168 -0
  74. package/src/custom/charts/radar-chart.tsx +126 -0
  75. package/src/custom/checkbox-tree.tsx +100 -0
  76. package/src/custom/combobox.tsx +296 -0
  77. package/src/custom/confirm-dialog.tsx +102 -0
  78. package/src/custom/country-selector.tsx +204 -0
  79. package/src/custom/date-picker/calendar-rac.tsx +109 -0
  80. package/src/custom/date-picker/datefield-rac.tsx +84 -0
  81. package/src/custom/date-picker/index.tsx +273 -0
  82. package/src/custom/date-picker/types/index.ts +4 -0
  83. package/src/custom/date-picker/utils/index.ts +42 -0
  84. package/src/custom/date-picker-old.tsx +50 -0
  85. package/src/custom/date-tooltip.tsx +98 -0
  86. package/src/custom/document-scanner/consts.ts +5 -0
  87. package/src/custom/document-scanner/corner-adjustment/action-buttons.tsx +33 -0
  88. package/src/custom/document-scanner/corner-adjustment/corner-handle.tsx +43 -0
  89. package/src/custom/document-scanner/corner-adjustment/hooks/use-corner-drag.ts +85 -0
  90. package/src/custom/document-scanner/corner-adjustment/index.tsx +125 -0
  91. package/src/custom/document-scanner/corner-adjustment/types.ts +53 -0
  92. package/src/custom/document-scanner/corner-adjustment/utils/clip-path.ts +22 -0
  93. package/src/custom/document-scanner/corner-adjustment/zoom-magnifier.tsx +115 -0
  94. package/src/custom/document-scanner/hooks/use-document-capture.ts +81 -0
  95. package/src/custom/document-scanner/hooks/use-document-scanner.ts +80 -0
  96. package/src/custom/document-scanner/hooks/use-perspective-crop.ts +38 -0
  97. package/src/custom/document-scanner/index.tsx +255 -0
  98. package/src/custom/document-scanner/lib.ts +407 -0
  99. package/src/custom/document-scanner/types.ts +205 -0
  100. package/src/custom/document-scanner/utils/perspective-correction.ts +139 -0
  101. package/src/custom/document-viewer/controllers.tsx +98 -0
  102. package/src/custom/document-viewer/index.tsx +43 -0
  103. package/src/custom/document-viewer/renderers/image.tsx +37 -0
  104. package/src/custom/document-viewer/renderers/index.tsx +2 -0
  105. package/src/custom/document-viewer/renderers/pdf.tsx +105 -0
  106. package/src/custom/email-input/domains.json +159 -0
  107. package/src/custom/email-input/email.tsx +229 -0
  108. package/src/custom/email-input/index.tsx +4 -0
  109. package/src/custom/email-input/types.ts +104 -0
  110. package/src/custom/file-uploader.tsx +541 -0
  111. package/src/custom/filter-component/fields/async-select.tsx +33 -0
  112. package/src/custom/filter-component/fields/date.tsx +60 -0
  113. package/src/custom/filter-component/fields/multi-select.tsx +30 -0
  114. package/src/custom/filter-component/index.tsx +217 -0
  115. package/src/custom/image-canvas.tsx +260 -0
  116. package/src/custom/json-editor.tsx +22 -0
  117. package/src/custom/master-data-grid/components/dialogs/column-settings-dialog.tsx +100 -0
  118. package/src/custom/master-data-grid/components/dialogs/index.ts +1 -0
  119. package/src/custom/master-data-grid/components/filters/client-filter.tsx +368 -0
  120. package/src/custom/master-data-grid/components/filters/filter-input.tsx +256 -0
  121. package/src/custom/master-data-grid/components/filters/index.ts +3 -0
  122. package/src/custom/master-data-grid/components/filters/inline-column-filter.tsx +233 -0
  123. package/src/custom/master-data-grid/components/filters/multi-filter-dialog.tsx +90 -0
  124. package/src/custom/master-data-grid/components/filters/server-filter.tsx +255 -0
  125. package/src/custom/master-data-grid/components/master-data-grid.tsx +472 -0
  126. package/src/custom/master-data-grid/components/pagination/index.ts +1 -0
  127. package/src/custom/master-data-grid/components/pagination/pagination.tsx +178 -0
  128. package/src/custom/master-data-grid/components/table/cell-renderer.tsx +634 -0
  129. package/src/custom/master-data-grid/components/table/header-cell.tsx +162 -0
  130. package/src/custom/master-data-grid/components/table/index.ts +4 -0
  131. package/src/custom/master-data-grid/components/table/table-body-renderer.tsx +113 -0
  132. package/src/custom/master-data-grid/components/table/virtual-body.tsx +138 -0
  133. package/src/custom/master-data-grid/components/toolbar/index.ts +1 -0
  134. package/src/custom/master-data-grid/components/toolbar/toolbar.tsx +314 -0
  135. package/src/custom/master-data-grid/hooks/index.ts +3 -0
  136. package/src/custom/master-data-grid/hooks/use-columns.tsx +332 -0
  137. package/src/custom/master-data-grid/hooks/use-editing.ts +106 -0
  138. package/src/custom/master-data-grid/hooks/use-table-state-reducer.ts +157 -0
  139. package/src/custom/master-data-grid/hooks/use-table-state.ts +31 -0
  140. package/src/custom/master-data-grid/index.ts +16 -0
  141. package/src/custom/master-data-grid/types.ts +466 -0
  142. package/src/custom/master-data-grid/utils/column-generator.tsx +306 -0
  143. package/src/custom/master-data-grid/utils/export-utils.ts +67 -0
  144. package/src/custom/master-data-grid/utils/filter-fns.ts +290 -0
  145. package/src/custom/master-data-grid/utils/index.ts +8 -0
  146. package/src/custom/master-data-grid/utils/pinning-utils.ts +88 -0
  147. package/src/custom/master-data-grid/utils/translation-utils.ts +42 -0
  148. package/src/custom/multi-select.tsx +432 -0
  149. package/src/custom/password-input.tsx +194 -0
  150. package/src/custom/phone-input.tsx +172 -0
  151. package/src/custom/schema-form/custom/index.tsx +1 -0
  152. package/src/custom/schema-form/custom/label.tsx +53 -0
  153. package/src/custom/schema-form/fields/base-input-field.tsx +82 -0
  154. package/src/custom/schema-form/fields/field.tsx +67 -0
  155. package/src/custom/schema-form/fields/index.tsx +5 -0
  156. package/src/custom/schema-form/fields/object.tsx +12 -0
  157. package/src/custom/schema-form/fields/table-array/array-field-item.tsx +90 -0
  158. package/src/custom/schema-form/fields/table-array/array-field-template.tsx +115 -0
  159. package/src/custom/schema-form/index.tsx +259 -0
  160. package/src/custom/schema-form/templates/description.tsx +20 -0
  161. package/src/custom/schema-form/templates/index.tsx +2 -0
  162. package/src/custom/schema-form/templates/submit.tsx +32 -0
  163. package/src/custom/schema-form/types.ts +64 -0
  164. package/src/custom/schema-form/utils/index.ts +4 -0
  165. package/src/custom/schema-form/utils/schema-dependency.ts +655 -0
  166. package/src/custom/schema-form/utils/schemas.ts +289 -0
  167. package/src/custom/schema-form/utils/validation.ts +23 -0
  168. package/src/custom/schema-form/widgets/boolean.tsx +77 -0
  169. package/src/custom/schema-form/widgets/combobox.tsx +274 -0
  170. package/src/custom/schema-form/widgets/date.tsx +59 -0
  171. package/src/custom/schema-form/widgets/email.tsx +34 -0
  172. package/src/custom/schema-form/widgets/index.tsx +10 -0
  173. package/src/custom/schema-form/widgets/password.tsx +40 -0
  174. package/src/custom/schema-form/widgets/phone.tsx +40 -0
  175. package/src/custom/schema-form/widgets/select.tsx +105 -0
  176. package/src/custom/schema-form/widgets/selectable.tsx +25 -0
  177. package/src/custom/schema-form/widgets/string-array.tsx +296 -0
  178. package/src/custom/schema-form/widgets/url.tsx +56 -0
  179. package/src/custom/section-layout-v2.tsx +212 -0
  180. package/src/custom/select-tabs.tsx +109 -0
  181. package/src/custom/selectable.tsx +316 -0
  182. package/src/custom/stepper.tsx +236 -0
  183. package/src/custom/tab-layout.tsx +213 -0
  184. package/src/custom/tanstack-table/fields/index.tsx +12 -0
  185. package/src/custom/tanstack-table/fields/tanstack-table-action-dialogs.tsx +89 -0
  186. package/src/custom/tanstack-table/fields/tanstack-table-column-header.tsx +66 -0
  187. package/src/custom/tanstack-table/fields/tanstack-table-filter-date.tsx +180 -0
  188. package/src/custom/tanstack-table/fields/tanstack-table-filter-faceted.tsx +158 -0
  189. package/src/custom/tanstack-table/fields/tanstack-table-filter-text.tsx +76 -0
  190. package/src/custom/tanstack-table/fields/tanstack-table-pagination.tsx +136 -0
  191. package/src/custom/tanstack-table/fields/tanstack-table-plain-table.tsx +142 -0
  192. package/src/custom/tanstack-table/fields/tanstack-table-row-actions-confirmation.tsx +77 -0
  193. package/src/custom/tanstack-table/fields/tanstack-table-row-actions-custom-dialog.tsx +87 -0
  194. package/src/custom/tanstack-table/fields/tanstack-table-row-actions.tsx +151 -0
  195. package/src/custom/tanstack-table/fields/tanstack-table-table-actions-custom-dialog.tsx +88 -0
  196. package/src/custom/tanstack-table/fields/tanstack-table-table-actions-schemaform-dialog.tsx +47 -0
  197. package/src/custom/tanstack-table/fields/tanstack-table-toolbar.tsx +143 -0
  198. package/src/custom/tanstack-table/fields/tanstack-table-view-options.tsx +171 -0
  199. package/src/custom/tanstack-table/index.tsx +244 -0
  200. package/src/custom/tanstack-table/types/index.ts +328 -0
  201. package/src/custom/tanstack-table/utils/cell-with-actions.tsx +21 -0
  202. package/src/custom/tanstack-table/utils/column-names.ts +26 -0
  203. package/src/custom/tanstack-table/utils/columns-by-row-data.tsx +312 -0
  204. package/src/custom/tanstack-table/utils/editable-columns-by-row-data.tsx +219 -0
  205. package/src/custom/tanstack-table/utils/faceted-boolean-options.tsx +22 -0
  206. package/src/custom/tanstack-table/utils/index.tsx +10 -0
  207. package/src/custom/tanstack-table/utils/pinning-styles.ts +57 -0
  208. package/src/custom/tanstack-table/utils/table.tsx +83 -0
  209. package/src/custom/tanstack-table/utils/test-conditions.ts +17 -0
  210. package/src/custom/timeline.tsx +208 -0
  211. package/src/custom/tree.tsx +200 -0
  212. package/src/custom/tscanify/browser.ts +66 -0
  213. package/src/custom/tscanify/index.ts +51 -0
  214. package/src/custom/tscanify/tscanify-browser.ts +522 -0
  215. package/src/custom/tscanify/tscanify.ts +262 -0
  216. package/src/custom/tscanify/types.ts +22 -0
  217. package/src/custom/webcam.tsx +737 -0
  218. package/src/hooks/.gitkeep +0 -0
  219. package/src/hooks/use-callback-ref.ts +27 -0
  220. package/src/hooks/use-controllable-state.ts +67 -0
  221. package/src/hooks/use-debounce.ts +19 -0
  222. package/src/hooks/use-is-visible.ts +23 -0
  223. package/src/hooks/use-media-query.ts +21 -0
  224. package/src/hooks/use-mobile.ts +21 -0
  225. package/src/hooks/use-on-window-resize.ts +15 -0
  226. package/src/hooks/use-scroll.tsx +22 -0
  227. package/src/lib/utils.ts +61 -0
  228. package/src/lib/zod.ts +2 -0
  229. package/src/styles/core.css +57 -0
  230. package/src/styles/globals.css +130 -0
  231. package/src/test/email-input.test.tsx +217 -0
  232. package/src/test/password-input.test.tsx +92 -0
  233. package/src/test/select-tabs.test.tsx +302 -0
  234. package/src/test/selectable.test.tsx +1093 -0
  235. package/tsconfig.json +13 -0
  236. package/tsconfig.lint.json +8 -0
@@ -0,0 +1,83 @@
1
+ "use client";
2
+
3
+ import * as React from "react";
4
+ import * as ToggleGroupPrimitive from "@radix-ui/react-toggle-group";
5
+ import { type VariantProps } from "class-variance-authority";
6
+
7
+ import { cn } from "@repo/ayasofyazilim-ui/lib/utils";
8
+ import { toggleVariants } from "@repo/ayasofyazilim-ui/components/toggle";
9
+
10
+ const ToggleGroupContext = React.createContext<
11
+ VariantProps<typeof toggleVariants> & {
12
+ spacing?: number;
13
+ }
14
+ >({
15
+ size: "default",
16
+ variant: "default",
17
+ spacing: 0,
18
+ });
19
+
20
+ function ToggleGroup({
21
+ className,
22
+ variant,
23
+ size,
24
+ spacing = 0,
25
+ children,
26
+ ...props
27
+ }: React.ComponentProps<typeof ToggleGroupPrimitive.Root> &
28
+ VariantProps<typeof toggleVariants> & {
29
+ spacing?: number;
30
+ }) {
31
+ return (
32
+ <ToggleGroupPrimitive.Root
33
+ data-slot="toggle-group"
34
+ data-variant={variant}
35
+ data-size={size}
36
+ data-spacing={spacing}
37
+ style={{ "--gap": spacing } as React.CSSProperties}
38
+ className={cn(
39
+ "group/toggle-group flex w-fit items-center gap-[--spacing(var(--gap))] rounded-md data-[spacing=default]:data-[variant=outline]:shadow-xs",
40
+ className
41
+ )}
42
+ {...props}
43
+ >
44
+ <ToggleGroupContext.Provider value={{ variant, size, spacing }}>
45
+ {children}
46
+ </ToggleGroupContext.Provider>
47
+ </ToggleGroupPrimitive.Root>
48
+ );
49
+ }
50
+
51
+ function ToggleGroupItem({
52
+ className,
53
+ children,
54
+ variant,
55
+ size,
56
+ ...props
57
+ }: React.ComponentProps<typeof ToggleGroupPrimitive.Item> &
58
+ VariantProps<typeof toggleVariants>) {
59
+ const context = React.useContext(ToggleGroupContext);
60
+
61
+ return (
62
+ <ToggleGroupPrimitive.Item
63
+ data-slot="toggle-group-item"
64
+ data-variant={context.variant || variant}
65
+ data-size={context.size || size}
66
+ data-spacing={context.spacing}
67
+ className={cn(
68
+ toggleVariants({
69
+ variant: context.variant || variant,
70
+ size: context.size || size,
71
+ }),
72
+ "w-auto min-w-0 shrink-0 px-3 focus:z-10 focus-visible:z-10",
73
+ "data-[spacing=0]:rounded-none data-[spacing=0]:shadow-none data-[spacing=0]:first:rounded-l-md data-[spacing=0]:last:rounded-r-md data-[spacing=0]:data-[variant=outline]:border-l-0 data-[spacing=0]:data-[variant=outline]:first:border-l",
74
+ className
75
+ )}
76
+ {...props}
77
+ >
78
+ {children}
79
+ </ToggleGroupPrimitive.Item>
80
+ );
81
+ }
82
+
83
+ export { ToggleGroup, ToggleGroupItem };
@@ -0,0 +1,47 @@
1
+ "use client";
2
+
3
+ import * as React from "react";
4
+ import * as TogglePrimitive from "@radix-ui/react-toggle";
5
+ import { cva, type VariantProps } from "class-variance-authority";
6
+
7
+ import { cn } from "@repo/ayasofyazilim-ui/lib/utils";
8
+
9
+ const toggleVariants = cva(
10
+ "inline-flex items-center justify-center gap-2 rounded-md text-sm font-medium hover:bg-muted hover:text-muted-foreground disabled:pointer-events-none disabled:opacity-50 data-[state=on]:bg-accent data-[state=on]:text-accent-foreground [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0 focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] outline-none transition-[color,box-shadow] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive whitespace-nowrap",
11
+ {
12
+ variants: {
13
+ variant: {
14
+ default: "bg-transparent",
15
+ outline:
16
+ "border border-input bg-transparent shadow-xs hover:bg-accent hover:text-accent-foreground",
17
+ },
18
+ size: {
19
+ default: "h-9 px-2 min-w-9",
20
+ sm: "h-8 px-1.5 min-w-8",
21
+ lg: "h-10 px-2.5 min-w-10",
22
+ },
23
+ },
24
+ defaultVariants: {
25
+ variant: "default",
26
+ size: "default",
27
+ },
28
+ }
29
+ );
30
+
31
+ function Toggle({
32
+ className,
33
+ variant,
34
+ size,
35
+ ...props
36
+ }: React.ComponentProps<typeof TogglePrimitive.Root> &
37
+ VariantProps<typeof toggleVariants>) {
38
+ return (
39
+ <TogglePrimitive.Root
40
+ data-slot="toggle"
41
+ className={cn(toggleVariants({ variant, size, className }))}
42
+ {...props}
43
+ />
44
+ );
45
+ }
46
+
47
+ export { Toggle, toggleVariants };
@@ -0,0 +1,66 @@
1
+ "use client";
2
+
3
+ import * as React from "react";
4
+ import * as TooltipPrimitive from "@radix-ui/react-tooltip";
5
+
6
+ import { cn } from "@repo/ayasofyazilim-ui/lib/utils";
7
+
8
+ function TooltipProvider({
9
+ delayDuration = 0,
10
+ ...props
11
+ }: React.ComponentProps<typeof TooltipPrimitive.Provider>) {
12
+ return (
13
+ <TooltipPrimitive.Provider
14
+ data-slot="tooltip-provider"
15
+ delayDuration={delayDuration}
16
+ {...props}
17
+ />
18
+ );
19
+ }
20
+
21
+ function Tooltip({
22
+ ...props
23
+ }: React.ComponentProps<typeof TooltipPrimitive.Root>) {
24
+ return (
25
+ <TooltipProvider>
26
+ <TooltipPrimitive.Root data-slot="tooltip" {...props} />
27
+ </TooltipProvider>
28
+ );
29
+ }
30
+
31
+ function TooltipTrigger({
32
+ ...props
33
+ }: React.ComponentProps<typeof TooltipPrimitive.Trigger>) {
34
+ return <TooltipPrimitive.Trigger data-slot="tooltip-trigger" {...props} />;
35
+ }
36
+
37
+ function TooltipContent({
38
+ className,
39
+ sideOffset = 0,
40
+ children,
41
+ ...props
42
+ }: React.ComponentProps<typeof TooltipPrimitive.Content>) {
43
+ return (
44
+ <TooltipPrimitive.Portal>
45
+ <TooltipPrimitive.Content
46
+ data-slot="tooltip-content"
47
+ sideOffset={sideOffset}
48
+ className={cn(
49
+ "bg-foreground text-background animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-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 w-fit origin-(--radix-tooltip-content-transform-origin) rounded-md px-3 py-1.5 text-xs text-balance",
50
+ className
51
+ )}
52
+ {...props}
53
+ >
54
+ {children}
55
+ <TooltipPrimitive.Arrow
56
+ className="-my-px border-none fill-(--tooltip-color) "
57
+ width={12}
58
+ height={7}
59
+ aria-hidden="true"
60
+ />
61
+ </TooltipPrimitive.Content>
62
+ </TooltipPrimitive.Portal>
63
+ );
64
+ }
65
+
66
+ export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };
@@ -0,0 +1,48 @@
1
+ import {
2
+ Button,
3
+ buttonVariants,
4
+ } from "@repo/ayasofyazilim-ui/components/button";
5
+ import { cn } from "@repo/ayasofyazilim-ui/lib/utils";
6
+ import { VariantProps } from "class-variance-authority";
7
+ import React, { ComponentType } from "react";
8
+
9
+ export function ActionList({
10
+ className,
11
+ children,
12
+ }: {
13
+ className?: string;
14
+ children: React.ReactNode;
15
+ }) {
16
+ return (
17
+ <div
18
+ className={cn(
19
+ "justify-end gap-2 rounded-md border p-2 has-[*]:flex hidden",
20
+ className
21
+ )}
22
+ >
23
+ {children}
24
+ </div>
25
+ );
26
+ }
27
+
28
+ export function ActionButton({
29
+ loading,
30
+ onClick,
31
+ text,
32
+ icon: Icon,
33
+ variant = "outline",
34
+ }: {
35
+ loading: boolean;
36
+ onClick?: () => void;
37
+ text: string;
38
+ icon: ComponentType<{ className?: string }>;
39
+ variant?: VariantProps<typeof buttonVariants>["variant"];
40
+ }) {
41
+ return (
42
+ <Button disabled={loading} onClick={onClick} variant={variant}>
43
+ <Icon className="mr-2 size-4" />
44
+ <span className="sr-only">{text}</span>
45
+ <span className="sm:hidden md:block">{text}</span>
46
+ </Button>
47
+ );
48
+ }
@@ -0,0 +1,287 @@
1
+ "use client";
2
+
3
+ import { CheckIcon, ChevronDown, XCircle, XIcon } from "lucide-react";
4
+ import { Dispatch, SetStateAction, useEffect, useState } from "react";
5
+ import { Badge } from "@repo/ayasofyazilim-ui/components/badge";
6
+ import { Button } from "@repo/ayasofyazilim-ui/components/button";
7
+ import {
8
+ Command as Cmd,
9
+ CommandGroup,
10
+ CommandInput,
11
+ CommandItem,
12
+ CommandList,
13
+ } from "@repo/ayasofyazilim-ui/components/command";
14
+ import {
15
+ Popover,
16
+ PopoverContent,
17
+ PopoverTrigger,
18
+ } from "@repo/ayasofyazilim-ui/components/popover";
19
+ import { Separator } from "@repo/ayasofyazilim-ui/components/separator";
20
+ import { Skeleton } from "@repo/ayasofyazilim-ui/components/skeleton";
21
+ import { cn } from "@repo/ayasofyazilim-ui/lib/utils";
22
+ import { useDebounce } from "../hooks/use-debounce";
23
+
24
+ type SearchItem = { id: string; name: string };
25
+
26
+ function CommandGroupItem({
27
+ items,
28
+ id,
29
+ title,
30
+ onChange,
31
+ value,
32
+ multiple,
33
+ }: {
34
+ title: string;
35
+ id: string;
36
+ items: SearchItem[];
37
+ value: SearchItem[];
38
+ onChange: (value: SearchItem[]) => void;
39
+ multiple: boolean;
40
+ }) {
41
+ return (
42
+ <CommandGroup heading={title}>
43
+ {items?.map((currentItem, index) => (
44
+ <CommandItem
45
+ id={`${id}_${index}`}
46
+ key={currentItem.id}
47
+ onSelect={() => {
48
+ if (value.find((i) => i.id === currentItem.id)) {
49
+ return onChange(value.filter((i) => i.id !== currentItem.id));
50
+ }
51
+ if (multiple) {
52
+ return onChange([...value, currentItem]);
53
+ }
54
+ return onChange([currentItem]);
55
+ }}
56
+ value={`${currentItem.id}__${currentItem.name}`}
57
+ >
58
+ {currentItem.name}
59
+ {value.find((i) => i.id === currentItem.id) && (
60
+ <CheckIcon className={cn("ml-auto h-4 w-4")} />
61
+ )}
62
+ </CommandItem>
63
+ ))}
64
+ </CommandGroup>
65
+ );
66
+ }
67
+
68
+ export type AsyncSelectType = {
69
+ suggestions?: SearchItem[];
70
+ data?: SearchItem[];
71
+ value: SearchItem[];
72
+ onChange: (value: SearchItem[]) => void;
73
+ fetchAction: (search: string) => Promise<SearchItem[]>;
74
+ resultText?: string;
75
+ searchText?: string;
76
+ noResultText?: string;
77
+ disabled?: boolean;
78
+ closeOnSelect?: boolean;
79
+ multiple?: boolean;
80
+ id: string;
81
+ classNames?: {
82
+ trigger?: string;
83
+ };
84
+ };
85
+
86
+ export function AsyncSelectBase({
87
+ suggestions = [],
88
+ data,
89
+ value,
90
+ fetchAction,
91
+ onChange,
92
+ resultText = "Results",
93
+ searchText = "Search",
94
+ noResultText = "No result",
95
+ disabled = false,
96
+ multiple = true,
97
+ closeOnSelect = false,
98
+ id,
99
+ setIsPopoverOpen,
100
+ }: Omit<AsyncSelectType, "classNames"> & {
101
+ setIsPopoverOpen: Dispatch<SetStateAction<boolean>>;
102
+ }) {
103
+ const [loading, setLoading] = useState(false);
104
+ const [searchInput, setSearchInput] = useState("");
105
+ const searchValue = useDebounce(searchInput, 500);
106
+
107
+ const [items, setItems] = useState<SearchItem[]>(data || []);
108
+ const showableItems = items.filter(
109
+ (item) => !value.find((i) => i.id === item.id)
110
+ );
111
+ const showableSuggestions = suggestions.filter(
112
+ (item) => !value.find((i) => i.id === item.id)
113
+ );
114
+ function onSearch(search: string) {
115
+ setSearchInput(search);
116
+ setLoading(true);
117
+ setItems([]);
118
+ }
119
+ function handleOnChange(value: SearchItem[]) {
120
+ if (disabled) return;
121
+ onChange(value);
122
+ }
123
+
124
+ useEffect(() => {
125
+ if (searchValue === "" && searchInput === "") {
126
+ setLoading(true);
127
+ fetchAction("").then((res) => {
128
+ setItems(res);
129
+ setLoading(false);
130
+ });
131
+ return;
132
+ }
133
+ if (searchValue !== searchInput) return;
134
+
135
+ fetchAction(searchValue).then((res) => {
136
+ setItems(res);
137
+ setLoading(false);
138
+ });
139
+ }, [searchValue, searchInput, fetchAction]);
140
+
141
+ return (
142
+ <Cmd aria-disabled={disabled}>
143
+ <CommandInput
144
+ id={`${id}_input`}
145
+ data-testid={`${id}_input`}
146
+ placeholder={searchText}
147
+ onValueChange={(search) => onSearch(search)}
148
+ disabled={disabled}
149
+ />
150
+
151
+ <CommandList className="overflow-y-auto max-h-48">
152
+ {loading && (
153
+ <div className="p-1 text-sm">
154
+ <Skeleton className="h-7 w-full mb-1" />
155
+ </div>
156
+ )}
157
+
158
+ {!loading && items.length === 0 && searchValue.length > 0 && (
159
+ <div className="text-sm p-2">{noResultText}</div>
160
+ )}
161
+
162
+ {value.length > 0 && (
163
+ <CommandGroupItem
164
+ items={value}
165
+ id={`${id}_selected`}
166
+ data-testid={`${id}_selected`}
167
+ value={value}
168
+ title="Selected"
169
+ onChange={(value) => {
170
+ handleOnChange(value);
171
+ if (closeOnSelect) setIsPopoverOpen(false);
172
+ }}
173
+ multiple={multiple}
174
+ />
175
+ )}
176
+
177
+ {!loading &&
178
+ searchValue.length === 0 &&
179
+ showableSuggestions?.length > 0 && (
180
+ <CommandGroupItem
181
+ id={`${id}_item`}
182
+ items={showableSuggestions}
183
+ value={value}
184
+ title="Suggestions"
185
+ onChange={(value) => {
186
+ handleOnChange(value);
187
+ if (closeOnSelect) setIsPopoverOpen(false);
188
+ }}
189
+ multiple={multiple}
190
+ />
191
+ )}
192
+
193
+ {!loading && showableItems.length > 0 && (
194
+ <CommandGroupItem
195
+ id={`${id}_item`}
196
+ items={showableItems}
197
+ value={value}
198
+ title={resultText}
199
+ onChange={(value) => {
200
+ handleOnChange(value);
201
+ if (closeOnSelect) setIsPopoverOpen(false);
202
+ }}
203
+ multiple={multiple}
204
+ />
205
+ )}
206
+ </CommandList>
207
+ </Cmd>
208
+ );
209
+ }
210
+ export default function AsyncSelect(props: AsyncSelectType) {
211
+ const [isPopoverOpen, setIsPopoverOpen] = useState(false);
212
+ return (
213
+ <Popover open={isPopoverOpen} onOpenChange={setIsPopoverOpen}>
214
+ <PopoverTrigger asChild className="w-full">
215
+ <Button
216
+ id={props.id}
217
+ data-testid={props.id}
218
+ disabled={props.disabled}
219
+ type="button"
220
+ onClick={() => setIsPopoverOpen(true)}
221
+ className={cn(
222
+ "flex w-full p-1 rounded-md border items-center justify-between bg-inherit hover:bg-inherit",
223
+ props.classNames?.trigger
224
+ )}
225
+ >
226
+ {props.value.length > 0 ? (
227
+ <div className="flex justify-between items-center w-full">
228
+ <div className="flex flex-wrap items-center">
229
+ {props.value.slice(0, 3).map((value) => (
230
+ <Badge
231
+ key={value.id}
232
+ data-testid={`${props.id}_badge_${value.name}`}
233
+ className="m-1 transition ease-in-out delay-150 hover:-translate-y-1 hover:scale-110 duration-300 border-foreground/10 text-foreground bg-card hover:bg-card/80"
234
+ onClick={() => {
235
+ props.onChange(
236
+ props.value.filter((i) => i.id !== value.id)
237
+ );
238
+ }}
239
+ >
240
+ {value.name}
241
+ <XCircle className="ml-2 h-4 w-4 cursor-pointer" />
242
+ </Badge>
243
+ ))}
244
+ {props.value.length > 3 && (
245
+ <Badge
246
+ className={cn(
247
+ "bg-transparent text-foreground border-foreground/1 hover:bg-transparent"
248
+ )}
249
+ >
250
+ {props.value.length - 3} more
251
+ </Badge>
252
+ )}
253
+ </div>
254
+ <div className="flex items-center justify-between">
255
+ <XIcon
256
+ className="h-4 mx-2 cursor-pointer text-muted-foreground"
257
+ onClick={() => {
258
+ props.onChange([]);
259
+ }}
260
+ />
261
+ <Separator
262
+ orientation="vertical"
263
+ className="flex min-h-6 h-full"
264
+ />
265
+ <ChevronDown className="h-4 mx-2 cursor-pointer text-muted-foreground" />
266
+ </div>
267
+ </div>
268
+ ) : (
269
+ <div className="flex items-center justify-between w-full mx-auto">
270
+ <span className="text-sm text-black mx-3 font-normal">
271
+ {props.searchText}
272
+ </span>
273
+ <ChevronDown className="h-4 cursor-pointer text-muted-foreground mx-2" />
274
+ </div>
275
+ )}
276
+ </Button>
277
+ </PopoverTrigger>
278
+ <PopoverContent
279
+ className="p-0"
280
+ align="start"
281
+ onEscapeKeyDown={() => setIsPopoverOpen(false)}
282
+ >
283
+ <AsyncSelectBase {...props} setIsPopoverOpen={setIsPopoverOpen} />
284
+ </PopoverContent>
285
+ </Popover>
286
+ );
287
+ }
@@ -0,0 +1,116 @@
1
+ "use client";
2
+ import {
3
+ ButtonProps,
4
+ buttonVariants,
5
+ } from "@repo/ayasofyazilim-ui/components/button";
6
+ import {
7
+ Empty,
8
+ EmptyContent,
9
+ EmptyDescription,
10
+ EmptyHeader,
11
+ EmptyTitle,
12
+ } from "@repo/ayasofyazilim-ui/components/empty";
13
+ import { cn } from "@repo/ayasofyazilim-ui/lib/utils";
14
+ import { motion } from "motion/react";
15
+ import Link from "next/link";
16
+
17
+ const PRIMARY_ORB_HORIZONTAL_OFFSET = 40;
18
+ const PRIMARY_ORB_VERTICAL_OFFSET = 20;
19
+
20
+ export function AwesomeNotFound({
21
+ title = "404",
22
+ description = "The page you are looking for does not exist.",
23
+ actions = [],
24
+ }: {
25
+ title?: string;
26
+ description?: string;
27
+ actions?: {
28
+ label: string;
29
+ href: string;
30
+ variant?: ButtonProps["variant"];
31
+ size?: ButtonProps["size"];
32
+ icon?: React.ComponentType;
33
+ }[];
34
+ }) {
35
+ return (
36
+ <div className="relative flex min-h-screen w-full items-center justify-center overflow-hidden bg-[radial-gradient(circle_at_center,rgba(99,102,241,0.1),transparent_70%)] text-foreground">
37
+ <div
38
+ aria-hidden={true}
39
+ className="-z-10 absolute inset-0 overflow-hidden"
40
+ >
41
+ <motion.div
42
+ animate={{
43
+ x: [
44
+ 0,
45
+ PRIMARY_ORB_HORIZONTAL_OFFSET,
46
+ -PRIMARY_ORB_HORIZONTAL_OFFSET,
47
+ 0,
48
+ ],
49
+ y: [
50
+ 0,
51
+ PRIMARY_ORB_VERTICAL_OFFSET,
52
+ -PRIMARY_ORB_VERTICAL_OFFSET,
53
+ 0,
54
+ ],
55
+ rotate: [0, 10, -10, 0],
56
+ }}
57
+ className="absolute top-1/2 left-1/3 size-90 rounded-full bg-linear-to-tr from-purple-500/20 to-blue-500/20 blur-3xl"
58
+ transition={{
59
+ repeat: Number.POSITIVE_INFINITY,
60
+ duration: 4,
61
+ ease: "easeInOut",
62
+ }}
63
+ />
64
+ <motion.div
65
+ animate={{
66
+ x: [
67
+ 0,
68
+ -PRIMARY_ORB_HORIZONTAL_OFFSET,
69
+ PRIMARY_ORB_HORIZONTAL_OFFSET,
70
+ 0,
71
+ ],
72
+ y: [
73
+ 0,
74
+ -PRIMARY_ORB_VERTICAL_OFFSET,
75
+ PRIMARY_ORB_VERTICAL_OFFSET,
76
+ 0,
77
+ ],
78
+ }}
79
+ className="absolute right-1/4 bottom-1/3 size-120 rounded-full bg-linear-to-br from-indigo-400/10 to-pink-400/10 blur-3xl"
80
+ transition={{
81
+ repeat: Number.POSITIVE_INFINITY,
82
+ duration: 4,
83
+ ease: "easeInOut",
84
+ }}
85
+ />
86
+ </div>
87
+
88
+ <Empty>
89
+ <EmptyHeader>
90
+ <EmptyTitle className="font-extrabold text-8xl">{title}</EmptyTitle>
91
+ <EmptyDescription className="text-nowrap">
92
+ {description}
93
+ </EmptyDescription>
94
+ </EmptyHeader>
95
+ <EmptyContent>
96
+ <div className="flex gap-2">
97
+ {actions.map((action) => (
98
+ <Link
99
+ href={action.href}
100
+ className={cn(
101
+ buttonVariants({
102
+ variant: action.variant || "default",
103
+ size: action.size || "default",
104
+ })
105
+ )}
106
+ key={action.label}
107
+ >
108
+ {action.icon && <action.icon />} {action.label}
109
+ </Link>
110
+ ))}
111
+ </div>
112
+ </EmptyContent>
113
+ </Empty>
114
+ </div>
115
+ );
116
+ }