Skip to content

Daily RC#476

Merged
softmarshmallow merged 10 commits intomainfrom
canary
Dec 20, 2025
Merged

Daily RC#476
softmarshmallow merged 10 commits intomainfrom
canary

Conversation

@softmarshmallow
Copy link
Copy Markdown
Member

@softmarshmallow softmarshmallow commented Dec 20, 2025

  • [rendering] feat: enhance hit testing with parent container clipping checks
  • [rendering] fix: text-layout-box-layout pipeline
  • [ux] update css cursors

Summary by CodeRabbit

  • New Features

    • Added lasso and bend-vertex cursors; client-side Grida Fonts search and "Popular" fonts in the font picker.
  • Improvements

    • Hit testing now respects parent-container clipping for more accurate picks.
    • Layout integrates text measurement for improved text sizing and bounds.
    • Cursor and editor point styling refined for clearer editing UX; minor UI separators added in icon browsers.
  • Tests

    • Added unit test ensuring culled (clipped) items are not hit-tested.
  • Chores

    • CI/test profile tuned, cursor README updated, and wasm package version bumped.

✏️ Tip: You can customize this high-level summary in your review settings.

@vercel
Copy link
Copy Markdown

vercel Bot commented Dec 20, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Review Updated (UTC)
docs Ready Ready Preview, Comment Dec 20, 2025 2:15pm
grida Ready Ready Preview, Comment Dec 20, 2025 2:15pm
5 Skipped Deployments
Project Deployment Review Updated (UTC)
code Ignored Ignored Dec 20, 2025 2:15pm
legacy Ignored Ignored Dec 20, 2025 2:15pm
backgrounds Skipped Skipped Dec 20, 2025 2:15pm
blog Skipped Skipped Dec 20, 2025 2:15pm
viewer Skipped Skipped Dec 20, 2025 2:15pm

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Dec 20, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Layout gains optional text-measure integration (TextMeasureProvider) threaded through compute and the layout tree; TextSpan geometry now uses layout results when present. Hit testing can optionally cull by scene-graph clipping. Example/test call sites and runtime code updated; cursor assets and small editor UI/cursor tweaks added.

Changes

