startx 1.0.1 → 1.0.3

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 (147) hide show
  1. package/.dockerignore +4 -0
  2. package/apps/cli/src/commands/index.ts +1 -1
  3. package/apps/cli/src/commands/{common → test}/test.ts +4 -2
  4. package/apps/cli/tsconfig.json +0 -1
  5. package/apps/core-server/Dockerfile +5 -4
  6. package/apps/core-server/package.json +1 -1
  7. package/apps/core-server/tsconfig.json +1 -1
  8. package/apps/queue-worker/package.json +1 -1
  9. package/apps/queue-worker/tsconfig.json +1 -1
  10. package/apps/startx-cli/dist/index.mjs +68 -53
  11. package/apps/startx-cli/src/commands/package.ts +453 -0
  12. package/apps/startx-cli/src/configs/scripts.ts +18 -2
  13. package/apps/startx-cli/src/index.ts +2 -4
  14. package/apps/startx-cli/src/types.ts +2 -4
  15. package/apps/startx-cli/src/utils/inquirer.ts +8 -1
  16. package/apps/web-client/.dockerignore +4 -0
  17. package/apps/web-client/app/app.css +1 -0
  18. package/apps/web-client/app/components.json +23 -0
  19. package/apps/web-client/app/config/auth/auth-state.ts +59 -0
  20. package/apps/web-client/app/config/axios-client.ts +87 -0
  21. package/apps/web-client/app/config/env.ts +5 -0
  22. package/apps/web-client/app/entry.client.tsx +7 -0
  23. package/apps/web-client/app/eslint.config.ts +4 -0
  24. package/apps/web-client/app/root.tsx +77 -0
  25. package/apps/web-client/app/routes/home.tsx +12 -0
  26. package/apps/web-client/app/routes.ts +3 -0
  27. package/apps/web-client/eslint.config.ts +4 -0
  28. package/apps/web-client/package.json +55 -0
  29. package/apps/web-client/react-router.config.ts +7 -0
  30. package/apps/web-client/tsconfig.json +22 -0
  31. package/apps/web-client/vite-env.d.ts +8 -0
  32. package/apps/web-client/vite.config.ts +30 -0
  33. package/biome.json +5 -0
  34. package/configs/eslint-config/eslint.config.ts +1 -0
  35. package/configs/eslint-config/src/configs/base.ts +0 -1
  36. package/configs/eslint-config/src/configs/frontend.ts +1 -1
  37. package/configs/eslint-config/tsconfig.json +1 -1
  38. package/configs/typescript-config/tsconfig.frontend.json +1 -1
  39. package/configs/vitest-config/tsconfig.json +1 -1
  40. package/package.json +1 -1
  41. package/packages/@db/drizzle/tsconfig.json +1 -1
  42. package/packages/@db/sqlite/tsconfig.json +1 -1
  43. package/packages/@repo/env/package.json +1 -2
  44. package/packages/@repo/env/src/utils.ts +17 -11
  45. package/packages/@repo/lib/package.json +3 -1
  46. package/packages/@repo/lib/src/session-module/i-session.ts +108 -0
  47. package/packages/@repo/lib/src/session-module/index.ts +8 -111
  48. package/packages/@repo/lib/src/session-module/redis-session.ts +44 -0
  49. package/packages/@repo/lib/tsconfig.json +0 -1
  50. package/packages/@repo/logger/package.json +0 -1
  51. package/packages/@repo/logger/tsconfig.json +1 -1
  52. package/packages/@repo/mail/tsconfig.json +1 -1
  53. package/packages/@repo/redis/tsconfig.json +1 -1
  54. package/packages/aix/package.json +2 -0
  55. package/packages/aix/src/providers/ai-interface.ts +4 -4
  56. package/packages/aix/src/providers/bedrock/bedrock.ts +261 -0
  57. package/packages/aix/src/providers/default-models.ts +65 -0
  58. package/packages/aix/src/providers/openai/openai.ts +2 -2
  59. package/packages/aix/src/providers/providers.ts +11 -0
  60. package/packages/aix/src/providers/types.ts +1 -1
  61. package/packages/{constants → common}/package.json +4 -2
  62. package/packages/{constants/src/index.ts → common/src/constants.ts} +0 -5
  63. package/packages/common/src/types/users.ts +10 -0
  64. package/packages/{constants → common}/tsconfig.json +0 -3
  65. package/packages/ui/components.json +15 -8
  66. package/packages/ui/package.json +23 -36
  67. package/packages/ui/src/api/axios/i-client.ts +40 -0
  68. package/packages/ui/src/api/index.ts +6 -0
  69. package/packages/ui/src/api/query-provider.tsx +34 -0
  70. package/packages/ui/src/api/use-api/api-builder.ts +139 -0
  71. package/packages/ui/src/api/use-api/api-helpers.ts +165 -0
  72. package/packages/ui/src/api/use-api/api-types.ts +138 -0
  73. package/packages/ui/src/api/use-api/query-factory.ts +66 -0
  74. package/packages/ui/src/api/use-api/react-query/types.ts +64 -0
  75. package/packages/ui/src/api/use-api/react-query/use-api-client.ts +56 -0
  76. package/packages/ui/src/api/use-api/react-query/use-api.ts +297 -0
  77. package/packages/ui/src/components/custom/form-wrapper.tsx +113 -160
  78. package/packages/ui/src/components/custom/grid-component.tsx +4 -4
  79. package/packages/ui/src/components/custom/hover-tool.tsx +1 -1
  80. package/packages/ui/src/components/custom/image-picker.tsx +18 -20
  81. package/packages/ui/src/components/custom/no-content.tsx +6 -16
  82. package/packages/ui/src/components/custom/page-section.tsx +14 -17
  83. package/packages/ui/src/components/custom/simple-popover.tsx +5 -9
  84. package/packages/ui/src/components/custom/theme-provider.tsx +117 -42
  85. package/packages/ui/src/components/custom/typography.tsx +20 -22
  86. package/packages/ui/src/components/extensions/timeline.tsx +100 -0
  87. package/packages/ui/src/components/ui/alert-dialog.tsx +46 -108
  88. package/packages/ui/src/components/ui/avatar.tsx +79 -42
  89. package/packages/ui/src/components/ui/badge.tsx +29 -34
  90. package/packages/ui/src/components/ui/breadcrumb.tsx +65 -81
  91. package/packages/ui/src/components/ui/button.tsx +80 -80
  92. package/packages/ui/src/components/ui/card.tsx +48 -69
  93. package/packages/ui/src/components/ui/carousel.tsx +184 -211
  94. package/packages/ui/src/components/ui/checkbox.tsx +21 -24
  95. package/packages/ui/src/components/ui/command.tsx +121 -102
  96. package/packages/ui/src/components/ui/dialog.tsx +45 -32
  97. package/packages/ui/src/components/ui/dropdown-menu.tsx +45 -33
  98. package/packages/ui/src/components/ui/field.tsx +218 -0
  99. package/packages/ui/src/components/ui/form.tsx +63 -76
  100. package/packages/ui/src/components/ui/input-group.tsx +137 -0
  101. package/packages/ui/src/components/ui/input-otp.tsx +60 -50
  102. package/packages/ui/src/components/ui/input.tsx +16 -15
  103. package/packages/ui/src/components/ui/label.tsx +14 -17
  104. package/packages/ui/src/components/ui/multiple-select.tsx +22 -33
  105. package/packages/ui/src/components/ui/popover.tsx +20 -8
  106. package/packages/ui/src/components/ui/select.tsx +33 -34
  107. package/packages/ui/src/components/ui/separator.tsx +8 -8
  108. package/packages/ui/src/components/ui/sheet.tsx +32 -59
  109. package/packages/ui/src/components/ui/sidebar.tsx +654 -0
  110. package/packages/ui/src/components/ui/skeleton.tsx +2 -8
  111. package/packages/ui/src/components/ui/sonner.tsx +39 -0
  112. package/packages/ui/src/components/ui/spinner.tsx +6 -13
  113. package/packages/ui/src/components/ui/switch.tsx +15 -10
  114. package/packages/ui/src/components/ui/table.tsx +48 -89
  115. package/packages/ui/src/components/ui/tabs.tsx +37 -15
  116. package/packages/ui/src/components/ui/textarea.tsx +13 -13
  117. package/packages/ui/src/components/ui/tooltip.tsx +37 -23
  118. package/packages/ui/src/{components/hooks → hooks}/event/use-click.tsx +6 -10
  119. package/packages/ui/src/hooks/time/use-timer.tsx +51 -0
  120. package/packages/ui/src/hooks/use-media-query.tsx +19 -0
  121. package/packages/ui/src/hooks/use-mobile.tsx +17 -0
  122. package/packages/ui/src/{components/hooks → hooks}/use-update-effect.tsx +2 -2
  123. package/packages/ui/src/lib/utils.ts +113 -0
  124. package/packages/ui/src/styles/globals.css +311 -0
  125. package/packages/ui/src/styles/tailwind.css +89 -0
  126. package/packages/ui/tsconfig.json +7 -9
  127. package/pnpm-workspace.yaml +74 -64
  128. package/packages/ui/postcss.config.mjs +0 -9
  129. package/packages/ui/src/components/extensions/carousel.tsx +0 -392
  130. package/packages/ui/src/components/hooks/time/useTimer.tsx +0 -51
  131. package/packages/ui/src/components/hooks/use-media-query.tsx +0 -19
  132. package/packages/ui/src/components/lib/utils.ts +0 -242
  133. package/packages/ui/src/components/ui/timeline.tsx +0 -118
  134. package/packages/ui/src/components/util/n-formattor.ts +0 -22
  135. package/packages/ui/src/components/util/storage.ts +0 -37
  136. package/packages/ui/src/globals.css +0 -87
  137. package/packages/ui/tailwind.config.ts +0 -94
  138. /package/packages/{constants → common}/eslint.config.ts +0 -0
  139. /package/packages/{constants → common}/src/api.ts +0 -0
  140. /package/packages/{constants → common}/src/time.ts +0 -0
  141. /package/packages/{constants → common}/vitest.config.ts +0 -0
  142. /package/packages/ui/src/{components/hooks/time/useDebounce.tsx → hooks/time/use-debounce.tsx} +0 -0
  143. /package/packages/ui/src/{components/hooks/time/useInterval.tsx → hooks/time/use-interval.tsx} +0 -0
  144. /package/packages/ui/src/{components/hooks/time/useTimeout.tsx → hooks/time/use-timeout.tsx} +0 -0
  145. /package/packages/ui/src/{components/hooks → hooks}/use-persistent-storage.tsx +0 -0
  146. /package/packages/ui/src/{components/hooks → hooks}/use-window-dimension.tsx +0 -0
  147. /package/packages/ui/src/{components/sonner.tsx → sonner.ts} +0 -0
