-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
docs(solid-router): search-validator-adapters #5848
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
f15d7ce
c0f482a
97a7430
fb02127
bb7e913
ddaced6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| node_modules | ||
| .DS_Store | ||
| dist | ||
| dist-ssr | ||
| *.local |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| { | ||
| "files.watcherExclude": { | ||
| "**/routeTree.gen.ts": true | ||
| }, | ||
| "search.exclude": { | ||
| "**/routeTree.gen.ts": true | ||
| }, | ||
| "files.readonlyInclude": { | ||
| "**/routeTree.gen.ts": true | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| # Example | ||
|
|
||
| To run this example: | ||
|
|
||
| - `npm install` or `yarn` | ||
| - `npm start` or `yarn start` |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| <!doctype html> | ||
| <html lang="en"> | ||
| <head> | ||
| <meta charset="UTF-8" /> | ||
| <meta name="viewport" content="width=device-width, initial-scale=1.0" /> | ||
| <title>Vite App</title> | ||
| </head> | ||
| <body> | ||
| <div id="app"></div> | ||
| <script type="module" src="/src/main.tsx"></script> | ||
| </body> | ||
| </html> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| { | ||
| "name": "tanstack-solid-router-search-validator-adapters", | ||
| "private": true, | ||
| "type": "module", | ||
| "scripts": { | ||
| "dev": "vite --port 3000", | ||
| "build": "vite build && tsc --noEmit", | ||
| "serve": "vite preview", | ||
| "start": "vite", | ||
| "test:unit": "vitest" | ||
| }, | ||
| "dependencies": { | ||
| "@tailwindcss/postcss": "^4.1.15", | ||
| "@tanstack/arktype-adapter": "^1.135.2", | ||
| "@tanstack/solid-query": "^5.90.0", | ||
| "@tanstack/solid-router": "^1.135.2", | ||
| "@tanstack/solid-router-devtools": "^1.135.2", | ||
| "@tanstack/router-plugin": "^1.135.2", | ||
| "@tanstack/valibot-adapter": "^1.135.2", | ||
| "@tanstack/zod-adapter": "^1.135.2", | ||
| "arktype": "^2.1.7", | ||
| "postcss": "^8.5.1", | ||
| "solid-js": "^1.9.10", | ||
| "tailwindcss": "^4.1.15", | ||
| "valibot": "1.0.0-beta.15", | ||
| "zod": "^3.24.2" | ||
| }, | ||
| "devDependencies": { | ||
| "@testing-library/jest-dom": "^6.6.3", | ||
| "@solidjs/testing-library": "^0.8.10", | ||
| "vite-plugin-solid": "^2.11.10", | ||
| "typescript": "^5.7.2", | ||
| "vite": "^7.1.7" | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| export default { | ||
| plugins: { | ||
| '@tailwindcss/postcss': {}, | ||
| }, | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| import type { JSX } from 'solid-js' | ||
|
|
||
| export interface ContentProps { | ||
| readonly children: JSX.Element | ||
| } | ||
|
|
||
| export const Content = ({ children }: ContentProps) => { | ||
| return <section class="my-2 flex flex-col gap-2">{children}</section> | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| import { Link } from '@tanstack/solid-router' | ||
|
|
||
| const HeaderLink: typeof Link = (props) => { | ||
| return <Link class="text-lg text-blue-700" {...props} /> | ||
| } | ||
|
|
||
| export interface HeaderProps { | ||
| readonly title: string | ||
| } | ||
|
|
||
| export const Header = ({ title }: HeaderProps) => { | ||
| return ( | ||
| <header class="flex items-end gap-8 border-b-2 border-slate-150 py-4"> | ||
| <h1 class="text-4xl">{title}</h1> | ||
| <nav class="flex gap-4"> | ||
| <HeaderLink to="/users/zod">Zod</HeaderLink> | ||
| <HeaderLink to="/users/valibot">Valibot</HeaderLink> | ||
| <HeaderLink to="/users/arktype">Arktype</HeaderLink> | ||
| </nav> | ||
| </header> | ||
| ) | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| export interface SearchProps { | ||
| search: string | ||
| onChange: (search: string) => void | ||
| } | ||
|
|
||
| export const Search = ({ search, onChange }: SearchProps) => { | ||
| return ( | ||
| <div class="flex gap-2 align-center items-center"> | ||
| <label>Search</label> | ||
| <input | ||
| type="search" | ||
| class="border p-1 px-2 rounded-sm" | ||
| value={search} | ||
| onInput={(e) => onChange(e.currentTarget.value)} | ||
| ></input> | ||
|
Comment on lines
+6
to
+15
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Give the search input an accessible name Without associating the +import { createUniqueId } from 'solid-js'
+
export interface SearchProps {
search: string
onChange: (search: string) => void
}
export const Search = ({ search, onChange }: SearchProps) => {
+ const inputId = createUniqueId()
+
return (
<div class="flex gap-2 align-center items-center">
- <label>Search</label>
+ <label for={inputId}>Search</label>
<input
type="search"
class="border p-1 px-2 rounded-sm"
+ id={inputId}
value={search}
onInput={(e) => onChange(e.currentTarget.value)}
></input>
</div>
)
}🤖 Prompt for AI Agents |
||
| </div> | ||
| ) | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,84 @@ | ||
| import { queryOptions, useQuery } from '@tanstack/solid-query' | ||
|
|
||
| export interface Geo { | ||
| lat: string | ||
| lng: string | ||
| } | ||
|
|
||
| export interface Address { | ||
| street: string | ||
| suite: string | ||
| city: string | ||
| zipcode: string | ||
| geo: Geo | ||
| } | ||
|
|
||
| export interface Company { | ||
| name: string | ||
| catchPhrase: string | ||
| bs: string | ||
| } | ||
|
|
||
| export interface User { | ||
| id: number | ||
| name: string | ||
| username: string | ||
| email: string | ||
| address: Address | ||
| phone: string | ||
| website: string | ||
| company: Company | ||
| } | ||
|
|
||
| export const getUsers = async (): Promise<Array<User>> => { | ||
| const response = await fetch('https://jsonplaceholder.typicode.com/users') | ||
| const users: Array<User> = await response.json() | ||
| return users | ||
| } | ||
|
|
||
| export const searchUsers = async (search: string): Promise<Array<User>> => { | ||
| const users = await getUsers() | ||
| const normalizedSearch = search.toLowerCase() | ||
| return users.filter( | ||
| (user) => | ||
| user.name.toLowerCase().includes(normalizedSearch) || | ||
| user.username.toLowerCase().includes(normalizedSearch), | ||
| ) | ||
| } | ||
|
|
||
| export const usersQueryOptions = (search: string) => | ||
| queryOptions({ | ||
| queryKey: ['users', search], | ||
| queryFn: async () => { | ||
| return await searchUsers(search) | ||
| }, | ||
| }) | ||
|
|
||
| export interface UsersProps { | ||
| search: string | ||
| } | ||
|
|
||
| export const Users = ({ search }: UsersProps) => { | ||
| const users = useQuery(() => usersQueryOptions(search)) | ||
|
|
||
| return ( | ||
| <table class="table-auto"> | ||
| <thead> | ||
| <tr class="border text-left"> | ||
| <th class="p-4">Username</th> | ||
| <th class="p-4">Name</th> | ||
| <th class="p-4">Email</th> | ||
| </tr> | ||
| </thead> | ||
| <tbody> | ||
| {users.data?.map((user) => ( | ||
| <tr class="border"> | ||
| <td class="p-4">{user.username}</td> | ||
| <td class="p-4">{user.name}</td> | ||
| <td class="p-4">{user.email}</td> | ||
| </tr> | ||
| ))} | ||
| </tbody> | ||
| </table> | ||
| ) | ||
| } | ||
|
Comment on lines
+61
to
+84
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Keep the Solid components execute once; destructuring props in the parameter list snapshots their initial values and severs reactivity. As a result, -export const Users = ({ search }: UsersProps) => {
- const users = useQuery(() => usersQueryOptions(search))
+export const Users = (props: UsersProps) => {
+ const users = useQuery(() => usersQueryOptions(props.search))🤖 Prompt for AI Agents |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| import { render } from 'solid-js/web' | ||
| import { RouterProvider, createRouter } from '@tanstack/solid-router' | ||
| import { QueryClient, QueryClientProvider } from '@tanstack/solid-query' | ||
| import { routeTree } from './routeTree.gen' | ||
| import './styles.css' | ||
|
|
||
| export const queryClient = new QueryClient() | ||
|
|
||
| export const router = createRouter({ | ||
| routeTree, | ||
| context: { | ||
| queryClient, | ||
| }, | ||
| scrollRestoration: true, | ||
| }) | ||
|
|
||
| declare module '@tanstack/solid-router' { | ||
| interface Register { | ||
| router: typeof router | ||
| } | ||
| } | ||
|
|
||
| export function App() { | ||
| return <RouterProvider router={router} /> | ||
| } | ||
|
|
||
| const rootElement = document.getElementById('app')! | ||
|
|
||
| if (!rootElement.innerHTML) { | ||
| render( | ||
| () => ( | ||
| <QueryClientProvider client={queryClient}> | ||
| <App /> | ||
| </QueryClientProvider> | ||
| ), | ||
|
|
||
| rootElement, | ||
| ) | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use
workspace:*protocol for internal dependencies.All
@tanstack/*packages are internal dependencies and should use theworkspace:*protocol instead of semver ranges.As per coding guidelines.
Apply this diff:
🤖 Prompt for AI Agents