Cohort / File(s) Summary
Layout engine & tree
crates/grida-canvas/src/layout/engine.rs, crates/grida-canvas/src/layout/tree.rs
LayoutEngine::compute now accepts Option<TextMeasureProvider<'_>>. Added LayoutNodeContext, TextMeasureContext, TextMeasureProvider; new_text_leaf and taffy_to_scene mapping; compute_layout accepts optional measure_provider and measures text when provided.
Examples & tests call sites
crates/grida-canvas/examples/golden_layout_flex.rs, crates/grida-canvas/examples/golden_layout_flex_alignment.rs, crates/grida-canvas/examples/golden_layout_flex_padding.rs, crates/grida-canvas/examples/golden_layout_padding.rs, crates/grida-canvas/tests/*
Calls to LayoutEngine::compute(...) updated to include the new third parameter (passing None in examples/tests). Minor test import adjustments and added clipping-related unit test.
Geometry / Bounds
crates/grida-canvas/src/cache/geometry.rs
TextSpan measurement/positioning and bounds now prefer layout-provided width/height/position/rotation when available; fall back to prior node-derived measurements otherwise. World/local bounds and transforms updated to use layout results when present.
Hit testing
crates/grida-canvas/src/hittest/hit_tester.rs
HitTester gains graph: Option<&SceneGraph> and with_graph constructor; when graph supplied, hit results are culled against ancestor container clip bounds via is_point_within_parent_clip_bounds.
Runtime integration
crates/grida-canvas/src/runtime/scene.rs, crates/grida-canvas/src/window/application.rs
Runtime now constructs and passes a TextMeasureProvider (scoped mutable ParagraphCache + fonts) into LayoutEngine::compute. get_hit_tester uses HitTester::with_graph when a scene graph is present.
Editor cursors & UI
editor/components/cursor/cursor-data.ts, editor/public/assets/css-cursors-grida/README.md, editor/grida-canvas-react/provider.tsx, editor/grida-canvas-react/viewport/ui/point.tsx, editor/grida-canvas-react/viewport/ui/surface-vector-editor.tsx
Added lasso_png and bend_vertex_png cursor exports and README entries; provider maps lasso/bend to new cursor css; removed some explicit cursor: "pointer" styles and adjusted hover border opacity; conditional cursor inheritance for bend vertex points.
Icons browser UI
editor/grida-canvas-hosted/library/icons-browser.tsx, editor/grida-canvas-hosted/library/icons-logos-browser.tsx
Inserted a horizontal rule (<hr />) between search input and controls in icons/logos browsers.
New font search hook
editor/hooks/use-grida-fonts-search.ts
Added client-side Grida Fonts search utility and useGridaFontsSearch hook with types, fetch logic, SWR integration, and result mapping.
Font picker
editor/scaffolds/sidecontrol/controls/font-family.tsx
Added "popular" fonts support, integrates useGridaFontsSearch, FontFamilyCommand accepts optional popularFonts?: string[].
CI & Cargo
.github/workflows/test-crates.yml, Cargo.toml, crates/grida-canvas-wasm/package.json
CI: set CARGO_BUILD_JOBS=2 for cargo test step. Cargo.toml: added [profile.test] debug = 1. Wasm package version bumped to 0.89.0-canary.1.
Small tests
crates/grida-canvas/tests/dashed_stroke.rs, crates/grida-canvas/tests/open_path_stroke_align.rs
Minor import adjustments (removed unused Path import); no behavioral changes.

Sequence Diagram(s)

sequenceDiagram
    participant Runtime as Runtime/Scene
    participant Cache as ParagraphCache
    participant Engine as LayoutEngine
    participant Tree as LayoutTree
    participant Taffy as Taffy
    participant Geom as GeometryCache

    Note over Runtime,Cache: Optional text-measure path during layout compute

    Runtime->>Cache: borrow mutably
    Runtime->>Runtime: build TextMeasureProvider(cache, fonts)
    Runtime->>Engine: compute(scene, viewport_size, Some(provider))

    Engine->>Tree: compute_layout(measure_provider)

    alt Text node + provider present
        Tree->>Tree: new_text_leaf(node_id, TextMeasureContext)
        Tree->>Cache: request measurement via provider
        Cache-->>Tree: measured size (w,h)
        Tree->>Taffy: set text constraints and create leaf
    else no provider
        Tree->>Taffy: create leaf without text context
    end

    Taffy->>Taffy: compute layout
    Taffy-->>Tree: layout results
    Tree-->>Engine: &LayoutResult
    Engine-->>Runtime: &LayoutResult

    Runtime->>Geom: compute_node_bounds(using layout result)
    Geom-->>Runtime: node local/world bounds
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

  • Pay extra attention to:
    • crates/grida-canvas/src/layout/engine.rs and crates/grida-canvas/src/layout/tree.rs (API, lifetimes, taffy generic changes).
    • crates/grida-canvas/src/hittest/hit_tester.rs (ancestor traversal/clipping correctness).
    • crates/grida-canvas/src/cache/geometry.rs (bounds fallback logic and transform selection).
    • crates/grida-canvas/src/runtime/scene.rs (mutable borrow scopes for ParagraphCache and provider lifetimes).
    • editor/hooks/use-grida-fonts-search.ts (network/error handling and SWR key stability).

Possibly related PRs

Suggested labels

daily, canvas/io, ux

Poem

🐰 I hop through lines, measuring text in tiny bounds,
I tuck clipped children safe where parent clips are found.
I nibble at cursors — lasso, bend — and twitch my nose with cheer,
Layouts fit like carrot snug; the rabbit’s work is clear! 🥕

Pre-merge checks and finishing touches

❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Title check ❓ Inconclusive The PR title 'Daily RC' is vague and generic, providing no meaningful information about the changeset's primary changes, which include hit testing enhancements, text layout pipeline fixes, cursor updates, and popular fonts features. Use a more descriptive title that summarizes the main changes, such as 'Enhance hit testing with clipping and text layout measurement' or include key feature areas affected by this release candidate.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch canary

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
crates/grida-canvas/src/cache/geometry.rs (1)

403-432: Critical: Return value must be world_bounds, not local_bounds.

Line 432 returns local_bounds (local coordinate space), but all other node types in this function return world-space bounds (absolute_bounding_box or union_world_bounds). This breaks the function's contract and will cause incorrect bounds calculations when parent nodes attempt to union child bounds.

Impact:

  • Parent containers will compute incorrect union bounds for TextSpan children
  • World-space hit testing and culling will fail for TextSpan nodes
  • Transforms from parent nodes won't be properly accounted for
🔎 Proposed fix
-                local_bounds
+                world_bounds

This matches the pattern used by all other node types (e.g., leaf nodes return entry.absolute_bounding_box on line 502).

crates/grida-canvas/src/hittest/hit_tester.rs (1)

248-268: Center-point approximation may cause false negatives for edge-case selections.

The center-point check for rectangle intersections can miss nodes where the selection rectangle overlaps clipped content but the center falls outside clip bounds. This could cause unexpected behavior during marquee/lasso selection near clip boundaries.

Consider either:

  1. Checking if any corner of the selection rectangle is within clip bounds, or
  2. Using rectangle-rectangle intersection with clip bounds

However, given the existing documentation and that this is an edge case, this may be acceptable for initial implementation.

🧹 Nitpick comments (4)
crates/grida-canvas/src/cache/geometry.rs (1)

393-401: Consider investigating the need for MIN_SIZE_DIRTY_HACK.

The constant explicitly marks this as a "dirty hack" to avoid zero-size bounds. Consider whether:

  1. The root cause of zero-size measurements or layout results should be addressed upstream
  2. A more explicit zero-size handling strategy would be clearer
  3. This minimum size of 1.0 has unintended visual or layout side effects
crates/grida-canvas/src/layout/engine.rs (1)

275-290: Consider using copied() instead of clone() for Option<usize>.

Option<usize> implements Copy, so cloning is unnecessary. Using .copied() or direct assignment would be more idiomatic.

🔎 Proposed fix
             Node::TextSpan(n) => {
                 let ctx = TextMeasureContext {
                     scene_node_id: *node_id,
                     text: n.text.clone(),
                     text_style: n.text_style.clone(),
                     text_align: n.text_align.clone(),
-                    max_lines: n.max_lines.clone(),
+                    max_lines: n.max_lines,
                     ellipsis: n.ellipsis.clone(),
                     width: n.width,
                     height: n.height,
                 };
                 self.tree.new_text_leaf(*node_id, style, ctx).ok()
             }
crates/grida-canvas/src/layout/tree.rs (2)

131-132: Remove unnecessary rebinding.

let provider = provider; is a no-op that doesn't affect behavior. This appears to be leftover from refactoring.

🔎 Proposed fix
         if let Some(provider) = measure_provider {
-            let provider = provider;
             self.taffy.compute_layout_with_measure(

159-162: Consider documenting the minimum 1.0 size constraint rationale.

Clamping dimensions to max(1.0) prevents zero-size nodes in layout, which is a reasonable guard against layout edge cases. However, this means empty text will occupy at least 1×1 pixels. Consider adding a comment explaining this design decision.

🔎 Proposed documentation
+                        // Ensure non-zero dimensions to prevent layout collapse.
+                        // Taffy may have issues with zero-sized nodes in certain layouts.
                         Size {
                             width: width.max(1.0),
                             height: height.max(1.0),
                         }
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a7d7201 and 843bd23.

⛔ Files ignored due to path filters (4)
  • editor/public/assets/css-cursors-grida/bend-vertex-mirror-all-64-x12y12-000000.png is excluded by !**/*.png
  • editor/public/assets/css-cursors-grida/bend-vertex-mirror-all-64-x12y12-000000.svg is excluded by !**/*.svg
  • editor/public/assets/css-cursors-grida/lasso-64-x12y12-000000.png is excluded by !**/*.png
  • editor/public/assets/css-cursors-grida/lasso-64-x12y12-000000.svg is excluded by !**/*.svg
📒 Files selected for processing (18)
  • crates/grida-canvas/examples/golden_layout_flex.rs (4 hunks)
  • crates/grida-canvas/examples/golden_layout_flex_alignment.rs (2 hunks)
  • crates/grida-canvas/examples/golden_layout_flex_padding.rs (1 hunks)
  • crates/grida-canvas/examples/golden_layout_padding.rs (1 hunks)
  • crates/grida-canvas/src/cache/geometry.rs (2 hunks)
  • crates/grida-canvas/src/hittest/hit_tester.rs (7 hunks)
  • crates/grida-canvas/src/layout/engine.rs (22 hunks)
  • crates/grida-canvas/src/layout/tree.rs (6 hunks)
  • crates/grida-canvas/src/runtime/scene.rs (2 hunks)
  • crates/grida-canvas/src/window/application.rs (1 hunks)
  • crates/grida-canvas/tests/dashed_stroke.rs (1 hunks)
  • crates/grida-canvas/tests/hit_test.rs (1 hunks)
  • crates/grida-canvas/tests/open_path_stroke_align.rs (1 hunks)
  • editor/components/cursor/cursor-data.ts (1 hunks)
  • editor/grida-canvas-react/provider.tsx (1 hunks)
  • editor/grida-canvas-react/viewport/ui/point.tsx (1 hunks)
  • editor/grida-canvas-react/viewport/ui/surface-vector-editor.tsx (2 hunks)
  • editor/public/assets/css-cursors-grida/README.md (1 hunks)
🧰 Additional context used
📓 Path-based instructions (7)
crates/**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

crates/**/*.rs: Use Rust 2024 edition for wasm builds and graphics core
Use Skia graphics backend for 2D graphics, bound with skia-safe
Rust crates in /crates directory are under rapid development and serve as the new rendering backend; ensure high quality implementations

