@tanstack/create 0.61.6 → 0.62.0

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 (101) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/dist/config-file.js +5 -2
  3. package/dist/custom-add-ons/starter.js +45 -28
  4. package/dist/file-helpers.js +1 -0
  5. package/dist/frameworks/react/add-ons/shadcn/assets/src/styles.css +224 -15
  6. package/dist/frameworks/react/add-ons/store/assets/src/lib/demo-store.ts +5 -6
  7. package/dist/frameworks/react/add-ons/store/assets/src/routes/demo/store.tsx.ejs +1 -1
  8. package/dist/frameworks/react/add-ons/store/package.json +2 -2
  9. package/dist/frameworks/react/index.js +2 -2
  10. package/dist/frameworks/react/project/base/content/blog/fifth-post.mdx.ejs +54 -0
  11. package/dist/frameworks/react/project/base/content/blog/first-post.md.ejs +47 -0
  12. package/dist/frameworks/react/project/base/content/blog/fourth-post.md.ejs +42 -0
  13. package/dist/frameworks/react/project/base/content/blog/second-post.mdx.ejs +46 -0
  14. package/dist/frameworks/react/project/base/content/blog/third-post.md.ejs +49 -0
  15. package/dist/frameworks/react/project/base/content-collections.ts.ejs +37 -0
  16. package/dist/frameworks/react/project/base/package.json +8 -1
  17. package/dist/frameworks/react/project/base/public/images/lagoon-1.svg +13 -0
  18. package/dist/frameworks/react/project/base/public/images/lagoon-2.svg +12 -0
  19. package/dist/frameworks/react/project/base/public/images/lagoon-3.svg +12 -0
  20. package/dist/frameworks/react/project/base/public/images/lagoon-4.svg +12 -0
  21. package/dist/frameworks/react/project/base/public/images/lagoon-5.svg +12 -0
  22. package/dist/frameworks/react/project/base/public/images/lagoon-about.svg +14 -0
  23. package/dist/frameworks/react/project/base/src/components/Footer.tsx.ejs +42 -0
  24. package/dist/frameworks/react/project/base/src/components/Header.tsx.ejs +92 -138
  25. package/dist/frameworks/react/project/base/src/components/MdxCallout.tsx.ejs +16 -0
  26. package/dist/frameworks/react/project/base/src/components/MdxMetrics.tsx.ejs +23 -0
  27. package/dist/frameworks/react/project/base/src/components/ThemeToggle.tsx.ejs +81 -0
  28. package/dist/frameworks/react/project/base/src/lib/site.ts.ejs +4 -0
  29. package/dist/frameworks/react/project/base/src/main.tsx.ejs +0 -1
  30. package/dist/frameworks/react/project/base/src/routes/__root.tsx.ejs +10 -6
  31. package/dist/frameworks/react/project/base/src/routes/about.tsx.ejs +27 -0
  32. package/dist/frameworks/react/project/base/src/routes/blog.$slug.tsx.ejs +71 -0
  33. package/dist/frameworks/react/project/base/src/routes/blog.index.tsx.ejs +93 -0
  34. package/dist/frameworks/react/project/base/src/routes/index.tsx.ejs +58 -91
  35. package/dist/frameworks/react/project/base/src/routes/rss[.]xml.ts.ejs +35 -0
  36. package/dist/frameworks/react/project/base/src/styles.css.ejs +268 -6
  37. package/dist/frameworks/react/project/base/tsconfig.json.ejs +2 -0
  38. package/dist/frameworks/react/project/base/vite.config.ts.ejs +2 -0
  39. package/dist/frameworks/solid/add-ons/store/assets/src/lib/demo-store.ts +5 -6
  40. package/dist/frameworks/solid/add-ons/store/assets/src/routes/demo.store.tsx.ejs +2 -2
  41. package/dist/frameworks/solid/examples/tanchat/assets/src/lib/demo-store.ts +5 -6
  42. package/dist/frameworks/solid/project/base/src/components/Header.tsx.ejs +8 -6
  43. package/dist/frameworks/solid/project/base/src/routes/__root.tsx.ejs +1 -1
  44. package/dist/frameworks/solid/project/base/src/routes/index.tsx.ejs +1 -1
  45. package/dist/frameworks.js +3 -0
  46. package/dist/package-json.js +1 -1
  47. package/dist/registry.js +21 -4
  48. package/dist/types/registry.d.ts +38 -0
  49. package/package.json +1 -1
  50. package/src/config-file.ts +6 -2
  51. package/src/custom-add-ons/starter.ts +30 -10
  52. package/src/file-helpers.ts +1 -0
  53. package/src/frameworks/react/add-ons/shadcn/assets/src/styles.css +224 -15
  54. package/src/frameworks/react/add-ons/store/assets/src/lib/demo-store.ts +5 -6
  55. package/src/frameworks/react/add-ons/store/assets/src/routes/demo/store.tsx.ejs +1 -1
  56. package/src/frameworks/react/add-ons/store/package.json +2 -2
  57. package/src/frameworks/react/index.ts +2 -2
  58. package/src/frameworks/react/project/base/content/blog/fifth-post.mdx.ejs +54 -0
  59. package/src/frameworks/react/project/base/content/blog/first-post.md.ejs +47 -0
  60. package/src/frameworks/react/project/base/content/blog/fourth-post.md.ejs +42 -0
  61. package/src/frameworks/react/project/base/content/blog/second-post.mdx.ejs +46 -0
  62. package/src/frameworks/react/project/base/content/blog/third-post.md.ejs +49 -0
  63. package/src/frameworks/react/project/base/content-collections.ts.ejs +37 -0
  64. package/src/frameworks/react/project/base/package.json +8 -1
  65. package/src/frameworks/react/project/base/public/images/lagoon-1.svg +13 -0
  66. package/src/frameworks/react/project/base/public/images/lagoon-2.svg +12 -0
  67. package/src/frameworks/react/project/base/public/images/lagoon-3.svg +12 -0
  68. package/src/frameworks/react/project/base/public/images/lagoon-4.svg +12 -0
  69. package/src/frameworks/react/project/base/public/images/lagoon-5.svg +12 -0
  70. package/src/frameworks/react/project/base/public/images/lagoon-about.svg +14 -0
  71. package/src/frameworks/react/project/base/src/components/Footer.tsx.ejs +42 -0
  72. package/src/frameworks/react/project/base/src/components/Header.tsx.ejs +92 -138
  73. package/src/frameworks/react/project/base/src/components/MdxCallout.tsx.ejs +16 -0
  74. package/src/frameworks/react/project/base/src/components/MdxMetrics.tsx.ejs +23 -0
  75. package/src/frameworks/react/project/base/src/components/ThemeToggle.tsx.ejs +81 -0
  76. package/src/frameworks/react/project/base/src/lib/site.ts.ejs +4 -0
  77. package/src/frameworks/react/project/base/src/main.tsx.ejs +0 -1
  78. package/src/frameworks/react/project/base/src/routes/__root.tsx.ejs +10 -6
  79. package/src/frameworks/react/project/base/src/routes/about.tsx.ejs +27 -0
  80. package/src/frameworks/react/project/base/src/routes/blog.$slug.tsx.ejs +71 -0
  81. package/src/frameworks/react/project/base/src/routes/blog.index.tsx.ejs +93 -0
  82. package/src/frameworks/react/project/base/src/routes/index.tsx.ejs +58 -91
  83. package/src/frameworks/react/project/base/src/routes/rss[.]xml.ts.ejs +35 -0
  84. package/src/frameworks/react/project/base/src/styles.css.ejs +268 -6
  85. package/src/frameworks/react/project/base/tsconfig.json.ejs +2 -0
  86. package/src/frameworks/react/project/base/vite.config.ts.ejs +2 -0
  87. package/src/frameworks/solid/add-ons/store/assets/src/lib/demo-store.ts +5 -6
  88. package/src/frameworks/solid/add-ons/store/assets/src/routes/demo.store.tsx.ejs +2 -2
  89. package/src/frameworks/solid/examples/tanchat/assets/src/lib/demo-store.ts +5 -6
  90. package/src/frameworks/solid/project/base/src/components/Header.tsx.ejs +8 -6
  91. package/src/frameworks/solid/project/base/src/routes/__root.tsx.ejs +1 -1
  92. package/src/frameworks/solid/project/base/src/routes/index.tsx.ejs +1 -1
  93. package/src/frameworks.ts +4 -0
  94. package/src/package-json.ts +1 -1
  95. package/src/registry.ts +28 -4
  96. package/tests/add-ons.test.ts +4 -4
  97. package/tests/config-file.test.ts +3 -3
  98. package/tests/custom-add-ons/starter.test.ts +34 -2
  99. package/tests/frameworks.test.ts +24 -0
  100. package/tests/options.test.ts +4 -4
  101. package/tests/utils.test.ts +2 -2
