Skip to content

Commit b7d07ed

Browse files
authored
Grid cell lines (#6674)
**Problem:** When a grid item is selected, there should be outline lines around the cell bounds, which also expand to meet the ruler markers. **Fix:** Implement one component to render the cell bounds outline, and one component for the lines stretching to the markers from the cell perimeter. <img width="807" alt="Screenshot 2024-11-22 at 11 59 11" src="https://github.com/user-attachments/assets/e82672bc-f7dd-4dd2-9b24-6f2c6d286feb"> https://github.com/user-attachments/assets/9a69b131-a052-42ab-88c6-f1534c3865af **Manual Tests:** I hereby swear that: - [x] I opened a hydrogen project and it loaded - [x] I could navigate to various routes in Play mode Fixes #6675
1 parent 0e30131 commit b7d07ed

File tree

1 file changed

+103
-5
lines changed

1 file changed

+103
-5
lines changed

editor/src/components/canvas/controls/grid-controls.tsx

+103-5
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import {
2828
import type { CanvasPoint, CanvasRectangle, LocalRectangle } from '../../../core/shared/math-utils'
2929
import {
3030
canvasPoint,
31+
canvasRectangle,
3132
isFiniteRectangle,
3233
isInfinityRectangle,
3334
nullIfInfinity,
@@ -2160,6 +2161,8 @@ const rulerMarkerIconSize = 12 // px
21602161

21612162
type RulerMarkerData = {
21622163
parentGrid: GridContainerProperties
2164+
cellRect: CanvasRectangle
2165+
gridRect: CanvasRectangle
21632166
columnStart: RulerMarkerPositionData
21642167
columnEnd: RulerMarkerPositionData
21652168
rowStart: RulerMarkerPositionData
@@ -2243,8 +2246,18 @@ const RulerMarkers = React.memo((props: { path: ElementPath }) => {
22432246
store.editor.jsxMetadata,
22442247
)
22452248

2249+
const cellRect = parentGridCellGlobalFrames[cellBounds.row - 1][cellBounds.column - 1]
2250+
const cellRectResized = canvasRectangle({
2251+
x: cellRect.x,
2252+
y: cellRect.y,
2253+
width: width,
2254+
height: height,
2255+
})
2256+
22462257
return {
22472258
parentGrid: parentGrid,
2259+
cellRect: cellRectResized,
2260+
gridRect: gridRect,
22482261
columnStart: {
22492262
top: gridRect.y,
22502263
left: left,
@@ -2280,6 +2293,7 @@ const RulerMarkers = React.memo((props: { path: ElementPath }) => {
22802293

22812294
return (
22822295
<React.Fragment>
2296+
{/* Indicators */}
22832297
<RulerMarkerIndicator
22842298
parentGrid={markers.parentGrid}
22852299
marker={markers.columnStart}
@@ -2296,6 +2310,38 @@ const RulerMarkers = React.memo((props: { path: ElementPath }) => {
22962310
axis={'row'}
22972311
/>
22982312
<RulerMarkerIndicator parentGrid={markers.parentGrid} marker={markers.rowEnd} axis={'row'} />
2313+
{/* Offset lines */}
2314+
<GridCellOffsetLine
2315+
top={markers.columnStart.top}
2316+
left={markers.columnStart.left}
2317+
size={markers.cellRect.y - markers.gridRect.y}
2318+
orientation='vertical'
2319+
/>
2320+
<GridCellOffsetLine
2321+
top={markers.columnEnd.top}
2322+
left={markers.columnEnd.left}
2323+
size={markers.cellRect.y - markers.gridRect.y}
2324+
orientation='vertical'
2325+
/>
2326+
<GridCellOffsetLine
2327+
top={markers.rowStart.top}
2328+
left={markers.rowStart.left}
2329+
size={markers.cellRect.x - markers.gridRect.x}
2330+
orientation='horizontal'
2331+
/>
2332+
<GridCellOffsetLine
2333+
top={markers.rowEnd.top}
2334+
left={markers.rowEnd.left}
2335+
size={markers.cellRect.x - markers.gridRect.x}
2336+
orientation='horizontal'
2337+
/>
2338+
{/* Cell outline */}
2339+
<GridCellOutline
2340+
top={markers.cellRect.y}
2341+
left={markers.cellRect.x}
2342+
width={markers.cellRect.width + 1}
2343+
height={markers.cellRect.height + 1}
2344+
/>
22992345
</React.Fragment>
23002346
)
23012347
})
@@ -2496,16 +2542,17 @@ function skewMarkerPosition(
24962542
// span-end triangle, on the column
24972543
const spanEndColumn = axis === 'column' && markerType === 'span-end'
24982544
if (spanEndColumn) {
2499-
return 10
2545+
return 9
25002546
}
2501-
const pinnedEndColumn = axis === 'column' && markerType === 'pinned'
2547+
// pinned triangle, on the column
2548+
const pinnedEndColumn = axis === 'column' && markerType === 'pinned' && bound === 'end'
25022549
if (pinnedEndColumn) {
25032550
return 5
25042551
}
25052552
// any other ending marker, on the column
25062553
const endColumn = bound === 'end' && axis === 'column'
25072554
if (endColumn) {
2508-
return 2
2555+
return 1
25092556
}
25102557

25112558
// span-end triangle, on the row
@@ -2516,18 +2563,22 @@ function skewMarkerPosition(
25162563
// any other ending marker, on the row
25172564
const endRow = bound === 'end' && axis === 'row'
25182565
if (endRow) {
2519-
return 6
2566+
return 4
25202567
}
25212568

25222569
// span-start triangle, on the column
25232570
const spanStartColumn = axis === 'column' && markerType === 'span-start'
25242571
if (spanStartColumn) {
25252572
return 0
25262573
}
2574+
const pinnedStartColumn = axis === 'column' && markerType === 'pinned' && bound === 'start'
2575+
if (pinnedStartColumn) {
2576+
return 5
2577+
}
25272578
// any starting marker, on the column
25282579
const startColumn = bound === 'start' && axis === 'column'
25292580
if (startColumn) {
2530-
return 5
2581+
return 1
25312582
}
25322583

25332584
// span-start starting triangle, on the row
@@ -2543,3 +2594,50 @@ function skewMarkerPosition(
25432594

25442595
return 0
25452596
}
2597+
2598+
const GridCellOffsetLine = React.memo(
2599+
(props: { top: number; left: number; size: number; orientation: 'vertical' | 'horizontal' }) => {
2600+
const colorTheme = useColorTheme()
2601+
2602+
return (
2603+
<div
2604+
style={{
2605+
position: 'absolute',
2606+
top: props.top,
2607+
left: props.left,
2608+
width: props.orientation === 'horizontal' ? props.size : 1,
2609+
height: props.orientation === 'vertical' ? props.size : 1,
2610+
borderLeft:
2611+
props.orientation === 'vertical' ? `1px dashed ${colorTheme.primary.value}` : undefined,
2612+
borderTop:
2613+
props.orientation === 'horizontal'
2614+
? `1px dashed ${colorTheme.primary.value}`
2615+
: undefined,
2616+
pointerEvents: 'none',
2617+
}}
2618+
/>
2619+
)
2620+
},
2621+
)
2622+
GridCellOffsetLine.displayName = 'GridCellOffsetLine'
2623+
2624+
const GridCellOutline = React.memo(
2625+
(props: { top: number; left: number; width: number; height: number }) => {
2626+
const colorTheme = useColorTheme()
2627+
2628+
return (
2629+
<div
2630+
style={{
2631+
position: 'absolute',
2632+
top: props.top,
2633+
left: props.left,
2634+
width: props.width,
2635+
height: props.height,
2636+
border: `1px dashed ${colorTheme.primary.value}`,
2637+
pointerEvents: 'none',
2638+
}}
2639+
/>
2640+
)
2641+
},
2642+
)
2643+
GridCellOutline.displayName = 'GridCellOutline'

0 commit comments

Comments
 (0)