@tanstack/cta-ui 0.15.3 → 0.15.4

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 (88) hide show
  1. package/dist/assets/index-BLGJkAxX.css +1 -0
  2. package/dist/assets/index-DPjMQkKx.js +208 -0
  3. package/dist/assets/index-DPjMQkKx.js.map +1 -0
  4. package/dist/index.html +3 -2
  5. package/index.html +1 -0
  6. package/lib/engine-handling/create-app-wrapper.ts +3 -4
  7. package/lib/engine-handling/generate-initial-payload.ts +12 -20
  8. package/lib/engine-handling/server-environment.ts +2 -2
  9. package/lib/index.ts +33 -15
  10. package/lib-dist/engine-handling/create-app-wrapper.js +3 -2
  11. package/lib-dist/engine-handling/generate-initial-payload.d.ts +8 -6
  12. package/lib-dist/engine-handling/generate-initial-payload.js +9 -14
  13. package/lib-dist/engine-handling/server-environment.d.ts +3 -3
  14. package/lib-dist/index.d.ts +1 -0
  15. package/lib-dist/index.js +29 -11
  16. package/package.json +3 -32
  17. package/src/index.tsx +2 -42
  18. package/src/main.tsx +0 -1
  19. package/src/styles.css +2 -0
  20. package/src/types.d.ts +13 -8
  21. package/dist/assets/index-BktnQA5a.js +0 -213
  22. package/dist/assets/index-BktnQA5a.js.map +0 -1
  23. package/dist/assets/index-CpoUtYXp.css +0 -1
  24. package/dist/logo-color-100w.png +0 -0
  25. package/dist/logo192.png +0 -0
  26. package/dist/logo512.png +0 -0
  27. package/dist/tailwind.svg +0 -1
  28. package/dist/tanstack.png +0 -0
  29. package/dist/typescript.svg +0 -1
  30. package/lib/engine-handling/framework-registration.ts +0 -11
  31. package/lib-dist/engine-handling/framework-registration.d.ts +0 -1
  32. package/lib-dist/engine-handling/framework-registration.js +0 -10
  33. package/public/logo-color-100w.png +0 -0
  34. package/public/logo192.png +0 -0
  35. package/public/logo512.png +0 -0
  36. package/public/tailwind.svg +0 -1
  37. package/public/tanstack.png +0 -0
  38. package/public/typescript.svg +0 -1
  39. package/src/components/StatusList.tsx +0 -22
  40. package/src/components/add-on-info-dialog.tsx +0 -39
  41. package/src/components/background-animation.tsx +0 -229
  42. package/src/components/cta-sidebar.tsx +0 -50
  43. package/src/components/custom-add-on-dialog.tsx +0 -79
  44. package/src/components/file-navigator.tsx +0 -203
  45. package/src/components/file-tree.tsx +0 -35
  46. package/src/components/file-viewer.tsx +0 -67
  47. package/src/components/header.tsx +0 -31
  48. package/src/components/sidebar-items/add-ons.tsx +0 -94
  49. package/src/components/sidebar-items/mode-selector.tsx +0 -57
  50. package/src/components/sidebar-items/project-name.tsx +0 -28
  51. package/src/components/sidebar-items/run-add-ons.tsx +0 -71
  52. package/src/components/sidebar-items/run-create-app.tsx +0 -82
  53. package/src/components/sidebar-items/starter.tsx +0 -123
  54. package/src/components/sidebar-items/typescript-switch.tsx +0 -52
  55. package/src/components/starters-carousel.tsx +0 -45
  56. package/src/components/startup-dialog.tsx +0 -71
  57. package/src/components/toaster.tsx +0 -29
  58. package/src/components/ui/button.tsx +0 -61
  59. package/src/components/ui/carousel.tsx +0 -239
  60. package/src/components/ui/checkbox.tsx +0 -30
  61. package/src/components/ui/dialog.tsx +0 -138
  62. package/src/components/ui/dropdown-menu.tsx +0 -255
  63. package/src/components/ui/input.tsx +0 -21
  64. package/src/components/ui/label.tsx +0 -22
  65. package/src/components/ui/popover.tsx +0 -46
  66. package/src/components/ui/separator.tsx +0 -28
  67. package/src/components/ui/sheet.tsx +0 -137
  68. package/src/components/ui/sidebar.tsx +0 -726
  69. package/src/components/ui/skeleton.tsx +0 -13
  70. package/src/components/ui/sonner.tsx +0 -23
  71. package/src/components/ui/switch.tsx +0 -29
  72. package/src/components/ui/table.tsx +0 -114
  73. package/src/components/ui/tabs.tsx +0 -64
  74. package/src/components/ui/toggle-group.tsx +0 -71
  75. package/src/components/ui/toggle.tsx +0 -49
  76. package/src/components/ui/tooltip.tsx +0 -61
  77. package/src/components/ui/tree-view.tsx +0 -497
  78. package/src/file-classes.ts +0 -54
  79. package/src/hooks/use-mobile.ts +0 -19
  80. package/src/hooks/use-mounted.ts +0 -9
  81. package/src/hooks/use-preferred-reduced-motion.ts +0 -27
  82. package/src/hooks/use-streaming-status.ts +0 -70
  83. package/src/lib/api.ts +0 -92
  84. package/src/lib/utils.ts +0 -6
  85. package/src/store/add-ons.ts +0 -81
  86. package/src/store/project.ts +0 -347
  87. package/tests/store/add-ons.test.ts +0 -222
  88. package/vitest.config.ts +0 -6
