Skip to content

Conversation

@seefeldb
Copy link
Contributor

@seefeldb seefeldb commented Oct 21, 2025

Summary by cubic

Adds shopping list patterns (basic, categorized, composed) and updates CommonTools docs to center on bidirectional binding, making recipes simpler and faster to build. Also refreshes ct-select/ct-checkbox demos and introduces a comprehensive PATTERNS.md.

  • New Features
    • Added shopping-list.tsx, shopping-list-categorized.tsx (grouping via derive), and shopping-list-composed.tsx (shared state rendered with ct-render).
    • Updated ct-checkbox and ct-select demos to showcase $checked/$value binding, logging, and numeric selections.
    • Introduced docs/common/PATTERNS.md with the “prefer bidirectional binding” rule and quick decision guides; expanded COMPONENTS.md, HANDLERS.md, and RECIPES.md to clarify when handlers are needed.
    • Improved tutorials and dev workflow tips; added PATTERN_DOCUMENTATION_FEEDBACK.md capturing gaps and proposed fixes.

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

5 issues found across 14 files

Prompt for AI agents (all 5 issues)

Understand the root cause of the following 5 issues and fix them.


<file name="docs/common/HANDLERS.md">

<violation number="1" location="docs/common/HANDLERS.md:51">
The example calls `items.key(el)` with the array element, but `Cell.key` expects an array index. Update the example to pass the index so developers don&#39;t copy a non-compiling pattern.</violation>
</file>

<file name="packages/patterns/shopping-list.tsx">

<violation number="1" location="packages/patterns/shopping-list.tsx:57">
Add a stable key prop to the element rendered inside items.map so React can track each shopping list item during updates.</violation>
</file>

<file name="packages/patterns/ct-select.tsx">

<violation number="1" location="packages/patterns/ct-select.tsx:36">
Both selects share the same `selected` state but expose disjoint value sets, so changing the categories select leaves the string select with a value it can&#39;t render. Give the categories example its own state so each select&#39;s value always matches its items.</violation>
</file>

<file name="docs/common/RECIPES.md">

<violation number="1" location="docs/common/RECIPES.md:603">
Numbering jumps backward here, so the ordered list now contains duplicate headings and no longer reads sequentially.</violation>

<violation number="2" location="docs/common/RECIPES.md:920">
This example reintroduces index-based removal even though the new best-practices section just marked index passing as an anti-pattern, so the guidance conflicts within the same page.</violation>
</file>

React with 👍 or 👎 to teach cubic. Mention @cubic-dev-ai to give feedback, ask questions, or re-run the review.

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

5 issues found across 13 files

Prompt for AI agents (all 5 issues)

Understand the root cause of the following 5 issues and fix them.


<file name="docs/common/PATTERNS.md">

<violation number="1" location="docs/common/PATTERNS.md:58">
The Level 3 Shopping List Editor example calls `cell(&quot;Uncategorized&quot;)`, but the matching import omits `cell`, so the snippet won’t compile as written.</violation>
</file>

<file name="packages/patterns/shopping-list-categorized.tsx">

<violation number="1" location="packages/patterns/shopping-list-categorized.tsx:48">
Add a stable `key` prop to the `&lt;div&gt;` returned from `categories.map` so React can reconcile the list correctly.</violation>

<violation number="2" location="packages/patterns/shopping-list-categorized.tsx:73">
Provide a unique `key` on each `&lt;ct-checkbox&gt;` rendered inside the item map to keep React’s list reconciliation stable.</violation>
</file>

<file name="packages/patterns/ct-select.tsx">

<violation number="1" location="packages/patterns/ct-select.tsx:36">
The new categories demo reuses the same `$value={selected}` cell as the string-options demo, but the item values differ, so selecting a category (or even the initial default &quot;opt_1&quot;) has no matching option and leaves both selects blank. Please bind the categories example to its own state or align its option values.</violation>
</file>

<file name="docs/common/RECIPES.md">

<violation number="1" location="docs/common/RECIPES.md:300">
Example 1 still instructs removing items by index, contradicting rule 5’s new guidance to prefer item references. Please update this sample to align with the rule.</violation>
</file>

