--- name: pattern-implement description: Build Common Fabric patterns and sub-patterns user-invocable: false --- Use the `cf` skill, or read `skills/cf/SKILL.md`, for CLI documentation when running commands. # Implement Pattern ## Core Rule Match the implementation mode to the task. For Pattern Factory Build, implement the top-level pattern deliverable described by the brief, spec, UX design, and UI design. Use sub-patterns only when they make the implementation clearer. For an isolated sub-pattern task, write one sub-pattern with minimal UI first so data flow can be verified before polish. **Always use `pattern()`** - expose actions as `Stream` for testability. ## Order 1. Leaf patterns first (no dependencies on other patterns) 2. Container patterns (compose leaf patterns) 3. main.tsx last (composes everything) ## Read First - The reads mandated by pattern-dev: `docs/common/ai/pattern-development-guide.md` (especially the SES authoring limits and escape-hatch guidance), `docs/common/concepts/reactivity.md`, `docs/common/patterns/new-cells.md`, and — in a Pattern Factory Build workspace — `docs/common/ai/pattern-factory-build-guide.md` - `docs/common/patterns/` - generalizable pattern idioms - `docs/common/concepts/action.md` - action() for local state - `docs/common/concepts/handler.md` - handler() for reusable logic - `docs/common/concepts/identity.md` - equals() for object comparison For Pattern Factory Build, do not start implementation until you have read the Build guide plus the two foundational reactivity/local-cell references above. ## Key Patterns **action()** - Closes over local state in pattern body: ```tsx const inputValue = new Writable(""); const submit = action(() => { items.push({ text: inputValue.get() }); inputValue.set(""); }); ``` Use `new Writable()` only for pattern-owned local cells initialized from static values. Do not pass an input prop, mapped field, computed value, or other reactive value into `new Writable()`. If the pattern receives writable state, use that input cell directly; if a draft needs to copy from input state, copy in an action or another valid reactive/event context. For Pattern Factory Build, this rule applies to the top-level pattern input object too. Do not initialize local state with `new Writable(input.name || "")`, `new Writable(input.items || [])`, `new Cell(input.field)`, or helper calls around `input.field`. First decide whether each field is primary pattern state, static local UI state, or draft/editing state: - Primary pattern state: expose it in the `Input`/`Output` contract with `Default<>` and `Writable<>` as needed, then use the reactive input directly. - Static local UI state: create it with `new Writable(...)` from static literals only. - Draft/editing state: create it from a static value, then copy from input state inside an `action()` or another valid event/reactive context. Transient UI state (active tab, selected item, filter text, open modal): apply the PerSession new-tab test from the pattern-dev skill. Use `safeDateNow()` and `nonPrivateRandom()` instead of ambient `Date.now()` and `Math.random()` when a pattern needs explicit time or randomness. If a control is already bound to a cell, usually via `$value` or `$checked`, let that binding own the control value. Use `oncf-change` / `oncf-input` only for dependent state or other side effects. Do not invoke streams or writes while assigning JSX event props. For example, `onClick={selectItem.send(index)}` runs during render; use `onClick={() => selectItem.send(index)}` or a bound `handler()` instead. This is especially important inside `.map()` bodies because render-time writes can make `raw:map` non-idempotent. **handler()** - Reused with different bindings: ```tsx const deleteItem = handler; index: number }>( (_, { items, index }) => items.set(items.get().toSpliced(index, 1)), ); // In JSX: onClick={deleteItem({ items, index })} ``` **Rendering sub-patterns** - Function calls and JSX both work (verified: both forms pass `cf check` with a typed Output interface): ```tsx // ✅ Function call form return <>{items.map((item) => ItemPattern({ item, allItems: items }))}; // ✅ JSX form return <>{items.map((item) => )}; ``` The sub-pattern's Output type must include `[UI]: VNode` — see `docs/common/patterns/composition.md`. ## Done When - Pattern compiles: `deno task cf check pattern.tsx --no-run` - The top-level UI or sub-pattern UI renders the behavior needed for the task - New behavior is structured so tests can exercise it through typed streams, handlers, or observable state - Ready for testing