diff --git a/web/sections/BlockSettings.tsx b/web/sections/BlockSettings.tsx index aa327d5..a919a08 100644 --- a/web/sections/BlockSettings.tsx +++ b/web/sections/BlockSettings.tsx @@ -134,7 +134,20 @@ export const BlockSettings = ({ - {steps.map((step) => ( + {/* + Horizontal offers NEGATIVES, vertical does not. + + A negative horizontal is how a block escapes the gutter its band applied — a video + that runs to the edge of the window inside an inset band. It becomes `-mx-*`, which + cancels the band's `px-*` exactly, so the value to pick is the band's own number. + + Vertically there is nothing to cancel: a band's vertical padding is the room around + the whole band, and a block pulling itself into the one above is a bug. + */} + {(axis === 'x' + ? [...steps.filter((step) => step > 0).map((step) => -step).reverse(), ...steps] + : steps + ).map((step) => ( diff --git a/web/sections/PageBuilderPanel.tsx b/web/sections/PageBuilderPanel.tsx index 89759f0..9bff87f 100644 --- a/web/sections/PageBuilderPanel.tsx +++ b/web/sections/PageBuilderPanel.tsx @@ -7,7 +7,7 @@ import { useClient } from 'hooks/useClient'; import { readableError } from '../errors'; import { SitePreview, useDevPort } from '../SitePreview'; import { usePreviewable, useViewMode } from '../ViewMode'; -import { paintSelection, type CanvasComponent, type CanvasSection } from '../canvas'; +import { paintMeasure, paintSelection, type CanvasComponent, type CanvasSection } from '../canvas'; /* What the Spacing dialog calls a block, by kind. @@ -226,7 +226,16 @@ export const PageBuilderPanel = () => { const onDocument = useCallback( (frameDocument: Document) => { frameDoc.current = frameDocument; - return paintSelection(frameDocument, { + + /* + The measure, here as well as on Layout. + + Where the content column ends is invisible until something is placed against it, and this is + the screen where things are placed. It also answers the question a negative margin asks: a + block escaping the gutter has to be seen escaping it, against the line it crossed. + */ + const measure = paintMeasure(frameDocument); + const selection = paintSelection(frameDocument, { sections, onAddSection: () => handlersRef.current.add(), onDeleteSection: (section) => handlersRef.current.remove(section.id), @@ -245,6 +254,11 @@ export const PageBuilderPanel = () => { onSpaceSection: (section) => handlersRef.current.spaceSection(section), onSpaceComponent: (component) => handlersRef.current.spaceComponent(component), }); + + return () => { + selection(); + measure(); + }; }, // `mode` is in here so switching to View gives SitePreview a NEW function, which runs the previous // paint's cleanup and then paints nothing. That is what removes the chrome without a reload.