Skip to content

Commit

Permalink
Fix Grid Track Labels and Resize Indicators (#6566)
Browse files Browse the repository at this point in the history
# **Problem:**
The grid labels and the grid resize indicators are in a state of being
fucked:

![image](https://github.com/user-attachments/assets/e68f433a-93e5-4f3a-92c7-a53764357651)

![image](https://github.com/user-attachments/assets/d2347204-9ae4-48de-bc5f-31592f81e751)

![image](https://github.com/user-attachments/assets/c0105ee6-793e-48d1-b68b-b2f9eb6f64e2)

# **Goal:**
Fix the various layout issues, and make the labels subdued until
hovered. The hovered label should z-index over its siblings:

![image](https://github.com/user-attachments/assets/52b0f170-6d6b-4fed-8290-1eb6f9a022c8)

# **Fix:**
<img width="566" alt="image"
src="https://github.com/user-attachments/assets/ade0a053-321f-438c-a9e2-d8538f5be293">


![image](https://github.com/user-attachments/assets/9cb73a40-b205-45c8-a43f-2f1aae5ff6bf)



**Commit Details:**

- Split `GridResizingControl` into `GridTrackSizeLabelForDimension` and
`GridResizingStripedIndicator`
- Render _two_ helper grids, one for the label and one for the sizing
indicator. This avoids future css intermingling problems, going forward
bug fixing one should not meaningfully affect the other.
- The helper grids use the blessed
`getGridHelperStyleMatchingTargetGrid` style instead of manually picking
an assortment of relevant grid properties. This simplifies our life 97%

**Note:**
The code could be further simplified, as this is now a copy-paste job. I
tried to remove the obviously unnecessary things, but there's still a
little too much div wrappers going on.

**Manual Tests:**
I hereby swear that:

- [ ] I opened a hydrogen project and it loaded
- [ ] I could navigate to various routes in Play mode
  • Loading branch information
balazsbajorics authored and liady committed Dec 13, 2024
1 parent 94e028a commit 132c7d5
Show file tree
Hide file tree
Showing 3 changed files with 136 additions and 95 deletions.
229 changes: 134 additions & 95 deletions editor/src/components/canvas/controls/grid-controls.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,11 @@ import { windowToCanvasCoordinates } from '../dom-lookup'
import type { Axis } from '../gap-utils'
import { useCanvasAnimation } from '../ui-jsx-canvas-renderer/animation-context'
import { CanvasOffsetWrapper } from './canvas-offset-wrapper'
import type { GridControlsProps, GridData } from './grid-controls-for-strategies'
import type {
GridControlsProps,
GridData,
GridMeasurementHelperData,
} from './grid-controls-for-strategies'
import {
edgePositionToGridResizeEdge,
GridCellTestId,
Expand Down Expand Up @@ -112,7 +116,6 @@ function getLabelForAxis(
return gridCSSNumberToLabel(defaultEither(fromDOM, fromPropsAtIndex))
}

const GRID_RESIZE_HANDLE_CONTAINER_SIZE = 30 // px
const GRID_RESIZE_HANDLE_SIZE = 15 // px

interface GridResizingControlProps {
Expand All @@ -128,7 +131,7 @@ interface GridResizingControlProps {
stripedAreaLength: number | null
}

const GridResizingControl = React.memo((props: GridResizingControlProps) => {
const GridTrackSizeLabel = React.memo((props: GridResizingControlProps) => {
const { setResizingIndex } = props

const canvasOffset = useEditorState(
Expand Down Expand Up @@ -200,15 +203,18 @@ const GridResizingControl = React.memo((props: GridResizingControlProps) => {
const labelId = `grid-${props.axis}-handle-${props.dimensionIndex}`
const containerId = `${labelId}-container`

const shadowSize = React.useMemo(() => {
return props.axis === 'column'
? props.containingFrame.height + GRID_RESIZE_HANDLE_CONTAINER_SIZE
: props.containingFrame.width + GRID_RESIZE_HANDLE_CONTAINER_SIZE
}, [props.containingFrame, props.axis])

const stripedAreaSkew = React.useMemo(
() => GRID_RESIZE_HANDLE_CONTAINER_SIZE / scale + props.padding,
[scale, props.padding],
const cssProp = React.useMemo(
() => ({
backgroundColor:
props.resizing === 'resize-target'
? colorTheme.primary.value
: colorTheme.primarySubdued.value,
'&:hover': {
zIndex: 1,
backgroundColor: colorTheme.primary.value,
},
}),
[props.resizing, colorTheme],
)

return (
Expand All @@ -219,20 +225,22 @@ const GridResizingControl = React.memo((props: GridResizingControlProps) => {
display: 'flex',
alignItems: props.axis === 'column' ? 'flex-start' : 'center',
justifyContent: props.axis === 'column' ? 'center' : 'flex-start',
height: props.axis === 'column' && props.resizing !== 'not-resizing' ? shadowSize : '100%',
width: props.axis === 'row' && props.resizing !== 'not-resizing' ? shadowSize : '100%',
height: '100%',
width: '100%',
position: 'relative',
}}
>
<div
data-testid={labelId}
style={{
position: 'absolute',
zoom: 1 / scale,
height: GRID_RESIZE_HANDLE_SIZE,
right: props.axis === 'row' ? 'calc(100% + 8px)' : undefined,
bottom: props.axis === 'column' ? 'calc(100% + 8px)' : undefined,
borderRadius: 3,
padding: '0 4px',
border: `.1px solid ${colorTheme.white.value}`,
background: colorTheme.primary.value,
color: colorTheme.white.value,
display: 'flex',
alignItems: 'center',
Expand All @@ -244,27 +252,46 @@ const GridResizingControl = React.memo((props: GridResizingControlProps) => {
}}
onMouseDown={mouseDownHandler}
onMouseMove={onMouseMove}
css={cssProp}
>
{getLabelForAxis(props.dimension, props.dimensionIndex, props.fromPropsAxisValues)}
</div>
</div>
)
})
GridTrackSizeLabel.displayName = 'GridTrackSizeLabel'

const GridResizingStripedIndicator = React.memo((props: GridResizingControlProps) => {
const scale = useEditorState(
Substores.canvas,
(store) => store.editor.canvas.scale,
'GridResizingControl scale',
)
const colorTheme = useColorTheme()

const labelId = `grid-${props.axis}-handle-${props.dimensionIndex}`
const containerId = `${labelId}-container`

return (
<div
key={containerId}
data-testid={containerId}
style={{
display: 'flex',
alignItems: props.axis === 'column' ? 'flex-start' : 'center',
justifyContent: props.axis === 'column' ? 'center' : 'flex-start',
height: '100%',
width: '100%',
position: 'relative',
}}
>
{when(
props.resizing !== 'not-resizing',
<div
style={{
position: 'absolute',
top: props.axis === 'column' ? stripedAreaSkew : 0,
left: props.axis === 'row' ? stripedAreaSkew : 0,
right: props.axis === 'row' || props.stripedAreaLength == null ? undefined : 0,
width:
props.axis === 'row' && props.stripedAreaLength != null
? props.stripedAreaLength
: undefined,
bottom: props.axis === 'column' || props.stripedAreaLength == null ? undefined : 0,
height:
props.axis === 'column' && props.stripedAreaLength != null
? props.stripedAreaLength
: undefined,
display: 'flex',
width: '100%',
height: '100%',
alignItems: 'center',
justifyContent: 'center',
border: `1px solid ${
Expand Down Expand Up @@ -302,9 +329,10 @@ const GridResizingControl = React.memo((props: GridResizingControlProps) => {
</div>
)
})
GridResizingControl.displayName = 'GridResizingControl'
GridResizingStripedIndicator.displayName = 'GridResizingStripedIndicator'

interface GridResizingProps {
targetGrid: GridMeasurementHelperData
axisValues: GridAutoOrTemplateBase | null
fromPropsAxisValues: GridAutoOrTemplateBase | null
stripedAreaLength: number | null
Expand Down Expand Up @@ -375,75 +403,84 @@ const GridResizing = React.memo((props: GridResizingProps) => {
}
switch (props.axisValues.type) {
case 'DIMENSIONS':
const size = GRID_RESIZE_HANDLE_CONTAINER_SIZE / canvasScale
const dimensions = props.axisValues.dimensions

const helperGridBaseStyle: React.CSSProperties = getGridHelperStyleMatchingTargetGrid(
props.targetGrid,
)

const helperGridStyle: React.CSSProperties = {
...helperGridBaseStyle,
gridTemplateRows: props.axis === 'row' ? helperGridBaseStyle.gridTemplateRows : '1fr',
gridTemplateColumns:
props.axis === 'column' ? helperGridBaseStyle.gridTemplateColumns : '1fr',
}

return (
<div
style={{
position: 'absolute',
top: props.containingFrame.y - (props.axis === 'column' ? size : 0),
left: props.containingFrame.x - (props.axis === 'row' ? size : 0),
width: props.axis === 'column' ? props.containingFrame.width : size,
height: props.axis === 'row' ? props.containingFrame.height : size,
display: 'grid',
gridTemplateColumns:
props.axis === 'column'
? dimensions.map((dim) => printGridCSSNumber(dim)).join(' ')
: undefined,
gridTemplateRows:
props.axis === 'row'
? dimensions.map((dim) => printGridCSSNumber(dim)).join(' ')
: undefined,
gap: props.gap ?? 0,
paddingLeft:
props.axis === 'column' && props.padding != null
? `${props.padding.left}px`
: undefined,
paddingTop:
props.axis === 'row' && props.padding != null ? `${props.padding.top}px` : undefined,
paddingRight:
props.axis === 'column' && props.padding != null
? `${props.padding.right}px`
: undefined,
paddingBottom:
props.axis === 'row' && props.padding != null
? `${props.padding.bottom}px`
: undefined,
justifyContent: props.justifyContent ?? undefined,
alignContent: props.alignContent ?? undefined,
}}
>
{dimensions.flatMap((dimension, dimensionIndex) => {
return (
<GridResizingControl
key={`grid-resizing-control-${dimensionIndex}`}
dimensionIndex={dimensionIndex}
dimension={dimension}
fromPropsAxisValues={fromProps}
stripedAreaLength={props.stripedAreaLength}
axis={props.axis}
containingFrame={props.containingFrame}
resizing={
resizingIndex === dimensionIndex
? 'resize-target'
: coresizingIndexes.includes(dimensionIndex)
? 'resize-generated'
: 'not-resizing'
}
resizeLocked={resizeLocked}
setResizingIndex={setResizingIndex}
padding={
props.padding == null
? 0
: props.axis === 'column'
? props.padding.top ?? 0
: props.padding.left ?? 0
}
/>
)
})}
</div>
<React.Fragment>
<div style={helperGridStyle}>
{dimensions.flatMap((dimension, dimensionIndex) => {
return (
<GridResizingStripedIndicator
key={`grid-resizing-striped-indicator-${dimensionIndex}`}
dimensionIndex={dimensionIndex}
dimension={dimension}
fromPropsAxisValues={fromProps}
stripedAreaLength={props.stripedAreaLength}
axis={props.axis}
containingFrame={props.containingFrame}
resizing={
resizingIndex === dimensionIndex
? 'resize-target'
: coresizingIndexes.includes(dimensionIndex)
? 'resize-generated'
: 'not-resizing'
}
resizeLocked={resizeLocked}
setResizingIndex={setResizingIndex}
padding={
props.padding == null
? 0
: props.axis === 'column'
? props.padding.top ?? 0
: props.padding.left ?? 0
}
/>
)
})}
</div>
<div style={helperGridStyle}>
{dimensions.flatMap((dimension, dimensionIndex) => {
return (
<GridTrackSizeLabel
key={`grid-resizing-label-${dimensionIndex}`}
dimensionIndex={dimensionIndex}
dimension={dimension}
fromPropsAxisValues={fromProps}
stripedAreaLength={props.stripedAreaLength}
axis={props.axis}
containingFrame={props.containingFrame}
resizing={
resizingIndex === dimensionIndex
? 'resize-target'
: coresizingIndexes.includes(dimensionIndex)
? 'resize-generated'
: 'not-resizing'
}
resizeLocked={resizeLocked}
setResizingIndex={setResizingIndex}
padding={
props.padding == null
? 0
: props.axis === 'column'
? props.padding.top ?? 0
: props.padding.left ?? 0
}
/>
)
})}
</div>
</React.Fragment>
)
case 'FALLBACK':
return null
Expand Down Expand Up @@ -525,6 +562,7 @@ export const GridRowColumnResizingControlsComponent = ({
return (
<GridResizing
key={`grid-resizing-column-${EP.toString(grid.elementPath)}`}
targetGrid={grid}
axisValues={grid.gridTemplateColumns}
fromPropsAxisValues={grid.gridTemplateColumnsFromProps}
containingFrame={grid.frame}
Expand All @@ -544,6 +582,7 @@ export const GridRowColumnResizingControlsComponent = ({
return (
<GridResizing
key={`grid-resizing-row-${EP.toString(grid.elementPath)}`}
targetGrid={grid}
axisValues={grid.gridTemplateRows}
fromPropsAxisValues={grid.gridTemplateRowsFromProps}
containingFrame={grid.frame}
Expand Down
1 change: 1 addition & 0 deletions editor/src/uuiui/styles/theme/dark.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import type { light } from './light'

const darkBase = {
primary: createUtopiColor('oklch(59% 0.25 254)'),
primarySubdued: createUtopiColor('oklch(43% 0.15 254)'),
primary10solid: createUtopiColor('oklch(0.98 0.01 253.75)'),
primary10: createUtopiColor('oklch(59% 0.25 254 / 10%)'),
primary25: createUtopiColor('oklch(59% 0.25 254 / 25%)'),
Expand Down
1 change: 1 addition & 0 deletions editor/src/uuiui/styles/theme/light.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import type { dark } from './dark'

const lightBase = {
primary: createUtopiColor('oklch(59% 0.25 254)'),
primarySubdued: createUtopiColor('oklch(75% 0.15 254)'),
primary10solid: createUtopiColor('oklch(0.98 0.01 253.75)'),
primary10: createUtopiColor('oklch(59% 0.25 254 / 10%)'),
primary25: createUtopiColor('oklch(59% 0.25 254 / 25%)'),
Expand Down

0 comments on commit 132c7d5

Please sign in to comment.