@@ -0,0 +1,218 @@
1
+ "use client";
2
+
3
+ import { cva, type VariantProps } from "class-variance-authority";
4
+ import { useMemo } from "react";
5
+
6
+ import { Label } from "@repo/ui/components/ui/label";
7
+ import { Separator } from "@repo/ui/components/ui/separator";
8
+ import { cn } from "@repo/ui/lib/utils";
9
+
10
+ function FieldSet({ className, ...props }: React.ComponentProps<"fieldset">) {
11
+ return (
12
+ <fieldset
13
+ data-slot="field-set"
14
+ className={cn(
15
+ "flex flex-col gap-4 has-[>[data-slot=checkbox-group]]:gap-3 has-[>[data-slot=radio-group]]:gap-3",
16
+ className
17
+ )}
18
+ {...props}
19
+ />
20
+ );
21
+ }
22
+
23
+ function FieldLegend({
24
+ className,
25
+ variant = "legend",
26
+ ...props
27
+ }: React.ComponentProps<"legend"> & { variant?: "legend" | "label" }) {
28
+ return (
29
+ <legend
30
+ data-slot="field-legend"
31
+ data-variant={variant}
32
+ className={cn("mb-1.5 font-medium data-[variant=label]:text-sm data-[variant=legend]:text-base", className)}
33
+ {...props}
34
+ />
35
+ );
36
+ }
37
+
38
+ function FieldGroup({ className, ...props }: React.ComponentProps<"div">) {
39
+ return (
40
+ <div
41
+ data-slot="field-group"
42
+ className={cn(
43
+ "group/field-group @container/field-group flex w-full flex-col gap-5 data-[slot=checkbox-group]:gap-3 *:data-[slot=field-group]:gap-4",
44
+ className
45
+ )}
46
+ {...props}
47
+ />
48
+ );
49
+ }
50
+
51
+ const fieldVariants = cva("group/field flex w-full gap-2 data-[invalid=true]:text-destructive", {
52
+ variants: {
53
+ orientation: {
54
+ vertical: "flex-col *:w-full [&>.sr-only]:w-auto",
55
+ horizontal:
56
+ "flex-row items-center has-[>[data-slot=field-content]]:items-start *:data-[slot=field-label]:flex-auto has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px",
57
+ responsive:
58
+ "flex-col *:w-full @md/field-group:flex-row @md/field-group:items-center @md/field-group:*:w-auto @md/field-group:has-[>[data-slot=field-content]]:items-start @md/field-group:*:data-[slot=field-label]:flex-auto [&>.sr-only]:w-auto @md/field-group:has-[>[data-slot=field-content]]:[&>[role=checkbox],[role=radio]]:mt-px",
59
+ },
60
+ },
61
+ defaultVariants: {
62
+ orientation: "vertical",
63
+ },
64
+ });
65
+
66
+ function Field({
67
+ className,
68
+ orientation = "vertical",
69
+ ...props
70
+ }: React.ComponentProps<"div"> & VariantProps<typeof fieldVariants>) {
71
+ return (
72
+ <div
73
+ role="group"
74
+ data-slot="field"
75
+ data-orientation={orientation}
76
+ className={cn(fieldVariants({ orientation }), className)}
77
+ {...props}
78
+ />
79
+ );
80
+ }
81
+
82
+ function FieldContent({ className, ...props }: React.ComponentProps<"div">) {
83
+ return (
84
+ <div
85
+ data-slot="field-content"
86
+ className={cn("group/field-content flex flex-1 flex-col gap-0.5 leading-snug", className)}
87
+ {...props}
88
+ />
89
+ );
90
+ }
91
+
92
+ function FieldLabel({ className, ...props }: React.ComponentProps<typeof Label>) {
93
+ return (
94
+ <Label
95
+ data-slot="field-label"
96
+ className={cn(
97
+ "group/field-label peer/field-label flex w-fit gap-2 leading-snug group-data-[disabled=true]/field:opacity-50 has-data-checked:border-primary/30 has-data-checked:bg-primary/5 has-[>[data-slot=field]]:rounded-lg has-[>[data-slot=field]]:border *:data-[slot=field]:p-2.5 dark:has-data-checked:border-primary/20 dark:has-data-checked:bg-primary/10",
98
+ "has-[>[data-slot=field]]:w-full has-[>[data-slot=field]]:flex-col",
99
+ className
100
+ )}
101
+ {...props}
102
+ />
103
+ );
104
+ }
105
+
106
+ function FieldTitle({ className, ...props }: React.ComponentProps<"div">) {
107
+ return (
108
+ <div
109
+ data-slot="field-label"
110
+ className={cn(
111
+ "flex w-fit items-center gap-2 text-sm font-medium group-data-[disabled=true]/field:opacity-50",
112
+ className
113
+ )}
114
+ {...props}
115
+ />
116
+ );
117
+ }
118
+
119
+ function FieldDescription({ className, ...props }: React.ComponentProps<"p">) {
120
+ return (
121
+ <p
122
+ data-slot="field-description"
123
+ className={cn(
124
+ "text-left text-sm leading-normal font-normal text-muted-foreground group-has-data-horizontal/field:text-balance [[data-variant=legend]+&]:-mt-1.5",
125
+ "last:mt-0 nth-last-2:-mt-1",
126
+ "[&>a]:underline [&>a]:underline-offset-4 [&>a:hover]:text-primary",
127
+ className
128
+ )}
129
+ {...props}
130
+ />
131
+ );
132
+ }
133
+
134
+ function FieldSeparator({
135
+ children,
136
+ className,
137
+ ...props
138
+ }: React.ComponentProps<"div"> & {
139
+ children?: React.ReactNode;
140
+ }) {
141
+ return (
142
+ <div
143
+ data-slot="field-separator"
144
+ data-content={!!children}
145
+ className={cn("relative -my-2 h-5 text-sm group-data-[variant=outline]/field-group:-mb-2", className)}
146
+ {...props}
147
+ >
148
+ <Separator className="absolute inset-0 top-1/2" />
149
+ {children ? (
150
+ <span
151
+ className="relative mx-auto block w-fit bg-background px-2 text-muted-foreground"
152
+ data-slot="field-separator-content"
153
+ >
154
+ {children}
155
+ </span>
156
+ ) : null}
157
+ </div>
158
+ );
159
+ }
160
+
161
+ function FieldError({
162
+ className,
163
+ children,
164
+ errors,
165
+ ...props
166
+ }: React.ComponentProps<"div"> & {
167
+ errors?: Array<{ message?: string } | undefined>;
168
+ }) {
169
+ const content = useMemo(() => {
170
+ if (children) {
171
+ return children;
172
+ }
173
+
174
+ if (!errors?.length) {
175
+ return null;
176
+ }
177
+
178
+ const uniqueErrors = [...new Map(errors.map(error => [error?.message, error])).values()];
179
+
180
+ if (uniqueErrors?.length == 1) {
181
+ return uniqueErrors[0]?.message;
182
+ }
183
+
184
+ return (
185
+ <ul className="ml-4 flex list-disc flex-col gap-1">
186
+ {uniqueErrors.map((error, index) => error?.message && <li key={index}>{error.message}</li>)}
187
+ </ul>
188
+ );
189
+ }, [children, errors]);
190
+
191
+ if (!content) {
192
+ return null;
193
+ }
194
+
195
+ return (
196
+ <div
197
+ role="alert"
198
+ data-slot="field-error"
199
+ className={cn("text-sm font-normal text-destructive", className)}
200
+ {...props}
201
+ >
202
+ {content}
203
+ </div>
204
+ );
205
+ }
206
+
207
+ export {
208
+ Field,
209
+ FieldLabel,
210
+ FieldDescription,
211
+ FieldError,
212
+ FieldGroup,
213
+ FieldLegend,
214
+ FieldSeparator,
215
+ FieldSet,
216
+ FieldContent,
217
+ FieldTitle,
218
+ };
@@ -1,13 +1,11 @@
1
- import type * as LabelPrimitive from "@radix-ui/react-label";
2
- import { Slot } from "@radix-ui/react-slot";
3
1
  import { CircleAlert } from "lucide-react";
