Skip to content

Commit

Permalink
added Typescript support for proxy fn
Browse files Browse the repository at this point in the history
  • Loading branch information
overthemike committed Sep 25, 2024
1 parent 01296aa commit e877e68
Show file tree
Hide file tree
Showing 4 changed files with 186 additions and 131 deletions.
72 changes: 35 additions & 37 deletions examples/react/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import './App.css';
import { z } from 'zod';
import { schema, useSnapshot } from '../../../src/index';
import './App.css'
import { z } from 'zod'
import { schema, useSnapshot } from '../../../src/index'

const userSchema = z.object({
username: z.string(),
Expand All @@ -10,10 +10,10 @@ const userSchema = z.object({
lastName: z.string(),
address: z.object({
city: z.string(),
country: z.string(),
}),
}),
});
country: z.string()
})
})
})

const userState = schema(userSchema).proxy(
{
Expand All @@ -24,77 +24,75 @@ const userState = schema(userSchema).proxy(
lastName: 'Smith',
address: {
city: 'Wonderland',
country: 'Fantasy',
},
},
country: 'Fantasy'
}
}
},
{ safeParse: true, errorHandler: (e) => console.log(e.message) },
);
{ safeParse: true, errorHandler: (e) => console.log(e.message) }
)

function App() {
const user = useSnapshot(userState);
const user = useSnapshot(userState)

return (
<div>
<h1>Vite + React</h1>

<label htmlFor="username">Username</label>
<label htmlFor='username'>Username</label>
<input
id="username"
type="text"
id='username'
type='text'
value={user.username}
onChange={(e) => (userState.username = e.target.value)}
/>
<p>Username: {user.username}</p>

<label htmlFor="age">Age</label>
<label htmlFor='age'>Age</label>
<input
id="age"
type="text"
id='age'
type='text'
value={'' + user.age}
onChange={(e) => (userState.age = Number(e.target.value))}
onChange={(e) => (userState.age = e.target.value)}
/>
<p>Age: {user.age}</p>

<label htmlFor="lastName">First Name</label>
<label htmlFor='lastName'>First Name</label>
<input
id="firstName"
type="text"
id='firstName'
type='text'
value={user.profile.firstName}
onChange={(e) => (userState.profile.firstName = e.target.value)}
/>
<p>First Name: {user.profile.firstName}</p>

<label htmlFor="lastName">Last Name</label>
<label htmlFor='lastName'>Last Name</label>
<input
id="lastName"
type="text"
id='lastName'
type='text'
value={user.profile.lastName}
onChange={(e) => (userState.profile.lastName = e.target.value)}
/>
<p>Last Name: {user.profile.lastName}</p>

<label htmlFor="lastName">Last Name</label>
<label htmlFor='lastName'>Last Name</label>
<input
id="city"
type="text"
id='city'
type='text'
value={user.profile.address.city}
onChange={(e) => (userState.profile.address.city = e.target.value)}
/>
<p>City: {user.profile.address.city}</p>

<label htmlFor="country">Last Name</label>
<label htmlFor='country'>Last Name</label>
<input
id="country"
type="text"
id='country'
type='text'
value={user.profile.address.country}
onChange={(e) =>
(userState.profile.address.country = Number(e.target.value))
}
onChange={(e) => (userState.profile.address.country = e.target.value)}
/>
<p>Last Name: {user.profile.address.country}</p>
</div>
);
)
}

export default App;
export default App
6 changes: 6 additions & 0 deletions examples/react/src/test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { ImageMetadataSchema, ImageMetadata } from './types'
import { schema } from '../../../src/index'

const store = schema(ImageMetadataSchema).proxy<ImageMetadata>({
base64: null
})
48 changes: 48 additions & 0 deletions examples/react/src/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { z } from 'zod'

export type ImageMetadataType = {
base64: string
filename: string
tags: string[]
title: string
contentType: string
width: number
height: number
}

export type SelectFieldOption = { label: string; value: string }

// Base64 validation regex
const base64Regex =
/^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/

// Content type validation regex (matches any MIME type starting with 'image/')
const contentTypeRegex = /^image\/[a-zA-Z0-9+\.-]+$/

// Filename validation regex (simple validation to exclude invalid filename characters)
const filenameRegex = /^[^<>:"/\\|?*\x00-\x1F]+$/

// Define the ImageMetadata schema
export const ImageMetadataSchema = z.object({
base64: z.string().regex(base64Regex, { message: 'Invalid image data' }),
filename: z
.string({ required_error: 'Filename cannot be empty' })
.regex(filenameRegex, { message: 'Filename contains invalid characters' }),
tags: z.array(z.string({ required_error: 'Tags cannot be empty strings' })),
title: z.string({ required_error: 'Title cannot be empty' }),
contentType: z.string().regex(contentTypeRegex, {
message:
'Content type must start with "image/" and contain valid characters'
}),
width: z
.number()
.int({ message: 'Width must be an integer' })
.positive({ message: 'Width must be a positive number' }),
height: z
.number()
.int({ message: 'Height must be an integer' })
.positive({ message: 'Height must be a positive number' })
})

// Export the TypeScript type inferred from the schema
export type ImageMetadata = z.infer<typeof ImageMetadataSchema>
Loading

0 comments on commit e877e68

Please sign in to comment.