-
Notifications
You must be signed in to change notification settings - Fork 6
feat(builder): one mapping between the canvas frame and the host #683
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
Merged
Merged
Changes from all commits
Commits
Show all changes
18 commits
Select commit
Hold shift + click to select a range
ed4f6fe
feat(builder): one mapping between the canvas frame and the host
mobeenabdullah 7852bb1
chore(release): add the changeset for the frame geometry module
mobeenabdullah b3a17c0
fix(builder): match the geometry module exactly, and let e2e measure …
mobeenabdullah 4c56456
docs(builder): say what the geometry guard checks, and what review holds
mobeenabdullah 4162735
fix(builder): match the geometry module by path, and typecheck e2e wi…
mobeenabdullah 1771e39
fix(builder): follow every source extension, and map from the content…
mobeenabdullah 6fe5d98
fix(builder): decide test files from one list the runner also reads
mobeenabdullah c8868f8
fix(builder): scale the frame's border inset with the frame
mobeenabdullah b8ad32a
fix(builder): hash the extensions the guards read, and see an aliased…
mobeenabdullah 594701f
fix(builder): route the indicator reader through the driver's content…
mobeenabdullah 10dc87f
docs(builder): describe the guard's reach, not its history
mobeenabdullah bd9b334
fix(builder): map the nearest-zone centre with the shared helper
mobeenabdullah 10989ca
docs(builder): call the scan a review aid at the top of the file too
mobeenabdullah a2182e6
docs(builder): qualify what the release note claims the guard does
mobeenabdullah ada39f5
docs(builder): state why the origin is built here, not how it used to be
mobeenabdullah b277381
fix(builder): report a collapsed frame's scale instead of substitutin…
mobeenabdullah 02c1a9f
refactor(builder): both guards find their files by one rule
mobeenabdullah 348c63d
test(builder): pin that the walk covers every extension it claims
mobeenabdullah File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| --- | ||
| "nextly": patch | ||
| "create-nextly-app": patch | ||
| "@nextlyhq/admin": patch | ||
| "@nextlyhq/admin-css": patch | ||
| "@nextlyhq/blocks-engine": patch | ||
| "@nextlyhq/blocks-react": patch | ||
| "@nextlyhq/ui": patch | ||
| "@nextlyhq/adapter-drizzle": patch | ||
| "@nextlyhq/adapter-postgres": patch | ||
| "@nextlyhq/adapter-mysql": patch | ||
| "@nextlyhq/adapter-sqlite": patch | ||
| "@nextlyhq/storage-s3": patch | ||
| "@nextlyhq/storage-uploadthing": patch | ||
| "@nextlyhq/storage-vercel-blob": patch | ||
| "@nextlyhq/plugin-form-builder": patch | ||
| "@nextlyhq/plugin-page-builder": patch | ||
| "@nextlyhq/plugin-seo": patch | ||
| "@nextlyhq/plugin-sdk": patch | ||
| "@nextlyhq/eslint-config": patch | ||
| "@nextlyhq/prettier-config": patch | ||
| "@nextlyhq/telemetry": patch | ||
| "@nextlyhq/tsconfig": patch | ||
| "@nextlyhq/builder": patch | ||
| --- | ||
|
|
||
| Add the builder's host-canvas coordinate mapping: one module converts between the canvas frame and the host page, including the scaled border inset that places the frame's content origin. A sibling test scans for cross-frame rectangle reads elsewhere in the package, recognising a bounded set of spellings; it narrows the paths taken by accident rather than enforcing single ownership. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,58 +1,81 @@ | ||
| /** | ||
| * The canvas↔host mapping the acceptance tests measure against. | ||
| * | ||
| * **Adapts the editor's own mapping rather than restating it.** The arithmetic | ||
| * lives once, in `@nextlyhq/builder`, and this file only changes the call shape: | ||
| * these helpers take `(value, frameOrigin, scale)` because that is how a | ||
| * Playwright test has the numbers to hand — origin from the frame element's | ||
| * box, scale read off the page — while the editor holds them together as one | ||
| * `FrameGeometry`. | ||
| * | ||
| * The reason it is an adapter and not a copy is what the tests are FOR. A | ||
| * browser harness carrying its own arithmetic certifies its own arithmetic: the | ||
| * two agree on the day they are written, and the first correction to either | ||
| * makes the acceptance suite validate a stale copy while reporting that the | ||
| * editor is fine. That failure is invisible, because both sides are | ||
| * individually self-consistent. | ||
| * | ||
| * A consequence worth knowing before it surprises someone: a frame that cannot | ||
| * describe a mapping — a zero, negative or non-finite scale — now THROWS rather | ||
| * than returning `NaN` coordinates, because that is what the editor's mapping | ||
| * does. A test measuring an unrendered element gets an error naming the problem | ||
| * instead of an assertion failure about numbers that were never meaningful. | ||
| */ | ||
| import { | ||
| frameContentOrigin, | ||
| pointToCanvas, | ||
| pointToHost, | ||
| rectToHost, | ||
| type FrameGeometry, | ||
| type FrameInset, | ||
| } from "@nextlyhq/builder"; | ||
|
mobeenabdullah marked this conversation as resolved.
|
||
|
|
||
| import type { Point, Rect } from "./driver"; | ||
|
|
||
| /** The two numbers a Playwright test has, in the shape the editor's mapping takes. */ | ||
| function frame(frameOrigin: Point, scale: number): FrameGeometry { | ||
| return { origin: frameOrigin, scale }; | ||
| } | ||
|
|
||
| /** | ||
| * Convert a point inside the canvas frame to the host document's coordinates. | ||
| * | ||
| * Kept as a pure function so it can be tested against browser-reported | ||
| * geometry rather than inferred from whether an overlay happens to look right. | ||
| * | ||
| * A frame-local point is scaled by whatever transform the frame carries and | ||
| * then offset by the frame's own position in the host. The scale term is not | ||
| * optional: a canvas offering zoom-to-fit is exactly the case dnd-kit #1706 | ||
| * covered, and omitting it puts the overlay progressively further out the | ||
| * further a point sits from the frame's transform origin. | ||
| * The scale term is not optional: a canvas offering zoom-to-fit is exactly the | ||
| * case dnd-kit #1706 covered, and omitting it puts the overlay progressively | ||
| * further out the further a point sits from the frame's transform origin. | ||
| */ | ||
| export function mapFramePointToHost( | ||
| framePoint: Point, | ||
| frameOrigin: Point, | ||
| scale = 1 | ||
| ): Point { | ||
| return { | ||
| x: frameOrigin.x + framePoint.x * scale, | ||
| y: frameOrigin.y + framePoint.y * scale, | ||
| }; | ||
| return pointToHost(framePoint, frame(frameOrigin, scale)); | ||
| } | ||
|
|
||
| /** | ||
| * The inverse: a host point expressed in the canvas's own coordinates. | ||
| * | ||
| * Both directions are needed and neither is optional. Drawing an overlay in | ||
| * parent chrome maps canvas -> host; deciding which block sits under the | ||
| * pointer maps host -> canvas. A canvas that implements only one ends up | ||
| * open-coding the other at the call site, which is how the two drift apart. | ||
| */ | ||
| /** Convert a host-document point back into the canvas frame's coordinates. */ | ||
| export function mapHostPointToFrame( | ||
| hostPoint: Point, | ||
| frameOrigin: Point, | ||
| scale = 1 | ||
| ): Point { | ||
| return { | ||
| x: (hostPoint.x - frameOrigin.x) / scale, | ||
| y: (hostPoint.y - frameOrigin.y) / scale, | ||
| }; | ||
| return pointToCanvas(hostPoint, frame(frameOrigin, scale)); | ||
| } | ||
|
|
||
| /** The same mapping for a rect, so an indicator can be drawn in parent chrome. */ | ||
| /** Convert a rectangle inside the frame to the host document's coordinates. */ | ||
| export function mapFrameRectToHost( | ||
| frameRect: Rect, | ||
| frameOrigin: Point, | ||
| scale = 1 | ||
| ): Rect { | ||
| const topLeft = mapFramePointToHost(frameRect, frameOrigin, scale); | ||
| return { | ||
| x: topLeft.x, | ||
| y: topLeft.y, | ||
| width: frameRect.width * scale, | ||
| height: frameRect.height * scale, | ||
| }; | ||
| return rectToHost(frameRect, frame(frameOrigin, scale)); | ||
| } | ||
|
|
||
| /** | ||
| * Where the frame's content viewport starts, from a measured border box. | ||
| * | ||
| * Re-exported rather than wrapped: this is the arithmetic every caller needs | ||
| * after reading `boundingBox()` and `clientLeft`, and writing it at each call | ||
| * site is how one of them ends up adding the inset unscaled. The measurement | ||
| * stays in the driver; the sums stay in the editor's module. | ||
| */ | ||
| export { frameContentOrigin, type FrameInset }; | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.