-
Notifications
You must be signed in to change notification settings - Fork 11
making calendar tutorial #1902
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
making calendar tutorial #1902
Conversation
Add bidirectional support for HTML5 data-* attributes in JSX templates:
- Write support: setProp() now detects data-* properties and uses
setAttribute() to properly populate the browser's dataset API
- Read support: serializableEvent() extracts event.target.dataset
for use in event handlers
- Type safety: Added isHTMLElement() type guard
This enables recipes to pass data through DOM elements and access
it in event handlers via event.target.dataset.
Example usage:
<div data-date="2025-10-13" onClick={handler}>Click</div>
handler: (event) => {
const date = event.target.dataset.date; // Works!
}
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <[email protected]>
…r data, a todo map with date as key and list of string as todo list
- Handle null/undefined data-* attributes by removing them - Add proper TypeScript typing for setProp function - Replace isHTMLElement helper with more robust type checking - Ensure dataset values are properly stringified in serialization
Add tests covering: - Setting data-* attributes via setAttribute - Removing data-* attributes when value is null/undefined - Converting non-string values to strings - Updating data-* attributes when values change - Serializing event.target.dataset Update MockDoc test utilities: - Add setAttribute, hasAttribute, removeAttribute methods - Add dataset property getter with camelCase conversion - Update custom setProp to handle null/undefined for data-* attributes 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <[email protected]>
…e/tutorials-calendar-basics
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
1 issue found across 5 files
Prompt for AI agents (all 1 issues)
Understand the root cause of the following 1 issues and fix them.
<file name="packages/html/src/utils.ts">
<violation number="1" location="packages/html/src/utils.ts:138">
The new dataset getter returns a fresh object without wiring assignments back to attribs, so writes like `el.dataset.foo = "bar"` silently fail to create the corresponding `data-foo` attribute. Please make dataset behave like DOMStringMap and sync property writes to attributes.</violation>
</file>
React with 👍 or 👎 to teach cubic. Mention @cubic-dev-ai to give feedback, ask questions, or re-run the review.
| } | ||
| }, | ||
| }, | ||
| dataset: { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The new dataset getter returns a fresh object without wiring assignments back to attribs, so writes like el.dataset.foo = "bar" silently fail to create the corresponding data-foo attribute. Please make dataset behave like DOMStringMap and sync property writes to attributes.
Prompt for AI agents
Address the following comment on packages/html/src/utils.ts at line 138:
<comment>The new dataset getter returns a fresh object without wiring assignments back to attribs, so writes like `el.dataset.foo = "bar"` silently fail to create the corresponding `data-foo` attribute. Please make dataset behave like DOMStringMap and sync property writes to attributes.</comment>
<file context>
@@ -94,6 +110,48 @@ export class MockDoc {
+ }
+ },
+ },
+ dataset: {
+ get() {
+ const el = this as any;
</file context>
There was a problem hiding this 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 1 file
This change ensures that when writing arrays to cells or pushing to array
cells, all objects are given IDs so they can be stored as separate documents
with links. This applies to both explicitly written arrays and default values
from schemas.
Changes to cell.ts:
1. Modified the `set` method to call `addIDIfNeeded` on each element when
writing an array, ensuring all objects get IDs before being processed by
`diffAndUpdate`.
2. Enhanced the `push` method to:
- Process default values from schemas using `processDefaultValue` to ensure
they're properly materialized with IDs
- Apply `addIDIfNeeded` to all elements (both existing defaults and newly
pushed values) to ensure consistent ID assignment
3. Improved the `update` method's schema validation to:
- Use `resolveSchema` to properly handle schema references
- Check for undefined schemas (which allow objects)
- Consolidate the schema validation logic to determine if objects are
allowed
4. Added new `addIDIfNeeded` helper function that:
- Checks if a value is an object without an ID
- Generates a new ID from the frame's counter if needed
- Preserves existing IDs when present
New tests in cell.test.ts:
- "set operations with arrays" suite:
- Tests that objects written as arrays each get their own document ID
- Verifies that existing IDs are preserved during array writes
- Uses `asSchema` with `asCell: true` to read back as cells and verify
each element has a distinct document ID
- "push operations with default values" suite:
- Tests that default values from schemas are properly materialized with IDs
- Verifies all objects (defaults + pushed) get unique IDs
- Tests push operations both with and without schema defaults
These changes ensure that array operations consistently create separate
documents for each object, maintaining proper referential structure in the
storage layer.
…identally points at the old object
…eate-cells-on-array-writes' into ellyse/tutorials-calendar-basics
Move data URI inlining logic to occur before write redirect (alias) handling in normalizeAndDiff. This ensures the correct evaluation order when a data URI contains a redirect link. Previously, when newValue was a data URI containing a redirect, the code would: 1. Check currentValue for redirects (line 290) 2. Follow currentValue redirect if present 3. Process data URI inlining later (line 318) This caused the redirect within the data URI to be written to the wrong location - it would follow the currentValue redirect first, then inline the data URI, resulting in the redirect being written to the destination of the currentValue alias instead of to the intended target. The fix reorders the logic so data URIs are inlined immediately after unwrapping proxies and cells (line 212), before any redirect handling. This preserves the invariant that redirect handling at line 290 only applies when newValue is not itself an alias. The order is now: 1. Unwrap proxies/cells 2. Inline data URIs (exposing any contained redirects) 3. Handle redirects in newValue 4. Handle redirects in currentValue This ensures redirects contained in data URIs are properly recognized and handled as part of newValue, not incorrectly written through a currentValue redirect.
…to ellyse/tutorials-calendar-basics
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
1 issue found across 7 files
Prompt for AI agents (all 1 issues)
Understand the root cause of the following 1 issues and fix them.
<file name="packages/runner/src/cell.ts">
<violation number="1" location="packages/runner/src/cell.ts:456">
Calling `recursivelyAddIDIfNeeded` here converts `Cell` arguments into plain objects before `diffAndUpdate` runs, so flows like `cell.set(otherCell)` or `push(cell)` stop emitting links and instead serialize the cell’s internal fields, breaking link-based updates.</violation>
</file>
React with 👍 or 👎 to teach cubic. Mention @cubic-dev-ai to give feedback, ask questions, or re-run the review.
| if (!this.synced) this.sync(); | ||
|
|
||
| // Looks for arrays and makes sure each object gets its own doc. | ||
| newValue = recursivelyAddIDIfNeeded(newValue); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Calling recursivelyAddIDIfNeeded here converts Cell arguments into plain objects before diffAndUpdate runs, so flows like cell.set(otherCell) or push(cell) stop emitting links and instead serialize the cell’s internal fields, breaking link-based updates.
Prompt for AI agents
Address the following comment on packages/runner/src/cell.ts at line 456:
<comment>Calling `recursivelyAddIDIfNeeded` here converts `Cell` arguments into plain objects before `diffAndUpdate` runs, so flows like `cell.set(otherCell)` or `push(cell)` stop emitting links and instead serialize the cell’s internal fields, breaking link-based updates.</comment>
<file context>
@@ -448,6 +452,9 @@ export class RegularCell<T> implements Cell<T> {
if (!this.synced) this.sync();
+ // Looks for arrays and makes sure each object gets its own doc.
+ newValue = recursivelyAddIDIfNeeded(newValue);
+
// TODO(@ubik2) investigate whether i need to check classified as i walk down my own obj
</file context>
Summary by cubic
Adds a “Calendar Basics” tutorial that renders a list of dates with per-day todos using Common Tools state and UI primitives. This teaches how to model lists and maps, and conditionally show content.