-
Notifications
You must be signed in to change notification settings - Fork 119
Daily RC #482
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
Daily RC #482
Conversation
|
Caution Review failedThe pull request is closed. WalkthroughRefactors insertion/paste to use explicit targets and surface APIs, replaces selection mutations with decision-based selection UX, moves paint-resolution into editor namespace, extends schema for corner radii and stroke controls, and adds related UI, utils, and tests. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant Surface as EditorSurface
participant Store as EditorDocumentStore
participant Reducer as document.reducer
participant State as editor.state
User->>Surface: surface.insert(payload)
Surface->>Surface: resolveInsertTargetParent(selection)
Surface->>Store: insert(payload, target)
activate Store
Store->>Reducer: dispatch insert action
activate Reducer
Reducer->>Reducer: resolve parent from target, compute position
Reducer->>State: add nodes, update selection
deactivate Reducer
Store-->>Surface: return newIds
deactivate Store
Surface-->>User: [newNodeIds]
sequenceDiagram
participant User
participant Event as EventTargetReducer
participant Decide as SelectionDecision
participant State as editor.state
User->>Event: onPointerDown(event)
Event->>Decide: decidePointerDownSelection(context)
Decide-->>Event: SelectionOperation (immediate | deferred | none)
alt immediate
Event->>State: apply selection, clear deferred
else deferred
Event->>State: store __deferred_selection
else none
Event->>State: no selection change
end
User->>Event: onClick(event)
Event->>Decide: decideClickSelection(context)
Decide-->>Event: SelectionOperation
alt immediate
Event->>State: apply selection, clear deferred
else none
Event->>State: clear deferred
end
sequenceDiagram
participant User
participant DataTransfer as use-data-transfer
participant Surface as EditorSurface
participant Store as EditorDocumentStore
User->>DataTransfer: paste(items)
DataTransfer->>DataTransfer: tryInsertFromGridaClipboard / decode
DataTransfer->>Surface: surface.a11yPaste()
Surface->>Surface: resolvePasteTargetParents(selection, copiedIds)
Surface->>Store: paste(targets)
activate Store
Store->>Store: insert per target, return insertedIds
Store-->>Surface: insertedIds
deactivate Store
Surface->>Surface: updateSelection(insertedIds)
Surface-->>DataTransfer: paste result
Estimated code review effort🎯 4 (Complex) | ⏱️ ~75 minutes Possibly related PRs
Suggested labels
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
📜 Recent review detailsConfiguration used: Organization UI Review profile: CHILL Plan: Pro 📒 Files selected for processing (2)
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. Comment |
…nd deferred selection changes based on user intent
…ointer down, click, and drag actions in the selection module
…erience improvements
…ution and improved user experience
…roperties for enhanced styling options
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
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.
Actionable comments posted: 6
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
editor/scaffolds/sidecontrol/sidecontrol-node-selection.tsx (1)
729-805: Duplicate Layout section found.This entire block (lines 729-805) is a duplicate of the Layout section at lines 412-528. Both sections render when
config.layout !== "off", resulting in two Layout sections appearing in the UI. The second section is also missing the newly added Gap and Padding controls.This appears to be leftover code that should be removed.
🔎 Suggested fix: Remove duplicate section
- <SidebarSection - hidden={config.layout === "off"} - className="border-b pb-4" - > - <SidebarSectionHeaderItem> - <SidebarSectionHeaderLabel>Layout</SidebarSectionHeaderLabel> - </SidebarSectionHeaderItem> - <SidebarMenuSectionContent className="space-y-2"> - <PropertyLine hidden={config.size === "off"}> - <PropertyLineLabel>Width</PropertyLineLabel> - <LengthPercentageControl - value={width?.value} - onValueCommit={change.width} - /> - </PropertyLine> - <PropertyLine hidden={config.size === "off"}> - <PropertyLineLabel>Height</PropertyLineLabel> - <LengthPercentageControl - value={height?.value} - onValueCommit={change.height} - /> - </PropertyLine> - {types.has("container") && ( - <PropertyLine> - <PropertyLineLabel>Flow</PropertyLineLabel> - <LayoutControl - value={ - layout?.value === grida.mixed || - direction?.value === grida.mixed || - layout?.value === undefined || - (layout?.value === "flex" && direction?.value === undefined) - ? undefined - : { - layoutMode: layout?.value ?? "flow", - direction: - layout?.value === "flex" - ? direction?.value - : undefined, - } - } - onValueChange={(value) => { - change.layout(value.layoutMode); - if (value.direction) { - change.direction(value.direction); - } - }} - /> - </PropertyLine> - )} - <PropertyLine hidden={!has_flex_container}> - <PropertyLineLabel>Alignment</PropertyLineLabel> - <FlexAlignControl - className="w-full" - direction={ - direction?.value === grida.mixed - ? "horizontal" - : (direction?.value ?? "horizontal") - } - value={ - main_axis_alignment?.value === grida.mixed || - cross_axis_alignment?.value === grida.mixed || - main_axis_alignment?.value === undefined || - cross_axis_alignment?.value === undefined - ? undefined - : { - mainAxisAlignment: main_axis_alignment.value, - crossAxisAlignment: cross_axis_alignment.value, - } - } - onValueChange={(value) => { - change.main_axis_alignment(value.mainAxisAlignment); - change.cross_axis_alignment(value.crossAxisAlignment); - }} - /> - </PropertyLine> - </SidebarMenuSectionContent> - </SidebarSection>
🧹 Nitpick comments (14)
crates/grida-canvas/src/painter/geometry.rs (1)
324-328: Clarify the catch-all case scope with explicit node type comment.The TODO comment is helpful for documenting a known limitation, but the catch-all
_ => return Nonesilently handles other non-shape node types (TextSpan, InitialContainer) beyond Group. Consider making this explicit to avoid confusion about which node types fail in boolean operations.🔎 Suggested improvement for clarity
Node::Error(n) => Node::Error(n.clone()), ~ // TODO: Support Group nodes as children of boolean operations. ~ // Currently, boolean operations like `boolop(group(a, b), c)` are not supported. ~ // When a Group is encountered, this function returns None, causing the boolean ~ // operation to fail rendering. - _ => return None, // Non-shape nodes (including Group) + // Non-shape nodes (Group, TextSpan, InitialContainer, etc.) are not supported + // as children of boolean operations. They result in None. + _ => return None,editor/scaffolds/sidecontrol/controls/padding.tsx (1)
87-116: Consider extracting the value resolution logic to reduce repetition.The pattern
side === X ? newValue : typeof paddingValues.X === "number" ? paddingValues.X : 0is repeated four times. This could be simplified with a helper.🔎 Proposed refactor
const handleIndividualChange = ( side: "top" | "right" | "bottom" | "left", newValue: number | undefined ) => { if (newValue === undefined) return; + const resolveValue = ( + key: "top" | "right" | "bottom" | "left" + ): number => + side === key + ? newValue + : typeof paddingValues[key] === "number" + ? paddingValues[key] + : 0; + onValueCommit?.({ - padding_top: - side === "top" - ? newValue - : typeof paddingValues.top === "number" - ? paddingValues.top - : 0, - padding_right: - side === "right" - ? newValue - : typeof paddingValues.right === "number" - ? paddingValues.right - : 0, - padding_bottom: - side === "bottom" - ? newValue - : typeof paddingValues.bottom === "number" - ? paddingValues.bottom - : 0, - padding_left: - side === "left" - ? newValue - : typeof paddingValues.left === "number" - ? paddingValues.left - : 0, + padding_top: resolveValue("top"), + padding_right: resolveValue("right"), + padding_bottom: resolveValue("bottom"), + padding_left: resolveValue("left"), }); };editor/scaffolds/sidecontrol/controls/gap.tsx (2)
127-129: Variable shadowing:valueshadows the prop.The callback parameter
_vis correctly used, but thenvalueis re-declared, shadowing the outervalueprop. Consider renaming for clarity.🔎 Suggested rename
onValueChange={(_v) => { - const value = parseInt(_v); - handleChange(value); + const numericValue = parseInt(_v, 10); + handleChange(numericValue); }}
96-99: Simplify useMemo dependencies.
isMixedis derived fromvalue, so listing both is redundant. The dependency array can be simplified.🔎 Simplified version
const hasPreset = useMemo(() => { - if (isMixed) return false; - return typeof value === "number" && Object.values(twgap).some((preset) => preset.gap === value); - }, [value, isMixed]); + if (value === grida.mixed) return false; + return typeof value === "number" && Object.values(twgap).some((preset) => preset.gap === value); + }, [value]);editor/grida-canvas-react/use-data-transfer.ts (1)
451-451: Consider adding error handling for fallback paste operations.Multiple fallback code paths invoke
instance.surface.a11yPaste()without error handling. If these operations can fail, errors would be silently swallowed.🔎 Example of defensive error handling
if (!event.clipboardData) { - instance.surface.a11yPaste(); + try { + instance.surface.a11yPaste(); + } catch (error) { + console.error("Fallback paste failed:", error); + } event.preventDefault(); return; }Apply similar pattern at lines 482, 512, 516, and 520.
Also applies to: 482-482, 512-512, 516-516, 520-520
editor/grida-canvas-react/use-mixed-properties.ts (1)
491-558: Performance optimization noted in TODO.The refactored paint grouping logic correctly implements deep equality comparison and grouping, but as the TODO comment acknowledges, resolving and comparing all paints upfront is expensive. The suggested optimization approach (limiting by n initially, loading more on demand) would improve performance for large selections.
The current implementation is correct and follows the new paint resolution pattern. The performance optimization can be addressed in a follow-up.
💡 Future optimization approach
Consider implementing the lazy-loading pattern mentioned in the TODO:
- Initially compute only the first N paint groups (e.g., N=10)
- Track if there are more paints to load
- Expose a
loadMore()method in the returned API- UI can show a "Load more" button when needed
This would improve initial render performance while maintaining full functionality.
editor/grida-canvas/action.ts (1)
290-316: Explicit targets for paste/delete/order/insert are consistent, but paste type and runtime guard diverge slightlyUnifying the action surface around explicit targets (
EditorPasteAction.target: NodeID | NodeID[],EditorDeleteAction.target: NodeID[],EditorHierarchyOrderAction.target: NodeID[],EditorUngroupAction.target: NodeID,DocumentEditorInsertNodeAction.target: NodeID | null) matches the PR’s goal of explicit targeting and will make reducers and callers easier to reason about.One small consistency nit:
EditorPasteAction.targetis now non‑optional at the type level, but the reducer still defends withif (!action.target) break;. If you expect all typed call sites to always supply a target, you could either drop this guard, or widen the type toNodeID | NodeID[] | nullto document the “no-op when target is missing” fallback more explicitly.Also applies to: 325-343, 573-608, 616-619, 944-952
editor/grida-canvas/reducers/document.reducer.ts (1)
330-342: Paste refactor (prototypes and vector networks) aligns with explicit targets; shared vector paste path could be extractedThe revised
"paste"logic now:
- Uses
editor.resolvePaintsfor image-paint clipboard, which centralizes paint resolution.- Requires
user_clipboard.type === "prototypes"and a non-emptyaction.target, then:
- Computes a viewport-space rect (with inset) from
context.viewportandstate.transform.- For each target parent and prototype, clones a packed subtree, nudges it into view via
getViewportAwareDelta, and, when a parent exists, subtracts the parent’s absolute rect so children are correctly parent‑relative before callingself_insertSubDocument.The new
"paste-vector-network"action mirrors the existing vector-edit paste behavior (union into current vector node when in vector CEM, or creating a newVectorNodeand inserting it undertarget/scene root), which fits the separation between document-level paste and content-edit-mode paste.There’s notable duplication between the vector branch inside
"paste"and the"paste-vector-network"case (offset handling, union, selection update). If this code evolves further, consider extracting a small helper like__pasteVectorNetworkIntoNode(draft, node_id, net, maybeOffset)to reduce divergence.Also applies to: 419-478, 537-600, 601-696
editor/grida-canvas/reducers/methods/select.ts (1)
33-91: Scene-filteredself_selectNodelooks solid;self_clearSelectionbehavior with non-vector CEM is worth a quick check
self_selectNode:
- Filters out any IDs in
draft.document.scenes_ref, preventing scenes from ever enteringdraft.selection.- Asserts that each remaining ID exists.
- Applies reset/add/toggle modes with
dq.pruneNestedNodesto normalize out parent+child selections.- Only resets
active_duplicationwhen a reset selection actually changes, which is good for duplication UX.
self_clearSelection:
- When
content_edit_mode.type === "vector", clears vector-geometry selection and related state but leavesdraft.selectionintact.- When no
content_edit_modeis active, clearsdraft.selection.Given
EditorBlurActiondelegates directly toself_clearSelection, it may be worth confirming that leavingdraft.selectionunchanged whencontent_edit_modeis non-vector (e.g., text or gradient modes) is the desired behavior, rather than also clearing the node selection in those cases.Also applies to: 93-115
editor/grida-canvas/reducers/event-target.cem-vector.reducer.ts (1)
861-887: Acknowledged: Duplicate helper with planned refactoring.The TODO comments clearly document the duplication across three reducers and the planned improvements (locked container filtering, root node filtering, z-order preservation). Consider creating a tracking issue to ensure this refactoring is addressed, as maintaining three copies risks divergent behavior over time.
Would you like me to open an issue to track consolidating
__get_insertion_targetinto a shared utility inutils/insertion-targeting.ts?editor/grida-canvas/reducers/event-target.cem-bitmap.reducer.ts (1)
225-251: Duplicate helper function across reducers.This is identical to the implementation in
event-target.cem-vector.reducer.ts. The TODO comments appropriately document the planned consolidation. As noted in the other file, consider tracking this refactoring to avoid maintaining parallel implementations.editor/grida-canvas-react/viewport/ui/surface-gradient-editor.tsx (1)
15-16: Clarify the import aliasing.The dual import creates potential confusion:
- Line 15:
editorfor component-level usage (outsideEditorUser)- Line 16:
_editoralias for usage insideEditorUserwhereconst editor = useCurrentEditor()shadows the module importConsider renaming the hook result to avoid shadowing:
🔎 Suggested refactor
- import { editor } from "@/grida-canvas"; - import { editor as _editor } from "@/grida-canvas"; + import { editor as editorModule } from "@/grida-canvas";Then use
editorModule.resolvePaints(...)consistently throughout, and rename the hook variable to something likeeditorInstanceinEditorUser.editor/grida-canvas/reducers/event-target.reducer.ts (1)
253-263: TODO: Compute is_empty_space_within_overlay from selection geometry.The code currently passes
undefinedforis_empty_space_within_overlay, which causes the decision function to treat empty space as "outside overlay" and perform immediate clear. The TODO comment at lines 254-256 indicates this should be computed using selection geometry rects and pointer position.According to the inline documentation, the proper implementation would:
- Get selection geometry rects from context.geometry
- Compute the union overlay
- Check if pointer position is within the overlay bounds
This logic is already implemented in
__self_drag_start_selection_like_cursorat lines 372-383 and could be extracted into a shared helper function.editor/grida-canvas/editor.ts (1)
930-948: Good documentation of technical debt.The TODO comment clearly explains the naming inconsistency and potential refactoring directions. The implementation correctly guards against missing
scene_idand uses explicit targeting.Would you like me to open an issue to track the refactoring of
pasteVectorto either rename it toinsertVectoror align it with the clipboard-based paste flow?
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (42)
crates/grida-canvas/src/painter/geometry.rsdocs/wg/feat-editor/ux-surface/selection.mdeditor/grida-canvas-hosted/playground/uxhost-menu.tsxeditor/grida-canvas-react-starter-kit/starterkit-artboard-list/index.tsxeditor/grida-canvas-react-starter-kit/starterkit-hierarchy/index.tsxeditor/grida-canvas-react-starter-kit/starterkit-hierarchy/tree-scene.tsxeditor/grida-canvas-react/ui-config.tseditor/grida-canvas-react/use-context-menu-actions.tseditor/grida-canvas-react/use-data-transfer.tseditor/grida-canvas-react/use-mixed-properties.tseditor/grida-canvas-react/viewport/hotkeys.tsxeditor/grida-canvas-react/viewport/surface.tsxeditor/grida-canvas-react/viewport/ui/floating-bar.tsxeditor/grida-canvas-react/viewport/ui/surface-gradient-editor.tsxeditor/grida-canvas-react/viewport/ui/surface-image-editor.tsxeditor/grida-canvas/ASSERTIONS.mdeditor/grida-canvas/action.tseditor/grida-canvas/editor.i.tseditor/grida-canvas/editor.tseditor/grida-canvas/reducers/__tests__/history.test.tseditor/grida-canvas/reducers/document.reducer.tseditor/grida-canvas/reducers/event-target.cem-bitmap.reducer.tseditor/grida-canvas/reducers/event-target.cem-vector.reducer.tseditor/grida-canvas/reducers/event-target.reducer.tseditor/grida-canvas/reducers/methods/__tests__/selection.test.tseditor/grida-canvas/reducers/methods/duplicate.tseditor/grida-canvas/reducers/methods/index.tseditor/grida-canvas/reducers/methods/select.tseditor/grida-canvas/reducers/methods/selection.tseditor/grida-canvas/reducers/methods/tool.tseditor/grida-canvas/reducers/methods/wrap.tseditor/grida-canvas/utils/__tests__/insertion.test.tseditor/grida-canvas/utils/insertion-targeting.tseditor/grida-canvas/utils/insertion.tseditor/grida-canvas/utils/paint-resolution.tseditor/scaffolds/sidecontrol/controls/color.tsxeditor/scaffolds/sidecontrol/controls/gap.tsxeditor/scaffolds/sidecontrol/controls/padding.tsxeditor/scaffolds/sidecontrol/sidecontrol-node-selection.tsxpackages/grida-canvas-io/__tests__/clipboard.test.tspackages/grida-canvas-io/index.tspackages/grida-canvas-schema/grida.ts
💤 Files with no reviewable changes (3)
- editor/grida-canvas/utils/paint-resolution.ts
- editor/grida-canvas/utils/insertion.ts
- editor/grida-canvas/utils/tests/insertion.test.ts
🧰 Additional context used
📓 Path-based instructions (10)
**/*.{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/reducers/methods/tool.tseditor/grida-canvas-hosted/playground/uxhost-menu.tsxpackages/grida-canvas-io/index.tseditor/grida-canvas-react/use-context-menu-actions.tseditor/grida-canvas/reducers/__tests__/history.test.tseditor/grida-canvas-react-starter-kit/starterkit-artboard-list/index.tsxeditor/grida-canvas/utils/insertion-targeting.tseditor/scaffolds/sidecontrol/controls/gap.tsxeditor/grida-canvas-react/ui-config.tseditor/grida-canvas/reducers/methods/duplicate.tseditor/scaffolds/sidecontrol/controls/padding.tsxeditor/grida-canvas-react-starter-kit/starterkit-hierarchy/tree-scene.tsxeditor/grida-canvas-react/use-data-transfer.tseditor/grida-canvas/reducers/methods/index.tseditor/grida-canvas-react/viewport/hotkeys.tsxeditor/grida-canvas/reducers/methods/select.tseditor/scaffolds/sidecontrol/sidecontrol-node-selection.tsxeditor/grida-canvas/reducers/event-target.reducer.tseditor/grida-canvas-react/use-mixed-properties.tseditor/grida-canvas/reducers/methods/wrap.tseditor/grida-canvas-react/viewport/ui/floating-bar.tsxeditor/grida-canvas-react-starter-kit/starterkit-hierarchy/index.tsxeditor/grida-canvas-react/viewport/surface.tsxeditor/grida-canvas-react/viewport/ui/surface-gradient-editor.tsxeditor/grida-canvas/reducers/document.reducer.tseditor/scaffolds/sidecontrol/controls/color.tsxeditor/grida-canvas/reducers/event-target.cem-bitmap.reducer.tseditor/grida-canvas/action.tseditor/grida-canvas/reducers/methods/selection.tseditor/grida-canvas-react/viewport/ui/surface-image-editor.tsxpackages/grida-canvas-io/__tests__/clipboard.test.tseditor/grida-canvas/reducers/event-target.cem-vector.reducer.tseditor/grida-canvas/reducers/methods/__tests__/selection.test.tspackages/grida-canvas-schema/grida.tseditor/grida-canvas/editor.tseditor/grida-canvas/editor.i.ts
{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/reducers/methods/tool.tseditor/grida-canvas-hosted/playground/uxhost-menu.tsxpackages/grida-canvas-io/index.tseditor/grida-canvas-react/use-context-menu-actions.tseditor/grida-canvas/reducers/__tests__/history.test.tseditor/grida-canvas-react-starter-kit/starterkit-artboard-list/index.tsxeditor/grida-canvas/utils/insertion-targeting.tseditor/scaffolds/sidecontrol/controls/gap.tsxeditor/grida-canvas-react/ui-config.tseditor/grida-canvas/reducers/methods/duplicate.tseditor/scaffolds/sidecontrol/controls/padding.tsxeditor/grida-canvas-react-starter-kit/starterkit-hierarchy/tree-scene.tsxeditor/grida-canvas-react/use-data-transfer.tseditor/grida-canvas/reducers/methods/index.tseditor/grida-canvas-react/viewport/hotkeys.tsxeditor/grida-canvas/reducers/methods/select.tseditor/scaffolds/sidecontrol/sidecontrol-node-selection.tsxeditor/grida-canvas/reducers/event-target.reducer.tseditor/grida-canvas-react/use-mixed-properties.tseditor/grida-canvas/reducers/methods/wrap.tseditor/grida-canvas-react/viewport/ui/floating-bar.tsxeditor/grida-canvas-react-starter-kit/starterkit-hierarchy/index.tsxeditor/grida-canvas-react/viewport/surface.tsxeditor/grida-canvas-react/viewport/ui/surface-gradient-editor.tsxeditor/grida-canvas/reducers/document.reducer.tseditor/scaffolds/sidecontrol/controls/color.tsxeditor/grida-canvas/reducers/event-target.cem-bitmap.reducer.tseditor/grida-canvas/action.tseditor/grida-canvas/reducers/methods/selection.tseditor/grida-canvas-react/viewport/ui/surface-image-editor.tsxpackages/grida-canvas-io/__tests__/clipboard.test.tseditor/grida-canvas/reducers/event-target.cem-vector.reducer.tseditor/grida-canvas/reducers/methods/__tests__/selection.test.tspackages/grida-canvas-schema/grida.tseditor/grida-canvas/editor.tseditor/grida-canvas/editor.i.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/reducers/methods/tool.tseditor/grida-canvas-hosted/playground/uxhost-menu.tsxeditor/grida-canvas-react/use-context-menu-actions.tseditor/grida-canvas/reducers/__tests__/history.test.tseditor/grida-canvas-react-starter-kit/starterkit-artboard-list/index.tsxeditor/grida-canvas/utils/insertion-targeting.tseditor/grida-canvas-react/ui-config.tseditor/grida-canvas/reducers/methods/duplicate.tseditor/grida-canvas-react-starter-kit/starterkit-hierarchy/tree-scene.tsxeditor/grida-canvas-react/use-data-transfer.tseditor/grida-canvas/reducers/methods/index.tseditor/grida-canvas-react/viewport/hotkeys.tsxeditor/grida-canvas/reducers/methods/select.tseditor/grida-canvas/reducers/event-target.reducer.tseditor/grida-canvas-react/use-mixed-properties.tseditor/grida-canvas/reducers/methods/wrap.tseditor/grida-canvas-react/viewport/ui/floating-bar.tsxeditor/grida-canvas-react-starter-kit/starterkit-hierarchy/index.tsxeditor/grida-canvas-react/viewport/surface.tsxeditor/grida-canvas-react/viewport/ui/surface-gradient-editor.tsxeditor/grida-canvas/reducers/document.reducer.tseditor/grida-canvas/reducers/event-target.cem-bitmap.reducer.tseditor/grida-canvas/action.tseditor/grida-canvas/reducers/methods/selection.tseditor/grida-canvas-react/viewport/ui/surface-image-editor.tsxeditor/grida-canvas/reducers/event-target.cem-vector.reducer.tseditor/grida-canvas/reducers/methods/__tests__/selection.test.tseditor/grida-canvas/editor.tseditor/grida-canvas/editor.i.ts
**/*.{jsx,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Use React.js 19 for web applications
Files:
editor/grida-canvas-hosted/playground/uxhost-menu.tsxeditor/grida-canvas-react-starter-kit/starterkit-artboard-list/index.tsxeditor/scaffolds/sidecontrol/controls/gap.tsxeditor/scaffolds/sidecontrol/controls/padding.tsxeditor/grida-canvas-react-starter-kit/starterkit-hierarchy/tree-scene.tsxeditor/grida-canvas-react/viewport/hotkeys.tsxeditor/scaffolds/sidecontrol/sidecontrol-node-selection.tsxeditor/grida-canvas-react/viewport/ui/floating-bar.tsxeditor/grida-canvas-react-starter-kit/starterkit-hierarchy/index.tsxeditor/grida-canvas-react/viewport/surface.tsxeditor/grida-canvas-react/viewport/ui/surface-gradient-editor.tsxeditor/scaffolds/sidecontrol/controls/color.tsxeditor/grida-canvas-react/viewport/ui/surface-image-editor.tsx
packages/grida-canvas-*/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
Packages under /packages/grida-canvas-* power the canvas; some are published to npm, refer to individual package README
Files:
packages/grida-canvas-io/index.tspackages/grida-canvas-io/__tests__/clipboard.test.tspackages/grida-canvas-schema/grida.ts
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/painter/geometry.rs
crates/grida-canvas/**/*.rs
📄 CodeRabbit inference engine (crates/grida-canvas/AGENTS.md)
crates/grida-canvas/**/*.rs: UseNodeId(u64) for internal structs (NodeRecs, SceneGraph, caches) in the rendering engine for high-performance operations
UseUserNodeId(String) for public APIs that accept or return node IDs for stability and serialization
Handle NodeId to UserNodeId conversion viaIdConverterduring .grida file loading
Auto-generate IDs (ID=0) inNodeRepositoryfor factory-created nodes
Maintain bidirectional mapping between NodeId and UserNodeId at the application layer for API boundary management
Useskia-safecrate for painting operations in the rendering engine
Usemath2crate for geometry and common math operations
Runcargo fmtto maintain code formatting standards
Runcargo clippy --no-deps --all-targets --all-featuresfor linting to check style, performance, and correctness suggestions
Files:
crates/grida-canvas/src/painter/geometry.rs
docs/**/*.md
📄 CodeRabbit inference engine (AGENTS.md)
Documentation source of truth is in the ./docs directory; deployment is handled by apps/docs
Files:
docs/wg/feat-editor/ux-surface/selection.md
docs/{wg,reference}/**/*.md
📄 CodeRabbit inference engine (AGENTS.md)
Only actively maintain docs/wg/** and docs/reference/** directories; see docs/AGENTS.md for contribution scope
Files:
docs/wg/feat-editor/ux-surface/selection.md
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/gap.tsxeditor/scaffolds/sidecontrol/controls/padding.tsxeditor/scaffolds/sidecontrol/sidecontrol-node-selection.tsxeditor/scaffolds/sidecontrol/controls/color.tsx
🧠 Learnings (27)
📓 Common learnings
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
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.)
📚 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/reducers/methods/tool.tseditor/grida-canvas/reducers/__tests__/history.test.tseditor/grida-canvas-react-starter-kit/starterkit-artboard-list/index.tsxeditor/grida-canvas-react/viewport/hotkeys.tsxeditor/grida-canvas/reducers/methods/select.tseditor/scaffolds/sidecontrol/sidecontrol-node-selection.tsxeditor/grida-canvas-react/use-mixed-properties.tseditor/grida-canvas-react/viewport/ui/surface-gradient-editor.tsxeditor/grida-canvas/reducers/document.reducer.tseditor/grida-canvas/action.tseditor/grida-canvas/reducers/methods/selection.tseditor/grida-canvas-react/viewport/ui/surface-image-editor.tsxeditor/grida-canvas/reducers/methods/__tests__/selection.test.tspackages/grida-canvas-schema/grida.tseditor/grida-canvas/editor.i.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 : 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/reducers/methods/tool.tseditor/scaffolds/sidecontrol/sidecontrol-node-selection.tsxeditor/grida-canvas-react/use-mixed-properties.tseditor/grida-canvas-react/viewport/ui/surface-gradient-editor.tsxeditor/grida-canvas/reducers/document.reducer.tseditor/grida-canvas-react/viewport/ui/surface-image-editor.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/reducers/methods/tool.tseditor/grida-canvas-react-starter-kit/starterkit-artboard-list/index.tsxeditor/grida-canvas-react/use-data-transfer.tseditor/grida-canvas/reducers/methods/select.tseditor/scaffolds/sidecontrol/sidecontrol-node-selection.tsxeditor/grida-canvas-react/use-mixed-properties.tseditor/grida-canvas-react/viewport/ui/surface-gradient-editor.tsxeditor/grida-canvas/reducers/document.reducer.tseditor/grida-canvas-react/viewport/ui/surface-image-editor.tsxpackages/grida-canvas-schema/grida.tseditor/grida-canvas/editor.i.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 {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/reducers/methods/tool.tseditor/grida-canvas-hosted/playground/uxhost-menu.tsxeditor/grida-canvas-react/use-context-menu-actions.tseditor/grida-canvas-react-starter-kit/starterkit-artboard-list/index.tsxeditor/grida-canvas/reducers/methods/duplicate.tseditor/grida-canvas-react-starter-kit/starterkit-hierarchy/tree-scene.tsxeditor/grida-canvas-react/use-data-transfer.tseditor/grida-canvas/reducers/methods/index.tseditor/grida-canvas-react/viewport/hotkeys.tsxeditor/grida-canvas/reducers/event-target.reducer.tseditor/grida-canvas-react/use-mixed-properties.tseditor/grida-canvas/reducers/methods/wrap.tseditor/grida-canvas-react-starter-kit/starterkit-hierarchy/index.tsxeditor/grida-canvas-react/viewport/ui/surface-gradient-editor.tsxeditor/grida-canvas/reducers/document.reducer.tseditor/grida-canvas/reducers/methods/selection.tseditor/grida-canvas-react/viewport/ui/surface-image-editor.tsxeditor/grida-canvas/reducers/event-target.cem-vector.reducer.tseditor/grida-canvas/editor.tseditor/grida-canvas/editor.i.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/grida-canvas/reducers/methods/tool.tseditor/grida-canvas-react/use-data-transfer.tseditor/scaffolds/sidecontrol/sidecontrol-node-selection.tsxeditor/grida-canvas/reducers/event-target.reducer.tseditor/grida-canvas-react/viewport/ui/surface-gradient-editor.tsxeditor/scaffolds/sidecontrol/controls/color.tsxeditor/grida-canvas-react/viewport/ui/surface-image-editor.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:
packages/grida-canvas-io/index.tseditor/grida-canvas-react/use-data-transfer.tseditor/grida-canvas/reducers/methods/index.tseditor/grida-canvas/reducers/methods/select.tseditor/grida-canvas/reducers/document.reducer.tseditor/grida-canvas-react/viewport/ui/surface-image-editor.tsxpackages/grida-canvas-io/__tests__/clipboard.test.tspackages/grida-canvas-schema/grida.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:
packages/grida-canvas-io/index.tseditor/grida-canvas-react-starter-kit/starterkit-artboard-list/index.tsxeditor/grida-canvas-react/use-data-transfer.tseditor/grida-canvas/reducers/methods/index.tseditor/scaffolds/sidecontrol/sidecontrol-node-selection.tsxeditor/grida-canvas/reducers/event-target.reducer.tseditor/grida-canvas-react/use-mixed-properties.tseditor/grida-canvas/reducers/methods/wrap.tseditor/grida-canvas-react/viewport/ui/surface-gradient-editor.tsxeditor/grida-canvas/reducers/document.reducer.tseditor/grida-canvas-react/viewport/ui/surface-image-editor.tsxpackages/grida-canvas-io/__tests__/clipboard.test.tspackages/grida-canvas-schema/grida.tseditor/grida-canvas/editor.tseditor/grida-canvas/editor.i.ts
📚 Learning: 2025-12-20T08:11:16.220Z
Learnt from: CR
Repo: gridaco/grida PR: 0
File: crates/grida-canvas/AGENTS.md:0-0
Timestamp: 2025-12-20T08:11:16.220Z
Learning: Applies to crates/grida-canvas/**/*.rs : Use `math2` crate for geometry and common math operations
Applied to files:
crates/grida-canvas/src/painter/geometry.rs
📚 Learning: 2025-12-20T08:11:16.220Z
Learnt from: CR
Repo: gridaco/grida PR: 0
File: crates/grida-canvas/AGENTS.md:0-0
Timestamp: 2025-12-20T08:11:16.220Z
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/painter/geometry.rs
📚 Learning: 2025-12-20T08:11:16.220Z
Learnt from: CR
Repo: gridaco/grida PR: 0
File: crates/grida-canvas/AGENTS.md:0-0
Timestamp: 2025-12-20T08:11:16.220Z
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/src/painter/geometry.rs
📚 Learning: 2025-12-20T08:11:16.220Z
Learnt from: CR
Repo: gridaco/grida PR: 0
File: crates/grida-canvas/AGENTS.md:0-0
Timestamp: 2025-12-20T08:11:16.220Z
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/painter/geometry.rs
📚 Learning: 2025-12-20T08:11:16.220Z
Learnt from: CR
Repo: gridaco/grida PR: 0
File: crates/grida-canvas/AGENTS.md:0-0
Timestamp: 2025-12-20T08:11:16.220Z
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/painter/geometry.rseditor/grida-canvas/editor.ts
📚 Learning: 2025-12-20T08:11:16.220Z
Learnt from: CR
Repo: gridaco/grida PR: 0
File: crates/grida-canvas/AGENTS.md:0-0
Timestamp: 2025-12-20T08:11:16.220Z
Learning: Applies to crates/grida-canvas/**/*.rs : Run `cargo fmt` to maintain code formatting standards
Applied to files:
crates/grida-canvas/src/painter/geometry.rs
📚 Learning: 2025-12-20T08:11:16.220Z
Learnt from: CR
Repo: gridaco/grida PR: 0
File: crates/grida-canvas/AGENTS.md:0-0
Timestamp: 2025-12-20T08:11:16.220Z
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/painter/geometry.rs
📚 Learning: 2025-12-20T08:11:16.220Z
Learnt from: CR
Repo: gridaco/grida PR: 0
File: crates/grida-canvas/AGENTS.md:0-0
Timestamp: 2025-12-20T08:11:16.220Z
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/painter/geometry.rs
📚 Learning: 2025-12-20T08:11:16.220Z
Learnt from: CR
Repo: gridaco/grida PR: 0
File: crates/grida-canvas/AGENTS.md:0-0
Timestamp: 2025-12-20T08:11:16.220Z
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/src/painter/geometry.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 editor/scaffolds/**/*.{ts,tsx} : Use /editor/scaffolds for feature-specific larger components, pages, and editors
Applied to files:
editor/scaffolds/sidecontrol/controls/gap.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/grida-*/**/*.{ts,tsx} : Use /editor/grida-* directories to isolate domain-specific modules; promote well-defined modules to <root>/packages
Applied to files:
editor/grida-canvas/reducers/methods/duplicate.tseditor/grida-canvas-react/use-data-transfer.tseditor/grida-canvas/reducers/methods/index.tseditor/grida-canvas/reducers/event-target.reducer.tseditor/grida-canvas-react/viewport/ui/surface-gradient-editor.tsxeditor/grida-canvas/editor.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 editor/lib/**/*.{ts,tsx} : Use /editor/lib for core, strictly designed modules with non-opinionated, reusable, and stable implementations
Applied to files:
editor/grida-canvas/reducers/methods/duplicate.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 : Custom images used as halftone shapes should be loaded as HTMLImageElement for efficient canvas rendering and preserve original image colors in as-is mode
Applied to files:
editor/grida-canvas-react/use-data-transfer.tseditor/grida-canvas-react/viewport/ui/surface-gradient-editor.tsxeditor/grida-canvas-react/viewport/ui/surface-image-editor.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 parameters to the halftone tool, add state with useState, include in useEffect dependency array, pass to renderHalftone() function, use in rendering logic, and add UI control
Applied to files:
editor/scaffolds/sidecontrol/sidecontrol-node-selection.tsxeditor/grida-canvas-react/use-mixed-properties.tseditor/grida-canvas-react/viewport/ui/surface-gradient-editor.tsxeditor/scaffolds/sidecontrol/controls/color.tsxeditor/grida-canvas-react/viewport/ui/surface-image-editor.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 : Calculate halftone dot radius using: radius = (1 - mapped) * maxRadius, where darker areas get larger dots
Applied to files:
editor/grida-canvas/reducers/event-target.reducer.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 : Cache ImageData and dimensions in refs (imageDataRef, sizeRef) for efficient exports
Applied to files:
editor/grida-canvas-react/use-mixed-properties.tseditor/grida-canvas-react/viewport/ui/surface-gradient-editor.tsxeditor/grida-canvas-react/viewport/ui/surface-image-editor.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/grida-canvas-react/viewport/ui/surface-gradient-editor.tsxeditor/scaffolds/sidecontrol/controls/color.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/color.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 : Image input should be automatically scaled down to a maximum of 1024px for performance
Applied to files:
editor/grida-canvas-react/viewport/ui/surface-image-editor.tsx
🧬 Code graph analysis (19)
editor/grida-canvas-hosted/playground/uxhost-menu.tsx (2)
crates/grida-canvas/src/io/io_figma.rs (1)
instance(902-906)packages/grida-canvas-io-figma/lib.ts (1)
FigImporter(2800-2814)
editor/grida-canvas-react/use-context-menu-actions.ts (1)
editor/grida-canvas/index.ts (1)
editor(4-4)
editor/grida-canvas/reducers/__tests__/history.test.ts (1)
editor/grida-canvas/action.ts (1)
Action(9-14)
editor/grida-canvas/utils/insertion-targeting.ts (1)
editor/grida-canvas/editor.i.ts (1)
IEditorState(1476-1495)
editor/scaffolds/sidecontrol/controls/gap.tsx (1)
editor/scaffolds/sidecontrol/ui/number.tsx (1)
InputPropertyNumber(127-246)
editor/scaffolds/sidecontrol/controls/padding.tsx (1)
packages/grida-canvas-schema/grida.ts (1)
IPadding(1486-1507)
editor/grida-canvas-react/use-data-transfer.ts (1)
editor/grida-canvas/editor.i.ts (1)
InsertPayload(2803-2810)
editor/grida-canvas/reducers/methods/select.ts (1)
editor/grida-canvas/editor.i.ts (1)
VectorContentEditModeGeometryControlsSelection(1231-1249)
editor/scaffolds/sidecontrol/sidecontrol-node-selection.tsx (6)
editor/scaffolds/sidecontrol/controls/gap.tsx (1)
GapControl(210-242)editor/scaffolds/sidecontrol/controls/padding.tsx (1)
PaddingControl(19-248)packages/grida-canvas-io-svg/lib.ts (1)
stroke(147-178)editor/scaffolds/sidecontrol/controls/stroke-align.tsx (1)
StrokeAlignControl(5-32)editor/scaffolds/sidecontrol/controls/stroke-join.tsx (1)
StrokeJoinControl(5-32)editor/scaffolds/sidecontrol/controls/stroke-miter-limit.tsx (1)
StrokeMiterLimitControl(28-59)
editor/grida-canvas/reducers/event-target.reducer.ts (2)
editor/grida-canvas/reducers/methods/selection.ts (3)
decideClickSelection(169-190)decidePointerDownSelection(108-159)decideDragStartAction(210-246)editor/grida-canvas/reducers/methods/select.ts (2)
self_clearSelection(93-115)self_selectNode(33-91)
editor/grida-canvas-react/use-mixed-properties.ts (6)
crates/grida-canvas/src/cg/types.rs (3)
value(585-587)value(1234-1236)value(1580-1582)packages/grida-canvas-cg/lib.ts (3)
StrokeAlign(197-197)StrokeJoin(191-191)Paint(699-705)crates/grida-canvas/src/io/io_figma.rs (1)
instance(902-906)packages/grida-canvas-schema/grida.ts (1)
IPadding(1486-1507)crates/grida-canvas/src/painter/layer.rs (1)
paints(220-224)packages/grida-canvas-io-svg/lib.ts (1)
paint(35-123)
editor/grida-canvas/reducers/methods/wrap.ts (3)
editor/grida-canvas/editor.i.ts (1)
IDocumentGeometryQuery(2663-2694)editor/grida-canvas/reducers/methods/move.ts (1)
self_moveNode(9-43)editor/grida-canvas/reducers/methods/insert.ts (1)
self_insertSubDocument(9-61)
editor/grida-canvas-react/viewport/ui/floating-bar.tsx (1)
editor/grida-canvas-react/ui-config.ts (1)
FLOATING_BAR_Z_INDEX(76-76)
editor/grida-canvas-react/viewport/ui/surface-gradient-editor.tsx (1)
editor/grida-canvas/index.ts (1)
editor(4-4)
editor/scaffolds/sidecontrol/controls/color.tsx (1)
editor/scaffolds/sidecontrol/controls/color-picker.tsx (1)
ColorPicker32FWithOptions(110-124)
editor/grida-canvas/action.ts (4)
packages/grida-canvas-schema/grida.ts (1)
NodeID(1101-1101)editor/grida-canvas/editor.i.ts (1)
NodeID(136-136)packages/grida-canvas-io-figma/lib.ts (1)
VectorNetwork(53-65)packages/grida-canvas-vn/vn.ts (1)
VectorNetwork(206-209)
editor/grida-canvas/reducers/methods/selection.ts (3)
packages/grida-canvas-schema/grida.ts (1)
INodesRepositoryRuntimeHierarchyContext(899-899)crates/csscascade/src/tree/mod.rs (1)
node_id(267-270)crates/grida-canvas/src/window/state.rs (1)
context(65-67)
packages/grida-canvas-io/__tests__/clipboard.test.ts (2)
packages/grida-canvas-schema/grida.ts (1)
NodePrototype(1246-1279)packages/grida-canvas-io/index.ts (1)
ClipboardPayload(83-86)
editor/grida-canvas/reducers/methods/__tests__/selection.test.ts (1)
editor/grida-canvas/reducers/methods/selection.ts (6)
PointerDownContext(17-33)decidePointerDownSelection(108-159)ClickContext(35-41)decideClickSelection(169-190)DragStartContext(53-68)decideDragStartAction(210-246)
🪛 LanguageTool
docs/wg/feat-editor/ux-surface/selection.md
[style] ~62-~62: This phrase is redundant. Consider writing “space”.
Context: ... Shift) → adds to selection - Target is empty space outside selection overlay (without Shif...
(EMPTY_HOLE)
[style] ~73-~73: This phrase is redundant. Consider writing “space”.
Context: ...→ defer reset to that child - Target is empty space within selection overlay (without Shift...
(EMPTY_HOLE)
[style] ~183-~183: This phrase is redundant. Consider writing “Space”.
Context: ...multi-selection. ### Multi-Selection - Empty Space Drag Within Overlay Scenario: - T...
(EMPTY_HOLE)
[style] ~188-~188: This phrase is redundant. Consider writing “space”.
Context: ... overlay - User presses pointer down on empty space within the selection overlay bounds (no...
(EMPTY_HOLE)
[style] ~198-~198: This phrase is redundant. Consider writing “space”.
Context: ..., not clear selection or start marquee. Empty space within the overlay bounds is part of th...
(EMPTY_HOLE)
⏰ 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). (1)
- GitHub Check: test
| const padding = useCallback( | ||
| (value: grida.program.nodes.i.IPadding) => { | ||
| mixedProperties.padding_top?.ids.forEach((id) => { | ||
| instance.commands.changeContainerNodePadding(id, value); | ||
| }); | ||
| }, | ||
| [mixedProperties.padding_top?.ids, instance.commands] | ||
| ); |
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.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# First, let's locate and examine the file in question
find . -name "use-mixed-properties.ts" -type fRepository: gridaco/grida
Length of output: 108
🏁 Script executed:
#!/bin/bash
# Check if the file exists and get its size to determine how to read it
if [ -f "editor/grida-canvas-react/use-mixed-properties.ts" ]; then
wc -l "editor/grida-canvas-react/use-mixed-properties.ts"
else
echo "File not found at expected location"
# Try finding it
find . -name "use-mixed-properties.ts" -type f 2>/dev/null | head -5
fiRepository: gridaco/grida
Length of output: 110
🏁 Script executed:
#!/bin/bash
# Read the relevant section around lines 357-364
sed -n '340,380p' editor/grida-canvas-react/use-mixed-properties.tsRepository: gridaco/grida
Length of output: 1414
🏁 Script executed:
#!/bin/bash
# Also look for the gap handler mentioned as comparison context
sed -n '1,400p' editor/grida-canvas-react/use-mixed-properties.ts | grep -A 10 "const gap"Repository: gridaco/grida
Length of output: 447
🏁 Script executed:
#!/bin/bash
# Search for changeContainerNodePadding implementation
rg "changeContainerNodePadding" --type ts --type tsx -A 5 -B 2Repository: gridaco/grida
Length of output: 84
🏁 Script executed:
#!/bin/bash
# Let's search for the changeContainerNodePadding command definition using rg with different approach
rg "changeContainerNodePadding" --type ts -A 5 -B 2Repository: gridaco/grida
Length of output: 2235
🏁 Script executed:
#!/bin/bash
# Also search for command definitions or implementation files
fd "command" --type f | head -20Repository: gridaco/grida
Length of output: 189
🏁 Script executed:
#!/bin/bash
# Look for where changeContainerNodePadding might be defined - likely in a commands or actions file
rg "changeContainerNodePadding" -A 10 | head -50Repository: gridaco/grida
Length of output: 3164
🏁 Script executed:
#!/bin/bash
# Let's understand the structure of mixedProperties by looking at its definition
sed -n '1,100p' editor/grida-canvas-react/use-mixed-properties.ts | grep -A 20 "mixedProperties"Repository: gridaco/grida
Length of output: 1260
🏁 Script executed:
#!/bin/bash
# Check the function/hook signature and how mixedProperties is created
head -100 editor/grida-canvas-react/use-mixed-properties.tsRepository: gridaco/grida
Length of output: 2746
🏁 Script executed:
#!/bin/bash
# Let's check what the mixed library does and understand the structure better
# First, find where the mixed library is defined
find . -name "mixed-properties*" -o -name "*mixed*" | grep -E "(package\.json|index|src)" | head -10Repository: gridaco/grida
Length of output: 39
🏁 Script executed:
#!/bin/bash
# Look for mixed-properties package or definition
find . -path "*/node_modules" -prune -o -name "mixed.ts" -type f -print
find . -path "*/node_modules" -prune -o -name "mixed.d.ts" -type f -print
find . -path "*/node_modules" -prune -o -path "*mixed-properties*" -type f -name "*.ts" -print 2>/dev/null | head -5Repository: gridaco/grida
Length of output: 209
🏁 Script executed:
#!/bin/bash
# Let's check the entire padding handler and surrounding context more carefully
sed -n '350,375p' editor/grida-canvas-react/use-mixed-properties.tsRepository: gridaco/grida
Length of output: 858
🏁 Script executed:
#!/bin/bash
# Check if there's any documentation or comment explaining the mixed property pattern
sed -n '300,365p' editor/grida-canvas-react/use-mixed-properties.ts | cat -nRepository: gridaco/grida
Length of output: 2648
🏁 Script executed:
#!/bin/bash
# Let's search for how padding is handled elsewhere - maybe in provider.tsx for single node
sed -n '1,100p' editor/grida-canvas-react/provider.tsx | grep -A 5 -B 5 "padding"Repository: gridaco/grida
Length of output: 39
🏁 Script executed:
#!/bin/bash
# Check if there are any other padding-related handlers to understand the intent
rg "padding_top\|padding_left\|padding_right\|padding_bottom" --type ts -B 2 -A 2 | head -80Repository: gridaco/grida
Length of output: 39
🏁 Script executed:
#!/bin/bash
# Let's examine the mixed-properties package implementation
cat packages/grida-mixed-properties/index.tsRepository: gridaco/grida
Length of output: 5102
🏁 Script executed:
#!/bin/bash
# Also check the test file to understand expected behavior
cat packages/grida-mixed-properties/__tests__/mixed.test.tsRepository: gridaco/grida
Length of output: 5040
🏁 Script executed:
#!/bin/bash
# Let's also look at how other properties like stroke are handled in comparison
sed -n '200,250p' editor/grida-canvas-react/use-mixed-properties.ts | cat -nRepository: gridaco/grida
Length of output: 1904
🏁 Script executed:
#!/bin/bash
# Check if there are any other places where padding is updated to see the pattern
rg "padding_top\|padding" editor/grida-canvas-react/ --type ts -B 3 -A 3 | head -100Repository: gridaco/grida
Length of output: 39
Verify node selection for padding updates.
Similar to the gap handler, this uses only mixedProperties.padding_top?.ids when setting all four padding properties via IPadding. If nodes have inconsistent padding property definitions (e.g., a node with padding_left but no padding_top), some nodes might not receive the update.
Use the union of all padding property ids, or all container nodes from the selection.
🤖 Prompt for AI Agents
In editor/grida-canvas-react/use-mixed-properties.ts around lines 357 to 364,
the padding handler only iterates mixedProperties.padding_top?.ids so nodes
missing padding_top but having other padding keys (left/right/bottom) won't get
updated; change the logic to compute the union of all padding ids (padding_top,
padding_right, padding_bottom, padding_left) or gather all selected container
node ids, then iterate that union and call
instance.commands.changeContainerNodePadding(id, value) for each id to apply the
full IPadding object to every relevant node, and update the useCallback
dependency array to reference the unified id list (or selection source) instead
of only padding_top?.ids.
| export function resolvePasteTargetParents( | ||
| state: editor.state.IEditorState, | ||
| selection: string[], | ||
| copiedIds: string[] | ||
| ): Array<string | null> { | ||
| return Array.from( | ||
| new Set( | ||
| selection | ||
| .map((node_id) => { | ||
| const node = dq.__getNodeById(state, node_id); | ||
|
|
||
| // If node is a container, use it as target parent (paste as child) | ||
| if (node.type === "container") { | ||
| return node_id; | ||
| } | ||
|
|
||
| // Otherwise, use its parent as target parent (paste as sibling) | ||
| const parent_id = dq.getParentId(state.document_ctx, node_id); | ||
|
|
||
| // Parent can be null (scene) or a container | ||
| if (!parent_id) return null; | ||
|
|
||
| const parent = dq.__getNodeById(state, parent_id); | ||
| // Only return valid container parents | ||
| return parent?.type === "container" ? parent_id : null; | ||
| }) | ||
| .filter((target_id) => { | ||
| // Ensure target parent is not one of the originals | ||
| if (target_id && copiedIds.includes(target_id)) return false; | ||
| return true; | ||
| }) | ||
| ) | ||
| ); | ||
| } |
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.
Add null checks for retrieved nodes to prevent runtime errors.
The function retrieves nodes at lines 50 and 63 without validating they exist before accessing their properties:
- Line 53:
node.typeaccessed without checking ifnodeis null/undefined - Line 65:
parent?.typeuses optional chaining but line 63 doesn't check if parent_id is valid before the lookup
If the selection contains invalid or deleted node IDs, these will cause TypeError exceptions.
🔎 Proposed fix
export function resolvePasteTargetParents(
state: editor.state.IEditorState,
selection: string[],
copiedIds: string[]
): Array<string | null> {
return Array.from(
new Set(
selection
.map((node_id) => {
const node = dq.__getNodeById(state, node_id);
+
+ if (!node) return null;
// If node is a container, use it as target parent (paste as child)
if (node.type === "container") {
return node_id;
}
// Otherwise, use its parent as target parent (paste as sibling)
const parent_id = dq.getParentId(state.document_ctx, node_id);
// Parent can be null (scene) or a container
if (!parent_id) return null;
const parent = dq.__getNodeById(state, parent_id);
+ if (!parent) return null;
+
// Only return valid container parents
- return parent?.type === "container" ? parent_id : null;
+ return parent.type === "container" ? parent_id : null;
})
.filter((target_id) => {
// Ensure target parent is not one of the originals
if (target_id && copiedIds.includes(target_id)) return false;
return true;
})
)
);
}🤖 Prompt for AI Agents
In editor/grida-canvas/utils/insertion-targeting.ts around lines 41 to 74, add
null checks for nodes returned from dq.__getNodeById to avoid runtime TypeErrors
when selection contains invalid/deleted IDs: after retrieving node (line ~50)
return null immediately if node is falsy before accessing node.type, and after
computing parent_id and retrieving parent (line ~63) return null immediately if
parent is falsy before checking parent.type; keep existing logic that returns
container IDs or null and still filter out copiedIds.
Summary by CodeRabbit
New Features
Bug Fixes
Documentation
✏️ Tip: You can customize this high-level summary in your review settings.