@@ -5,17 +5,17 @@ import <%= integration.jsName %> from "<%= relativePath(integration.path) %>";
5
5
  const icons = new Set([
6
6
  "Menu",
7
7
  "X",
8
- "House",
9
8
  "Home",
10
9
  "Globe",
11
- "ChevronDown",
12
- "ChevronRight",
13
- "Layers",
14
10
  ])
15
11
 
16
12
  for(const addOn of addOns) {
17
13
  for(const route of (addOn?.routes||[])?.filter(r => r.url && r.name)) {
18
14
  icons.add( route.icon || "Globe");
15
+ if (route.children?.length) {
16
+ icons.add("ChevronDown")
17
+ icons.add("ChevronRight")
18
+ }
19
19
  }
20
20
  }
21
21
  %>
@@ -26,11 +26,13 @@ import {
26
26
 
27
27
  export default function Header() {
28
28
  <%
29
- const menusWithChildren = addOns.filter(a => a.routes?.some(r => r.children));
29
+ const hasNestedRouteGroups = addOns.some(a => a.routes?.some(r => r.children?.length));
30
30
  const userHeaders = integrations.filter(i => i.type === 'header-user');
31
31
  %>
32
32
  const [isOpen, setIsOpen] = createSignal(false);
33
+ <% if (hasNestedRouteGroups) { %>
33
34
  const [groupedExpanded, setGroupedExpanded] = createSignal<Record<string, boolean>>({});
35
+ <% } %>
34
36
 
35
37
  return (
36
38
  <>
@@ -45,7 +47,7 @@ const userHeaders = integrations.filter(i => i.type === 'header-user');
45
47
  <h1 class="ml-4 text-xl font-semibold">
46
48
  <Link to="/">
47
49
  <img
48
- src="/tanstack-word-logo-white.svg"
50
+ src="/logo192.png"
49
51
  alt="TanStack Logo"
50
52
  class="h-10"
51
53
  />
@@ -21,7 +21,7 @@ import { HeadContent, Outlet, Scripts, createRootRouteWithContext } from '@tanst
21
21
  import { TanStackRouterDevtools } from '@tanstack/solid-router-devtools'
22
22
 
23
23
  <% if (addOnEnabled['solid-ui']) { %>
24
- import "@fontsource/inter"
24
+ import "@fontsource/inter/400.css"
25
25
  <% } %>
26
26
 
27
27
  import { HydrationScript } from 'solid-js/web'
@@ -47,7 +47,7 @@ function App() {
47
47
  <div class="relative max-w-5xl mx-auto">
48
48
  <div class="flex items-center justify-center gap-6 mb-6">
49
49
  <img
50
- src="/tanstack-circle-logo.png"
50
+ src="/logo192.png"
51
51
  alt="TanStack Logo"
52
52
  class="w-24 h-24 md:w-32 md:h-32"
53
53
  />
package/src/frameworks.ts CHANGED
@@ -155,6 +155,10 @@ export function registerFramework(framework: FrameworkDefinition) {
155
155
  }
156
156
 
157
157
  export function getFrameworkById(id: string) {
158
+ if (id === 'react-cra') {
159
+ return frameworks.find((framework) => framework.id === 'react')
160
+ }
161
+
158
162
  return frameworks.find((framework) => framework.id === id)
159
163
  }
160
164
 
@@ -99,7 +99,7 @@ export function createPackageJSON(options: Options) {
99
99
  }
100
100
 
101
101
  if (options.routerOnly) {
102
- if (options.framework.id === 'react-cra') {
102
+ if (options.framework.id === 'react') {
103
103
  delete packageJSON.dependencies?.['@tanstack/react-start']
104
104
  delete packageJSON.dependencies?.['@tanstack/react-router-ssr-query']
105
105
  packageJSON.devDependencies = {
package/src/registry.ts CHANGED
@@ -6,6 +6,18 @@ import { handleSpecialURL } from './utils.js'
6
6
  import type { AddOn, Starter } from './types'
7
7
 
8
8
  const registrySchema = z.object({
9
+ templates: z
10
+ .array(
11
+ z.object({
12
+ name: z.string(),
13
+ description: z.string(),
14
+ url: z.string(),
15
+ banner: z.string().optional(),
16
+ mode: z.string(),
17
+ framework: z.string(),
18
+ }),
19
+ )
20
+ .optional(),
9
21
  starters: z
10
22
  .array(
11
23
  z.object({
@@ -49,15 +61,27 @@ export async function getRawRegistry(
49
61
  const url = handleSpecialURL(regUrl)
50
62
  const registry = (await fetch(url).then((res) => res.json())) as Registry
51
63
  const parsedRegistry = registrySchema.parse(registry)
64
+
65
+ if (!parsedRegistry.starters && parsedRegistry.templates) {
66
+ parsedRegistry.starters = parsedRegistry.templates
67
+ }
68
+
69
+ if (!parsedRegistry.templates && parsedRegistry.starters) {
70
+ parsedRegistry.templates = parsedRegistry.starters
71
+ }
72
+
52
73
  for (const addOn of parsedRegistry['add-ons'] || []) {
53
74
  addOn.url = absolutizeUrl(url, addOn.url)
54
75
  }
55
- for (const starter of parsedRegistry.starters || []) {
56
- starter.url = absolutizeUrl(url, starter.url)
57
- if (starter.banner) {
58
- starter.banner = absolutizeUrl(url, starter.banner)
76
+ for (const template of parsedRegistry.templates || []) {
77
+ template.url = absolutizeUrl(url, template.url)
78
+ if (template.banner) {
79
+ template.banner = absolutizeUrl(url, template.banner)
59
80
  }
60
81
  }
82
+
83
+ parsedRegistry.starters = parsedRegistry.templates
84
+
61
85
  return parsedRegistry
62
86
  }
63
87
  }
@@ -8,7 +8,7 @@ describe('getAllAddOns', () => {
8
8
  it('filter add-ons', () => {
9
9
  const addOns = getAllAddOns(
10
10
  {
11
- id: 'react-cra',
11
+ id: 'react',
12
12
  getAddOns: () => [
13
13
  {
14
14
  id: 'add-on-1',
@@ -32,7 +32,7 @@ describe('getAllAddOns', () => {
32
32
  it('should sort add-ons by priority (higher priority first)', () => {
33
33
  const addOns = getAllAddOns(
34
34
  {
35
- id: 'react-cra',
35
+ id: 'react',
36
36
  getAddOns: () => [
37
37
  {
38
38
  id: 'low-priority',
@@ -72,7 +72,7 @@ describe('getAllAddOns', () => {
72
72
  it('should filter by mode and then sort by priority', () => {
73
73
  const addOns = getAllAddOns(
74
74
  {
75
- id: 'react-cra',
75
+ id: 'react',
76
76
  getAddOns: () => [
77
77
  {
78
78
  id: 'file-router-low',
@@ -107,7 +107,7 @@ describe('finalizeAddOns', () => {
107
107
  it('should finalize add-ons', async () => {
108
108
  const addOns = await finalizeAddOns(
109
109
  {
110
- id: 'react-cra',
110
+ id: 'react',
111
111
  getAddOns: () => [
112
112
  {
113
113
  id: 'add-on-1',
@@ -22,7 +22,7 @@ describe('writeConfigFile', () => {
22
22
  const targetDir = 'test-dir'
23
23
  const options = {
24
24
  framework: {
25
- id: 'react-cra',
25
+ id: 'react',
26
26
  getAddOns: () => [],
27
27
  } as unknown as Framework,
28
28
  chosenAddOns: [
@@ -54,7 +54,7 @@ describe('readConfigFileFromEnvironment', () => {
54
54
  const targetDir = 'test-dir'
55
55
  const persistedOptions = {
56
56
  version: 1,
57
- framework: 'react-cra',
57
+ framework: 'react',
58
58
  chosenAddOns: ['add-on-1'],
59
59
  }
60
60
  const { environment } = createMemoryEnvironment()
@@ -91,7 +91,7 @@ describe('readConfigFileFromEnvironment', () => {
91
91
  environment.finishRun()
92
92
 
93
93
  expect(config).toEqual({
94
- framework: 'react-cra',
94
+ framework: 'react',
95
95
  projectName: 'foo',
96
96
  typescript: false,
97
97
  tailwind: false,
@@ -1,7 +1,10 @@
1
1
  import { beforeEach, describe, expect, it, vi } from 'vitest'
2
2
  import { fs, vol } from 'memfs'
3
3
 
4
- import { readOrGenerateStarterInfo } from '../../src/custom-add-ons/starter.js'
4
+ import {
5
+ loadStarter,
6
+ readOrGenerateStarterInfo,
7
+ } from '../../src/custom-add-ons/starter.js'
5
8
 
6
9
  vi.mock('node:fs', () => fs)
7
10
  vi.mock('node:fs/promises', () => fs.promises)
@@ -23,7 +26,7 @@ describe('readOrGenerateStarterInfo', () => {
23
26
  git: true,
24
27
  chosenAddOns: [],
25
28
  })
26
- expect(starterInfo.id).toEqual('test-starter')
29
+ expect(starterInfo.id).toEqual('test-template')
27
30
  })
28
31
 
29
32
  it('should read the starter info', async () => {
@@ -84,4 +87,33 @@ describe('readOrGenerateStarterInfo', () => {
84
87
  })
85
88
  expect(starterInfo.version).toEqual('0.0.1')
86
89
  })
90
+
91
+ it('should load a local template/starter file path', async () => {
92
+ fs.mkdirSync(process.cwd(), { recursive: true })
93
+ fs.writeFileSync(
94
+ './template.json',
95
+ JSON.stringify({
96
+ id: 'template-id',
97
+ name: 'Template Name',
98
+ version: '0.0.1',
99
+ description: 'template description',
100
+ author: 'Test Author',
101
+ license: 'MIT',
102
+ link: 'https://example.com/template',
103
+ type: 'starter',
104
+ framework: 'react',
105
+ mode: 'file-router',
106
+ typescript: true,
107
+ files: {
108
+ './package.json': '{}',
109
+ },
110
+ deletedFiles: [],
111
+ }),
112
+ )
113
+
114
+ const starter = await loadStarter('./template.json')
115
+
116
+ expect(starter.id).toEqual('./template.json')
117
+ await expect(starter.getFiles()).resolves.toEqual(['./package.json'])
118
+ })
87
119
  })
@@ -2,6 +2,7 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'
2
2
  import { fs, vol } from 'memfs'
3
3
 
4
4
  import {
5
+ __testClearFrameworks,
5
6
  getFrameworks,
6
7
  getFrameworkById,
7
8
  getFrameworkByName,
@@ -13,6 +14,7 @@ vi.mock('node:fs/promises', () => fs.promises)
13
14
 
14
15
  beforeEach(() => {
15
16
  vol.reset()
17
+ __testClearFrameworks()
16
18
  })
17
19
 
18
20
  describe('registerFramework', () => {
@@ -60,4 +62,26 @@ describe('registerFramework', () => {
60
62
  expect(getFrameworkByName('test')).not.toBeUndefined()
61
63
  expect(getFrameworks().length).toEqual(1)
62
64
  })
65
+
66
+ it('should resolve legacy react-cra framework id', () => {
67
+ registerFramework({
68
+ id: 'react',
69
+ name: 'React',
70
+ addOns: [],
71
+ description: 'React',
72
+ version: '1.0.0',
73
+ base: {},
74
+ basePackageJSON: {},
75
+ optionalPackages: {},
76
+ supportedModes: {
77
+ 'file-router': {
78
+ displayName: 'File Router',
79
+ description: 'File Router',
80
+ forceTypescript: true,
81
+ },
82
+ },
83
+ })
84
+
85
+ expect(getFrameworkById('react-cra')?.id).toBe('react')
86
+ })
63
87
  })
@@ -7,12 +7,12 @@ describe('createSerializedOptions', () => {
7
7
  it('handle no add-ons', () => {
8
8
  const options = createSerializedOptions({
9
9
  framework: {
10
- id: 'react-cra',
10
+ id: 'react',
11
11
  } as Framework,
12
12
  chosenAddOns: [],
13
13
  } as unknown as Options)
14
14
  expect(options).toEqual({
15
- framework: 'react-cra',
15
+ framework: 'react',
16
16
  chosenAddOns: [],
17
17
  })
18
18
  })
@@ -20,7 +20,7 @@ describe('createSerializedOptions', () => {
20
20
  it('handle add-ons and a starter', () => {
21
21
  const options = createSerializedOptions({
22
22
  framework: {
23
- id: 'react-cra',
23
+ id: 'react',
24
24
  } as Framework,
25
25
  chosenAddOns: [
26
26
  {
@@ -34,7 +34,7 @@ describe('createSerializedOptions', () => {
34
34
  } as unknown as Starter,
35
35
  } as unknown as Options)
36
36
  expect(options).toEqual({
37
- framework: 'react-cra',
37
+ framework: 'react',
38
38
  chosenAddOns: ['add-on-1'],
39
39
  starter: 'starter-1',
40
40
  })
@@ -31,10 +31,10 @@ describe('handleSpecialURL', () => {
31
31
  it('should handle special URLs', () => {
32
32
  expect(
33
33
  handleSpecialURL(
34
- 'https://github.com/TanStack/create-tsrouter-app/blob/main/examples/react-cra/registry.json',
34
+ 'https://github.com/TanStack/create-tsrouter-app/blob/main/examples/react/registry.json',
35
35
  ),
36
36
  ).toEqual(
37
- 'https://raw.githubusercontent.com/TanStack/create-tsrouter-app/refs/heads/main/examples/react-cra/registry.json',
37
+ 'https://raw.githubusercontent.com/TanStack/create-tsrouter-app/refs/heads/main/examples/react/registry.json',
38
38
  )
39
39
 
40
40
  expect(