Files:

  • crates/grida-canvas/src/runtime/scene.rs
  • crates/grida-canvas/tests/open_path_stroke_align.rs
  • crates/grida-canvas/examples/golden_layout_flex.rs
  • crates/grida-canvas/src/window/application.rs
  • crates/grida-canvas/src/cache/geometry.rs
  • crates/grida-canvas/src/layout/engine.rs
  • crates/grida-canvas/src/hittest/hit_tester.rs
  • crates/grida-canvas/examples/golden_layout_flex_padding.rs
  • crates/grida-canvas/examples/golden_layout_padding.rs
  • crates/grida-canvas/examples/golden_layout_flex_alignment.rs
  • crates/grida-canvas/src/layout/tree.rs
  • crates/grida-canvas/tests/dashed_stroke.rs
  • crates/grida-canvas/tests/hit_test.rs
crates/grida-canvas/**/*.rs

📄 CodeRabbit inference engine (crates/grida-canvas/AGENTS.md)

crates/grida-canvas/**/*.rs: Use NodeId (u64) for internal structs (NodeRecs, SceneGraph, caches) in the rendering engine for high-performance operations
Use UserNodeId (String) for public APIs that accept or return node IDs for stability and serialization
Handle NodeId to UserNodeId conversion via IdConverter during .grida file loading
Auto-generate IDs (ID=0) in NodeRepository for factory-created nodes
Maintain bidirectional mapping between NodeId and UserNodeId at the application layer for API boundary management
Use skia-safe crate for painting operations in the rendering engine
Use math2 crate for geometry and common math operations
Run cargo fmt to maintain code formatting standards
Run cargo clippy --no-deps --all-targets --all-features for linting to check style, performance, and correctness suggestions

Files:

  • crates/grida-canvas/src/runtime/scene.rs
  • crates/grida-canvas/tests/open_path_stroke_align.rs
  • crates/grida-canvas/examples/golden_layout_flex.rs
  • crates/grida-canvas/src/window/application.rs
  • crates/grida-canvas/src/cache/geometry.rs
  • crates/grida-canvas/src/layout/engine.rs
  • crates/grida-canvas/src/hittest/hit_tester.rs
  • crates/grida-canvas/examples/golden_layout_flex_padding.rs
  • crates/grida-canvas/examples/golden_layout_padding.rs
  • crates/grida-canvas/examples/golden_layout_flex_alignment.rs
  • crates/grida-canvas/src/layout/tree.rs
  • crates/grida-canvas/tests/dashed_stroke.rs
  • crates/grida-canvas/tests/hit_test.rs
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Use TypeScript 5 as the main language for most apps
Use Lucide or Radix Icons for icons

Files:

  • editor/grida-canvas-react/viewport/ui/surface-vector-editor.tsx
  • editor/grida-canvas-react/provider.tsx
  • editor/grida-canvas-react/viewport/ui/point.tsx
  • editor/components/cursor/cursor-data.ts
**/*.{jsx,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use React.js 19 for web applications

Files:

  • editor/grida-canvas-react/viewport/ui/surface-vector-editor.tsx
  • editor/grida-canvas-react/provider.tsx
  • editor/grida-canvas-react/viewport/ui/point.tsx
{editor/**/*.{ts,tsx},packages/grida-canvas-*/**/*.{ts,tsx}}

📄 CodeRabbit inference engine (AGENTS.md)

Use DOM (plain DOM as canvas) for website builder canvas, bound with React

Files:

  • editor/grida-canvas-react/viewport/ui/surface-vector-editor.tsx
  • editor/grida-canvas-react/provider.tsx
  • editor/grida-canvas-react/viewport/ui/point.tsx
  • editor/components/cursor/cursor-data.ts
editor/grida-*/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use /editor/grida-* directories to isolate domain-specific modules; promote well-defined modules to /packages

Files:

  • editor/grida-canvas-react/viewport/ui/surface-vector-editor.tsx
  • editor/grida-canvas-react/provider.tsx
  • editor/grida-canvas-react/viewport/ui/point.tsx
editor/components/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use /editor/components for generally reusable components

Files:

  • editor/components/cursor/cursor-data.ts
🧠 Learnings (23)
📚 Learning: 2025-12-20T08:11:16.201Z
Learnt from: CR
Repo: gridaco/grida PR: 0
File: crates/grida-canvas/AGENTS.md:0-0
Timestamp: 2025-12-20T08:11:16.201Z
Learning: Applies to crates/grida-canvas/**/*.rs : Use `NodeId` (u64) for internal structs (NodeRecs, SceneGraph, caches) in the rendering engine for high-performance operations

Applied to files:

  • crates/grida-canvas/src/runtime/scene.rs
  • crates/grida-canvas/examples/golden_layout_flex.rs
  • crates/grida-canvas/src/window/application.rs
  • crates/grida-canvas/src/cache/geometry.rs
  • crates/grida-canvas/src/layout/engine.rs
  • crates/grida-canvas/src/hittest/hit_tester.rs
  • crates/grida-canvas/examples/golden_layout_flex_padding.rs
  • crates/grida-canvas/examples/golden_layout_padding.rs
  • crates/grida-canvas/examples/golden_layout_flex_alignment.rs
  • crates/grida-canvas/tests/dashed_stroke.rs
  • crates/grida-canvas/tests/hit_test.rs
📚 Learning: 2025-12-20T08:11:16.201Z
Learnt from: CR
Repo: gridaco/grida PR: 0
File: crates/grida-canvas/AGENTS.md:0-0
Timestamp: 2025-12-20T08:11:16.201Z
Learning: Applies to crates/grida-canvas/**/*.rs : Use `skia-safe` crate for painting operations in the rendering engine

Applied to files:

  • crates/grida-canvas/src/runtime/scene.rs
  • crates/grida-canvas/tests/open_path_stroke_align.rs
  • crates/grida-canvas/examples/golden_layout_flex.rs
  • crates/grida-canvas/src/window/application.rs
  • crates/grida-canvas/src/cache/geometry.rs
  • crates/grida-canvas/src/hittest/hit_tester.rs
  • crates/grida-canvas/examples/golden_layout_flex_padding.rs
  • crates/grida-canvas/examples/golden_layout_padding.rs
  • crates/grida-canvas/examples/golden_layout_flex_alignment.rs
  • crates/grida-canvas/tests/dashed_stroke.rs
  • crates/grida-canvas/tests/hit_test.rs