React with 👍 or 👎 to teach cubic. Mention @cubic-dev-ai to give feedback, ask questions, or re-run the review.

ellyxir and others added 3 commits October 21, 2025 18:47
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

5 issues found across 13 files

Prompt for AI agents (all 5 issues)

Understand the root cause of the following 5 issues and fix them.


<file name="docs/common/PATTERNS.md">

<violation number="1" location="docs/common/PATTERNS.md:100">
The Level 1 example uses a string for the `style` prop on a `&lt;div&gt;`, but JSX expects an object (`CSSProperties`) for HTML elements, so the sample won’t type-check. Please switch to object syntax so the documentation reflects working code.</violation>
</file>

<file name="docs/common/RECIPES.md">

<violation number="1" location="docs/common/RECIPES.md:920">
This example recommends removal by index right after Rule 5 marked index-based handlers as an anti-pattern, so the documentation gives conflicting guidance.</violation>
</file>

<file name="packages/patterns/shopping-list-categorized.tsx">

<violation number="1" location="packages/patterns/shopping-list-categorized.tsx:48">
Each category section rendered from categories.map needs a stable key so React can reconcile updates correctly. Please add a key for the enclosing &lt;div&gt;.</violation>

<violation number="2" location="packages/patterns/shopping-list-categorized.tsx:73">
List entries generated by the inner map also need keys so React can track each checkbox/item reliably when the grouped list changes.</violation>
</file>

<file name="docs/common/COMPONENTS.md">

<violation number="1" location="docs/common/COMPONENTS.md:122">
`ct-checkbox` emits the `ct-change` custom event, so handlers must be attached with `onct-change`. This example’s `onChange` prop will never fire, breaking the documented pattern.</violation>
</file>

React with 👍 or 👎 to teach cubic. Mention @cubic-dev-ai to give feedback, ask questions, or re-run the review.

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 2 files

Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed changes from recent commits (found 1 issue).

1 issue found across 4 files

Prompt for AI agents (all 1 issues)

Understand the root cause of the following 1 issues and fix them.


<file name="docs/common/PATTERNS.md">

<violation number="1" location="docs/common/PATTERNS.md:87">
`item` is an `OpaqueRef&lt;ShoppingItem&gt;` in this example, and `OpaqueRef` does not expose an `equals` method. Calling `item.equals(...)` therefore fails to type-check, breaking the pattern sample.</violation>
</file>

React with 👍 or 👎 to teach cubic. Mention @cubic-dev-ai to give feedback, ask questions, or re-run the review.

@seefeldb seefeldb merged commit a3f192c into main Oct 21, 2025
8 checks passed
@seefeldb seefeldb deleted the exp/shopping-pattern branch October 21, 2025 22:41
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed changes from recent commits (found 7 issues).

7 issues found across 8 files

Prompt for AI agents (all 7 issues)

Understand the root cause of the following 7 issues and fix them.


<file name="docs/common/RECIPES.md">

<violation number="1" location="docs/common/RECIPES.md:891">
`currentItems` is now referenced without being defined, so this handler example no longer compiles. Please remove the extra argument and push just the new item.</violation>
</file>

<file name="docs/common/PATTERNS.md">

<violation number="1" location="docs/common/PATTERNS.md:84">
The handler now requires `items: Cell&lt;Array&lt;Cell&lt;ShoppingItem&gt;&gt;&gt;`, but the recipe still provides `items` as `Cell&lt;ShoppingItem[]&gt;`, so this example no longer type-checks. Please keep the handler parameter aligned with the actual recipe input type.</violation>
</file>

<file name="docs/common/COMPONENTS.md">

<violation number="1" location="docs/common/COMPONENTS.md:111">
`items` and `max` are referenced here but never destructured, so this snippet fails to compile. Please include them in the parameter destructuring.</violation>

<violation number="2" location="docs/common/COMPONENTS.md:113">
`item.done` is a cell, so filtering on it counts every item. Use `.get()` so the max check reflects the true done count.</violation>

