@tanstack/cta-ui-base 0.32.3 → 0.33.2

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.
@@ -4,7 +4,7 @@ import { InfoIcon, SettingsIcon } from 'lucide-react';
4
4
  import { Switch } from '../ui/switch';
5
5
  import { Label } from '../ui/label';
6
6
  import { Button } from '../ui/button';
7
- import { useAddOns, useProjectOptions } from '../../store/project';
7
+ import { useAddOns, useProjectOptions, useShowHostingOptions, } from '../../store/project';
8
8
  import ImportCustomAddOn from '../custom-add-on-dialog';
9
9
  import AddOnInfoDialog from '../add-on-info-dialog';
10
10
  import AddOnConfigDialog from '../add-on-config-dialog';
@@ -15,11 +15,18 @@ const addOnTypeLabels = {
15
15
  example: 'Example',
16
16
  };
17
17
  export default function SelectedAddOns() {
18
+ const showHostingOptions = useShowHostingOptions();
18
19
  const { availableAddOns, addOnState, toggleAddOn, setAddOnOption } = useAddOns();
19
20
  const addOnOptions = useProjectOptions((state) => state.addOnOptions);
21
+ console.log('showHostingOptions', showHostingOptions);
20
22
  const sortedAddOns = useMemo(() => {
21
23
  return availableAddOns.sort((a, b) => {
22
- return a.name.localeCompare(b.name);
24
+ const aPriority = a.priority ?? 0;
25
+ const bPriority = b.priority ?? 0;
26
+ if (bPriority !== aPriority) {
27
+ return bPriority - aPriority; // Higher priority first
28
+ }
29
+ return a.name.localeCompare(b.name); // Fallback to alphabetical
23
30
  });
24
31
  }, [availableAddOns]);
25
32
  const [infoAddOn, setInfoAddOn] = useState();
@@ -28,7 +35,10 @@ export default function SelectedAddOns() {
28
35
  if (configAddOn) {
29
36
  setAddOnOption(configAddOn.id, optionName, value);
30
37
  }
31
- }, onClose: () => setConfigAddOn(undefined), disabled: configAddOn ? !addOnState[configAddOn.id]?.enabled : false }), _jsx("div", { className: "max-h-[60vh] overflow-y-auto space-y-2", children: Object.keys(addOnTypeLabels).map((type) => (_jsx(Fragment, { children: sortedAddOns.filter((addOn) => addOn.type === type).length > 0 && (_jsxs("div", { className: "block p-4 bg-gray-500/10 hover:bg-gray-500/20 rounded-lg transition-colors space-y-4 active", children: [_jsx("h3", { className: "font-medium", children: addOnTypeLabels[type] }), _jsx("div", { className: "space-y-3", children: _jsx("div", { className: "flex flex-row flex-wrap", children: sortedAddOns
38
+ }, onClose: () => setConfigAddOn(undefined), disabled: configAddOn ? !addOnState[configAddOn.id]?.enabled : false }), _jsx("div", { className: "max-h-[60vh] overflow-y-auto space-y-2", children: Object.keys(addOnTypeLabels)
39
+ .filter((type) => (showHostingOptions ? true : type !== 'host'))
40
+ .map((type) => (_jsx(Fragment, { children: sortedAddOns.filter((addOn) => addOn.type === type).length >
41
+ 0 && (_jsxs("div", { className: "block p-4 bg-gray-500/10 hover:bg-gray-500/20 rounded-lg transition-colors space-y-4 active", children: [_jsx("h3", { className: "font-medium", children: addOnTypeLabels[type] }), _jsx("div", { className: "space-y-3", children: _jsx("div", { className: "flex flex-row flex-wrap", children: sortedAddOns
32
42
  .filter((addOn) => addOn.type === type)
33
43
  .map((addOn) => (_jsx("div", { className: "w-1/2", children: _jsxs("div", { className: "flex flex-row items-center justify-between", children: [_jsxs("div", { className: "p-1 flex flex-row items-center", children: [_jsx(Switch, { id: addOn.id, checked: addOnState[addOn.id].selected, disabled: !addOnState[addOn.id].enabled, onCheckedChange: () => {
34
44
  toggleAddOn(addOn.id);
@@ -1,7 +1,6 @@
1
1
  import { WebContainer } from '@webcontainer/api';
2
2
  import { createStore } from 'zustand';
3
3
  import shimALS from '../lib/als-shim';
4
- console.log('>>> startup');
5
4
  const processTerminalLine = (data) => {
6
5
  // Clean up terminal output - remove ANSI codes and control characters
7
6
  let cleaned = data;
@@ -13,6 +13,7 @@ export declare const useOriginalOutput: () => any;
13
13
  export declare const useOriginalOptions: () => any;
14
14
  export declare const useOriginalSelectedAddOns: () => any;
15
15
  export declare const useApplicationMode: () => import("../types").ApplicationMode | undefined;
16
+ export declare const useShowHostingOptions: () => boolean | undefined;
16
17
  export declare const useAddOnsByMode: () => Record<string, AddOnInfo[]> | undefined;
17
18
  export declare const useSupportedModes: () => Record<string, {
18
19
  displayName: string;
@@ -33,6 +33,7 @@ export const useOriginalOutput = () => useInitialData().data?.output;
33
33
  export const useOriginalOptions = () => useInitialData().data?.options;
34
34
  export const useOriginalSelectedAddOns = () => useOriginalOptions()?.chosenAddOns;
35
35
  export const useApplicationMode = () => useInitialData().data?.applicationMode;
36
+ export const useShowHostingOptions = () => useInitialData().data?.showHostingOptions;
36
37
  export const useAddOnsByMode = () => useInitialData().data?.addOns;
37
38
  export const useSupportedModes = () => useInitialData().data?.supportedModes;
38
39
  const useApplicationSettings = create(() => ({
package/package.json CHANGED
@@ -37,7 +37,7 @@
37
37
  "sonner": "^2.0.3",
38
38
  "tailwind-merge": "^3.0.2",
39
39
  "zustand": "^5.0.3",
40
- "@tanstack/cta-engine": "0.32.3"
40
+ "@tanstack/cta-engine": "0.33.0"
41
41
  },
42
42
  "devDependencies": {
43
43
  "@types/react": "^19.0.8",
@@ -46,6 +46,6 @@
46
46
  "vite-tsconfig-paths": "^5.1.4",
47
47
  "vitest": "^3.1.4"
48
48
  },
49
- "version": "0.32.3",
49
+ "version": "0.33.2",
50
50
  "scripts": {}
51
51
  }
@@ -5,7 +5,11 @@ import { Switch } from '../ui/switch'
5
5
  import { Label } from '../ui/label'
6
6
  import { Button } from '../ui/button'
7
7
 
8
- import { useAddOns, useProjectOptions } from '../../store/project'
8
+ import {
9
+ useAddOns,
10
+ useProjectOptions,
11
+ useShowHostingOptions,
12
+ } from '../../store/project'
9
13
 
10
14
  import ImportCustomAddOn from '../custom-add-on-dialog'
11
15
  import AddOnInfoDialog from '../add-on-info-dialog'
@@ -21,13 +25,21 @@ const addOnTypeLabels: Record<string, string> = {
21
25
  }
22
26
 
23
27
  export default function SelectedAddOns() {
28
+ const showHostingOptions = useShowHostingOptions()
24
29
  const { availableAddOns, addOnState, toggleAddOn, setAddOnOption } =
25
30
  useAddOns()
26
31
  const addOnOptions = useProjectOptions((state) => state.addOnOptions)
27
32
 
33
+ console.log('showHostingOptions', showHostingOptions)
34
+
28
35
  const sortedAddOns = useMemo(() => {
29
36
  return availableAddOns.sort((a, b) => {
30
- return a.name.localeCompare(b.name)
37
+ const aPriority = a.priority ?? 0
38
+ const bPriority = b.priority ?? 0
39
+ if (bPriority !== aPriority) {
40
+ return bPriority - aPriority // Higher priority first
41
+ }
42
+ return a.name.localeCompare(b.name) // Fallback to alphabetical
31
43
  })
32
44
  }, [availableAddOns])
33
45
 
@@ -52,74 +64,77 @@ export default function SelectedAddOns() {
52
64
  disabled={configAddOn ? !addOnState[configAddOn.id]?.enabled : false}
53
65
  />
54
66
  <div className="max-h-[60vh] overflow-y-auto space-y-2">
55
- {Object.keys(addOnTypeLabels).map((type) => (
56
- <Fragment key={type}>
57
- {sortedAddOns.filter((addOn) => addOn.type === type).length > 0 && (
58
- <div
59
- key={`${type}-add-ons`}
60
- className="block p-4 bg-gray-500/10 hover:bg-gray-500/20 rounded-lg transition-colors space-y-4 active"
61
- >
62
- <h3 className="font-medium">{addOnTypeLabels[type]}</h3>
63
- <div className="space-y-3">
64
- <div className="flex flex-row flex-wrap">
65
- {sortedAddOns
66
- .filter((addOn) => addOn.type === type)
67
- .map((addOn) => (
68
- <div key={addOn.id} className="w-1/2">
69
- <div className="flex flex-row items-center justify-between">
70
- <div className="p-1 flex flex-row items-center">
71
- <Switch
72
- id={addOn.id}
73
- checked={addOnState[addOn.id].selected}
74
- disabled={!addOnState[addOn.id].enabled}
75
- onCheckedChange={() => {
76
- toggleAddOn(addOn.id)
77
- }}
78
- />
79
- <Label
80
- htmlFor={addOn.id}
81
- className="pl-2 font-semibold text-gray-300 flex items-center gap-2"
82
- >
83
- {addOn.smallLogo && (
84
- <img
85
- src={`data:image/svg+xml,${encodeURIComponent(
86
- addOn.smallLogo,
87
- )}`}
88
- alt={addOn.name}
89
- className="w-5"
90
- />
91
- )}
92
- {addOn.name}
93
- </Label>
94
- </div>
95
- <div className="flex items-center gap-1">
96
- {addOnState[addOn.id].selected &&
97
- addOn.options &&
98
- Object.keys(addOn.options).length > 0 && (
99
- <Button
100
- variant="ghost"
101
- size="sm"
102
- className="h-6 w-6 p-0 text-gray-600 hover:text-gray-400"
103
- onClick={() => setConfigAddOn(addOn)}
104
- disabled={!addOnState[addOn.id].enabled}
105
- >
106
- <SettingsIcon className="w-4 h-4" />
107
- </Button>
108
- )}
109
- <InfoIcon
110
- className="w-4 text-gray-600 cursor-pointer hover:text-gray-400"
111
- onClick={() => setInfoAddOn(addOn)}
112
- />
67
+ {Object.keys(addOnTypeLabels)
68
+ .filter((type) => (showHostingOptions ? true : type !== 'host'))
69
+ .map((type) => (
70
+ <Fragment key={type}>
71
+ {sortedAddOns.filter((addOn) => addOn.type === type).length >
72
+ 0 && (
73
+ <div
74
+ key={`${type}-add-ons`}
75
+ className="block p-4 bg-gray-500/10 hover:bg-gray-500/20 rounded-lg transition-colors space-y-4 active"
76
+ >
77
+ <h3 className="font-medium">{addOnTypeLabels[type]}</h3>
78
+ <div className="space-y-3">
79
+ <div className="flex flex-row flex-wrap">
80
+ {sortedAddOns
81
+ .filter((addOn) => addOn.type === type)
82
+ .map((addOn) => (
83
+ <div key={addOn.id} className="w-1/2">
84
+ <div className="flex flex-row items-center justify-between">
85
+ <div className="p-1 flex flex-row items-center">
86
+ <Switch
87
+ id={addOn.id}
88
+ checked={addOnState[addOn.id].selected}
89
+ disabled={!addOnState[addOn.id].enabled}
90
+ onCheckedChange={() => {
91
+ toggleAddOn(addOn.id)
92
+ }}
93
+ />
94
+ <Label
95
+ htmlFor={addOn.id}
96
+ className="pl-2 font-semibold text-gray-300 flex items-center gap-2"
97
+ >
98
+ {addOn.smallLogo && (
99
+ <img
100
+ src={`data:image/svg+xml,${encodeURIComponent(
101
+ addOn.smallLogo,
102
+ )}`}
103
+ alt={addOn.name}
104
+ className="w-5"
105
+ />
106
+ )}
107
+ {addOn.name}
108
+ </Label>
109
+ </div>
110
+ <div className="flex items-center gap-1">
111
+ {addOnState[addOn.id].selected &&
112
+ addOn.options &&
113
+ Object.keys(addOn.options).length > 0 && (
114
+ <Button
115
+ variant="ghost"
116
+ size="sm"
117
+ className="h-6 w-6 p-0 text-gray-600 hover:text-gray-400"
118
+ onClick={() => setConfigAddOn(addOn)}
119
+ disabled={!addOnState[addOn.id].enabled}
120
+ >
121
+ <SettingsIcon className="w-4 h-4" />
122
+ </Button>
123
+ )}
124
+ <InfoIcon
125
+ className="w-4 text-gray-600 cursor-pointer hover:text-gray-400"
126
+ onClick={() => setInfoAddOn(addOn)}
127
+ />
128
+ </div>
113
129
  </div>
114
130
  </div>
115
- </div>
116
- ))}
131
+ ))}
132
+ </div>
117
133
  </div>
118
134
  </div>
119
- </div>
120
- )}
121
- </Fragment>
122
- ))}
135
+ )}
136
+ </Fragment>
137
+ ))}
123
138
  </div>
124
139
  <div className="mt-4">
125
140
  <ImportCustomAddOn />
@@ -12,8 +12,6 @@ export type SetupStep =
12
12
  | 'ready'
13
13
  | 'error'
14
14
 
15
- console.log('>>> startup')
16
-
17
15
  type WebContainerStore = {
18
16
  webContainer: Promise<WebContainer> | null
19
17
  ready: boolean
@@ -48,6 +48,8 @@ export const useOriginalOptions = () => useInitialData().data?.options
48
48
  export const useOriginalSelectedAddOns = () =>
49
49
  useOriginalOptions()?.chosenAddOns
50
50
  export const useApplicationMode = () => useInitialData().data?.applicationMode
51
+ export const useShowHostingOptions = () =>
52
+ useInitialData().data?.showHostingOptions
51
53
  export const useAddOnsByMode = () => useInitialData().data?.addOns
52
54
  export const useSupportedModes = () => useInitialData().data?.supportedModes
53
55
 
package/src/types.d.ts CHANGED
@@ -1,4 +1,8 @@
1
- import type { StatusStepType, AddOnOption, AddOnOptions } from '@tanstack/cta-engine'
1
+ import type {
2
+ StatusStepType,
3
+ AddOnOption,
4
+ AddOnOptions,
5
+ } from '@tanstack/cta-engine'
2
6
 
3
7
  export type ApplicationMode = 'add' | 'setup' | 'none'
4
8
 
@@ -35,6 +39,7 @@ export type AddOnInfo = {
35
39
  type: 'add-on' | 'example' | 'starter' | 'toolchain' | 'host'
36
40
  modes: Array<string>
37
41
  smallLogo?: string
42
+ priority?: number
38
43
  logo?: string
39
44
  link: string
40
45
  dependsOn?: Array<string>
@@ -84,6 +89,7 @@ export type InitialData = {
84
89
  localFiles: Record<string, string>
85
90
  addOns: Record<string, Array<AddOnInfo>>
86
91
  applicationMode: ApplicationMode
92
+ showHostingOptions?: boolean
87
93
  forcedRouterMode?: string
88
94
  forcedAddOns?: Array<string>
89
95
  registry?: Registry | undefined