@tanstack/cta-framework-react-cra 0.10.0-alpha.20
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.
- package/ADD-ON-AUTHORING.md +169 -0
- package/LICENSE +21 -0
- package/add-ons/clerk/README.md +3 -0
- package/add-ons/clerk/assets/_dot_env.local.append +2 -0
- package/add-ons/clerk/assets/src/integrations/clerk/header-user.tsx +19 -0
- package/add-ons/clerk/assets/src/integrations/clerk/provider.tsx +18 -0
- package/add-ons/clerk/assets/src/routes/demo.clerk.tsx +20 -0
- package/add-ons/clerk/info.json +28 -0
- package/add-ons/clerk/logo.svg +6 -0
- package/add-ons/clerk/package.json +5 -0
- package/add-ons/clerk/small-logo.svg +5 -0
- package/add-ons/convex/README.md +4 -0
- package/add-ons/convex/assets/_dot_cursorrules.append +93 -0
- package/add-ons/convex/assets/_dot_env.local.append +3 -0
- package/add-ons/convex/assets/convex/products.ts +8 -0
- package/add-ons/convex/assets/convex/schema.ts +10 -0
- package/add-ons/convex/assets/src/integrations/convex/provider.tsx +20 -0
- package/add-ons/convex/assets/src/routes/demo.convex.tsx +33 -0
- package/add-ons/convex/info.json +23 -0
- package/add-ons/convex/package.json +6 -0
- package/add-ons/convex/small-logo.svg +5 -0
- package/add-ons/form/assets/src/components/demo.FormComponents.tsx.ejs +300 -0
- package/add-ons/form/assets/src/hooks/demo.form-context.ts +4 -0
- package/add-ons/form/assets/src/hooks/demo.form.ts +22 -0
- package/add-ons/form/assets/src/routes/demo.form.address.tsx.ejs +213 -0
- package/add-ons/form/assets/src/routes/demo.form.simple.tsx.ejs +77 -0
- package/add-ons/form/info.json +31 -0
- package/add-ons/form/package.json +6 -0
- package/add-ons/form/small-logo.svg +1 -0
- package/add-ons/module-federation/assets/module-federation.config.js.ejs +31 -0
- package/add-ons/module-federation/assets/src/demo-mf-component.tsx +3 -0
- package/add-ons/module-federation/assets/src/demo-mf-self-contained.tsx +11 -0
- package/add-ons/module-federation/info.json +8 -0
- package/add-ons/module-federation/package.json +5 -0
- package/add-ons/netlify/README.md +11 -0
- package/add-ons/netlify/info.json +8 -0
- package/add-ons/netlify/small-logo.svg +1 -0
- package/add-ons/sentry/assets/_dot_cursorrules.append +22 -0
- package/add-ons/sentry/assets/_dot_env.local.append +11 -0
- package/add-ons/sentry/assets/src/app/global-middleware.ts +11 -0
- package/add-ons/sentry/assets/src/routes/demo.sentry.testing.tsx +489 -0
- package/add-ons/sentry/info.json +17 -0
- package/add-ons/sentry/package.json +5 -0
- package/add-ons/sentry/small-logo.svg +1 -0
- package/add-ons/shadcn/README.md +7 -0
- package/add-ons/shadcn/assets/_dot_cursorrules.append +7 -0
- package/add-ons/shadcn/assets/components.json +21 -0
- package/add-ons/shadcn/assets/src/lib/utils.ts +6 -0
- package/add-ons/shadcn/assets/src/styles.css +138 -0
- package/add-ons/shadcn/info.json +8 -0
- package/add-ons/shadcn/package.json +9 -0
- package/add-ons/shadcn/small-logo.svg +1 -0
- package/add-ons/start/assets/_dot_gitignore.append +2 -0
- package/add-ons/start/assets/app.config.ts.ejs +32 -0
- package/add-ons/start/assets/src/api.ts +6 -0
- package/add-ons/start/assets/src/client.tsx.ejs +33 -0
- package/add-ons/start/assets/src/router.tsx.ejs +48 -0
- package/add-ons/start/assets/src/routes/api.demo-names.ts +11 -0
- package/add-ons/start/assets/src/routes/demo.start.api-request.tsx.ejs +33 -0
- package/add-ons/start/assets/src/routes/demo.start.server-funcs.tsx +50 -0
- package/add-ons/start/assets/src/ssr.tsx.ejs +30 -0
- package/add-ons/start/info.json +31 -0
- package/add-ons/start/package.json +13 -0
- package/add-ons/start/small-logo.svg +1 -0
- package/add-ons/store/assets/src/lib/demo-store.ts +13 -0
- package/add-ons/store/assets/src/routes/demo.store.tsx.ejs +75 -0
- package/add-ons/store/info.json +16 -0
- package/add-ons/store/package.json +6 -0
- package/add-ons/store/small-logo.svg +1 -0
- package/add-ons/t3env/README.md +16 -0
- package/add-ons/t3env/assets/src/env.ts +39 -0
- package/add-ons/t3env/info.json +8 -0
- package/add-ons/t3env/package.json +6 -0
- package/add-ons/t3env/small-logo.svg +6 -0
- package/add-ons/tRPC/assets/src/integrations/trpc/init.ts +9 -0
- package/add-ons/tRPC/assets/src/integrations/trpc/react.ts +4 -0
- package/add-ons/tRPC/assets/src/integrations/trpc/router.ts +21 -0
- package/add-ons/tRPC/assets/src/routes/api.trpc.$.tsx +16 -0
- package/add-ons/tRPC/info.json +9 -0
- package/add-ons/tRPC/package.json +9 -0
- package/add-ons/tRPC/small-logo.svg +1 -0
- package/add-ons/table/assets/src/data/demo-table-data.ts +50 -0
- package/add-ons/table/assets/src/routes/demo.table.tsx.ejs +373 -0
- package/add-ons/table/info.json +16 -0
- package/add-ons/table/package.json +7 -0
- package/add-ons/table/small-logo.svg +1 -0
- package/add-ons/tanstack-query/assets/src/integrations/tanstack-query/layout.tsx +5 -0
- package/add-ons/tanstack-query/assets/src/integrations/tanstack-query/root-provider.tsx.ejs +70 -0
- package/add-ons/tanstack-query/assets/src/routes/demo.tanstack-query.tsx.ejs +53 -0
- package/add-ons/tanstack-query/info.json +28 -0
- package/add-ons/tanstack-query/package.json +6 -0
- package/add-ons/tanstack-query/small-logo.svg +1 -0
- package/dist/index.js +18 -0
- package/dist/types/index.d.ts +1 -0
- package/examples/tanchat/README.md +37 -0
- package/examples/tanchat/assets/_dot_env.local.append +2 -0
- package/examples/tanchat/assets/public/example-guitar-flowers.jpg +0 -0
- package/examples/tanchat/assets/public/example-guitar-motherboard.jpg +0 -0
- package/examples/tanchat/assets/public/example-guitar-racing.jpg +0 -0
- package/examples/tanchat/assets/public/example-guitar-steamer-trunk.jpg +0 -0
- package/examples/tanchat/assets/public/example-guitar-superhero.jpg +0 -0
- package/examples/tanchat/assets/public/example-guitar-traveling.jpg +0 -0
- package/examples/tanchat/assets/public/example-guitar-video-games.jpg +0 -0
- package/examples/tanchat/assets/src/components/example-AIAssistant.tsx +173 -0
- package/examples/tanchat/assets/src/components/example-GuitarRecommendation.tsx +47 -0
- package/examples/tanchat/assets/src/data/example-guitars.ts +83 -0
- package/examples/tanchat/assets/src/demo.index.css +220 -0
- package/examples/tanchat/assets/src/integrations/tanchat/header-user.tsx +5 -0
- package/examples/tanchat/assets/src/routes/api.messages.ts +24 -0
- package/examples/tanchat/assets/src/routes/api.sse.ts +23 -0
- package/examples/tanchat/assets/src/routes/example.chat.tsx +159 -0
- package/examples/tanchat/assets/src/routes/example.guitars/$guitarId.tsx +50 -0
- package/examples/tanchat/assets/src/routes/example.guitars/index.tsx +54 -0
- package/examples/tanchat/assets/src/store/example-assistant.ts +3 -0
- package/examples/tanchat/assets/src/utils/demo.ai.ts +62 -0
- package/examples/tanchat/assets/src/utils/demo.sse.ts +31 -0
- package/examples/tanchat/assets/src/utils/demo.tools.ts +47 -0
- package/examples/tanchat/info.json +35 -0
- package/examples/tanchat/package.json +16 -0
- package/examples/tanchat/small-logo.svg +1 -0
- package/package.json +34 -0
- package/project/base/README.md.ejs +558 -0
- package/project/base/_dot_gitignore +5 -0
- package/project/base/_dot_vscode/settings.json.ejs +35 -0
- package/project/base/index.html.ejs +20 -0
- package/project/base/package.json +30 -0
- package/project/base/public/favicon.ico +0 -0
- package/project/base/public/logo192.png +0 -0
- package/project/base/public/logo512.png +0 -0
- package/project/base/public/manifest.json +25 -0
- package/project/base/public/robots.txt +3 -0
- package/project/base/src/App.css.ejs +38 -0
- package/project/base/src/App.test.tsx.ejs +10 -0
- package/project/base/src/App.tsx.ejs +63 -0
- package/project/base/src/components/Header.tsx.ejs +27 -0
- package/project/base/src/logo.svg +44 -0
- package/project/base/src/main.tsx.ejs +155 -0
- package/project/base/src/reportWebVitals.ts.ejs +28 -0
- package/project/base/src/routes/__root.tsx.ejs +82 -0
- package/project/base/src/routes/index.tsx.ejs +67 -0
- package/project/base/src/styles.css.ejs +15 -0
- package/project/base/tsconfig.json.ejs +29 -0
- package/project/base/vite.config.js.ejs +23 -0
- package/project/packages.json +20 -0
- package/src/index.ts +26 -0
- package/tests/react-cra.test.ts +150 -0
- package/tests/snapshots/react-cra/cr-js-form-npm.json +29 -0
- package/tests/snapshots/react-cra/cr-js-npm.json +23 -0
- package/tests/snapshots/react-cra/cr-ts-npm.json +24 -0
- package/tests/snapshots/react-cra/cr-ts-start-npm.json +28 -0
- package/tests/snapshots/react-cra/cr-ts-start-tanstack-query-npm.json +31 -0
- package/tests/snapshots/react-cra/fr-ts-biome-npm.json +26 -0
- package/tests/snapshots/react-cra/fr-ts-npm.json +24 -0
- package/tests/snapshots/react-cra/fr-ts-tw-npm.json +23 -0
- package/tests/test-utilities.ts +44 -0
- package/toolchains/biome/assets/biome.json +31 -0
- package/toolchains/biome/info.json +8 -0
- package/toolchains/biome/package.json +10 -0
- package/toolchains/biome/small-logo.svg +5 -0
- package/toolchains/eslint/assets/_dot_prettierignore +3 -0
- package/toolchains/eslint/assets/eslint.config.js +5 -0
- package/toolchains/eslint/assets/prettier.config.js +10 -0
- package/toolchains/eslint/info.json +8 -0
- package/toolchains/eslint/package.json +11 -0
- package/toolchains/eslint/small-logo.svg +7 -0
- package/tsconfig.json +17 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 633 633"><defs><linearGradient id="b" x1="50%" x2="50%" y1="0%" y2="71.65%"><stop offset="0%" stop-color="#6BDAFF"/><stop offset="31.922%" stop-color="#F9FFB5"/><stop offset="70.627%" stop-color="#FFA770"/><stop offset="100%" stop-color="#FF7373"/></linearGradient><linearGradient id="d" x1="43.996%" x2="53.441%" y1="8.54%" y2="93.872%"><stop offset="0%" stop-color="#673800"/><stop offset="100%" stop-color="#B65E00"/></linearGradient><linearGradient id="e" x1="50%" x2="50%" y1="0%" y2="100%"><stop offset="0%" stop-color="#2F8A00"/><stop offset="100%" stop-color="#90FF57"/></linearGradient><linearGradient id="f" x1="50%" x2="50%" y1="0%" y2="100%"><stop offset="0%" stop-color="#2F8A00"/><stop offset="100%" stop-color="#90FF57"/></linearGradient><linearGradient id="g" x1="50%" x2="50%" y1="0%" y2="100%"><stop offset="0%" stop-color="#2F8A00"/><stop offset="100%" stop-color="#90FF57"/></linearGradient><linearGradient id="h" x1="50%" x2="50%" y1="0%" y2="100%"><stop offset="0%" stop-color="#2F8A00"/><stop offset="100%" stop-color="#90FF57"/></linearGradient><linearGradient id="i" x1="50%" x2="50%" y1="0%" y2="100%"><stop offset="0%" stop-color="#2F8A00"/><stop offset="100%" stop-color="#90FF57"/></linearGradient><linearGradient id="j" x1="50%" x2="50%" y1="0%" y2="100%"><stop offset="0%" stop-color="#2F8A00"/><stop offset="100%" stop-color="#90FF57"/></linearGradient><linearGradient id="k" x1="92.9%" x2="8.641%" y1="45.768%" y2="54.892%"><stop offset="0%" stop-color="#EE2700"/><stop offset="100%" stop-color="#FF008E"/></linearGradient><linearGradient id="l" x1="61.109%" x2="43.717%" y1="3.633%" y2="43.072%"><stop offset="0%" stop-color="#FFF400"/><stop offset="100%" stop-color="#3C8700"/></linearGradient><linearGradient id="m" x1="50%" x2="50%" y1="0%" y2="100%"><stop offset="0%" stop-color="#FFDF00"/><stop offset="100%" stop-color="#FF9D00"/></linearGradient><linearGradient id="n" x1="127.279%" x2="0%" y1="49.778%" y2="50.222%"><stop offset="0%" stop-color="#FFA400"/><stop offset="100%" stop-color="#FF5E00"/></linearGradient><linearGradient id="o" x1="127.279%" x2="0%" y1="47.531%" y2="52.469%"><stop offset="0%" stop-color="#FFA400"/><stop offset="100%" stop-color="#FF5E00"/></linearGradient><linearGradient id="p" x1="127.279%" x2="0%" y1="46.195%" y2="53.805%"><stop offset="0%" stop-color="#FFA400"/><stop offset="100%" stop-color="#FF5E00"/></linearGradient><linearGradient id="q" x1="127.279%" x2="0%" y1="35.33%" y2="64.67%"><stop offset="0%" stop-color="#FFA400"/><stop offset="100%" stop-color="#FF5E00"/></linearGradient><linearGradient id="r" x1="127.279%" x2="0%" y1="4.875%" y2="95.125%"><stop offset="0%" stop-color="#FFA400"/><stop offset="100%" stop-color="#FF5E00"/></linearGradient><linearGradient id="s" x1="78.334%" x2="31.668%" y1="0%" y2="100%"><stop offset="0%" stop-color="#FFA400"/><stop offset="100%" stop-color="#FF5E00"/></linearGradient><linearGradient id="t" x1="57.913%" x2="44.88%" y1="0%" y2="100%"><stop offset="0%" stop-color="#FFA400"/><stop offset="100%" stop-color="#FF5E00"/></linearGradient><linearGradient id="u" x1="50.495%" x2="49.68%" y1="0%" y2="100%"><stop offset="0%" stop-color="#FFA400"/><stop offset="100%" stop-color="#FF5E00"/></linearGradient><circle id="a" cx="308.5" cy="308.5" r="308.5"/><circle id="v" cx="307.5" cy="308.5" r="316.5"/></defs><g fill="none" fill-rule="evenodd" transform="translate(9 8)"><mask id="c" fill="#fff"><use xlink:href="#a"/></mask><use xlink:href="#a" fill="url(#b)"/><ellipse cx="81.5" cy="602.5" fill="#015064" stroke="#00CFE2" stroke-width="25" mask="url(#c)" rx="214.5" ry="185.968"/><ellipse cx="535.5" cy="602.5" fill="#015064" stroke="#00CFE2" stroke-width="25" mask="url(#c)" rx="214.5" ry="185.968"/><ellipse cx="81.5" cy="640.5" fill="#015064" stroke="#00A8B8" stroke-width="25" mask="url(#c)" rx="214.5" ry="185.968"/><ellipse cx="535.5" cy="640.5" fill="#015064" stroke="#00A8B8" stroke-width="25" mask="url(#c)" rx="214.5" ry="185.968"/><ellipse cx="81.5" cy="676.5" fill="#015064" stroke="#007782" stroke-width="25" mask="url(#c)" rx="214.5" ry="185.968"/><ellipse cx="535.5" cy="676.5" fill="#015064" stroke="#007782" stroke-width="25" mask="url(#c)" rx="214.5" ry="185.968"/><g mask="url(#c)"><path fill="url(#d)" stroke="#6E3A00" stroke-width="6.088" d="M98.318 88.007c7.691 37.104 16.643 72.442 26.856 106.013 10.212 33.571 25.57 68.934 46.07 106.088l-51.903 11.67c-10.057-60.01-17.232-99.172-21.525-117.487-4.293-18.315-10.989-51.434-20.089-99.357l20.591-6.927" transform="scale(-1 1) rotate(25 -300.37 -553.013)"/><g stroke="#2F8A00"><path fill="url(#e)" stroke-width="9.343" d="M108.544 66.538s-13.54-21.305-37.417-27.785c-15.917-4.321-33.933.31-54.048 13.892C33.464 65.975 47.24 73.52 58.405 75.28c16.749 2.64 50.14-8.74 50.14-8.74Z" transform="rotate(1 -6061.691 5926.397)"/><path fill="url(#f)" stroke-width="9.343" d="M108.544 67.138s-47.187-5.997-81.077 19.936C4.873 104.362-3.782 137.794 1.502 187.369c28.42-29.22 48.758-50.836 61.016-64.846 18.387-21.016 46.026-55.385 46.026-55.385Z" transform="rotate(1 -6061.691 5926.397)"/><path fill="url(#g)" stroke-width="9.343" d="M108.544 66.538c-1.96-21.705 3.98-38.018 17.82-48.94C140.203 6.674 154.85.808 170.303 0c-4.865 21.527-12.373 36.314-22.524 44.361-10.151 8.048-23.23 15.44-39.236 22.177Z" transform="rotate(1 -6061.691 5926.397)"/><path fill="url(#h)" stroke-width="9.343" d="M108.544 67.138c29.838-31.486 61.061-42.776 93.669-33.869C234.82 42.176 253.749 60.785 259 89.096c-34.898-3.657-59.974-6.343-75.228-8.058-15.254-1.716-40.33-6.349-75.228-13.9Z" transform="rotate(1 -6061.691 5926.397)"/><path fill="url(#i)" stroke-width="9.343" d="M108.544 67.138c34.868-9.381 64.503-3.658 88.905 17.17 24.402 20.829 39.656 46.686 45.762 77.571-39.626-7.574-68.4-20.115-86.322-37.624a395.051 395.051 0 0 1-48.345-57.117Z" transform="rotate(1 -6061.691 5926.397)"/><path fill="url(#j)" stroke-width="9.343" d="M108.544 67.138C76.206 82.6 57.608 105.366 52.75 135.436c-4.858 30.07-.292 62.89 13.698 98.462 24.873-41.418 38.905-71.368 42.096-89.849 3.191-18.48 3.191-44.118 0-76.91Z" transform="rotate(1 -6061.691 5926.397)"/><path stroke-linecap="round" stroke-width="5.91" d="M211.284 173.477c-13.851 21.992-23.291 42.022-28.32 60.093-5.03 18.071-8.175 33.143-9.436 45.216"/><path stroke-linecap="round" stroke-width="5.91" d="M209.814 176.884c-23.982 2.565-42.792 10.469-56.428 23.714-13.639 13.245-23.483 26.136-29.536 38.674M219.045 167.299c29.028-7.723 50.972-10.173 65.831-7.352 14.859 2.822 26.807 7.659 35.842 14.51M211.31 172.618c20.29 9.106 38.353 19.052 54.186 29.837 15.833 10.786 27.714 20.99 35.643 30.617"/></g><path stroke="#830305" stroke-linecap="round" stroke-linejoin="bevel" stroke-width="6.937" d="m409.379 398.157-23.176 18.556M328.04 375.516l-22.313 28.398M312.904 353.698l53.18 59.816"/><path fill="url(#k)" d="M67.585 27.463H5.68C1.893 28.148 0 30.38 0 34.16c0 3.78 1.893 6.211 5.68 7.293h67.17l41.751-30.356c2.488-2.646 2.794-5.315.92-8.006s-4.6-3.626-8.177-2.803l-39.76 27.174Z" transform="scale(-1 1) rotate(-9 2092.128 2856.854)"/><path fill="#D8D8D8" stroke="#FFF" stroke-linecap="round" stroke-linejoin="bevel" stroke-width="4.414" d="m402.861 391.51.471-4.088M382.21 388.752l.472-4.087M361.546 385.404l.485-3.845M337.59 371.883l2.56-2.498M324.276 359.567l2.56-2.497"/></g><ellipse cx="308.5" cy="720.5" fill="url(#l)" mask="url(#c)" rx="266" ry="316.5"/><ellipse cx="308.5" cy="720.5" stroke="#6DA300" stroke-opacity=".502" stroke-width="26" mask="url(#c)" rx="253" ry="303.5"/><g mask="url(#c)"><g transform="translate(389 -32)"><circle cx="168.5" cy="113.5" r="113.5" fill="url(#m)"/><circle cx="168.5" cy="113.5" r="106" stroke="#FFC900" stroke-opacity=".529" stroke-width="15"/><path stroke="url(#n)" stroke-linecap="round" stroke-linejoin="bevel" stroke-width="12" d="M30 113H0"/><path stroke="url(#o)" stroke-linecap="round" stroke-linejoin="bevel" stroke-width="12" d="M33.5 79.5 7 74"/><path stroke="url(#p)" stroke-linecap="round" stroke-linejoin="bevel" stroke-width="12" d="m34 146-29 8"/><path stroke="url(#q)" stroke-linecap="round" stroke-linejoin="bevel" stroke-width="12" d="m45 177-24 13"/><path stroke="url(#r)" stroke-linecap="round" stroke-linejoin="bevel" stroke-width="12" d="m67 204-20 19"/><path stroke="url(#s)" stroke-linecap="round" stroke-linejoin="bevel" stroke-width="12" d="m94.373 227-13.834 22.847"/><path stroke="url(#t)" stroke-linecap="round" stroke-linejoin="bevel" stroke-width="12" d="M127.5 243.5 120 268"/><path stroke="url(#u)" stroke-linecap="round" stroke-linejoin="bevel" stroke-width="12" d="m167.5 252.5.5 24.5"/></g></g><circle cx="307.5" cy="308.5" r="304" stroke="#000" stroke-width="25"/></g></svg>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
## T3Env
|
|
2
|
+
|
|
3
|
+
- You can use T3Env to add type safety to your environment variables.
|
|
4
|
+
- Add Environment variables to the `src/env.mjs` file.
|
|
5
|
+
- Use the environment variables in your code.
|
|
6
|
+
|
|
7
|
+
### Usage
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
import { env } from "@/env";
|
|
11
|
+
|
|
12
|
+
console.log(env.VITE_APP_TITLE);
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { createEnv } from "@t3-oss/env-core";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
|
|
4
|
+
export const env = createEnv({
|
|
5
|
+
server: {
|
|
6
|
+
SERVER_URL: z.string().url().optional(),
|
|
7
|
+
},
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* The prefix that client-side variables must have. This is enforced both at
|
|
11
|
+
* a type-level and at runtime.
|
|
12
|
+
*/
|
|
13
|
+
clientPrefix: "VITE_",
|
|
14
|
+
|
|
15
|
+
client: {
|
|
16
|
+
VITE_APP_TITLE: z.string().min(1).optional(),
|
|
17
|
+
},
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* What object holds the environment variables at runtime. This is usually
|
|
21
|
+
* `process.env` or `import.meta.env`.
|
|
22
|
+
*/
|
|
23
|
+
runtimeEnv: import.meta.env,
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* By default, this library will feed the environment variables directly to
|
|
27
|
+
* the Zod validator.
|
|
28
|
+
*
|
|
29
|
+
* This means that if you have an empty string for a value that is supposed
|
|
30
|
+
* to be a number (e.g. `PORT=` in a ".env" file), Zod will incorrectly flag
|
|
31
|
+
* it as a type mismatch violation. Additionally, if you have an empty string
|
|
32
|
+
* for a value that is supposed to be a string with a default value (e.g.
|
|
33
|
+
* `DOMAIN=` in an ".env" file), the default value will never be applied.
|
|
34
|
+
*
|
|
35
|
+
* In order to solve these issues, we recommend that all new projects
|
|
36
|
+
* explicitly specify this option as true.
|
|
37
|
+
*/
|
|
38
|
+
emptyStringAsUndefined: true,
|
|
39
|
+
});
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
<svg width="258" height="199" viewBox="0 0 258 199" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<path fill-rule="evenodd" clip-rule="evenodd" d="M165.735 25.0701L188.947 0.972412H0.465994V25.0701H165.735Z" fill="#e2e8f0"/>
|
|
3
|
+
<path d="M163.981 96.3239L254.022 3.68314L221.206 3.68295L145.617 80.7609L163.981 96.3239Z" fill="#e2e8f0"/>
|
|
4
|
+
<path d="M233.658 131.418C233.658 155.075 214.48 174.254 190.823 174.254C171.715 174.254 155.513 161.738 150 144.439L146.625 133.848L127.329 153.143L129.092 157.336C139.215 181.421 163.034 198.354 190.823 198.354C227.791 198.354 257.759 168.386 257.759 131.418C257.759 106.937 244.399 85.7396 224.956 74.0905L220.395 71.3582L202.727 89.2528L210.788 93.5083C224.403 100.696 233.658 114.981 233.658 131.418Z" fill="#e2e8f0"/>
|
|
5
|
+
<path fill-rule="evenodd" clip-rule="evenodd" d="M88.2625 192.669L88.2626 45.6459H64.1648L64.1648 192.669H88.2625Z" fill="#e2e8f0"/>
|
|
6
|
+
</svg>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// import { TRPCError } from '@trpc/server'
|
|
2
|
+
import type { TRPCRouterRecord } from '@trpc/server'
|
|
3
|
+
// import { z } from 'zod'
|
|
4
|
+
|
|
5
|
+
import { createTRPCRouter, publicProcedure } from './init'
|
|
6
|
+
|
|
7
|
+
const peopleRouter = {
|
|
8
|
+
list: publicProcedure.query(async () => [
|
|
9
|
+
{
|
|
10
|
+
name: 'John Doe',
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
name: 'Jane Doe',
|
|
14
|
+
},
|
|
15
|
+
]),
|
|
16
|
+
} satisfies TRPCRouterRecord
|
|
17
|
+
|
|
18
|
+
export const trpcRouter = createTRPCRouter({
|
|
19
|
+
people: peopleRouter,
|
|
20
|
+
})
|
|
21
|
+
export type TRPCRouter = typeof trpcRouter
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { createAPIFileRoute } from '@tanstack/react-start/api'
|
|
2
|
+
import { fetchRequestHandler } from '@trpc/server/adapters/fetch'
|
|
3
|
+
import { trpcRouter } from '@/integrations/trpc/router'
|
|
4
|
+
|
|
5
|
+
function handler({ request }: { request: Request }) {
|
|
6
|
+
return fetchRequestHandler({
|
|
7
|
+
req: request,
|
|
8
|
+
router: trpcRouter,
|
|
9
|
+
endpoint: '/api/trpc',
|
|
10
|
+
})
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const APIRoute = createAPIFileRoute('/api/trpc/$')({
|
|
14
|
+
GET: handler,
|
|
15
|
+
POST: handler,
|
|
16
|
+
})
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="512" height="512" fill="none" viewBox="0 0 512 512"><rect width="512" height="512" fill="#398CCB" rx="150"/><path fill="#fff" fill-rule="evenodd" d="m255.446 75 71.077 41.008v22.548l86.031 49.682v84.986l23.077 13.322v82.062L364.6 409.615l-31.535-18.237-76.673 44.268-76.214-44.012-31.093 17.981-71.031-41.077v-81.992l22.177-12.803v-85.505l84.184-48.6.047-.002v-23.628L255.446 75Zm71.077 84.879v38.144l-71.031 41.008-71.03-41.008v-37.087l-.047.002-65.723 37.962v64.184l30.393-17.546 71.03 41.008v81.992l-21.489 12.427 57.766 33.358 58.226-33.611-21.049-12.174v-81.992l71.031-41.008 29.492 17.027V198.9l-67.569-39.021Zm-14.492 198.09v-50.054l43.338 25.016v50.054l-43.338-25.016Zm105.138-50.123-43.338 25.016v50.123l43.338-25.085v-50.054ZM96.515 357.9v-50.054l43.339 25.016v50.053L96.515 357.9Zm105.139-50.054-43.339 25.016v50.053l43.339-25.015v-50.054Zm119.608-15.923 43.338-25.015 43.338 25.015-43.338 25.039-43.338-25.039Zm-172.177-25.085-43.339 25.085 43.339 24.969 43.338-24.969-43.338-25.085Zm53.838-79.476v-50.054l43.292 25.038v50.031l-43.292-25.015Zm105.092-50.054-43.292 25.038v50.008l43.292-24.992v-50.054Zm-95.861-15.97 43.292-25.015 43.339 25.015-43.339 25.016-43.292-25.016Z" clip-rule="evenodd"/></svg>
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { faker } from '@faker-js/faker'
|
|
2
|
+
|
|
3
|
+
export type Person = {
|
|
4
|
+
id: number
|
|
5
|
+
firstName: string
|
|
6
|
+
lastName: string
|
|
7
|
+
age: number
|
|
8
|
+
visits: number
|
|
9
|
+
progress: number
|
|
10
|
+
status: 'relationship' | 'complicated' | 'single'
|
|
11
|
+
subRows?: Person[]
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const range = (len: number) => {
|
|
15
|
+
const arr: number[] = []
|
|
16
|
+
for (let i = 0; i < len; i++) {
|
|
17
|
+
arr.push(i)
|
|
18
|
+
}
|
|
19
|
+
return arr
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const newPerson = (num: number): Person => {
|
|
23
|
+
return {
|
|
24
|
+
id: num,
|
|
25
|
+
firstName: faker.person.firstName(),
|
|
26
|
+
lastName: faker.person.lastName(),
|
|
27
|
+
age: faker.number.int(40),
|
|
28
|
+
visits: faker.number.int(1000),
|
|
29
|
+
progress: faker.number.int(100),
|
|
30
|
+
status: faker.helpers.shuffle<Person['status']>([
|
|
31
|
+
'relationship',
|
|
32
|
+
'complicated',
|
|
33
|
+
'single',
|
|
34
|
+
])[0]!,
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function makeData(...lens: number[]) {
|
|
39
|
+
const makeDataLevel = (depth = 0): Person[] => {
|
|
40
|
+
const len = lens[depth]!
|
|
41
|
+
return range(len).map((index): Person => {
|
|
42
|
+
return {
|
|
43
|
+
...newPerson(index),
|
|
44
|
+
subRows: lens[depth + 1] ? makeDataLevel(depth + 1) : undefined,
|
|
45
|
+
}
|
|
46
|
+
})
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return makeDataLevel()
|
|
50
|
+
}
|
|
@@ -0,0 +1,373 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { <% if (fileRouter) { %>createFileRoute<% } else { %>createRoute<% } %> } from '@tanstack/react-router'
|
|
3
|
+
import {
|
|
4
|
+
flexRender,
|
|
5
|
+
getCoreRowModel,
|
|
6
|
+
getFilteredRowModel,
|
|
7
|
+
getPaginationRowModel,
|
|
8
|
+
getSortedRowModel,
|
|
9
|
+
sortingFns,
|
|
10
|
+
useReactTable,
|
|
11
|
+
} from '@tanstack/react-table'
|
|
12
|
+
import { compareItems, rankItem } from '@tanstack/match-sorter-utils'
|
|
13
|
+
|
|
14
|
+
import { makeData } from '../data/demo-table-data'
|
|
15
|
+
|
|
16
|
+
import type {
|
|
17
|
+
Column,
|
|
18
|
+
ColumnDef,
|
|
19
|
+
ColumnFiltersState,
|
|
20
|
+
FilterFn,
|
|
21
|
+
SortingFn,
|
|
22
|
+
} from '@tanstack/react-table'
|
|
23
|
+
import type { RankingInfo } from '@tanstack/match-sorter-utils'
|
|
24
|
+
<% if (codeRouter) { %>
|
|
25
|
+
import type { RootRoute } from '@tanstack/react-router'
|
|
26
|
+
<% } %>
|
|
27
|
+
import type { Person } from '../data/demo-table-data'
|
|
28
|
+
<% if (fileRouter) { %>
|
|
29
|
+
export const Route = createFileRoute('/demo/table')({
|
|
30
|
+
component: TableDemo,
|
|
31
|
+
})
|
|
32
|
+
<% } %>
|
|
33
|
+
|
|
34
|
+
declare module '@tanstack/react-table' {
|
|
35
|
+
interface FilterFns {
|
|
36
|
+
fuzzy: FilterFn<unknown>
|
|
37
|
+
}
|
|
38
|
+
interface FilterMeta {
|
|
39
|
+
itemRank: RankingInfo
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// Define a custom fuzzy filter function that will apply ranking info to rows (using match-sorter utils)
|
|
44
|
+
const fuzzyFilter: FilterFn<any> = (row, columnId, value, addMeta) => {
|
|
45
|
+
// Rank the item
|
|
46
|
+
const itemRank = rankItem(row.getValue(columnId), value)
|
|
47
|
+
|
|
48
|
+
// Store the itemRank info
|
|
49
|
+
addMeta({
|
|
50
|
+
itemRank,
|
|
51
|
+
})
|
|
52
|
+
|
|
53
|
+
// Return if the item should be filtered in/out
|
|
54
|
+
return itemRank.passed
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Define a custom fuzzy sort function that will sort by rank if the row has ranking information
|
|
58
|
+
const fuzzySort: SortingFn<any> = (rowA, rowB, columnId) => {
|
|
59
|
+
let dir = 0
|
|
60
|
+
|
|
61
|
+
// Only sort by rank if the column has ranking information
|
|
62
|
+
if (rowA.columnFiltersMeta[columnId]) {
|
|
63
|
+
dir = compareItems(
|
|
64
|
+
rowA.columnFiltersMeta[columnId]?.itemRank!,
|
|
65
|
+
rowB.columnFiltersMeta[columnId]?.itemRank!,
|
|
66
|
+
)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Provide an alphanumeric fallback for when the item ranks are equal
|
|
70
|
+
return dir === 0 ? sortingFns.alphanumeric(rowA, rowB, columnId) : dir
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function TableDemo() {
|
|
74
|
+
const rerender = React.useReducer(() => ({}), {})[1]
|
|
75
|
+
|
|
76
|
+
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
|
|
77
|
+
[],
|
|
78
|
+
)
|
|
79
|
+
const [globalFilter, setGlobalFilter] = React.useState('')
|
|
80
|
+
|
|
81
|
+
const columns = React.useMemo<ColumnDef<Person, any>[]>(
|
|
82
|
+
() => [
|
|
83
|
+
{
|
|
84
|
+
accessorKey: 'id',
|
|
85
|
+
filterFn: 'equalsString', //note: normal non-fuzzy filter column - exact match required
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
accessorKey: 'firstName',
|
|
89
|
+
cell: (info) => info.getValue(),
|
|
90
|
+
filterFn: 'includesStringSensitive', //note: normal non-fuzzy filter column - case sensitive
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
accessorFn: (row) => row.lastName,
|
|
94
|
+
id: 'lastName',
|
|
95
|
+
cell: (info) => info.getValue(),
|
|
96
|
+
header: () => <span>Last Name</span>,
|
|
97
|
+
filterFn: 'includesString', //note: normal non-fuzzy filter column - case insensitive
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
accessorFn: (row) => `${row.firstName} ${row.lastName}`,
|
|
101
|
+
id: 'fullName',
|
|
102
|
+
header: 'Full Name',
|
|
103
|
+
cell: (info) => info.getValue(),
|
|
104
|
+
filterFn: 'fuzzy', //using our custom fuzzy filter function
|
|
105
|
+
// filterFn: fuzzyFilter, //or just define with the function
|
|
106
|
+
sortingFn: fuzzySort, //sort by fuzzy rank (falls back to alphanumeric)
|
|
107
|
+
},
|
|
108
|
+
],
|
|
109
|
+
[],
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
const [data, setData] = React.useState<Person[]>(() => makeData(5_000))
|
|
113
|
+
const refreshData = () => setData((_old) => makeData(50_000)) //stress test
|
|
114
|
+
|
|
115
|
+
const table = useReactTable({
|
|
116
|
+
data,
|
|
117
|
+
columns,
|
|
118
|
+
filterFns: {
|
|
119
|
+
fuzzy: fuzzyFilter, //define as a filter function that can be used in column definitions
|
|
120
|
+
},
|
|
121
|
+
state: {
|
|
122
|
+
columnFilters,
|
|
123
|
+
globalFilter,
|
|
124
|
+
},
|
|
125
|
+
onColumnFiltersChange: setColumnFilters,
|
|
126
|
+
onGlobalFilterChange: setGlobalFilter,
|
|
127
|
+
globalFilterFn: 'fuzzy', //apply fuzzy filter to the global filter (most common use case for fuzzy filter)
|
|
128
|
+
getCoreRowModel: getCoreRowModel(),
|
|
129
|
+
getFilteredRowModel: getFilteredRowModel(), //client side filtering
|
|
130
|
+
getSortedRowModel: getSortedRowModel(),
|
|
131
|
+
getPaginationRowModel: getPaginationRowModel(),
|
|
132
|
+
debugTable: true,
|
|
133
|
+
debugHeaders: true,
|
|
134
|
+
debugColumns: false,
|
|
135
|
+
})
|
|
136
|
+
|
|
137
|
+
//apply the fuzzy sort if the fullName column is being filtered
|
|
138
|
+
React.useEffect(() => {
|
|
139
|
+
if (table.getState().columnFilters[0]?.id === 'fullName') {
|
|
140
|
+
if (table.getState().sorting[0]?.id !== 'fullName') {
|
|
141
|
+
table.setSorting([{ id: 'fullName', desc: false }])
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}, [table.getState().columnFilters[0]?.id])
|
|
145
|
+
|
|
146
|
+
return (
|
|
147
|
+
<div className="min-h-screen bg-gray-900 p-6">
|
|
148
|
+
<div>
|
|
149
|
+
<DebouncedInput
|
|
150
|
+
value={globalFilter ?? ''}
|
|
151
|
+
onChange={(value) => setGlobalFilter(String(value))}
|
|
152
|
+
className="w-full p-3 bg-gray-800 text-white rounded-lg border border-gray-700 focus:ring-2 focus:ring-blue-500 focus:border-transparent outline-none"
|
|
153
|
+
placeholder="Search all columns..."
|
|
154
|
+
/>
|
|
155
|
+
</div>
|
|
156
|
+
<div className="h-4" />
|
|
157
|
+
<div className="overflow-x-auto rounded-lg border border-gray-700">
|
|
158
|
+
<table className="w-full text-sm text-gray-200">
|
|
159
|
+
<thead className="bg-gray-800 text-gray-100">
|
|
160
|
+
{table.getHeaderGroups().map((headerGroup) => (
|
|
161
|
+
<tr key={headerGroup.id}>
|
|
162
|
+
{headerGroup.headers.map((header) => {
|
|
163
|
+
return (
|
|
164
|
+
<th
|
|
165
|
+
key={header.id}
|
|
166
|
+
colSpan={header.colSpan}
|
|
167
|
+
className="px-4 py-3 text-left"
|
|
168
|
+
>
|
|
169
|
+
{header.isPlaceholder ? null : (
|
|
170
|
+
<>
|
|
171
|
+
<div
|
|
172
|
+
{...{
|
|
173
|
+
className: header.column.getCanSort()
|
|
174
|
+
? 'cursor-pointer select-none hover:text-blue-400 transition-colors'
|
|
175
|
+
: '',
|
|
176
|
+
onClick: header.column.getToggleSortingHandler(),
|
|
177
|
+
}}
|
|
178
|
+
>
|
|
179
|
+
{flexRender(
|
|
180
|
+
header.column.columnDef.header,
|
|
181
|
+
header.getContext(),
|
|
182
|
+
)}
|
|
183
|
+
{{
|
|
184
|
+
asc: ' 🔼',
|
|
185
|
+
desc: ' 🔽',
|
|
186
|
+
}[header.column.getIsSorted() as string] ?? null}
|
|
187
|
+
</div>
|
|
188
|
+
{header.column.getCanFilter() ? (
|
|
189
|
+
<div className="mt-2">
|
|
190
|
+
<Filter column={header.column} />
|
|
191
|
+
</div>
|
|
192
|
+
) : null}
|
|
193
|
+
</>
|
|
194
|
+
)}
|
|
195
|
+
</th>
|
|
196
|
+
)
|
|
197
|
+
})}
|
|
198
|
+
</tr>
|
|
199
|
+
))}
|
|
200
|
+
</thead>
|
|
201
|
+
<tbody className="divide-y divide-gray-700">
|
|
202
|
+
{table.getRowModel().rows.map((row) => {
|
|
203
|
+
return (
|
|
204
|
+
<tr
|
|
205
|
+
key={row.id}
|
|
206
|
+
className="hover:bg-gray-800 transition-colors"
|
|
207
|
+
>
|
|
208
|
+
{row.getVisibleCells().map((cell) => {
|
|
209
|
+
return (
|
|
210
|
+
<td key={cell.id} className="px-4 py-3">
|
|
211
|
+
{flexRender(
|
|
212
|
+
cell.column.columnDef.cell,
|
|
213
|
+
cell.getContext(),
|
|
214
|
+
)}
|
|
215
|
+
</td>
|
|
216
|
+
)
|
|
217
|
+
})}
|
|
218
|
+
</tr>
|
|
219
|
+
)
|
|
220
|
+
})}
|
|
221
|
+
</tbody>
|
|
222
|
+
</table>
|
|
223
|
+
</div>
|
|
224
|
+
<div className="h-4" />
|
|
225
|
+
<div className="flex flex-wrap items-center gap-2 text-gray-200">
|
|
226
|
+
<button
|
|
227
|
+
className="px-3 py-1 bg-gray-800 rounded-md hover:bg-gray-700 disabled:opacity-50 disabled:cursor-not-allowed"
|
|
228
|
+
onClick={() => table.setPageIndex(0)}
|
|
229
|
+
disabled={!table.getCanPreviousPage()}
|
|
230
|
+
>
|
|
231
|
+
{'<<'}
|
|
232
|
+
</button>
|
|
233
|
+
<button
|
|
234
|
+
className="px-3 py-1 bg-gray-800 rounded-md hover:bg-gray-700 disabled:opacity-50 disabled:cursor-not-allowed"
|
|
235
|
+
onClick={() => table.previousPage()}
|
|
236
|
+
disabled={!table.getCanPreviousPage()}
|
|
237
|
+
>
|
|
238
|
+
{'<'}
|
|
239
|
+
</button>
|
|
240
|
+
<button
|
|
241
|
+
className="px-3 py-1 bg-gray-800 rounded-md hover:bg-gray-700 disabled:opacity-50 disabled:cursor-not-allowed"
|
|
242
|
+
onClick={() => table.nextPage()}
|
|
243
|
+
disabled={!table.getCanNextPage()}
|
|
244
|
+
>
|
|
245
|
+
{'>'}
|
|
246
|
+
</button>
|
|
247
|
+
<button
|
|
248
|
+
className="px-3 py-1 bg-gray-800 rounded-md hover:bg-gray-700 disabled:opacity-50 disabled:cursor-not-allowed"
|
|
249
|
+
onClick={() => table.setPageIndex(table.getPageCount() - 1)}
|
|
250
|
+
disabled={!table.getCanNextPage()}
|
|
251
|
+
>
|
|
252
|
+
{'>>'}
|
|
253
|
+
</button>
|
|
254
|
+
<span className="flex items-center gap-1">
|
|
255
|
+
<div>Page</div>
|
|
256
|
+
<strong>
|
|
257
|
+
{table.getState().pagination.pageIndex + 1} of{' '}
|
|
258
|
+
{table.getPageCount()}
|
|
259
|
+
</strong>
|
|
260
|
+
</span>
|
|
261
|
+
<span className="flex items-center gap-1">
|
|
262
|
+
| Go to page:
|
|
263
|
+
<input
|
|
264
|
+
type="number"
|
|
265
|
+
defaultValue={table.getState().pagination.pageIndex + 1}
|
|
266
|
+
onChange={(e) => {
|
|
267
|
+
const page = e.target.value ? Number(e.target.value) - 1 : 0
|
|
268
|
+
table.setPageIndex(page)
|
|
269
|
+
}}
|
|
270
|
+
className="w-16 px-2 py-1 bg-gray-800 rounded-md border border-gray-700 focus:ring-2 focus:ring-blue-500 focus:border-transparent outline-none"
|
|
271
|
+
/>
|
|
272
|
+
</span>
|
|
273
|
+
<select
|
|
274
|
+
value={table.getState().pagination.pageSize}
|
|
275
|
+
onChange={(e) => {
|
|
276
|
+
table.setPageSize(Number(e.target.value))
|
|
277
|
+
}}
|
|
278
|
+
className="px-2 py-1 bg-gray-800 rounded-md border border-gray-700 focus:ring-2 focus:ring-blue-500 focus:border-transparent outline-none"
|
|
279
|
+
>
|
|
280
|
+
{[10, 20, 30, 40, 50].map((pageSize) => (
|
|
281
|
+
<option key={pageSize} value={pageSize}>
|
|
282
|
+
Show {pageSize}
|
|
283
|
+
</option>
|
|
284
|
+
))}
|
|
285
|
+
</select>
|
|
286
|
+
</div>
|
|
287
|
+
<div className="mt-4 text-gray-400">
|
|
288
|
+
{table.getPrePaginationRowModel().rows.length} Rows
|
|
289
|
+
</div>
|
|
290
|
+
<div className="mt-4 flex gap-2">
|
|
291
|
+
<button
|
|
292
|
+
onClick={() => rerender()}
|
|
293
|
+
className="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 transition-colors"
|
|
294
|
+
>
|
|
295
|
+
Force Rerender
|
|
296
|
+
</button>
|
|
297
|
+
<button
|
|
298
|
+
onClick={() => refreshData()}
|
|
299
|
+
className="px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 transition-colors"
|
|
300
|
+
>
|
|
301
|
+
Refresh Data
|
|
302
|
+
</button>
|
|
303
|
+
</div>
|
|
304
|
+
<pre className="mt-4 p-4 bg-gray-800 rounded-lg text-gray-300 overflow-auto">
|
|
305
|
+
{JSON.stringify(
|
|
306
|
+
{
|
|
307
|
+
columnFilters: table.getState().columnFilters,
|
|
308
|
+
globalFilter: table.getState().globalFilter,
|
|
309
|
+
},
|
|
310
|
+
null,
|
|
311
|
+
2,
|
|
312
|
+
)}
|
|
313
|
+
</pre>
|
|
314
|
+
</div>
|
|
315
|
+
)
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
function Filter({ column }: { column: Column<any, unknown> }) {
|
|
319
|
+
const columnFilterValue = column.getFilterValue()
|
|
320
|
+
|
|
321
|
+
return (
|
|
322
|
+
<DebouncedInput
|
|
323
|
+
type="text"
|
|
324
|
+
value={(columnFilterValue ?? '') as string}
|
|
325
|
+
onChange={(value) => column.setFilterValue(value)}
|
|
326
|
+
placeholder={`Search...`}
|
|
327
|
+
className="w-full px-2 py-1 bg-gray-700 text-white rounded-md border border-gray-600 focus:ring-2 focus:ring-blue-500 focus:border-transparent outline-none"
|
|
328
|
+
/>
|
|
329
|
+
)
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
// A typical debounced input react component
|
|
333
|
+
function DebouncedInput({
|
|
334
|
+
value: initialValue,
|
|
335
|
+
onChange,
|
|
336
|
+
debounce = 500,
|
|
337
|
+
...props
|
|
338
|
+
}: {
|
|
339
|
+
value: string | number
|
|
340
|
+
onChange: (value: string | number) => void
|
|
341
|
+
debounce?: number
|
|
342
|
+
} & Omit<React.InputHTMLAttributes<HTMLInputElement>, 'onChange'>) {
|
|
343
|
+
const [value, setValue] = React.useState(initialValue)
|
|
344
|
+
|
|
345
|
+
React.useEffect(() => {
|
|
346
|
+
setValue(initialValue)
|
|
347
|
+
}, [initialValue])
|
|
348
|
+
|
|
349
|
+
React.useEffect(() => {
|
|
350
|
+
const timeout = setTimeout(() => {
|
|
351
|
+
onChange(value)
|
|
352
|
+
}, debounce)
|
|
353
|
+
|
|
354
|
+
return () => clearTimeout(timeout)
|
|
355
|
+
}, [value])
|
|
356
|
+
|
|
357
|
+
return (
|
|
358
|
+
<input
|
|
359
|
+
{...props}
|
|
360
|
+
value={value}
|
|
361
|
+
onChange={(e) => setValue(e.target.value)}
|
|
362
|
+
/>
|
|
363
|
+
)
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
<% if (codeRouter) { %>
|
|
367
|
+
export default (parentRoute: RootRoute) => createRoute({
|
|
368
|
+
path: '/demo/table',
|
|
369
|
+
component: TableDemo,
|
|
370
|
+
getParentRoute: () => parentRoute,
|
|
371
|
+
})
|
|
372
|
+
<% } %>
|
|
373
|
+
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "Table",
|
|
3
|
+
"description": "Integrate TanStack Table into your application.",
|
|
4
|
+
"phase": "add-on",
|
|
5
|
+
"modes": ["file-router", "code-router"],
|
|
6
|
+
"link": "https://tanstack.com/table/latest",
|
|
7
|
+
"type": "add-on",
|
|
8
|
+
"routes": [
|
|
9
|
+
{
|
|
10
|
+
"url": "/demo/table",
|
|
11
|
+
"name": "TanStack Table",
|
|
12
|
+
"path": "src/routes/demo.table.tsx",
|
|
13
|
+
"jsName": "TableDemo"
|
|
14
|
+
}
|
|
15
|
+
]
|
|
16
|
+
}
|