<violation number="3" location="docs/common/COMPONENTS.md:117">
The `else` branch is left open here, resulting in invalid TypeScript. Add handling logic or remove the `else` so the example compiles.</violation>

<violation number="4" location="docs/common/COMPONENTS.md:121">
`max = 3` is invalid in an object literal—use a property assignment so the example parses.</violation>

<violation number="5" location="docs/common/COMPONENTS.md:149">
`v` is undefined in this scope. Compare against `validatedValue` (or destructure it first) so the ternary works.</violation>
</file>

React with 👍 or 👎 to teach cubic. Mention @cubic-dev-ai to give feedback, ask questions, or re-run the review.

const itemName = detail?.message?.trim();
if (!itemName) return;
items.push(currentItems, { title: itemName, done: false, category: "Uncategorized" });
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Oct 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

currentItems is now referenced without being defined, so this handler example no longer compiles. Please remove the extra argument and push just the new item.

Prompt for AI agents
Address the following comment on docs/common/RECIPES.md at line 891:

<comment>`currentItems` is now referenced without being defined, so this handler example no longer compiles. Please remove the extra argument and push just the new item.</comment>

<file context>
@@ -911,8 +888,7 @@ const addItem = handler&lt;
 
-  const currentItems = items.get();
-  items.set([...currentItems, { title: itemName, done: false, category: &quot;Uncategorized&quot; }]);
+  items.push(currentItems, { title: itemName, done: false, category: &quot;Uncategorized&quot; });
 });
 
</file context>
Suggested change
items.push(currentItems, { title: itemName, done: false, category: "Uncategorized" });
items.push({ title: itemName, done: false, category: "Uncategorized" });
Fix with Cubic

const removeItem = handler<
unknown,
{ items: Cell<Array<Cell<ShoppingItem>>>; item: Cell<ShoppingItem> }
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Oct 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The handler now requires items: Cell<Array<Cell<ShoppingItem>>>, but the recipe still provides items as Cell<ShoppingItem[]>, so this example no longer type-checks. Please keep the handler parameter aligned with the actual recipe input type.

Prompt for AI agents
Address the following comment on docs/common/PATTERNS.md at line 84:

<comment>The handler now requires `items: Cell&lt;Array&lt;Cell&lt;ShoppingItem&gt;&gt;&gt;`, but the recipe still provides `items` as `Cell&lt;ShoppingItem[]&gt;`, so this example no longer type-checks. Please keep the handler parameter aligned with the actual recipe input type.</comment>

<file context>
@@ -81,10 +81,10 @@ const addItem = handler&lt;
 const removeItem = handler&lt;
   unknown,
-  { items: Cell&lt;ShoppingItem[]&gt;; item: Cell&lt;ShoppingItem&gt; }
+  { items: Cell&lt;Array&lt;Cell&lt;ShoppingItem&gt;&gt;&gt;; item: Cell&lt;ShoppingItem&gt; }
 &gt;((_event, { items, item }) =&gt; {
   const currentItems = items.get();
</file context>
Suggested change
{ items: Cell<Array<Cell<ShoppingItem>>>; item: Cell<ShoppingItem> }
{ items: Cell<ShoppingItem[]>; item: Cell<ShoppingItem> }
Fix with Cubic

});

