Skip to content

Commit 2c1fce8

Browse files
committed
update docs to no longer recommend adding name to recipe (+ fix md linter warnings)
1 parent b56528f commit 2c1fce8

File tree

4 files changed

+90
-49
lines changed

4 files changed

+90
-49
lines changed

docs/common/COMPONENTS.md

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ A styled button component matching the regular `button` API. Pass a handler to t
66
type InputSchema = { count: Cell<number> };
77
type OutputSchema = { count: Cell<number> };
88

9-
const MyRecipe = recipe<InputSchema, OutputSchema>("MyRecipe", ({ count }) => {
9+
const MyRecipe = recipe<InputSchema, OutputSchema>(({ count }) => {
1010
const handleClick = handler<unknown, { count: Cell<number> }>((_event, { count }) => {
1111
count.set(count.get() + 1);
1212
});
@@ -22,7 +22,7 @@ Notice how handlers are bound to the cell from the input schema _in_ the VDOM de
2222

2323
(For even more detail, see `HANDLERS.md`)
2424

25-
# Bidirectional Binding with $ Prefix
25+
## Bidirectional Binding with $ Prefix
2626

2727
Many CommonTools components support **bidirectional binding** through the `$` prefix. This powerful feature automatically updates cells when users interact with components, eliminating the need for explicit onChange handlers in most cases.
2828

@@ -96,6 +96,7 @@ const toggle = handler<{detail: {checked: boolean}}, {item: Cell<Item>}>(
9696
```
9797

9898
The bidirectional binding version is:
99+
99100
- **Simpler**: No handler definition needed
100101
- **Less code**: One line instead of five
101102
- **More maintainable**: Less surface area for bugs
@@ -123,7 +124,7 @@ const toggle = handler(
123124
one-directional binding.
124125
125126
Note that the actual name for the `onChange` handler may be different depending
126-
on the component being used. For example, <ct-checkbox> uses `onct-change`.
127+
on the component being used. For example, `<ct-checkbox>` uses `onct-change`.
127128
Consult the component for details.
128129
129130
### Validation Example
@@ -152,7 +153,7 @@ const validatedValue = derive(rawInput, (value) => {
152153
153154
This approach separates concerns: bidirectional binding handles the UI sync, while derive handles validation logic.
154155
155-
# Styling: String vs Object Syntax
156+
## Styling: String vs Object Syntax
156157
157158
Different element types accept different style syntax in CommonTools JSX. This is a common source of TypeScript errors.
158159
@@ -242,15 +243,15 @@ CommonTools custom elements (`common-hstack`, `common-vstack`, `ct-card`, etc.)
242243
<common-hstack style="padding: 1rem;">
243244
```
244245

245-
# ct-input
246+
## ct-input
246247

247248
The `ct-input` component demonstrates bidirectional binding perfectly:
248249

249250
```tsx
250251
type InputSchema = { value: Cell<string> };
251252
type OutputSchema = { value: Cell<string> };
252253

253-
const MyRecipe = recipe<InputSchema, OutputSchema>("MyRecipe", ({ value }) => {
254+
const MyRecipe = recipe(({ value }: InputSchema) => {
254255
// Option 1: Bidirectional binding (simplest)
255256
const simpleInput = <ct-input $value={value} />;
256257

@@ -275,7 +276,7 @@ const MyRecipe = recipe<InputSchema, OutputSchema>("MyRecipe", ({ value }) => {
275276

276277
Both inputs update the cell, but the second one logs changes. Use the simple bidirectional binding unless you need the extra logic.
277278

278-
# ct-select
279+
## ct-select
279280

280281
The `ct-select` component creates a dropdown selector. **Important:** It uses an `items` attribute with an array of `{ label, value }` objects, **not** HTML `<option>` elements.
281282

@@ -284,7 +285,7 @@ type CategoryInput = {
284285
category: Default<string, "Other">;
285286
};
286287

287-
const MyRecipe = recipe<CategoryInput, CategoryInput>("MyRecipe", ({ category }) => {
288+
const MyRecipe = recipe(({ category }: CategoryInput) => {
288289
return {
289290
[UI]: (
290291
<ct-select
@@ -363,7 +364,7 @@ The `value` property doesn't have to be a string - it can be any type:
363364

364365
Like other components, `ct-select` supports bidirectional binding with the `$value` prefix, automatically updating the cell when the user selects an option.
365366

366-
# ct-list
367+
## ct-list
367368

368369
The `ct-list` component provides a convenient way to display and manage lists, but it has **specific schema requirements**.
369370

@@ -380,7 +381,7 @@ interface CtListItem {
380381

381382
type ListSchema = { items: Cell<CtListItem[]> };
382383

383-
const MyRecipe = recipe<ListSchema, ListSchema>("MyRecipe", ({ items }) => {
384+
const MyRecipe = recipe(({ items }: ListSchema) => {
384385
return {
385386
[UI]: <div>
386387
<ct-list $items={items} editable={false} />
@@ -418,16 +419,18 @@ interface ShoppingItem {
418419
## Trade-offs
419420

420421
**Use ct-list when:**
422+
421423
- Your items only need `title` and optionally `done`
422424
- You want a quick, pre-styled list component
423425
- You don't need custom rendering
424426

425427
**Use manual rendering when:**
428+
426429
- You have custom fields
427430
- You need custom styling or layout
428431
- You need fine-grained control over interactions
429432

430-
# ct-message-input
433+
## ct-message-input
431434

432435
This component bundles an input and a button to 'send a message' or 'add an item to a list' which is a common pattern. You don't need to worry about the value until submission time.
433436

@@ -449,7 +452,7 @@ const addItem = handler<
449452
/>
450453
````
451454

452-
# ct-outliner
455+
## ct-outliner
453456

454457
`ct-outliner` is conceptually similar to `ct-list` except it works on a tree data structure. Below is a demonstration of the minimal use, see `page.tsx` for a more complete example.
455458

@@ -510,7 +513,7 @@ export default recipe<PageInput, PageResult>(
510513
);
511514
```
512515

513-
# ct-render
516+
## ct-render
514517

515518
The `ct-render` component displays pattern instances within another pattern. Use this for **pattern composition** - combining multiple patterns together in a single recipe.
516519

@@ -571,7 +574,7 @@ interface Input {
571574
items: Default<Item[], []>;
572575
}
573576

574-
export default recipe<Input, Input>("Multi-View", ({ items }) => {
577+
export default recipe(({ items }: Input) => {
575578
// Both patterns receive the same items cell
576579
const listView = ListView({ items });
577580
const gridView = GridView({ items });
@@ -596,6 +599,7 @@ export default recipe<Input, Input>("Multi-View", ({ items }) => {
596599
```
597600

598601
**What happens:**
602+
599603
- Both patterns receive the same `items` cell reference
600604
- Changes in ListView automatically appear in GridView
601605
- Changes in GridView automatically appear in ListView
@@ -619,6 +623,7 @@ const counter = Counter({ value: state.value });
619623
```
620624

621625
**When to use each:**
626+
622627
- **Direct interpolation** (`{counter}`): Simple cases, most concise
623628
- **JSX component syntax** (`<Counter />`): When you want it to look like a component
624629
- **ct-render** (`<ct-render $cell={counter} />`): When the pattern wasn't instantiated from within this pattern but was passed in or was stored in a list.

docs/common/HANDLERS.md

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ const updateTitle = handler<
9999
## Common TypeScript Issues & Fixes
100100

101101
### Handler Function Parameters
102+
102103
- **First parameter**: Event data (from UI interactions)
103104
- **Second parameter**: State data (destructured from state schema)
104105
- **Parameter naming**: Use descriptive names or `_` prefix for unused parameters
@@ -273,7 +274,7 @@ const removeItem = handler<
273274
}
274275
});
275276

276-
export default recipe<Input, Input>("Shopping List", ({ items }) => {
277+
export default recipe<Input, Input>(({ items }) => {
277278
// items here is OpaqueRef<ShoppingItem[]>
278279

279280
return {
@@ -307,7 +308,7 @@ export default recipe<Input, Input>("Shopping List", ({ items }) => {
307308

308309
**Rule of thumb:** In handler type signatures, use `Cell<T[]>` for array parameters. The Cell wraps the entire array, not individual elements.
309310

310-
#### Event Parameter Patterns
311+
### Event Parameter Patterns
311312

312313
You can handle the event parameter in different ways depending on your needs:
313314

@@ -343,6 +344,7 @@ const simpleIncrement = handler<Record<string, never>, { count: Cell<number> }>(
343344
## Handler Invocation Patterns
344345

345346
### State Passing
347+
346348
When invoking handlers in UI, pass an object that matches your state schema:
347349

348350
```typescript
@@ -357,18 +359,21 @@ onClick={myHandler({ items: itemsArray, currentPage: currentPageString })}
357359
```
358360

359361
### Event vs Props Confusion
362+
360363
- **Event type**: Describes data coming FROM the UI event
361364
- **State type**: Describes data the handler needs to ACCESS
362365
- **Invocation object**: Must match the state type, NOT the event type
363366

364367
## Debugging Handler Issues
365368

366369
### Type Mismatches
370+
367371
1. Check that handler invocation object matches state type
368372
2. Verify event type matches actual UI event structure
369373
3. Ensure destructuring in handler function matches types
370374

371375
### Runtime Issues
376+
372377
1. Use `console.log` in handler functions to debug
373378
2. Check that state objects have expected properties
374379
3. Verify UI events are firing correctly
@@ -384,13 +389,15 @@ onClick={myHandler({ items: itemsArray, currentPage: currentPageString })}
384389
## Examples by Use Case
385390

386391
### Counter/Simple State
392+
387393
```typescript
388394
const increment = handler<Record<string, never>, { count: Cell<number> }>(
389395
(_, { count }) => count.set(count.get() + 1)
390396
);
391397
```
392398

393399
### Form/Input Updates
400+
394401
```typescript
395402
const updateField = handler<
396403
{ detail: { value: string } },
@@ -401,6 +408,7 @@ const updateField = handler<
401408
```
402409

403410
### List/Array Operations
411+
404412
```typescript
405413
const addItem = handler<
406414
{ message: string },
@@ -412,6 +420,7 @@ const addItem = handler<
412420
```
413421

414422
### Complex State Updates
423+
415424
```typescript
416425
const updatePageContent = handler<
417426
{ detail: { value: string } },
@@ -426,6 +435,7 @@ const updatePageContent = handler<
426435
## Advanced Patterns
427436

428437
### Handler Composition
438+
429439
```typescript
430440
// Base handlers for reuse
431441
const createTimestamp = () => Date.now();
@@ -491,6 +501,7 @@ const handleFormSubmit = handler<
491501
## Common Pitfalls
492502

493503
### 1. Type Mismatch
504+
494505
```typescript
495506
// ❌ Wrong: State type doesn't match invocation
496507
const handler = handler<Record<string, never>, { count: number }>(
@@ -502,6 +513,7 @@ onClick={handler({ value: 5 })} // Should be { count: 5 }
502513
```
503514

504515
### 2. Event Type Over-specification
516+
505517
```typescript
506518
// ❌ Wrong: Over-complicated event type for simple clicks
507519
const handler = handler<{
@@ -518,6 +530,7 @@ const handler = handler<Record<string, never>, any>(
518530
```
519531

520532
### 3. Mutation vs Immutability
533+
521534
```typescript
522535
// ❌ Wrong: Direct assignment to non-cell state
523536
(_, { title }) => {
@@ -538,6 +551,7 @@ const handler = handler<Record<string, never>, any>(
538551
## Debugging Handlers
539552

540553
### Console-based Debugging
554+
541555
```typescript
542556
// In recipes, use console logging for debugging
543557
const addItem = handler<

0 commit comments

Comments
 (0)