📚 Learning: 2025-12-20T08:11:16.201Z
Learnt from: CR
Repo: gridaco/grida PR: 0
File: crates/grida-canvas/AGENTS.md:0-0
Timestamp: 2025-12-20T08:11:16.201Z
Learning: Applies to crates/grida-canvas/**/*.rs : Run `cargo fmt` to maintain code formatting standards

Applied to files:

  • crates/grida-canvas/src/runtime/scene.rs
  • crates/grida-canvas/tests/open_path_stroke_align.rs
  • crates/grida-canvas/examples/golden_layout_flex.rs
  • crates/grida-canvas/src/cache/geometry.rs
  • crates/grida-canvas/src/hittest/hit_tester.rs
  • crates/grida-canvas/examples/golden_layout_flex_padding.rs
  • crates/grida-canvas/examples/golden_layout_padding.rs
  • crates/grida-canvas/examples/golden_layout_flex_alignment.rs
  • crates/grida-canvas/tests/dashed_stroke.rs
  • crates/grida-canvas/tests/hit_test.rs
📚 Learning: 2025-12-01T00:22:06.800Z
Learnt from: CR
Repo: gridaco/grida PR: 0
File: crates/grida-canvas-fonts/AGENTS.md:0-0
Timestamp: 2025-12-01T00:22:06.800Z
Learning: Applies to crates/grida-canvas-fonts/**/ui_parser_test.rs : High-level UI API tests should use `parse_ui` and be organized in `ui_parser_test.rs`

Applied to files:

  • crates/grida-canvas/src/runtime/scene.rs
  • crates/grida-canvas/tests/open_path_stroke_align.rs
  • crates/grida-canvas/tests/dashed_stroke.rs
  • crates/grida-canvas/tests/hit_test.rs
📚 Learning: 2025-12-20T08:11:16.201Z
Learnt from: CR
Repo: gridaco/grida PR: 0
File: crates/grida-canvas/AGENTS.md:0-0
Timestamp: 2025-12-20T08:11:16.201Z
Learning: Applies to crates/grida-canvas/**/*.rs : Use `math2` crate for geometry and common math operations

Applied to files:

  • crates/grida-canvas/src/runtime/scene.rs
  • crates/grida-canvas/tests/open_path_stroke_align.rs
  • crates/grida-canvas/examples/golden_layout_flex.rs
  • crates/grida-canvas/src/window/application.rs
  • crates/grida-canvas/src/cache/geometry.rs
  • crates/grida-canvas/src/hittest/hit_tester.rs
  • crates/grida-canvas/examples/golden_layout_flex_padding.rs
  • crates/grida-canvas/examples/golden_layout_padding.rs
  • crates/grida-canvas/examples/golden_layout_flex_alignment.rs
  • crates/grida-canvas/tests/dashed_stroke.rs
  • crates/grida-canvas/tests/hit_test.rs
📚 Learning: 2025-12-14T23:30:42.112Z
Learnt from: CR
Repo: gridaco/grida PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-14T23:30:42.112Z
Learning: Applies to crates/**/*.rs : Rust crates in /crates directory are under rapid development and serve as the new rendering backend; ensure high quality implementations

Applied to files:

  • crates/grida-canvas/src/runtime/scene.rs
📚 Learning: 2025-12-01T00:22:06.800Z
Learnt from: CR
Repo: gridaco/grida PR: 0
File: crates/grida-canvas-fonts/AGENTS.md:0-0
Timestamp: 2025-12-01T00:22:06.800Z
Learning: Applies to crates/grida-canvas-fonts/**/scenario_*.rs : Scenario-specific comprehensive tests should be organized in files matching `scenario_*.rs`

Applied to files:

  • crates/grida-canvas/src/runtime/scene.rs
  • crates/grida-canvas/tests/hit_test.rs
📚 Learning: 2025-12-01T00:22:19.083Z
Learnt from: CR
Repo: gridaco/grida PR: 0
File: crates/grida-canvas-wasm/AGENTS.md:0-0
Timestamp: 2025-12-01T00:22:19.083Z
Learning: Applies to crates/grida-canvas-wasm/**/main.rs : Update `grida-canvas-wasm.d.ts` TypeScript definitions file when new APIs are introduced via `main.rs`

Applied to files:

  • crates/grida-canvas/tests/open_path_stroke_align.rs
  • crates/grida-canvas/src/cache/geometry.rs
  • editor/grida-canvas-react/provider.tsx
  • crates/grida-canvas/src/hittest/hit_tester.rs
  • crates/grida-canvas/tests/dashed_stroke.rs
  • editor/components/cursor/cursor-data.ts
📚 Learning: 2025-12-14T23:30:42.112Z
Learnt from: CR
Repo: gridaco/grida PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-14T23:30:42.112Z
Learning: Applies to crates/**/*.rs : Use Skia graphics backend for 2D graphics, bound with skia-safe

Applied to files:

  • crates/grida-canvas/tests/open_path_stroke_align.rs
  • crates/grida-canvas/src/cache/geometry.rs
📚 Learning: 2025-12-01T00:22:06.800Z
Learnt from: CR
Repo: gridaco/grida PR: 0
File: crates/grida-canvas-fonts/AGENTS.md:0-0
Timestamp: 2025-12-01T00:22:06.800Z
Learning: Applies to crates/grida-canvas-fonts/**/*.rs : Run all tests with: `cargo test`

Applied to files:

  • crates/grida-canvas/tests/open_path_stroke_align.rs
  • crates/grida-canvas/tests/dashed_stroke.rs
  • crates/grida-canvas/tests/hit_test.rs
📚 Learning: 2025-12-20T08:11:16.201Z
Learnt from: CR
Repo: gridaco/grida PR: 0
File: crates/grida-canvas/AGENTS.md:0-0
Timestamp: 2025-12-20T08:11:16.201Z
Learning: Applies to crates/grida-canvas/**/*.rs : Run `cargo clippy --no-deps --all-targets --all-features` for linting to check style, performance, and correctness suggestions

Applied to files:

  • crates/grida-canvas/tests/open_path_stroke_align.rs
  • crates/grida-canvas/examples/golden_layout_flex.rs
  • crates/grida-canvas/src/cache/geometry.rs
  • crates/grida-canvas/src/hittest/hit_tester.rs
  • crates/grida-canvas/examples/golden_layout_flex_padding.rs
  • crates/grida-canvas/examples/golden_layout_flex_alignment.rs
  • crates/grida-canvas/tests/dashed_stroke.rs
  • crates/grida-canvas/tests/hit_test.rs
📚 Learning: 2025-12-20T08:11:16.201Z
Learnt from: CR
Repo: gridaco/grida PR: 0
File: crates/grida-canvas/AGENTS.md:0-0
Timestamp: 2025-12-20T08:11:16.201Z
Learning: Applies to crates/grida-canvas/**/*.rs : Maintain bidirectional mapping between NodeId and UserNodeId at the application layer for API boundary management