// Show validation status
{v !== null ?
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Oct 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

v is undefined in this scope. Compare against validatedValue (or destructure it first) so the ternary works.

Prompt for AI agents
Address the following comment on docs/common/COMPONENTS.md at line 149:

<comment>`v` is undefined in this scope. Compare against `validatedValue` (or destructure it first) so the ternary works.</comment>

<file context>
@@ -146,11 +146,10 @@ const validatedValue = derive(rawInput, (value) =&gt; {
-{ifElse(
-  derive(validatedValue, (v) =&gt; v !== null),
-  &lt;span style={{ color: &quot;green&quot; }}&gt;✓ Valid&lt;/span&gt;,
+{v !== null ?
+  &lt;span style={{ color: &quot;green&quot; }}&gt;✓ Valid&lt;/span&gt; :
   &lt;span style={{ color: &quot;red&quot; }}&gt;✗ Must be 3+ letters&lt;/span&gt;
</file context>
Suggested change
{v !== null ?
{validatedValue !== null ?
Fix with Cubic

}
);

<ct-checkbox $checked={item.done} onct-change={toggle({ items, item, max = 3 })} />
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Oct 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

max = 3 is invalid in an object literal—use a property assignment so the example parses.

Prompt for AI agents
Address the following comment on docs/common/COMPONENTS.md at line 121:

<comment>`max = 3` is invalid in an object literal—use a property assignment so the example parses.</comment>

<file context>
@@ -108,25 +108,25 @@ The bidirectional binding version is:
 );
 
-&lt;ct-checkbox $checked={item.done} onct-change={toggle({ item })} /&gt;
+&lt;ct-checkbox $checked={item.done} onct-change={toggle({ items, item, max = 3 })} /&gt;
 ```
 
</file context>
Suggested change
<ct-checkbox $checked={item.done} onct-change={toggle({ items, item, max = 3 })} />
<ct-checkbox $checked={item.done} onct-change={toggle({ items, item, max: 3 })} />
Fix with Cubic


if (currentValue || max === undefined || doneCount < max) {
item.done.set(!currentValue);
} else {
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Oct 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The else branch is left open here, resulting in invalid TypeScript. Add handling logic or remove the else so the example compiles.

Prompt for AI agents
Address the following comment on docs/common/COMPONENTS.md at line 117:

<comment>The `else` branch is left open here, resulting in invalid TypeScript. Add handling logic or remove the `else` so the example compiles.</comment>

<file context>
@@ -108,25 +108,25 @@ The bidirectional binding version is:
-    trackAnalytics(&quot;item_toggled&quot;, { done: !currentValue });
+    if (currentValue || max === undefined || doneCount &lt; max) {
+      item.done.set(!currentValue);
+    } else {
   }
 );
</file context>
Fix with Cubic

const toggle = handler(
(_event, { item }: { item: Cell<Item>, items: Item[], max: number }) => {
const currentValue = item.done.get();
const doneCount = items.filter(item => item.done).length;
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Oct 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

item.done is a cell, so filtering on it counts every item. Use .get() so the max check reflects the true done count.

Prompt for AI agents
Address the following comment on docs/common/COMPONENTS.md at line 113:

<comment>`item.done` is a cell, so filtering on it counts every item. Use `.get()` so the max check reflects the true done count.</comment>

<file context>
@@ -108,25 +108,25 @@ The bidirectional binding version is:
+  (_event, { item }: { item: Cell&lt;Item&gt;, items: Item[], max: number }) =&gt; {
     const currentValue = item.done.get();
-    item.done.set(!currentValue);
+    const doneCount = items.filter(item =&gt; item.done).length;
 
-    // Additional side effects
</file context>
Suggested change
const doneCount = items.filter(item => item.done).length;
const doneCount = items.filter(item => item.done.get()).length;
Fix with Cubic

```tsx
// ✅ CORRECT - Handler needed for side effects
const toggle = handler(
(_event, { item }: { item: Cell<Item>, items: Item[], max: number }) => {
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot Oct 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

items and max are referenced here but never destructured, so this snippet fails to compile. Please include them in the parameter destructuring.

Prompt for AI agents
Address the following comment on docs/common/COMPONENTS.md at line 111:

<comment>`items` and `max` are referenced here but never destructured, so this snippet fails to compile. Please include them in the parameter destructuring.</comment>

<file context>
@@ -108,25 +108,25 @@ The bidirectional binding version is:
 // ✅ CORRECT - Handler needed for side effects
 const toggle = handler(
-  (_event, { item }: { item: Cell&lt;Item&gt; }) =&gt; {
+  (_event, { item }: { item: Cell&lt;Item&gt;, items: Item[], max: number }) =&gt; {
     const currentValue = item.done.get();
-    item.done.set(!currentValue);
</file context>
Suggested change
(_event, { item }: { item: Cell<Item>, items: Item[], max: number }) => {
(_event, { item, items, max }: { item: Cell<Item>, items: Item[], max: number }) => {
Fix with Cubic

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants