# Closes#14855.
## The bug
When an `affine:embed-synced-doc` is placed on an edgeless canvas and
resized which sets `model.props.scale` to a value ≠ 1 - the
block-selection frame rendered **inside** that embedded editor is drawn
offset from the actual block boundary. The reporter hit this in Safari,
but the root cause is platform-independent.

## Root cause
`affine-embed-edgeless-synced-doc-block` applies `transform:
scale(modelScale)` to its `.affine-embed-synced-doc-container` so the
embedded editor visually fits inside its edgeless xywh
([embed-edgeless-synced-doc-block.ts#L48-L58](https://github.com/toeverything/AFFiNE/blob/canary/blocksuite/affine/blocks/embed-doc/src/embed-synced-doc-block/embed-edgeless-synced-doc-block.ts#L48-L58)).
The inner `Viewport` exposes that outer scale as `viewScale =
boundingClientRect.width / offsetWidth`.
PR #14015 and PR #14074 already taught the surface canvas and
`GfxBlockComponent.getCSSTransform` to compensate by dividing by
`viewScale`. But several selection-related overlays that render inside
the same scaled container were **not** updated in those PRs. They
either:
- read `viewport.toViewCoord(x, y)` - which returns `(x - viewportX) *
zoom * viewScale` and drop the result into CSS `left` / `top` inside the
scaled container, or
- hand-build a `translate(translateX, translateY) scale(zoom)` transform
without `viewScale` compensation.
The outer CSS `scale(viewScale)` then re-applies the scale, leaving the
overlays one factor of `viewScale` away from their blocks. That's
exactly the misalignment in the screenshot - the rect's size looks right
but its position is offset.
## The fix
Mirror the pattern shipped in #14074 everywhere the inner overlays are
placed:
- position: `(model - viewportX) * zoom / viewScale`
- transform scale: `zoom / viewScale`
- translate: `translateX / viewScale, translateY / viewScale`
This keeps the overlays in the same reference frame as
`GfxBlockComponent.getCSSTransform` so they line up with the block
they're framing. When `viewScale === 1` (normal edgeless canvas, outside
any embed) every `/ viewScale` is a no-op and behaviour is unchanged.
## Why this is safe
- When `viewScale === 1` - every existing caller outside
`embed-edgeless-synced-doc` - the math reduces to the original
expression byte-for-byte.
- The fix strictly mirrors the invariant already adopted by
`GfxBlockComponent.getCSSTransform` in #14074. It's the same division by
`viewScale` applied in the same place.
- No public API, type, or DOM structure changed.
## Scope / known limitations
- The `Viewport._cachedBoundingClientRect` cache is only invalidated by
its own `ResizeObserver`
([viewport.ts#L500-L505](https://github.com/toeverything/AFFiNE/blob/canary/blocksuite/framework/std/src/gfx/viewport.ts#L500-L505)).
A CSS-transform change on an ancestor (e.g. the user panning/zooming the
outer edgeless canvas) does not fire it, so in theory `viewScale` can go
stale between outer-viewport updates. In practice this hasn't come up in
repro - the inner viewport's shell is observed and fires whenever layout
shifts. If it turns out to matter I'm happy to add a
`viewport.onResize()` refresh hook off the existing
`GfxViewportInitializer` in a follow-up.
- No integration test added - the existing
`blocksuite/integration-test/edgeless/` suite has no `embed-synced-doc`
harness. Adding one is a larger scope; can follow up if requested.
## Test plan
- [x] `yarn typecheck` - passes
- [x] `yarn lint:ox` - `0 warnings, 0 errors`
- [x] `yarn prettier --write` on the 5 touched files - no changes
- [ ] Manual: on canary, create an edgeless canvas, drop an
embed-synced-doc, resize with `Shift` held so `model.props.scale` ≠ 1,
select any block inside, and verify the blue selection frame sits flush
with the block's boundary (confirm on Safari, Chrome, Firefox).
- [ ] Regression check: on a normal edgeless canvas (no embed), verify
element selection, drag handle, and text/shape inline editors still
render correctly (these code paths hit `viewScale === 1` and should be
unchanged).
## Related PRs
- #14015 - fixed surface canvas at non-1 `viewScale`.
- #14074 - fixed `GfxBlockComponent.getCSSTransform` at non-1
`viewScale`. This PR completes that series by covering the selection
overlays.
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Bug Fixes**
* Fixed positioning and scaling of inline text editors, selection
rectangles, drag handles, and remote cursors so overlays and editors
remain correctly aligned and sized when the viewport uses an additional
outer scale/transform during zooming and panning.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
### Changed
- Better snapping when resize elements
<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit
- **New Features**
- Improved resizing behavior with enhanced alignment and snapping during element resizing, supporting rotation and multiple element selection.
- Alignment lines now display more accurately when resizing elements.
- **Refactor**
- Resizing logic updated to use scale factors instead of position deltas, enabling smoother and more precise resize operations.
- Resize event data now includes richer details about handle positions, scaling, and original bounds.
- Coordinate transformations and scaling now account for rotation and aspect ratio locking more robustly.
- Cursor updates are disabled during active resize or rotate interactions for a smoother user experience.
- **Tests**
- Updated resizing tests to use square shapes, ensuring consistent verification of aspect ratio maintenance.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
### Changed
- Note scale issue
- Overlay should call refresh when `clear` is called
- Optimize edgeless-selected-rect to avoid unecessary rerendering
<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit
- **New Features**
- Edgeless note blocks now respect both minimum and maximum size limits when resizing.
- **Improvements**
- Enhanced performance and responsiveness of resize and rotate handles in selection overlays by caching allowed handles and optimizing cursor management.
- Cursor styles for resize and rotate handles are now set more reliably and efficiently through declarative styling.
- **Bug Fixes**
- Ensured overlay clearing now properly refreshes the renderer for more consistent visual updates.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Fixes [BS-3161](https://linear.app/affine-design/issue/BS-3161/发现已连接的connector会响应对齐线)
Fixes [BS-3337](https://linear.app/affine-design/issue/BS-3337/connector你肿么了)
Fixes [BS-3334](https://linear.app/affine-design/issue/BS-3334/connector-不应该能够被拖拽)
<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit
- **Bug Fixes**
- Corrected typos related to label editing state, ensuring more reliable label editing and display for connectors.
- Fixed logic in the auto-complete overlay, improving when overlays appear during hover actions.
- **New Features**
- Improved connector label handling by ensuring label state is preserved and restored during editing.
- Enhanced connector movement behavior, allowing connectors to be moved only when appropriate elements are selected.
- **Tests**
- Added end-to-end tests to verify connector movement and selection behaviors for improved reliability.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit
- **New Features**
- Introduced the Edgeless Selected Rectangle widget, providing enhanced selection and interaction capabilities in edgeless mode.
- Added rotation-aware resize cursors for improved usability when resizing selections.
- Integrated new autocomplete panels and selection components for a smoother user experience.
- **Refactor**
- Modularized the Edgeless Selected Rectangle widget as a standalone package for better maintainability and integration.
- Updated internal references and imports to utilize the new widget package.
- **Chores**
- Updated project and package configurations to include the new widget and ensure proper build and type-checking across the workspace.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->