Applied to files:

  • crates/grida-canvas/tests/open_path_stroke_align.rs
  • crates/grida-canvas/src/cache/geometry.rs
  • crates/grida-canvas/src/hittest/hit_tester.rs
📚 Learning: 2025-12-01T00:22:06.800Z
Learnt from: CR
Repo: gridaco/grida PR: 0
File: crates/grida-canvas-fonts/AGENTS.md:0-0
Timestamp: 2025-12-01T00:22:06.800Z
Learning: Applies to crates/grida-canvas-fonts/**/italic_level1.rs : Core font selection and italic detection tests should be organized in `italic_level1.rs`

Applied to files:

  • crates/grida-canvas/tests/open_path_stroke_align.rs
  • crates/grida-canvas/tests/dashed_stroke.rs
📚 Learning: 2025-12-01T00:22:56.899Z
Learnt from: CR
Repo: gridaco/grida PR: 0
File: editor/app/(tools)/tools/halftone/AGENTS.md:0-0
Timestamp: 2025-12-01T00:22:56.899Z
Learning: Applies to editor/app/(tools)/tools/halftone/app/(tools)/tools/halftone/_page.tsx : For SVG export, convert circles to <circle> elements, rectangles to <rect> elements, and polygons to <polygon> elements with calculated points

Applied to files:

  • editor/grida-canvas-react/viewport/ui/surface-vector-editor.tsx
  • editor/grida-canvas-react/viewport/ui/point.tsx
📚 Learning: 2025-12-01T00:22:56.899Z
Learnt from: CR
Repo: gridaco/grida PR: 0
File: editor/app/(tools)/tools/halftone/AGENTS.md:0-0
Timestamp: 2025-12-01T00:22:56.899Z
Learning: Applies to editor/app/(tools)/tools/halftone/app/(tools)/tools/halftone/_page.tsx : When adding new shape types, update the Shape type union, add cases in drawShape() function, add cases in shapeToSVG() function, and add SelectItem in UI

Applied to files:

  • editor/grida-canvas-react/viewport/ui/surface-vector-editor.tsx
  • editor/grida-canvas-react/provider.tsx
  • editor/grida-canvas-react/viewport/ui/point.tsx
📚 Learning: 2025-12-01T00:22:56.899Z
Learnt from: CR
Repo: gridaco/grida PR: 0
File: editor/app/(tools)/tools/halftone/AGENTS.md:0-0
Timestamp: 2025-12-01T00:22:56.899Z
Learning: Applies to editor/app/(tools)/tools/halftone/app/(tools)/tools/halftone/_page.tsx : Use Canvas 2D API with path commands for rendering geometric shapes (circle, square, triangle, etc.)

Applied to files:

  • editor/grida-canvas-react/viewport/ui/surface-vector-editor.tsx
  • editor/grida-canvas-react/provider.tsx
  • editor/grida-canvas-react/viewport/ui/point.tsx
📚 Learning: 2025-12-14T23:30:42.112Z
Learnt from: CR
Repo: gridaco/grida PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-14T23:30:42.112Z
Learning: Applies to {editor/**/*.{ts,tsx},packages/grida-canvas-*/**/*.{ts,tsx}} : Use DOM (plain DOM as canvas) for website builder canvas, bound with React

Applied to files:

  • editor/grida-canvas-react/viewport/ui/surface-vector-editor.tsx
  • editor/grida-canvas-react/provider.tsx
  • editor/grida-canvas-react/viewport/ui/point.tsx
📚 Learning: 2025-12-20T08:11:16.201Z
Learnt from: CR
Repo: gridaco/grida PR: 0
File: crates/grida-canvas/AGENTS.md:0-0
Timestamp: 2025-12-20T08:11:16.201Z
Learning: Applies to crates/grida-canvas/**/*.rs : Use `UserNodeId` (String) for public APIs that accept or return node IDs for stability and serialization

Applied to files:

  • crates/grida-canvas/src/cache/geometry.rs
  • crates/grida-canvas/src/hittest/hit_tester.rs
📚 Learning: 2025-12-20T08:11:16.201Z
Learnt from: CR
Repo: gridaco/grida PR: 0
File: crates/grida-canvas/AGENTS.md:0-0
Timestamp: 2025-12-20T08:11:16.201Z
Learning: Applies to crates/grida-canvas/**/*.rs : Handle NodeId to UserNodeId conversion via `IdConverter` during .grida file loading

Applied to files:

  • crates/grida-canvas/src/cache/geometry.rs
📚 Learning: 2025-12-20T08:11:16.201Z
Learnt from: CR
Repo: gridaco/grida PR: 0
File: crates/grida-canvas/AGENTS.md:0-0
Timestamp: 2025-12-20T08:11:16.201Z
Learning: Applies to crates/grida-canvas/**/*.rs : Auto-generate IDs (ID=0) in `NodeRepository` for factory-created nodes

Applied to files:

  • crates/grida-canvas/src/hittest/hit_tester.rs
  • crates/grida-canvas/examples/golden_layout_flex_padding.rs
  • crates/grida-canvas/tests/dashed_stroke.rs
📚 Learning: 2025-12-01T00:22:56.899Z
Learnt from: CR
Repo: gridaco/grida PR: 0
File: editor/app/(tools)/tools/halftone/AGENTS.md:0-0
Timestamp: 2025-12-01T00:22:56.899Z
Learning: Applies to editor/app/(tools)/tools/halftone/app/(tools)/tools/halftone/_page.tsx : Use React hooks for state management (imageSrc, shape, grid, maxRadius, gamma, jitter, opacity, color, customShapeImage, imageDataRef, sizeRef)

Applied to files:

  • editor/grida-canvas-react/viewport/ui/point.tsx
📚 Learning: 2025-12-01T00:22:06.800Z
Learnt from: CR
Repo: gridaco/grida PR: 0
File: crates/grida-canvas-fonts/AGENTS.md:0-0
Timestamp: 2025-12-01T00:22:06.800Z
Learning: Applies to crates/grida-canvas-fonts/**/scenario_level2_*.rs : Level 2+ placeholder and limitation tests should be organized in files matching `scenario_level2_*.rs`

Applied to files:

  • crates/grida-canvas/tests/hit_test.rs
📚 Learning: 2025-12-01T00:22:06.800Z
Learnt from: CR
Repo: gridaco/grida PR: 0
File: crates/grida-canvas-fonts/AGENTS.md:0-0
Timestamp: 2025-12-01T00:22:06.800Z
Learning: Applies to crates/grida-canvas-fonts/**/serde_test.rs : Run tests with serde feature using: `cargo test --features serde`

Applied to files:

  • crates/grida-canvas/tests/hit_test.rs
🧬 Code graph analysis (2)
crates/grida-canvas/src/window/application.rs (1)
crates/grida-canvas/src/hittest/hit_tester.rs (2)
  • with_graph (65-70)
  • new (58-60)