4
2
  import * as React from "react";
5
3
  import type { ControllerProps, FieldPath, FieldValues } from "react-hook-form";
6
4
  import { Controller, FormProvider, useFormContext } from "react-hook-form";
7
5
  import type { ClassNameValue } from "tailwind-merge";
8
6
 
7
+ import { cn } from "@repo/ui/lib/utils";
9
8
  import { Label } from "./label";
10
- import { cn } from "../lib/utils";
11
9
 
12
10
  const Form = FormProvider;
13
11
 
@@ -76,91 +74,80 @@ const FormItem = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivEl
76
74
  FormItem.displayName = "FormItem";
77
75
 
78
76
  const FormLabel = React.forwardRef<
79
- React.ElementRef<typeof LabelPrimitive.Root>,
80
- React.ComponentPropsWithoutRef<typeof LabelPrimitive.Root> & {
77
+ React.ElementRef<typeof Label>,
78
+ React.ComponentPropsWithoutRef<typeof Label> & {
81
79
  className?: ClassNameValue;
82
80
  }
83
81
  >(({ className, ...props }, ref) => {
84
82
  const { error, formItemId } = useFormField();
85
83
 
86
- return (
87
- <Label
88
- ref={ref}
89
- className={cn(error && "text-destructive", className)}
90
- htmlFor={formItemId}
91
- {...props}
92
- />
93
- );
84
+ return <Label ref={ref} className={cn(error && "text-destructive", className)} htmlFor={formItemId} {...props} />;
94
85
  });
95
86
  FormLabel.displayName = "FormLabel";
96
87
 
97
- const FormControl = React.forwardRef<
98
- React.ElementRef<typeof Slot>,
99
- React.ComponentPropsWithoutRef<typeof Slot>
100
- >(({ ...props }, ref) => {
101
- const { error, formItemId, formDescriptionId, formMessageId } = useFormField();
102
-
103
- return (
104
- <Slot
105
- ref={ref}
106
- id={formItemId}
107
- aria-describedby={!error ? `${formDescriptionId}` : `${formDescriptionId} ${formMessageId}`}
108
- aria-invalid={!!error}
109
- {...props}
110
- />
111
- );
112
- });
113
- FormControl.displayName = "FormControl";
114
-
115
- const FormDescription = React.forwardRef<
116
- HTMLParagraphElement,
117
- React.HTMLAttributes<HTMLParagraphElement>
118
- >(({ className, ...props }, ref) => {
119
- const { formDescriptionId } = useFormField();
88
+ const FormDescription = React.forwardRef<HTMLParagraphElement, React.HTMLAttributes<HTMLParagraphElement>>(
89
+ ({ className, ...props }, ref) => {
90
+ const { formDescriptionId } = useFormField();
120
91
 
121
- return (
122
- <p
123
- ref={ref}
124
- id={formDescriptionId}
125
- className={cn("text-sm text-muted-foreground", className)}
126
- {...props}
127
- />
128
- );
129
- });
92
+ return <p ref={ref} id={formDescriptionId} className={cn("text-sm text-muted-foreground", className)} {...props} />;
93
+ }
94
+ );
130
95
  FormDescription.displayName = "FormDescription";
131
96
 
132
- const FormMessage = React.forwardRef<
133
- HTMLParagraphElement,
134
- React.HTMLAttributes<HTMLParagraphElement>
135
- >(({ className, children, ...props }, ref) => {
136
- const { error, formMessageId } = useFormField();
137
- const body = error ? String(error?.message) : children;
97
+ const FormMessage = React.forwardRef<HTMLParagraphElement, React.HTMLAttributes<HTMLParagraphElement>>(
98
+ ({ className, children, ...props }, ref) => {
99
+ const { error, formMessageId } = useFormField();
100
+ const body = error ? String(error?.message) : children;
138
101
 
139
- if (!body) {
140
- return null;
141
- }
102
+ if (!body) {
103
+ return null;
104
+ }
142
105
 
143
- return (
144
- <span
145
- ref={ref}
146
- id={formMessageId}
147
- className={cn("text-sm flex gap-2 items-center font-medium text-destructive", className)}
148
- {...props}
149
- >
150
- <CircleAlert size={18} strokeWidth={2} />
151
- <p>{body}</p>
152
- </span>
153
- );
154
- });
106
+ return (
107
+ <span
108
+ ref={ref}
109
+ id={formMessageId}
110
+ className={cn("text-sm flex gap-2 items-center font-medium text-destructive", className)}
111
+ {...props}
112
+ >
113
+ <CircleAlert size={18} strokeWidth={2} />
114
+ <p>{body}</p>
115
+ </span>
116
+ );
117
+ }
118
+ );
155
119
  FormMessage.displayName = "FormMessage";
120
+ const FormControl = React.forwardRef<HTMLElement, React.HTMLAttributes<HTMLElement> & { children: React.ReactNode }>(
121
+ ({ className, children, ...props }, ref) => {
122
+ if (!React.isValidElement(children)) {
123
+ return <>{children}</>;
124
+ }
125
+
126
+ const child = children as React.ReactElement<React.HTMLAttributes<HTMLElement> & React.RefAttributes<HTMLElement>>;
127
+
128
+ return React.cloneElement(child, {
129
+ ...props,
130
+ ...child.props,
131
+ ref: (node: HTMLElement) => {
132
+ const childRef = (child as any)?.ref ?? child?.props?.ref;
133
+
134
+ if (typeof childRef === "function") {
135
+ childRef(node);
136
+ } else if (childRef && "current" in childRef) {
137
+ (childRef as React.MutableRefObject<HTMLElement | null>).current = node;
138
+ }
139
+
140
+ if (typeof ref === "function") {
141
+ ref(node);
142
+ } else if (ref && "current" in ref) {
143
+ (ref as React.MutableRefObject<HTMLElement | null>).current = node;
144
+ }
145
+ },
146
+ className: cn("w-full", className, child.props.className),
147
+ });
148
+ }
149
+ );
156
150
 
157
- export {
158
- useFormField,
159
- Form,
160
- FormItem,
161
- FormLabel,
162
- FormControl,
163
- FormDescription,
164
- FormMessage,
165
- FormField,
166
- };
151
+ FormControl.displayName = "FormControl";
152
+
153
+ export { useFormField, Form, FormItem, FormLabel, FormDescription, FormMessage, FormField };
@@ -0,0 +1,137 @@
1
+ /* eslint-disable jsx-a11y/click-events-have-key-events */
2
+ /* eslint-disable jsx-a11y/no-noninteractive-element-interactions */
3
+ "use client";
4
+
5
+ import { cva, type VariantProps } from "class-variance-authority";
6
+ import * as React from "react";
7
+
8
+ import { Button } from "@repo/ui/components/ui/button";
9
+ import { Input } from "@repo/ui/components/ui/input";
10
+ import { Textarea } from "@repo/ui/components/ui/textarea";
11
+ import { cn } from "@repo/ui/lib/utils";
12
+
13
+ function InputGroup({ className, ...props }: React.ComponentProps<"div">) {
14
+ return (
15
+ <div
16
+ data-slot="input-group"
17
+ role="group"
18
+ className={cn(
19
+ "group/input-group relative flex h-8 w-full min-w-0 items-center rounded-lg border border-input transition-colors outline-none in-data-[slot=combobox-content]:focus-within:border-inherit in-data-[slot=combobox-content]:focus-within:ring-0 has-disabled:bg-input/50 has-disabled:opacity-50 has-[[data-slot=input-group-control]:focus-visible]:border-ring has-[[data-slot=input-group-control]:focus-visible]:ring-3 has-[[data-slot=input-group-control]:focus-visible]:ring-ring/50 has-[[data-slot][aria-invalid=true]]:border-destructive has-[[data-slot][aria-invalid=true]]:ring-3 has-[[data-slot][aria-invalid=true]]:ring-destructive/20 has-[>[data-align=block-end]]:h-auto has-[>[data-align=block-end]]:flex-col has-[>[data-align=block-start]]:h-auto has-[>[data-align=block-start]]:flex-col has-[>textarea]:h-auto dark:bg-input/30 dark:has-disabled:bg-input/80 dark:has-[[data-slot][aria-invalid=true]]:ring-destructive/40 has-[>[data-align=block-end]]:[&>input]:pt-3 has-[>[data-align=block-start]]:[&>input]:pb-3 has-[>[data-align=inline-end]]:[&>input]:pr-1.5 has-[>[data-align=inline-start]]:[&>input]:pl-1.5",
20
+ className
21
+ )}
22
+ {...props}
23
+ />
24
+ );
25
+ }
26
+
27
+ const inputGroupAddonVariants = cva(
28
+ "flex h-auto cursor-text items-center justify-center gap-2 py-1.5 text-sm font-medium text-muted-foreground select-none group-data-[disabled=true]/input-group:opacity-50 [&>kbd]:rounded-[calc(var(--radius)-5px)] [&>svg:not([class*='size-'])]:size-4",
29
+ {
30
+ variants: {
31
+ align: {
32
+ "inline-start": "order-first pl-2 has-[>button]:ml-[-0.3rem] has-[>kbd]:ml-[-0.15rem]",
33
+ "inline-end": "order-last pr-2 has-[>button]:mr-[-0.3rem] has-[>kbd]:mr-[-0.15rem]",
34
+ "block-start":
35
+ "order-first w-full justify-start px-2.5 pt-2 group-has-[>input]/input-group:pt-2 [.border-b]:pb-2",
36
+ "block-end": "order-last w-full justify-start px-2.5 pb-2 group-has-[>input]/input-group:pb-2 [.border-t]:pt-2",
37
+ },
38
+ },
39
+ defaultVariants: {
40
+ align: "inline-start",
41
+ },
42
+ }
43
+ );
44
+
45
+ function InputGroupAddon({
46
+ className,
47
+ align = "inline-start",
48
+ ...props
49
+ }: React.ComponentProps<"div"> & VariantProps<typeof inputGroupAddonVariants>) {
50
+ return (
51
+ <div
52
+ role="group"
53
+ data-slot="input-group-addon"
54
+ data-align={align}
55
+ className={cn(inputGroupAddonVariants({ align }), className)}
56
+ onClick={e => {
57
+ if ((e.target as HTMLElement).closest("button")) {
58
+ return;
59
+ }
60
+ e.currentTarget.parentElement?.querySelector("input")?.focus();
61
+ }}
62
+ {...props}
63
+ />
64
+ );
65
+ }
66
+
67
+ const inputGroupButtonVariants = cva("flex items-center gap-2 text-sm shadow-none", {
68
+ variants: {
69
+ size: {
70
+ xs: "h-6 gap-1 rounded-[calc(var(--radius)-3px)] px-1.5 [&>svg:not([class*='size-'])]:size-3.5",
71
+ sm: "",
72
+ "icon-xs": "size-6 rounded-[calc(var(--radius)-3px)] p-0 has-[>svg]:p-0",
73
+ "icon-sm": "size-8 p-0 has-[>svg]:p-0",
74
+ },
75
+ },
76
+ defaultVariants: {
77
+ size: "xs",
78
+ },
79
+ });
80
+
81
+ function InputGroupButton({
82
+ className,
83
+ type = "button",
84
+ variant = "ghost",
85
+ size = "xs",
86
+ ...props
87
+ }: Omit<React.ComponentProps<typeof Button>, "size"> & VariantProps<typeof inputGroupButtonVariants>) {
88
+ return (
89
+ <Button
90
+ type={type}
91
+ data-size={size}
92
+ variant={variant}
93
+ className={cn(inputGroupButtonVariants({ size }), className)}
94
+ {...props}
95
+ />
96
+ );
97
+ }
98
+
99
+ function InputGroupText({ className, ...props }: React.ComponentProps<"span">) {
100
+ return (
101
+ <span
102
+ className={cn(
103
+ "flex items-center gap-2 text-sm text-muted-foreground [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4",
104
+ className
105
+ )}
106
+ {...props}
107
+ />
108
+ );
109
+ }
110
+
111
+ function InputGroupInput({ className, ...props }: React.ComponentProps<"input">) {
112
+ return (
113
+ <Input
114
+ data-slot="input-group-control"
115
+ className={cn(
116
+ "flex-1 rounded-none border-0 bg-transparent shadow-none ring-0 focus-visible:ring-0 disabled:bg-transparent aria-invalid:ring-0 dark:bg-transparent dark:disabled:bg-transparent",
117
+ className
118
+ )}
119
+ {...props}
120
+ />
121
+ );
122
+ }
123
+
124
+ function InputGroupTextarea({ className, ...props }: React.ComponentProps<"textarea">) {
125
+ return (
126
+ <Textarea
127
+ data-slot="input-group-control"
128
+ className={cn(
129
+ "flex-1 resize-none rounded-none border-0 bg-transparent py-2 shadow-none ring-0 focus-visible:ring-0 disabled:bg-transparent aria-invalid:ring-0 dark:bg-transparent dark:disabled:bg-transparent",
130
+ className
131
+ )}
132
+ {...props}
133
+ />
134
+ );
135
+ }
136
+
137
+ export { InputGroup, InputGroupAddon, InputGroupButton, InputGroupText, InputGroupInput, InputGroupTextarea };
@@ -1,74 +1,84 @@
1
+ /* eslint-disable @typescript-eslint/no-redundant-type-constituents */
1
2
  "use client";
3
+
2
4
  import { OTPInput, OTPInputContext } from "input-otp";
3
5
  import { MinusIcon } from "lucide-react";
4
6
  import * as React from "react";
5
7
 
6
- import { cn } from "../lib/utils";
8
+ import { cn } from "@repo/ui/lib/utils";
7
9
 
8
10
  function InputOTP({
9
- className,
10
- containerClassName,
11
- ...props
11
+ className,
12
+ containerClassName,
13
+ ...props
12
14
  }: React.ComponentProps<typeof OTPInput> & {
13
- containerClassName?: string;
15
+ containerClassName?: string;
14
16
  }) {
15
- return (
16
- <OTPInput
17
- data-slot="input-otp"
18
- containerClassName={cn(
19
- "flex items-center gap-2 has-disabled:opacity-50",
20
- containerClassName
21
- )}
22
- className={cn("disabled:cursor-not-allowed", className)}
23
- {...props}
24
- />
25
- );
17
+ return (
18
+ <OTPInput
19
+ data-slot="input-otp"
20
+ containerClassName={cn("cn-input-otp flex items-center has-disabled:opacity-50", containerClassName)}
21
+ spellCheck={false}
22
+ className={cn("disabled:cursor-not-allowed", className)}
23
+ {...props}
24
+ />
25
+ );
26
26
  }
27
27
 
28
28
  function InputOTPGroup({ className, ...props }: React.ComponentProps<"div">) {
29
- return (
30
- <div
31
- data-slot="input-otp-group"
32
- className={cn("flex items-center", className)}
33
- {...props}
34
- />
35
- );
29
+ return (
30
+ <div
31
+ data-slot="input-otp-group"
32
+ className={cn(
33
+ "flex items-center rounded-lg has-aria-invalid:border-destructive has-aria-invalid:ring-3 has-aria-invalid:ring-destructive/20 dark:has-aria-invalid:ring-destructive/40",
34
+ className
35
+ )}
36
+ {...props}
37
+ />
38
+ );
36
39
  }
37
40
 
38
41
  function InputOTPSlot({
39
- index,
40
- className,
41
- ...props
42
+ index,
43
+ className,
44
+ ...props
42
45
  }: React.ComponentProps<"div"> & {
43
- index: number;
46
+ index: number;
44
47
  }) {
45
- const inputOTPContext = React.useContext(OTPInputContext);
46
- const { char, hasFakeCaret, isActive } = inputOTPContext?.slots[index] ?? {};
48
+ const inputOTPContext = React.useContext(OTPInputContext);
49
+ const { char, hasFakeCaret, isActive } = inputOTPContext?.slots[index] ?? {};
47
50
 
48
- return (
49
- <div
50
- data-slot="input-otp-slot"
51
- data-active={isActive}
52
- className={cn(
53
- "data-[active=true]:border-ring data-[active=true]:ring-ring/50 data-[active=true]:aria-invalid:ring-destructive/20 dark:data-[active=true]:aria-invalid:ring-destructive/40 aria-invalid:border-destructive data-[active=true]:aria-invalid:border-destructive dark:bg-input/30 border-input relative flex h-9 w-9 items-center justify-center border-y border-r text-sm shadow-xs transition-all outline-none first:rounded-l-md first:border-l last:rounded-r-md data-[active=true]:z-10 data-[active=true]:ring-[3px]",
54
- className
55
- )}
56
- {...props}
57
- >
58
- {char}
59
- {hasFakeCaret ? <div className="pointer-events-none absolute inset-0 flex items-center justify-center">
60
- <div className="animate-caret-blink bg-foreground h-4 w-px duration-1000" />
61
- </div> : null}
62
- </div>
63
- );
51
+ return (
52
+ <div
53
+ data-slot="input-otp-slot"
54
+ data-active={isActive}
55
+ className={cn(
56
+ "relative flex size-8 items-center justify-center border-y border-r border-input text-sm transition-all outline-none first:rounded-l-lg first:border-l last:rounded-r-lg aria-invalid:border-destructive data-[active=true]:z-10 data-[active=true]:border-ring data-[active=true]:ring-3 data-[active=true]:ring-ring/50 data-[active=true]:aria-invalid:border-destructive data-[active=true]:aria-invalid:ring-destructive/20 dark:bg-input/30 dark:data-[active=true]:aria-invalid:ring-destructive/40",
57
+ className
58
+ )}
59
+ {...props}
60
+ >
61
+ {char}
62
+ {hasFakeCaret ? (
63
+ <div className="pointer-events-none absolute inset-0 flex items-center justify-center">
64
+ <div className="h-4 w-px animate-caret-blink bg-foreground duration-1000" />
65
+ </div>
66
+ ) : null}
67
+ </div>
68
+ );
64
69
  }
65
70
 
66
71
  function InputOTPSeparator({ ...props }: React.ComponentProps<"div">) {
67
- return (
68
- <div data-slot="input-otp-separator" role="separator" {...props}>
69
- <MinusIcon />
70
- </div>
71
- );
72
+ return (
73
+ <div
74
+ data-slot="input-otp-separator"
75
+ className="flex items-center [&_svg:not([class*='size-'])]:size-4"
76
+ role="separator"
77
+ {...props}
78
+ >
79
+ <MinusIcon />
80
+ </div>
81
+ );
72
82
  }
73
83
 
74
84
  export { InputOTP, InputOTPGroup, InputOTPSlot, InputOTPSeparator };