package/src/lib/api.ts DELETED
@@ -1,92 +0,0 @@
1
- import type { SerializedOptions } from '@tanstack/cta-engine'
2
-
3
- import type { AddOnInfo, DryRunOutput, InitialData, StarterInfo } from '@/types'
4
-
5
- const baseUrl = import.meta.env.VITE_API_BASE_URL || ''
6
-
7
- export async function createAppStreaming(
8
- options: SerializedOptions,
9
- chosenAddOns: Array<string>,
10
- projectStarter?: StarterInfo,
11
- ) {
12
- return await fetch(`${baseUrl}/api/create-app`, {
13
- method: 'POST',
14
- body: JSON.stringify({
15
- options: {
16
- ...options,
17
- chosenAddOns,
18
- starter: projectStarter?.url || undefined,
19
- },
20
- }),
21
- headers: {
22
- 'Content-Type': 'application/json',
23
- },
24
- })
25
- }
26
-
27
- export async function addToAppStreaming(chosenAddOns: Array<string>) {
28
- return await fetch(`${baseUrl}/api/add-to-app`, {
29
- method: 'POST',
30
- body: JSON.stringify({
31
- addOns: chosenAddOns,
32
- }),
33
- headers: {
34
- 'Content-Type': 'application/json',
35
- },
36
- })
37
- }
38
-
39
- export function shutdown() {
40
- return fetch(`${baseUrl}/api/shutdown`, {
41
- method: 'POST',
42
- })
43
- }
44
-
45
- export async function loadRemoteAddOn(url: string) {
46
- const response = await fetch(`${baseUrl}/api/load-remote-add-on?url=${url}`)
47
- return (await response.json()) as AddOnInfo | { error: string }
48
- }
49
-
50
- export async function loadRemoteStarter(url: string) {
51
- const response = await fetch(`${baseUrl}/api/load-starter?url=${url}`)
52
- return (await response.json()) as StarterInfo | { error: string }
53
- }
54
-
55
- export async function loadInitialData() {
56
- const payloadReq = await fetch(`${baseUrl}/api/initial-payload`)
57
- return (await payloadReq.json()) as InitialData
58
- }
59
-
60
- export async function dryRunCreateApp(
61
- options: SerializedOptions,
62
- chosenAddOns: Array<string>,
63
- projectStarter?: StarterInfo,
64
- ) {
65
- const outputReq = await fetch(`${baseUrl}/api/dry-run-create-app`, {
66
- method: 'POST',
67
- headers: {
68
- 'Content-Type': 'application/json',
69
- },
70
- body: JSON.stringify({
71
- options: {
72
- ...options,
73
- chosenAddOns: chosenAddOns,
74
- starter: projectStarter?.url,
75
- },
76
- }),
77
- })
78
- return outputReq.json() as Promise<DryRunOutput>
79
- }
80
-
81
- export async function dryRunAddToApp(addOns: Array<string>) {
82
- const outputReq = await fetch(`${baseUrl}/api/dry-run-add-to-app`, {
83
- method: 'POST',
84
- headers: {
85
- 'Content-Type': 'application/json',
86
- },
87
- body: JSON.stringify({
88
- addOns,
89
- }),
90
- })
91
- return outputReq.json() as Promise<DryRunOutput>
92
- }
package/src/lib/utils.ts DELETED
@@ -1,6 +0,0 @@
1
- import { clsx, type ClassValue } from "clsx"
2
- import { twMerge } from "tailwind-merge"
3
-
4
- export function cn(...inputs: ClassValue[]) {
5
- return twMerge(clsx(inputs))
6
- }
@@ -1,81 +0,0 @@
1
- import type { AddOnInfo } from '@/types'
2
-
3
- export function getAddOnStatus(
4
- availableAddOns: Array<AddOnInfo>,
5
- chosenAddOns: Array<string>,
6
- originalAddOns: Array<string>,
7
- ) {
8
- const addOnMap = new Map<
9
- string,
10
- {
11
- enabled: boolean
12
- selected: boolean
13
- dependedUpon: boolean
14
- }
15
- >()
16
-
17
- for (const addOn of availableAddOns) {
18
- addOnMap.set(addOn.id, {
19
- selected: false,
20
- enabled: true,
21
- dependedUpon: false,
22
- })
23
- }
24
-
25
- // Guard against cycles in the dependency graph. The results won't be great. But it won't crash.
26
- function cycleGuardedSelectAndDisableDependsOn(startingAddOnId: string) {
27
- const visited = new Set<string>()
28
- function selectAndDisableDependsOn(addOnId: string) {
29
- if (visited.has(addOnId)) {
30
- return
31
- }
32
- visited.add(addOnId)
33
- const selectedAddOn = availableAddOns.find(
34
- (addOn) => addOn.id === addOnId,
35
- )
36
- if (selectedAddOn) {
37
- for (const dependsOnId of selectedAddOn.dependsOn || []) {
38
- const dependsOnAddOn = addOnMap.get(dependsOnId)
39
- if (dependsOnAddOn) {
40
- dependsOnAddOn.selected = true
41
- dependsOnAddOn.enabled = false
42
- dependsOnAddOn.dependedUpon = true
43
- selectAndDisableDependsOn(dependsOnId)
44
- }
45
- }
46
- const addOn = addOnMap.get(addOnId)
47
- if (addOn) {
48
- addOn.selected = true
49
- if (!addOn.dependedUpon) {
50
- addOn.enabled = true
51
- }
52
- }
53
- }
54
- }
55
- selectAndDisableDependsOn(startingAddOnId)
56
- }
57
-
58
- for (const addOn of originalAddOns) {
59
- const addOnInfo = addOnMap.get(addOn)
60
- if (addOnInfo) {
61
- addOnInfo.selected = true
62
- addOnInfo.enabled = false
63
- addOnInfo.dependedUpon = true
64
- }
65
- cycleGuardedSelectAndDisableDependsOn(addOn)
66
- }
67
-
68
- for (const addOnId of chosenAddOns) {
69
- cycleGuardedSelectAndDisableDependsOn(addOnId)
70
- }
71
-
72
- return Object.fromEntries(
73
- Array.from(addOnMap.entries()).map(([v, addOn]) => [
74
- v,
75
- {
76
- enabled: addOn.enabled,
77
- selected: addOn.selected,
78
- },
79
- ]),
80
- )
81
- }
@@ -1,347 +0,0 @@
1
- import { useCallback, useEffect, useMemo } from 'react'
2
- import { create } from 'zustand'
3
- import { persist } from 'zustand/middleware'
4
- import { useQuery } from '@tanstack/react-query'
5
-
6
- import { getAddOnStatus } from './add-ons'
7
-
8
- import type { Mode, SerializedOptions } from '@tanstack/cta-engine'
9
-
10
- import type { AddOnInfo, DryRunOutput, StarterInfo } from '@/types.js'
11
- import { dryRunAddToApp, dryRunCreateApp, loadInitialData } from '@/lib/api'
12
-
13
- export const useProjectOptions = create<SerializedOptions>(() => ({
14
- framework: 'react-cra',
15
- mode: 'file-router',
16
- projectName: 'my-app',
17
- targetDir: 'my-app',
18
- typescript: true,
19
- tailwind: true,
20
- git: true,
21
- chosenAddOns: [],
22
- packageManager: 'pnpm',
23
- }))
24
-
25
- const useInitialData = () =>
26
- useQuery({
27
- queryKey: ['initial-data'],
28
- queryFn: async () => loadInitialData(),
29
- initialData: {
30
- options: {
31
- framework: 'react-cra',
32
- mode: 'file-router',
33
- projectName: 'my-app',
34
- targetDir: 'my-app',
35
- typescript: true,
36
- tailwind: true,
37
- git: true,
38
- chosenAddOns: [],
39
- packageManager: 'pnpm',
40
- },
41
- localFiles: {},
42
- output: {
43
- files: {},
44
- commands: [],
45
- deletedFiles: [],
46
- },
47
- addOns: {
48
- 'code-router': [],
49
- 'file-router': [],
50
- },
51
- applicationMode: 'none',
52
- forcedRouterMode: undefined,
53
- forcedAddOns: [],
54
- registry: undefined,
55
- },
56
- })
57
-
58
- const useForcedRouterMode = () => useInitialData().data.forcedRouterMode
59
- const useForcedAddOns = () => useInitialData().data.forcedAddOns
60
-
61
- export const useRegistry = () => useInitialData().data.registry
62
-
63
- export const useProjectLocalFiles = () => useInitialData().data.localFiles
64
- export const useOriginalOutput = () => useInitialData().data.output
65
- export const useOriginalOptions = () => useInitialData().data.options
66
- export const useOriginalSelectedAddOns = () => useOriginalOptions().chosenAddOns
67
- export const useApplicationMode = () => useInitialData().data.applicationMode
68
- export const useReady = () => useInitialData().isFetched
69
- export const useCodeRouterAddOns = () =>
70
- useInitialData().data.addOns['code-router']
71
- export const useFileRouterAddOns = () =>
72
- useInitialData().data.addOns['file-router']
73
-
74
- const useApplicationSettings = create<{
75
- includeFiles: Array<string>
76
- }>(() => ({
77
- includeFiles: ['unchanged', 'added', 'modified', 'deleted', 'overwritten'],
78
- }))
79
-
80
- const useMutableAddOns = create<{
81
- userSelectedAddOns: Array<string>
82
- customAddOns: Array<AddOnInfo>
83
- }>(() => ({
84
- userSelectedAddOns: [],
85
- customAddOns: [],
86
- }))
87
-
88
- export const useProjectStarter = create<{
89
- projectStarter: StarterInfo | undefined
90
- }>(() => ({
91
- projectStarter: undefined,
92
- }))
93
-
94
- export function addCustomAddOn(addOn: AddOnInfo) {
95
- useMutableAddOns.setState((state) => ({
96
- customAddOns: [...state.customAddOns, addOn],
97
- }))
98
- if (addOn.modes.includes(useProjectOptions.getState().mode)) {
99
- useMutableAddOns.setState((state) => ({
100
- userSelectedAddOns: [...state.userSelectedAddOns, addOn.id],
101
- }))
102
- }
103
- }
104
-
105
- export function useAddOns() {
106
- const routerMode = useRouterMode()
107
- const originalSelectedAddOns = useOriginalSelectedAddOns()
108
- const codeRouterAddOns = useCodeRouterAddOns()
109
- const fileRouterAddOns = useFileRouterAddOns()
110
- const forcedAddOns = useForcedAddOns()
111
- const { userSelectedAddOns, customAddOns } = useMutableAddOns()
112
- const projectStarter = useProjectStarter().projectStarter
113
-
114
- const availableAddOns = useMemo(() => {
115
- const baseAddOns =
116
- routerMode === 'code-router' ? codeRouterAddOns : fileRouterAddOns
117
- return [
118
- ...baseAddOns,
119
- ...customAddOns.filter((addOn) => addOn.modes.includes(routerMode)),
120
- ]
121
- }, [routerMode, codeRouterAddOns, fileRouterAddOns, customAddOns])
122
-
123
- const addOnState = useMemo(() => {
124
- const originalAddOns: Set<string> = new Set()
125
- for (const addOn of projectStarter?.dependsOn || []) {
126
- originalAddOns.add(addOn)
127
- }
128
- for (const addOn of originalSelectedAddOns) {
129
- originalAddOns.add(addOn)
130
- }
131
- for (const addOn of forcedAddOns || []) {
132
- originalAddOns.add(addOn)
133
- }
134
- return getAddOnStatus(
135
- availableAddOns,
136
- userSelectedAddOns,
137
- Array.from(originalAddOns),
138
- )
139
- }, [
140
- availableAddOns,
141
- userSelectedAddOns,
142
- originalSelectedAddOns,
143
- projectStarter?.dependsOn,
144
- forcedAddOns,
145
- ])
146
-
147
- const chosenAddOns = useMemo(() => {
148
- const addOns = new Set(
149
- Object.keys(addOnState).filter((addOn) => addOnState[addOn].selected),
150
- )
151
- for (const addOn of forcedAddOns || []) {
152
- addOns.add(addOn)
153
- }
154
- return Array.from(addOns)
155
- }, [addOnState, forcedAddOns])
156
-
157
- const toggleAddOn = useCallback(
158
- (addOnId: string) => {
159
- if (addOnState[addOnId].enabled) {
160
- if (addOnState[addOnId].selected) {
161
- useMutableAddOns.setState((state) => ({
162
- userSelectedAddOns: state.userSelectedAddOns.filter(
163
- (addOn) => addOn !== addOnId,
164
- ),
165
- }))
166
- } else {
167
- useMutableAddOns.setState((state) => ({
168
- userSelectedAddOns: [...state.userSelectedAddOns, addOnId],
169
- }))
170
- }
171
- }
172
- },
173
- [addOnState],
174
- )
175
-
176
- return {
177
- toggleAddOn,
178
- chosenAddOns,
179
- availableAddOns,
180
- userSelectedAddOns,
181
- originalSelectedAddOns,
182
- addOnState,
183
- }
184
- }
185
-
186
- const useHasProjectStarter = () =>
187
- useProjectStarter((state) => state.projectStarter === undefined)
188
-
189
- export const useModeEditable = () => {
190
- const forcedRouterMode = useForcedRouterMode()
191
- const hasProjectStarter = useHasProjectStarter()
192
- return !forcedRouterMode && hasProjectStarter
193
- }
194
-
195
- export const useTypeScriptEditable = () => {
196
- const hasProjectStarter = useHasProjectStarter()
197
- const routerMode = useRouterMode()
198
- return hasProjectStarter && routerMode === 'code-router'
199
- }
200
-
201
- export const useTailwindEditable = () => {
202
- const hasProjectStarter = useHasProjectStarter()
203
- const routerMode = useRouterMode()
204
- return hasProjectStarter && routerMode === 'code-router'
205
- }
206
-
207
- export const useProjectName = () =>
208
- useProjectOptions((state) => state.projectName)
209
-
210
- export const useRouterMode = () => {
211
- const forcedRouterMode = useForcedRouterMode()
212
- const userMode = useProjectOptions((state) => state.mode)
213
- return forcedRouterMode || userMode
214
- }
215
-
216
- export function useFilters() {
217
- const includedFiles = useApplicationSettings((state) => state.includeFiles)
218
-
219
- const toggleFilter = useCallback((filter: string) => {
220
- useApplicationSettings.setState((state) => ({
221
- includeFiles: state.includeFiles.includes(filter)
222
- ? state.includeFiles.filter((f) => f !== filter)
223
- : [...state.includeFiles, filter],
224
- }))
225
- }, [])
226
-
227
- return {
228
- includedFiles,
229
- toggleFilter,
230
- }
231
- }
232
-
233
- export function useDryRun() {
234
- const applicationMode = useApplicationMode()
235
- const projectOptions = useProjectOptions()
236
- const { userSelectedAddOns, chosenAddOns } = useAddOns()
237
- const projectStarter = useProjectStarter().projectStarter
238
-
239
- const { data: dryRunOutput } = useQuery<DryRunOutput>({
240
- queryKey: [
241
- 'dry-run',
242
- applicationMode,
243
- JSON.stringify(projectOptions),
244
- JSON.stringify(userSelectedAddOns),
245
- projectStarter?.url,
246
- ],
247
- queryFn: async () => {
248
- if (applicationMode === 'none') {
249
- return {
250
- files: {},
251
- commands: [],
252
- deletedFiles: [],
253
- }
254
- } else if (applicationMode === 'setup') {
255
- return dryRunCreateApp(projectOptions, chosenAddOns, projectStarter)
256
- } else {
257
- return dryRunAddToApp(userSelectedAddOns)
258
- }
259
- },
260
- initialData: {
261
- files: {},
262
- commands: [],
263
- deletedFiles: [],
264
- },
265
- })
266
-
267
- return dryRunOutput
268
- }
269
-
270
- type StartupDialogState = {
271
- open: boolean
272
- dontShowAgain: boolean
273
- setOpen: (open: boolean) => void
274
- setDontShowAgain: (dontShowAgain: boolean) => void
275
- }
276
-
277
- export const useStartupDialog = create<StartupDialogState>()(
278
- persist(
279
- (set) => ({
280
- open: false,
281
- dontShowAgain: false,
282
- setOpen: (open) => set({ open }),
283
- setDontShowAgain: (dontShowAgain) => set({ dontShowAgain }),
284
- }),
285
- {
286
- name: 'startup-dialog',
287
- partialize: (state) => ({
288
- dontShowAgain: state.dontShowAgain,
289
- }),
290
- merge: (persistedState: unknown, currentState) => {
291
- if (
292
- persistedState &&
293
- (persistedState as { dontShowAgain?: boolean }).dontShowAgain
294
- ) {
295
- currentState.open = false
296
- } else {
297
- currentState.open = true
298
- }
299
- return currentState
300
- },
301
- },
302
- ),
303
- )
304
-
305
- export const setProjectName = (projectName: string) =>
306
- useProjectOptions.setState({
307
- projectName,
308
- })
309
-
310
- export const setRouterMode = (mode: Mode) =>
311
- useProjectOptions.setState({
312
- mode,
313
- })
314
-
315
- export function setTypeScript(typescript: boolean) {
316
- useProjectOptions.setState({
317
- typescript,
318
- })
319
- }
320
-
321
- export function setTailwind(tailwind: boolean) {
322
- useProjectOptions.setState({
323
- tailwind,
324
- })
325
- }
326
-
327
- export function setProjectStarter(starter: StarterInfo | undefined) {
328
- useProjectStarter.setState(() => ({
329
- projectStarter: starter,
330
- }))
331
- if (starter) {
332
- useProjectOptions.setState({
333
- mode: starter.mode,
334
- })
335
- }
336
- }
337
-
338
- export function useManager() {
339
- const ready = useReady()
340
- const originalOptions = useOriginalOptions()
341
-
342
- useEffect(() => {
343
- if (ready) {
344
- useProjectOptions.setState(originalOptions)
345
- }
346
- }, [ready])
347
- }