crates/grida-canvas/src/layout/tree.rs (1)
crates/grida-canvas/src/cache/paragraph.rs (1)
  • paragraph (361-426)
🪛 LanguageTool
editor/public/assets/css-cursors-grida/README.md

[style] ~20-~20: Using many exclamation marks might seem excessive (in this case: 11 exclamation marks for a text that’s 3560 characters long)
Context: ... | 64 | x28 y28 | 000000 | default | default-64-x28y28-000000.svg | | lasso | 64 | x12 y12 | 000000 | lasso | lasso-64-x12y12-000000.svg | | bend-vertex-mirror-all | 64 | x12 y12 | 000000 | bend-vertex-mirror-all | bend-vertex-mirror-all-64-x12y12-000000.svg | | ew-resize | 64 | x32 y32 | 000000 | ew-resize | ew-resize-64-x32y32-000000.svg | | ew-resize-scale | 64 | x32 y32 | 000000 | ew-resize-scale | ew-resize-scale-64-x32y32-000000.svg | | ns-resize | 64 | x32 y32 | 000000 | ns-resize | ns-resize-64-x32y32-000000.svg | | ns-resize-scale | 64 | x32 y32 | 000000 | ns-resize-scale | ns-resize-scale-64-x32y32-000000.svg | | nesw-resize | 64 | x32 y32 | 000000 | nesw-resize | nesw-resize-64-x32y32-000000.svg | | nesw-resize-scale | 64 | x32 y32 | 000000 | nesw-resize-scale | nesw-resize-scale-64-x32y32-000000.svg | | nwse-resize | 64 | x32 y32 | 000000 | nwse-resize | nwse-resize-64-x32y32-000000.svg | | nwse-resize-scale | 64 | x32 y32 | 000000 | ![nwse-resize-scale](./nwse-resize-scale-...

(EN_EXCESSIVE_EXCLAMATION)

🔇 Additional comments (26)
crates/grida-canvas/tests/open_path_stroke_align.rs (1)

3-3: LGTM! Good cleanup of unused import.

Removing the unused Path import is correct. The Path type is implicitly inferred from builder.detach() and only used via borrows, so the explicit import is unnecessary.

crates/grida-canvas/src/cache/geometry.rs (1)

378-391: LGTM: Layout-aware text measurement integration.

The logic correctly prioritizes layout-computed width for text measurement, ensuring consistency between the layout engine and paragraph cache. The fallback to node width maintains backward compatibility when no layout result is available.

editor/grida-canvas-react/viewport/ui/point.tsx (1)

59-59: LGTM! Subtle hover state refinement.

The reduced border opacity (from 50% to 25%) provides a more subtle hover indication, which aligns with the removal of explicit cursor styles mentioned in the summary.

editor/grida-canvas-react/viewport/ui/surface-vector-editor.tsx (2)

479-479: LGTM! Cursor inheritance from parent context.

Removing the explicit cursor: "pointer" allows the Point to inherit the appropriate cursor from the parent context, which now provides tool-specific cursors (e.g., bend_vertex_png) via the provider.


647-649: LGTM! Conditional cursor for bend tool.

The conditional cursor ensures that when the bend tool is active, vertex points inherit the custom bend cursor from the parent context. Otherwise, they fall back to default cursor behavior.

editor/public/assets/css-cursors-grida/README.md (1)

18-30: LGTM! Cursor documentation updated with new assets.

The table has been reformatted with improved inline image display and now includes the new lasso and bend-vertex-mirror-all cursor entries. The hotspot coordinates (x12 y12) are properly documented and align with the cursor-data.ts implementation.

Note: The static analysis warning about "excessive exclamation marks" is a false positive—these are markdown image syntax (![...]), not punctuation.

editor/components/cursor/cursor-data.ts (1)

45-56: LGTM! New cursor exports follow established patterns.

The lasso_png and bend_vertex_png exports are correctly structured following the same pattern as default_png. The hotspot coordinates (12, 12) are appropriately divided by 2 in pngsetcss to produce the correct CSS hotspot values (6, 6).

editor/grida-canvas-react/provider.tsx (1)

482-484: Both cursor PNG assets are present in the repository and correctly referenced in the code.

  • /editor/public/assets/css-cursors-grida/lasso-64-x12y12-000000.png exists
  • /editor/public/assets/css-cursors-grida/bend-vertex-mirror-all-64-x12y12-000000.png exists

The cursor mappings for the lasso and bend tools are properly configured.

crates/grida-canvas/tests/dashed_stroke.rs (1)

3-3: LGTM! Clean import optimization.

Removing the unused Path import while keeping PathBuilder is appropriate.

crates/grida-canvas/examples/golden_layout_flex.rs (1)

142-142: LGTM! Correct API adaptation.

All four compute calls properly updated to pass None for the new text measurement provider parameter. This is appropriate for layout examples that don't require text measurement.

Also applies to: 202-202, 261-261, 329-329

crates/grida-canvas/examples/golden_layout_flex_padding.rs (1)

60-60: LGTM! Consistent API adaptation.

The compute call correctly includes the new text measurement provider parameter as None.

crates/grida-canvas/examples/golden_layout_padding.rs (1)

118-118: LGTM! Correct API adaptation.

The compute call properly includes the new text measurement provider parameter as None.

crates/grida-canvas/src/window/application.rs (1)

708-713: LGTM! Proper integration of graph-based clipping.

The conditional construction correctly enables clipping checks when a scene graph is available. The pattern gracefully falls back to the basic HitTester::new when no scene is present, ensuring the API remains resilient.

crates/grida-canvas/examples/golden_layout_flex_alignment.rs (1)

136-136: LGTM! Consistent API adaptation.

Both compute calls correctly updated to include the new text measurement provider parameter as None.

Also applies to: 203-203

crates/grida-canvas/src/runtime/scene.rs (1)

389-399: LGTM! Clean text measurement integration.

Both integration points properly use scoped blocks to manage the mutable borrow of paragraph_cache. The TextMeasureProvider construction correctly wires the paragraph cache and font repository into the layout computation. This pattern ensures borrow conflicts are avoided while enabling text measurement during layout.

Also applies to: 458-468

crates/grida-canvas/tests/hit_test.rs (1)

130-207: LGTM! Comprehensive clipping test coverage.

The new test thoroughly validates parent container clipping behavior:

  • Properly configures the test scenario with clip=true and an overflowing child
  • Uses HitTester::with_graph to enable graph-based clipping checks
  • Tests multiple boundary conditions: visible region, culled region, outside bounds, and edge cases
  • Correctly uses assert_ne! to verify that points in culled regions do not hit the clipped node

This test provides strong validation for the new clipping feature introduced in this PR.

crates/grida-canvas/src/layout/engine.rs (2)

76-108: LGTM!

The text measurement integration into the compute method is well-designed. The optional TextMeasureProvider parameter maintains backward compatibility while enabling text measurement when available. The mut binding correctly allows reusing the provider across multiple root subtree computations via as_mut().


399-406: LGTM!

All test invocations correctly pass None for the text measurement provider, maintaining backward compatibility and ensuring existing layout tests continue to work without requiring font/paragraph infrastructure.

crates/grida-canvas/src/hittest/hit_tester.rs (4)

8-31: LGTM - Good documentation of performance trade-offs.

The TODO comment clearly documents the current O(depth × candidates) complexity and proposes a concrete optimization path (pre-computing effective clip bounds in GeometryCache). This is valuable for future maintainability.


77-113: LGTM!

The parent clipping traversal correctly walks up the hierarchy checking only Container nodes with clip = true. The early-return pattern efficiently short-circuits when a point fails any clip check. Based on learnings, using NodeId (u64) for internal operations aligns with coding guidelines.


116-131: LGTM!

The clipping check is correctly placed after the bounds containment check, ensuring the more expensive parent traversal only occurs for nodes that pass initial spatial filtering. This maintains good performance characteristics.


228-242: contains method lacks clipping check - verify if intentional.

Unlike other hit testing methods (hit_first, hits, etc.), the contains method does not apply parent clipping checks. This means calling contains(id, point) will return true even if the node is clipped by a parent container.

If this is intentional (e.g., for use cases where you want to know if a specific node geometrically contains a point regardless of visibility), consider adding a doc comment clarifying this behavior difference.

crates/grida-canvas/src/layout/tree.rs (4)

8-31: LGTM - Well-structured types for text measurement.

The TextMeasureContext captures all necessary text properties for measurement, and TextMeasureProvider properly encapsulates the paragraph cache and font repository dependencies. The pub(crate) visibility is appropriate for internal module use.


78-98: LGTM!

The new_text_leaf method correctly creates a Taffy leaf with context and maintains bidirectional mapping consistency. The mapping cleanup logic is appropriately duplicated to ensure each method is self-contained.


163-168: LGTM!

The fallback for non-text nodes correctly returns Taffy's known dimensions or zero. This handles edge cases where a node enters the measure callback without text context.


289-297: LGTM!

Test correctly updated to pass None for the measure provider, maintaining existing test behavior without requiring text measurement infrastructure.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +90 to +95
Node::Container(n) => {
if n.clip {
// Check if the point is within this container's bounds
if let Some(bounds) = self.cache.geometry.get_world_bounds(&id) {
if !rect::contains_point(&bounds, point) {
// Point is outside this clipping container's bounds
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Clip checks use unioned bounds so overflow still hits

is_point_within_parent_clip_bounds uses get_world_bounds for container culling, but containers’ world bounds are stored as the union of their own box plus all children (see the container case in geometry.rs where union_world_bounds accumulates child bounds). That means a clipped container that has an overflowing child expands its bounds to the child’s extent, so rect::contains_point returns true even for points outside the container’s clipping area and the child still registers in hit tests. For example, a clip=true 100×100 container with a 100×100 child at (50,50) will still hit at (120,120) even though that region should be culled. The clip check needs to use the container’s own render/layout box instead of the union of descendants.

Useful? React with 👍 / 👎.

@vercel vercel Bot temporarily deployed to Preview – blog December 20, 2025 13:58 Inactive
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (2)
editor/scaffolds/sidecontrol/controls/font-family.tsx (1)

207-222: Consider displaying the popular fonts count for UI consistency.

Other category options display item counts (e.g., "All fonts (1234)"), but "Popular" doesn't. Consider adding the count for consistency:

🔎 Suggested change
-            <NativeSelectOption value="popular">Popular</NativeSelectOption>
+            <NativeSelectOption value="popular">
+              Popular ({(popularFonts || []).filter((name) => availableFontSet.has(name)).length})
+            </NativeSelectOption>

Note: This would require passing popularFonts and availableFontSet to the JSX scope, or computing the count separately.

editor/hooks/use-grida-fonts-search.ts (1)

128-139: Potential SWR cache key instability.

The useMemo returns ["grida-fonts-search", options], but options is the original object reference passed to the hook, not a new stable object. SWR uses referential equality for key comparison, so if the caller doesn't memoize the options object, it will trigger refetches.

Consider creating a stable key from the individual properties:

🔎 Suggested fix
   // Create a stable key for SWR caching
   const key = useMemo(
-    () => ["grida-fonts-search", options],
+    () => [
+      "grida-fonts-search",
+      options.q,
+      options.category,
+      options.property,
+      options.sort,
+      options.page,
+      options.limit,
+    ],
     [
       options.q,
       options.category,
       options.property,
       options.sort,
       options.page,
       options.limit,
     ]
   );

Then update the fetcher to reconstruct options from the key array.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8abbcd6 and f99a57a.

📒 Files selected for processing (4)
  • editor/grida-canvas-hosted/library/icons-browser.tsx (1 hunks)
  • editor/grida-canvas-hosted/library/icons-logos-browser.tsx (1 hunks)
  • editor/hooks/use-grida-fonts-search.ts (1 hunks)
  • editor/scaffolds/sidecontrol/controls/font-family.tsx (8 hunks)
🧰 Additional context used
📓 Path-based instructions (5)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Use TypeScript 5 as the main language for most apps
Use Lucide or Radix Icons for icons

Files:

  • editor/grida-canvas-hosted/library/icons-logos-browser.tsx
  • editor/hooks/use-grida-fonts-search.ts
  • editor/grida-canvas-hosted/library/icons-browser.tsx
  • editor/scaffolds/sidecontrol/controls/font-family.tsx
**/*.{jsx,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use React.js 19 for web applications

Files:

  • editor/grida-canvas-hosted/library/icons-logos-browser.tsx
  • editor/grida-canvas-hosted/library/icons-browser.tsx
  • editor/scaffolds/sidecontrol/controls/font-family.tsx
{editor/**/*.{ts,tsx},packages/grida-canvas-*/**/*.{ts,tsx}}

📄 CodeRabbit inference engine (AGENTS.md)

Use DOM (plain DOM as canvas) for website builder canvas, bound with React

Files:

  • editor/grida-canvas-hosted/library/icons-logos-browser.tsx
  • editor/hooks/use-grida-fonts-search.ts
  • editor/grida-canvas-hosted/library/icons-browser.tsx
  • editor/scaffolds/sidecontrol/controls/font-family.tsx
editor/grida-*/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use /editor/grida-* directories to isolate domain-specific modules; promote well-defined modules to /packages

Files:

  • editor/grida-canvas-hosted/library/icons-logos-browser.tsx
  • editor/grida-canvas-hosted/library/icons-browser.tsx
editor/scaffolds/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Use /editor/scaffolds for feature-specific larger components, pages, and editors

Files:

  • editor/scaffolds/sidecontrol/controls/font-family.tsx
🧠 Learnings (8)
📚 Learning: 2025-12-14T23:30:42.112Z
Learnt from: CR
Repo: gridaco/grida PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-14T23:30:42.112Z
Learning: Applies to editor/grida-*/**/*.{ts,tsx} : Use /editor/grida-* directories to isolate domain-specific modules; promote well-defined modules to <root>/packages

Applied to files:

  • editor/hooks/use-grida-fonts-search.ts
  • editor/scaffolds/sidecontrol/controls/font-family.tsx
📚 Learning: 2025-12-01T00:22:19.083Z
Learnt from: CR
Repo: gridaco/grida PR: 0
File: crates/grida-canvas-wasm/AGENTS.md:0-0
Timestamp: 2025-12-01T00:22:19.083Z
Learning: Applies to crates/grida-canvas-wasm/**/main.rs : Update `grida-canvas-wasm.d.ts` TypeScript definitions file when new APIs are introduced via `main.rs`

Applied to files:

  • editor/hooks/use-grida-fonts-search.ts
📚 Learning: 2025-12-14T23:30:42.112Z
Learnt from: CR
Repo: gridaco/grida PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-14T23:30:42.112Z
Learning: Applies to packages/grida-canvas-*/**/*.{ts,tsx,js,jsx} : Packages under /packages/grida-canvas-* power the canvas; some are published to npm, refer to individual package README

Applied to files:

  • editor/hooks/use-grida-fonts-search.ts
  • editor/scaffolds/sidecontrol/controls/font-family.tsx
📚 Learning: 2025-12-01T00:22:56.899Z
Learnt from: CR
Repo: gridaco/grida PR: 0
File: editor/app/(tools)/tools/halftone/AGENTS.md:0-0
Timestamp: 2025-12-01T00:22:56.899Z
Learning: Applies to editor/app/(tools)/tools/halftone/app/(tools)/tools/halftone/_page.tsx : When adding new shape types, update the Shape type union, add cases in drawShape() function, add cases in shapeToSVG() function, and add SelectItem in UI

Applied to files:

  • editor/hooks/use-grida-fonts-search.ts
📚 Learning: 2025-12-01T00:22:56.899Z
Learnt from: CR
Repo: gridaco/grida PR: 0
File: editor/app/(tools)/tools/halftone/AGENTS.md:0-0
Timestamp: 2025-12-01T00:22:56.899Z
Learning: Applies to editor/app/(tools)/tools/halftone/app/(tools)/tools/halftone/_page.tsx : Use React hooks for state management (imageSrc, shape, grid, maxRadius, gamma, jitter, opacity, color, customShapeImage, imageDataRef, sizeRef)

Applied to files:

  • editor/scaffolds/sidecontrol/controls/font-family.tsx
📚 Learning: 2025-12-14T23:30:42.112Z
Learnt from: CR
Repo: gridaco/grida PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-14T23:30:42.112Z
Learning: Applies to {editor/**/*.{ts,tsx},packages/grida-canvas-*/**/*.{ts,tsx}} : Use DOM (plain DOM as canvas) for website builder canvas, bound with React

Applied to files:

  • editor/scaffolds/sidecontrol/controls/font-family.tsx
📚 Learning: 2025-12-14T23:30:42.112Z
Learnt from: CR
Repo: gridaco/grida PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-14T23:30:42.112Z
Learning: Applies to **/components/ui/**/*.{ts,tsx} : Use Shadcn UI for UI component library

Applied to files:

  • editor/scaffolds/sidecontrol/controls/font-family.tsx
📚 Learning: 2025-12-14T23:30:42.112Z
Learnt from: CR
Repo: gridaco/grida PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-14T23:30:42.112Z
Learning: Applies to editor/components/ui/**/*.{ts,tsx} : Use /editor/components/ui for shadcn UI components

Applied to files:

  • editor/scaffolds/sidecontrol/controls/font-family.tsx
🧬 Code graph analysis (1)
editor/scaffolds/sidecontrol/controls/font-family.tsx (3)
editor/grida-canvas/query/index.ts (1)
  • fonts (606-614)
editor/hooks/use-grida-fonts-search.ts (1)
  • useGridaFontsSearch (125-191)
editor/components/ui-editor/popover.tsx (1)
  • PopoverContent (62-62)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: cargo test
  • GitHub Check: build
  • GitHub Check: test
🔇 Additional comments (13)
editor/grida-canvas-hosted/library/icons-logos-browser.tsx (1)

255-255: LGTM: Visual separator added.

The horizontal rule provides clear visual separation between the search input and filter controls, improving the header's visual hierarchy.

editor/grida-canvas-hosted/library/icons-browser.tsx (1)

416-416: LGTM: Visual separator added.

The horizontal rule provides clear visual separation between the search input and vendor/variant controls. This change mirrors the separator added in the logos browser, maintaining consistency across the icon library UI.

editor/scaffolds/sidecontrol/controls/font-family.tsx (7)

24-24: LGTM!

The new import for the custom font search hook aligns with the feature requirements.


91-100: LGTM!

The optional popularFonts prop is correctly typed and integrated into the component signature.


121-123: LGTM!

The category type union is correctly expanded to include the new "popular" option.


125-162: LGTM!

The filtering logic is well-structured:

  • availableFontSet provides O(1) lookup for popular font validation
  • The category-based filtering with subsequent query filtering is efficient
  • Dependencies are correctly specified for both useMemo calls

261-261: LGTM!

Adding the title attribute improves accessibility by providing a tooltip with the font name.


294-301: LGTM!

The popular fonts integration is well implemented. SWR's caching ensures the API call is deduplicated across renders, and the useMemo efficiently extracts family names only when the data changes.


323-328: LGTM!

The collisionPadding={8} prop improves layout behavior by preventing the popover from being clipped at viewport edges.

editor/hooks/use-grida-fonts-search.ts (4)

1-4: LGTM!

The "use client" directive is correctly placed for a hook that uses SWR, and imports are minimal and appropriate.


82-113: LGTM!

The searchGridaFonts function is well-implemented with sensible defaults and proper error handling.


141-190: LGTM!

The SWR integration and result transformation are well-implemented with proper error normalization and sensible default values during loading states.


23-31: Align GridaFontsSearchFilters.category type with search API capabilities.

Google Fonts supports five categories: serif, sans-serif, display, handwriting, and monospace. However, GridaFont.category includes all five while GridaFontsSearchFilters.category and UseGridaFontsSearchOptions.category only support four (excluding "handwriting"). The code references the Grida Fonts search API, which appears to intentionally limit filtering to the four supported categories. Either document this limitation with a comment explaining why "handwriting" is excluded from the search filter, or align the types by adding "handwriting" if the backend now supports it.

@softmarshmallow softmarshmallow merged commit 0807013 into main Dec 20, 2025
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant