Skip to content

Conversation

benceruleanlu
Copy link
Member

@benceruleanlu benceruleanlu commented Sep 10, 2025

Summary

High-level refactor to standardize canvas-space layout updates for Vue nodes/slots, improve type safety around transform injection, and simplify/optimize ResizeObserver and slot tracking logic.

Changes

  • Typed TransformState InjectionKey and switch provide/inject sites to use it (no string keys, no ad-hoc assertions).
  • Centralized slot element tracking (useSlotElementTracking): batched measurements, cached offsets, fewer watchers, and canvas-space persistence.
  • Safer ResizeObserver sizing: prefer contentBoxSize[0] with contentRect fallback; removed as any cast.
  • Cleaned up dataset access to avoid any; use typed element.dataset[...] for read/write/delete.
  • Small readability updates: rename cfgconfig, use get‑or‑init pattern when batching updates.
  • Remove legacy modules superseded by the centralized tracker.

Review Focus

  • TransformPane provider + consumers now share a typed TransformStateKey.
  • RO callback conversion: screen→canvas conversion via per-element context remains; now typed and simpler.
  • Slot tracking: single RAF batch per node group; verify cached update path vs DOM read path.

Closes #5411

┆Issue is synchronized with this Notion page by Unito

christian-byrne and others added 13 commits September 8, 2025 13:33
…bserver sizing, centralized slot tracking, and small readability updates
… ResizeObserver sizing, centralized slot tracking, and small readability updates"

This reverts commit 4287526.
…utilities

- Rename parameters in useVueElementTracking for clarity (appIdentifier, trackingType)
- Add comprehensive docstring with examples to prevent DOM attribute confusion
- Extract mountLGraphNode test utility to eliminate repetitive mock setup
- Add technical implementation notes documenting optimization decisions

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>
@benceruleanlu benceruleanlu marked this pull request as ready for review September 10, 2025 03:25
@benceruleanlu benceruleanlu requested a review from a team as a code owner September 10, 2025 03:25
@dosubot dosubot bot added the size:XL This PR changes 500-999 lines, ignoring generated files. label Sep 10, 2025
@benceruleanlu benceruleanlu changed the title Update slots to new RO system Refactor vue slot tracking Sep 10, 2025
@christian-byrne christian-byrne requested a review from a team as a code owner September 11, 2025 05:38
@dosubot dosubot bot added size:XXL This PR changes 1000+ lines, ignoring generated files. and removed size:XL This PR changes 500-999 lines, ignoring generated files. labels Sep 11, 2025
Copy link
Contributor

@christian-byrne christian-byrne left a comment

Choose a reason for hiding this comment

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

Can we rebase?

For the naming with "measure", are we doing any measuring? Or is that leftover from when we used a static formula? Gbcr and such don't do measuring.

@dosubot dosubot bot added size:XL This PR changes 500-999 lines, ignoring generated files. and removed size:XXL This PR changes 1000+ lines, ignoring generated files. labels Sep 11, 2025
Copy link

github-actions bot commented Sep 11, 2025

🎭 Playwright Test Results

⚠️ Tests passed with flaky tests

⏰ Completed at: 09/16/2025, 06:46:07 AM UTC

📈 Summary

  • Total Tests: 449
  • Passed: 419 ✅
  • Failed: 0
  • Flaky: 1 ⚠️
  • Skipped: 29 ⏭️

📊 Test Reports by Browser

  • chromium: View Report • ✅ 412 / ❌ 0 / ⚠️ 1 / ⏭️ 29
  • chromium-2x: View Report • ✅ 2 / ❌ 0 / ⚠️ 0 / ⏭️ 0
  • chromium-0.5x: View Report • ✅ 1 / ❌ 0 / ⚠️ 0 / ⏭️ 0
  • mobile-chrome: View Report • ✅ 4 / ❌ 0 / ⚠️ 0 / ⏭️ 0

🎉 Click on the links above to view detailed test results for each browser configuration.

@benceruleanlu
Copy link
Member Author

fixed conflicts and renamed off of measure

although I still prefer measure

@christian-byrne
Copy link
Contributor

although I still prefer measure

Why's that?

@benceruleanlu
Copy link
Member Author

although I still prefer measure

Why's that?

I thought gBCR was all about measuring

Copy link
Contributor

Choose a reason for hiding this comment

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

In this file we have global state shared across the app and a component hook. Should we separate them into two modules and make the global state use a pinia store?

Copy link
Member Author

Choose a reason for hiding this comment

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

on second thought, these changes seem to just add complexity for not much gain right now

maybe on a later refactor if this code changes?

Copy link
Member Author

Choose a reason for hiding this comment

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

on third thought, the pinia store sounds OK, I added it

Comment on lines 228 to 231
// If node has no more slots, clean up
if (node.slots.size === 0) {
if (node.stopWatch) node.stopWatch()
nodeRegistry.delete(nodeId)
Copy link
Contributor

Choose a reason for hiding this comment

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

We should stop the watchers first before other things are done in the callback.

Copy link
Member Author

Choose a reason for hiding this comment

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

are you sure? that would bring the guard before slots are removed, seemingly never satisfying the node.slots.size === 0 because it wasn't removed before

Comment on lines 171 to 173
if (!nodeId) return
await nextTick()
const el = element.value
Copy link
Contributor

Choose a reason for hiding this comment

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

According to the docs on onMounted:

A component is considered mounted after:

  • All of its synchronous child components have been mounted (does not include async components or components inside trees).
  • Its own DOM tree has been created and inserted into the parent container. Note it only guarantees that the component's DOM tree is in-document if the application's root container is also in-document.

So this check should never be necessary in theory.

Instead of passing the element ref as a param we should follow pattern elsewhere

    const element = getCurrentInstance()?.proxy?.$el
    if (!(element instanceof HTMLElement)) return

Copy link
Member Author

Choose a reason for hiding this comment

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

the check is there because despite the child component being mounted, it's not guaranteed that it triggers the watchEffect in time to update its value for onMounted, I think the microtask that is scheduled doesn't happen synchronously compared to onMounted

even so, this seems like a very small thing to worry about in my opinion, the check seems very cheap

as for why I'd rather not use $el:

as dynamic slots come in, we can't exactly work with a component root from getCurrentInstance()?.proxy?.$el

we would need a lot more (brittle) code to work with a raw component, I don't see the benefit in doing that

@christian-byrne
Copy link
Contributor

I thought gBCR was all about measuring

It's about getting a value from a layout tree. When the tree is not dirty, it's just a getter.

Copy link
Contributor

@christian-byrne christian-byrne left a comment

Choose a reason for hiding this comment

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

LGTM!

@christian-byrne christian-byrne merged commit ff5d092 into main Sep 17, 2025
29 checks passed
@christian-byrne christian-byrne deleted the bl-update-slots branch September 17, 2025 02:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area:links area:vue-migration size:XL This PR changes 500-999 lines, ignoring generated files.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants