/// /** * TEST PATTERN: Pattern Composition with Shared Cell References * * CLAIM: "Both patterns receive the same `items` cell reference... Changes in * one view automatically update the other (they share the same cell)" * SOURCE: docs/common/PATTERNS.md, patterns.md folk wisdom * * WHAT THIS TESTS: * Two sub-patterns (BasicList and CategoryList) both receive the same `items` * cell. When you modify data through one pattern's UI, we verify whether the * other pattern's UI updates automatically. * * EXPECTED BEHAVIOR IF CLAIM IS TRUE: * 1. Adding an item via BasicList's input updates CategoryList instantly * 2. Toggling done state in either view updates the other view * 3. Removing an item from either view removes it from both * 4. The cell reference is truly shared, not copied * * MANUAL VERIFICATION STEPS: * 1. Note the items shown in both "Basic List" and "Category List" sections * 2. Add a new item using "Basic List" input with category * 3. Verify it appears immediately in BOTH views * 4. Check an item as done in "Basic List" * 5. Verify it shows as done (strikethrough) in "Category List" * 6. Remove an item from "Category List" using x button * 7. Verify it disappears from "Basic List" too */ import { Cell, computed, Default, derive, handler, ifElse, NAME, pattern, UI, } from "commontools"; interface ShoppingItem { title: string; done: Default; category: Default; } // Sub-pattern 1: Basic list view interface BasicListInput { items: Cell; } const BasicList = pattern(({ items }) => { const removeItem = handler< unknown, { items: Cell>>; item: Cell } >( (_event, { items: itemsList, item }) => { const current = itemsList.get(); const index = current.findIndex((el) => el.equals(item)); if (index >= 0) { itemsList.set(current.toSpliced(index, 1)); } }, ); const addItem = handler< { detail: { message: string } }, { items: Cell } >( ({ detail }, { items: itemsList }) => { const input = detail?.message?.trim(); if (input) { const [title, category = "Uncategorized"] = input.split(":"); itemsList.push({ title: title.trim(), done: false, category: category.trim(), }); } }, ); return { [NAME]: "Basic Shopping List", [UI]: (

Basic List View

{items.map((item) => (
(item.done ? { textDecoration: "line-through" } : {}), )} > {item.title} ({item.category}) x
))}
), items, }; }); // Sub-pattern 2: Categorized view interface CategoryListInput { items: Cell; } const CategoryList = pattern(({ items }) => { // Compute unique sorted categories from items const categories = derive( { items }, ({ items: itemsArray }: { items: ShoppingItem[] }) => { const cats = new Set(); for (const item of itemsArray) { cats.add(item.category || "Uncategorized"); } return Array.from(cats).sort(); }, ); const removeItem = handler< unknown, { items: Cell>>; item: Cell } >( (_event, { items: itemsList, item }) => { const current = itemsList.get(); const index = current.findIndex((el) => el.equals(item)); if (index >= 0) { itemsList.set(current.toSpliced(index, 1)); } }, ); return { [NAME]: "Shopping List by Category", [UI]: (

Category List View

{categories.map((category) => (

{category}

{items.map((item) => ifElse( computed(() => (item.category || "Uncategorized") === category),
(item.done ? { textDecoration: "line-through" } : {}) )} > {item.title} x
, null, ) )}
))}
), items, }; }); // Main pattern: Compose both views with shared cell interface ComposedInput { items: Default< ShoppingItem[], [ { title: "Milk"; done: false; category: "Dairy" }, { title: "Bread"; done: false; category: "Bakery" }, { title: "Cheese"; done: true; category: "Dairy" }, ] >; } export default pattern(({ items }) => { // Create both sub-patterns with the SAME items cell const basicView = BasicList({ items }); const categoryView = CategoryList({ items }); return { [NAME]: "Test: Pattern Composition with Shared Cells", [UI]: (

Pattern Composition Test

Test Instructions:

  1. Add an item in Basic List using format "Title:Category"
  2. Watch it appear in BOTH views instantly
  3. Toggle done state in one view, see it update in the other
  4. Remove an item from either view, watch it disappear from both

If all work correctly → Claim VERIFIED

{basicView}
{categoryView}

Technical Details

Both patterns receive: items (same Cell reference)

), items, }; });