start-vibing-stacks 2.0.2 → 2.0.3

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/dist/ui.js CHANGED
@@ -2,7 +2,7 @@
2
2
  * Start Vibing Stacks — Terminal UI
3
3
  */
4
4
  import chalk from 'chalk';
5
- const VERSION = '2.0.2';
5
+ const VERSION = '2.0.3';
6
6
  const gradient = (text) => {
7
7
  const colors = [chalk.hex('#FF6B6B'), chalk.hex('#FF8E53'), chalk.hex('#FFBD2E'), chalk.hex('#48BB78'), chalk.hex('#4299E1'), chalk.hex('#9F7AEA')];
8
8
  return text.split('').map((c, i) => colors[i % colors.length](c)).join('');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "start-vibing-stacks",
3
- "version": "2.0.2",
3
+ "version": "2.0.3",
4
4
  "description": "AI-powered multi-stack dev workflow for Claude Code. Supports PHP, Node.js, Python and more.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -104,10 +104,121 @@ const Heavy = lazy(() => import('./HeavyComponent'));
104
104
  <Suspense fallback={<Loading />}><Heavy /></Suspense>
105
105
  ```
106
106
 
107
+ ## React 19 Hooks
108
+
109
+ ```tsx
110
+ // useActionState — form submission state
111
+ import { useActionState } from 'react';
112
+
113
+ function LoginForm() {
114
+ const [state, formAction, isPending] = useActionState(
115
+ async (prev, formData: FormData) => {
116
+ const result = await login(formData);
117
+ if (result.error) return { error: result.error };
118
+ redirect('/dashboard');
119
+ },
120
+ { error: null }
121
+ );
122
+
123
+ return (
124
+ <form action={formAction}>
125
+ <input name="email" type="email" />
126
+ {state.error && <p className="text-destructive">{state.error}</p>}
127
+ <button disabled={isPending}>
128
+ {isPending ? 'Signing in...' : 'Sign In'}
129
+ </button>
130
+ </form>
131
+ );
132
+ }
133
+
134
+ // useOptimistic — instant UI feedback
135
+ import { useOptimistic } from 'react';
136
+
137
+ function TodoList({ todos }: { todos: Todo[] }) {
138
+ const [optimisticTodos, addOptimistic] = useOptimistic(
139
+ todos,
140
+ (state, newTodo: Todo) => [...state, newTodo]
141
+ );
142
+
143
+ const addTodo = async (formData: FormData) => {
144
+ const todo = { id: crypto.randomUUID(), title: formData.get('title') as string, done: false };
145
+ addOptimistic(todo); // Instant UI
146
+ await saveTodo(todo); // Server sync
147
+ };
148
+
149
+ return <ul>{optimisticTodos.map(t => <li key={t.id}>{t.title}</li>)}</ul>;
150
+ }
151
+ ```
152
+
153
+ ## State Management Selection
154
+
155
+ | Complexity | Solution | When |
156
+ |---|---|---|
157
+ | Simple local | `useState` | Single component, simple values |
158
+ | Complex local | `useReducer` | Multiple related state transitions |
159
+ | Parent-child | Lift state up | 1-2 levels |
160
+ | Subtree | Context + `useReducer` | Theme, auth, 3+ levels |
161
+ | Server state | React Query / SWR | API data, caching, refetch |
162
+ | Complex global | Zustand | Cross-feature, many consumers |
163
+
164
+ ## Error Boundaries
165
+
166
+ ```tsx
167
+ import { Component, type ReactNode } from 'react';
168
+
169
+ class ErrorBoundary extends Component<
170
+ { children: ReactNode; fallback?: ReactNode },
171
+ { hasError: boolean; error?: Error }
172
+ > {
173
+ state = { hasError: false, error: undefined as Error | undefined };
174
+
175
+ static getDerivedStateFromError(error: Error) {
176
+ return { hasError: true, error };
177
+ }
178
+
179
+ componentDidCatch(error: Error, info: React.ErrorInfo) {
180
+ console.error('ErrorBoundary caught:', error, info);
181
+ // Send to Sentry/logging
182
+ }
183
+
184
+ render() {
185
+ if (this.state.hasError) {
186
+ return this.props.fallback ?? (
187
+ <div className="p-8 text-center">
188
+ <h2 className="text-lg font-semibold text-foreground">Something went wrong</h2>
189
+ <button onClick={() => this.setState({ hasError: false })}
190
+ className="mt-4 px-4 py-2 bg-primary text-primary-foreground rounded-lg">
191
+ Try Again
192
+ </button>
193
+ </div>
194
+ );
195
+ }
196
+ return this.props.children;
197
+ }
198
+ }
199
+
200
+ // Usage: wrap routes/features
201
+ <ErrorBoundary fallback={<ErrorPage />}>
202
+ <DashboardFeature />
203
+ </ErrorBoundary>
204
+ ```
205
+
206
+ ## Component Types
207
+
208
+ | Type | Use | Example |
209
+ |---|---|---|
210
+ | **Server** (RSC) | Data fetching, static content | Page-level components |
211
+ | **Client** (`'use client'`) | Interactivity, hooks, browser APIs | Forms, modals, dropdowns |
212
+ | **Presentational** | Pure display, props only | `<Badge>`, `<Avatar>` |
213
+ | **Container** | Logic + state, renders presentational | `<UserListContainer>` |
214
+
107
215
  ## FORBIDDEN
108
216
 
109
- 1. **Class components** — function components only
217
+ 1. **Class components** — function components only (except ErrorBoundary)
110
218
  2. **Prop drilling** — use context or composition
111
219
  3. **Inline objects/functions in JSX** — causes re-renders
112
220
  4. **useEffect for derived state** — use useMemo
113
221
  5. **Mutating state directly** — always setState/dispatch
222
+ 6. **Index as key** — use stable unique ID (`uuid`, `id`)
223
+ 7. **Premature optimization** — profile first with React DevTools
224
+ 8. **useEffect for everything** — prefer server components for data