-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #159 from gutentag2012/fix/next-type-inference
Fix/next type inference
- Loading branch information
Showing
35 changed files
with
1,408 additions
and
53 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. | ||
|
||
# dependencies | ||
/node_modules | ||
/.pnp | ||
.pnp.* | ||
.yarn/* | ||
!.yarn/patches | ||
!.yarn/plugins | ||
!.yarn/releases | ||
!.yarn/versions | ||
|
||
# testing | ||
/coverage | ||
|
||
# next.js | ||
/.next/ | ||
/out/ | ||
|
||
# production | ||
/build | ||
|
||
# misc | ||
.DS_Store | ||
*.pem | ||
|
||
# debug | ||
npm-debug.log* | ||
yarn-debug.log* | ||
yarn-error.log* | ||
.pnpm-debug.log* | ||
|
||
# env files (can opt-in for committing if needed) | ||
.env* | ||
|
||
# vercel | ||
.vercel | ||
|
||
# typescript | ||
*.tsbuildinfo | ||
next-env.d.ts |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
# Form Signals Example | Next Form Signals | ||
|
||
This is an example application that demonstrates how to use the `form-signals` library within Next.js. | ||
|
||
[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/fork/github/gutentag2012/form-signals/tree/main/examples/react/next-form-signals?startScript=example&title=Form%20Signals%20|%20Next%2Ejs%20Example) | ||
|
||
> [!NOTE] | ||
> For now I did not find a way to use the `@preact/signals-react-transform` package to automatically track signals, that is why you will find the manual use of the `useSignals()` hook. | ||
## Quick Start | ||
|
||
Install the dependencies: | ||
|
||
```bash | ||
pnpm install | ||
``` | ||
|
||
Run the example: | ||
|
||
```bash | ||
pnpm example | ||
``` | ||
|
||
## Relevant Files | ||
|
||
- [`components/form/LoginForm.tsx`](./components/form/LoginForm.tsx): The main form components for the example. |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
@tailwind base; | ||
@tailwind components; | ||
@tailwind utilities; | ||
|
||
body { | ||
font-family: Arial, Helvetica, sans-serif; | ||
} | ||
|
||
@layer base { | ||
:root { | ||
--background: 0 0% 100%; | ||
--foreground: 222.2 84% 4.9%; | ||
--card: 0 0% 100%; | ||
--card-foreground: 222.2 84% 4.9%; | ||
--popover: 0 0% 100%; | ||
--popover-foreground: 222.2 84% 4.9%; | ||
--primary: 222.2 47.4% 11.2%; | ||
--primary-foreground: 210 40% 98%; | ||
--secondary: 210 40% 96.1%; | ||
--secondary-foreground: 222.2 47.4% 11.2%; | ||
--muted: 210 40% 96.1%; | ||
--muted-foreground: 215.4 16.3% 46.9%; | ||
--accent: 210 40% 96.1%; | ||
--accent-foreground: 222.2 47.4% 11.2%; | ||
--destructive: 0 84.2% 60.2%; | ||
--destructive-foreground: 210 40% 98%; | ||
--border: 214.3 31.8% 91.4%; | ||
--input: 214.3 31.8% 91.4%; | ||
--ring: 222.2 84% 4.9%; | ||
--chart-1: 12 76% 61%; | ||
--chart-2: 173 58% 39%; | ||
--chart-3: 197 37% 24%; | ||
--chart-4: 43 74% 66%; | ||
--chart-5: 27 87% 67%; | ||
--radius: 0.5rem; | ||
} | ||
.dark { | ||
--background: 222.2 84% 4.9%; | ||
--foreground: 210 40% 98%; | ||
--card: 222.2 84% 4.9%; | ||
--card-foreground: 210 40% 98%; | ||
--popover: 222.2 84% 4.9%; | ||
--popover-foreground: 210 40% 98%; | ||
--primary: 210 40% 98%; | ||
--primary-foreground: 222.2 47.4% 11.2%; | ||
--secondary: 217.2 32.6% 17.5%; | ||
--secondary-foreground: 210 40% 98%; | ||
--muted: 217.2 32.6% 17.5%; | ||
--muted-foreground: 215 20.2% 65.1%; | ||
--accent: 217.2 32.6% 17.5%; | ||
--accent-foreground: 210 40% 98%; | ||
--destructive: 0 62.8% 30.6%; | ||
--destructive-foreground: 210 40% 98%; | ||
--border: 217.2 32.6% 17.5%; | ||
--input: 217.2 32.6% 17.5%; | ||
--ring: 212.7 26.8% 83.9%; | ||
--chart-1: 220 70% 50%; | ||
--chart-2: 160 60% 45%; | ||
--chart-3: 30 80% 55%; | ||
--chart-4: 280 65% 60%; | ||
--chart-5: 340 75% 55%; | ||
} | ||
} | ||
|
||
@layer base { | ||
* { | ||
@apply border-border; | ||
} | ||
body { | ||
@apply bg-background text-foreground; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
import type { Metadata } from 'next' | ||
import { Geist, Geist_Mono } from 'next/font/google' | ||
import './globals.css' | ||
|
||
const geistSans = Geist({ | ||
variable: '--font-geist-sans', | ||
subsets: ['latin'], | ||
}) | ||
|
||
const geistMono = Geist_Mono({ | ||
variable: '--font-geist-mono', | ||
subsets: ['latin'], | ||
}) | ||
|
||
export const metadata: Metadata = { | ||
title: 'Create Next App', | ||
description: 'Generated by create next app', | ||
} | ||
|
||
export default function RootLayout({ | ||
children, | ||
}: Readonly<{ | ||
children: React.ReactNode | ||
}>) { | ||
return ( | ||
<html lang="en"> | ||
<body | ||
className={`${geistSans.variable} ${geistMono.variable} antialiased`} | ||
> | ||
{children} | ||
</body> | ||
</html> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import { LoginForm } from '@/components/form/LoginForm' | ||
|
||
export default function Home() { | ||
return ( | ||
<main className="mx-auto max-w-xl"> | ||
<h1 className="mt-8 text-center font-bold text-3xl">Login</h1> | ||
<LoginForm /> | ||
</main> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
{ | ||
"$schema": "https://ui.shadcn.com/schema.json", | ||
"style": "new-york", | ||
"rsc": true, | ||
"tsx": true, | ||
"tailwind": { | ||
"config": "tailwind.config.ts", | ||
"css": "app/globals.css", | ||
"baseColor": "slate", | ||
"cssVariables": true, | ||
"prefix": "" | ||
}, | ||
"aliases": { | ||
"components": "@/components", | ||
"utils": "@/lib/utils", | ||
"ui": "@/components/ui", | ||
"lib": "@/lib", | ||
"hooks": "@/hooks" | ||
}, | ||
"iconLibrary": "lucide" | ||
} |
25 changes: 25 additions & 0 deletions
25
examples/react/next-form-signals/components/form/ErrorText.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import { useFieldContext, useFieldGroupContext } from '@formsignals/form-react' | ||
|
||
export const ErrorText = () => { | ||
const field = useFieldContext() | ||
if (field.isValidating.value) | ||
return <p className="text-[0.8rem] opacity-70">Validating...</p> | ||
if (field.isValid.value) return null | ||
return ( | ||
<p className="font-medium text-[0.8rem] text-destructive"> | ||
{field.errors.value.join(', ')} | ||
</p> | ||
) | ||
} | ||
|
||
export const ErrorTextGroup = () => { | ||
const group = useFieldGroupContext() | ||
if (group.isValidating.value) | ||
return <p className="text-[0.8rem] opacity-70">Validating...</p> | ||
if (group.isValid.value) return null | ||
return ( | ||
<p className="font-medium text-[0.8rem] text-destructive"> | ||
{group.errors.value.join(', ')} | ||
</p> | ||
) | ||
} |
100 changes: 100 additions & 0 deletions
100
examples/react/next-form-signals/components/form/LoginForm.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
'use client' | ||
import { ErrorText } from '@/components/form/ErrorText' | ||
import { Button } from '@/components/ui/button' | ||
import { InputForm } from '@/components/ui/input' | ||
import { Label } from '@/components/ui/label' | ||
import { useForm, useFormContext } from '@formsignals/form-react' | ||
import { ZodAdapter } from '@formsignals/validation-adapter-zod' | ||
import { useSignals } from '@preact/signals-react/runtime' | ||
import { z } from 'zod' | ||
|
||
export function LoginForm() { | ||
useSignals() | ||
|
||
const form = useForm({ | ||
validatorAdapter: ZodAdapter, | ||
defaultValues: { | ||
username: '', | ||
password: '', | ||
passwordRepeat: '', | ||
}, | ||
onSubmit: (values) => { | ||
if ( | ||
!window.confirm( | ||
`Submitted login for ${values.username}. Do you want to reset the form?`, | ||
) | ||
) | ||
return | ||
form.reset() | ||
}, | ||
}) | ||
|
||
return ( | ||
<form.FormProvider> | ||
<form | ||
className="flex flex-col gap-2" | ||
onSubmit={async (e) => { | ||
e.preventDefault() | ||
e.stopPropagation() | ||
await form.handleSubmit() | ||
}} | ||
> | ||
<form.FieldProvider | ||
name="username" | ||
validator={z.string().min(3)} | ||
validatorOptions={{ validateOnChangeIfTouched: true }} | ||
> | ||
<div> | ||
<Label htmlFor="username">Username</Label> | ||
<InputForm id="username" /> | ||
<ErrorText /> | ||
</div> | ||
</form.FieldProvider> | ||
<form.FieldProvider | ||
name="password" | ||
validator={z.string().min(8)} | ||
validatorOptions={{ | ||
validateOnChangeIfTouched: true, | ||
}} | ||
> | ||
<div> | ||
<Label htmlFor="password">Password</Label> | ||
<InputForm id="password" type="password" /> | ||
<ErrorText /> | ||
</div> | ||
</form.FieldProvider> | ||
<form.FieldProvider | ||
name="passwordRepeat" | ||
validateMixin={['password']} | ||
validator={z | ||
.tuple([z.string(), z.string()]) | ||
.refine( | ||
([check, password]) => check === password, | ||
'Passwords did not match', | ||
)} | ||
validatorOptions={{ | ||
validateOnChangeIfTouched: true, | ||
}} | ||
> | ||
<div> | ||
<Label htmlFor="password-repeat">Password (repeat)</Label> | ||
<InputForm id="password-repeat" type="password" /> | ||
<ErrorText /> | ||
</div> | ||
</form.FieldProvider> | ||
|
||
<FormSubmitButton /> | ||
</form> | ||
</form.FormProvider> | ||
) | ||
} | ||
|
||
function FormSubmitButton() { | ||
const form = useFormContext() | ||
|
||
return ( | ||
<Button className="mt-2" type="submit" disabled={!form.canSubmit.value}> | ||
Login | ||
</Button> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
import { Slot } from '@radix-ui/react-slot' | ||
import { type VariantProps, cva } from 'class-variance-authority' | ||
import * as React from 'react' | ||
|
||
import { cn } from '@/lib/utils' | ||
|
||
const buttonVariants = cva( | ||
'inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0', | ||
{ | ||
variants: { | ||
variant: { | ||
default: | ||
'bg-primary text-primary-foreground shadow hover:bg-primary/90', | ||
destructive: | ||
'bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90', | ||
outline: | ||
'border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground', | ||
secondary: | ||
'bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80', | ||
ghost: 'hover:bg-accent hover:text-accent-foreground', | ||
link: 'text-primary underline-offset-4 hover:underline', | ||
}, | ||
size: { | ||
default: 'h-9 px-4 py-2', | ||
sm: 'h-8 rounded-md px-3 text-xs', | ||
lg: 'h-10 rounded-md px-8', | ||
icon: 'h-9 w-9', | ||
}, | ||
}, | ||
defaultVariants: { | ||
variant: 'default', | ||
size: 'default', | ||
}, | ||
}, | ||
) | ||
|
||
export interface ButtonProps | ||
extends React.ButtonHTMLAttributes<HTMLButtonElement>, | ||
VariantProps<typeof buttonVariants> { | ||
asChild?: boolean | ||
} | ||
|
||
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>( | ||
({ className, variant, size, asChild = false, ...props }, ref) => { | ||
const Comp = asChild ? Slot : 'button' | ||
return ( | ||
<Comp | ||
className={cn(buttonVariants({ variant, size, className }))} | ||
ref={ref} | ||
{...props} | ||
/> | ||
) | ||
}, | ||
) | ||
Button.displayName = 'Button' | ||
|
||
export { Button, buttonVariants } |
Oops, something went wrong.