Skip to content
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

Chore/mini grid design fixes #4275

Merged
merged 9 commits into from
Oct 2, 2023
4 changes: 2 additions & 2 deletions editor/src/components/canvas/design-panel-root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ import type { Menu, Pane, StoredPanel } from './grid-panels-state'
import type { ResizableProps } from '../../uuiui-deps'
import type { Direction } from 're-resizable/lib/resizer'
import { isFeatureEnabled } from '../../utils/feature-switches'
import { TitleBarEmpty, TitleBarUserProfile } from '../titlebar/title-bar'
import { TitleBarCode, TitleBarUserProfile } from '../titlebar/title-bar'
import type { EditorAction } from '../editor/action-types'
import { SettingsPane } from '../navigator/left-pane/settings-pane'
import { MenuTab } from '../../uuiui/menu-tab'
Expand Down Expand Up @@ -430,7 +430,7 @@ export const CodeEditorPane = React.memo<CodeEditorPaneProps>((props) => {
>
{when(
isFeatureEnabled('Draggable Floating Panels'),
<TitleBarEmpty panelData={props.panelData} />,
<TitleBarCode panelData={props.panelData} />,
)}
<div
style={{
Expand Down
8 changes: 6 additions & 2 deletions editor/src/components/canvas/grid-panels-container.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import React from 'react'
import { accumulate } from '../../core/shared/array-utils'
import { GridPanel } from './grid-panel'
import { ColumnDragTargets, GridColumnResizeHandle } from './grid-panels-drag-targets'
import {
CanvasPaneDragTargets,
ColumnDragTargets,
GridColumnResizeHandle,
} from './grid-panels-drag-targets'
import type { LayoutUpdate, StoredPanel } from './grid-panels-state'
import {
GridHorizontalExtraPadding,
Expand Down Expand Up @@ -55,7 +59,6 @@ export const GridPanelsContainer = React.memo(() => {

const canDrop = React.useCallback(
(itemToMove: StoredPanel, newPosition: LayoutUpdate) => {
return true // for now, just enable all drop areas while we are tweaking the behavior
const wouldBePanelState = updateLayout(panelState, itemToMove, newPosition)
const wouldBePanelStateEqualsCurrentPanelState = panelState.every((column, colIndex) =>
column.panels.every(
Expand Down Expand Up @@ -116,6 +119,7 @@ export const GridPanelsContainer = React.memo(() => {
style={{ position: 'absolute', gridColumn: 'canvas / span 1', gridRow: '1 / -1' }}
/>
{/* All future Panels need to be explicitly listed here */}
<CanvasPaneDragTargets onDrop={onDrop} canDrop={canDrop} />
{nonEmptyColumns.map((columnIndex) => (
<React.Fragment key={columnIndex}>
<GridColumnResizeHandle
Expand Down
101 changes: 101 additions & 0 deletions editor/src/components/canvas/grid-panels-drag-targets.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import type { LayoutUpdate, StoredPanel } from './grid-panels-state'
import {
ExtraHorizontalDropTargetPadding,
GridPanelHorizontalGapHalf,
IndexOfCanvas,
ResizeColumnWidth,
wrapAroundColIndex,
} from './grid-panels-state'
Expand Down Expand Up @@ -118,6 +119,106 @@ export const ColumnDragTargets = React.memo(
},
)

export const CanvasPaneDragTargets = React.memo(
(props: {
canDrop: (itemToMove: StoredPanel, newPosition: LayoutUpdate) => void
onDrop: (itemToMove: StoredPanel, newPosition: LayoutUpdate) => void
}) => {
const { onDrop, canDrop } = props
const { isDragActive, draggedPanel } = useGridPanelDragInfo()

const dropBeforeColumn: LayoutUpdate = React.useMemo(
() => ({
type: 'before-column',
columnIndex: IndexOfCanvas - 1,
}),
[],
)

const dropAfterColumn: LayoutUpdate = React.useMemo(
() => ({
type: 'after-column',
columnIndex: IndexOfCanvas - 1,
}),
[],
)

const canDropBefore = draggedPanel != null && canDrop(draggedPanel, dropBeforeColumn)
const canDropAfter = draggedPanel != null && canDrop(draggedPanel, dropAfterColumn)

const { drop: dropBefore, isOver: isOverBefore } = useGridPanelDropArea(
React.useCallback(
(itemToMove: StoredPanel) => onDrop(itemToMove, dropBeforeColumn),
[onDrop, dropBeforeColumn],
),
)

const { drop: dropAfter, isOver: isOverAfter } = useGridPanelDropArea(
React.useCallback(
(itemToMove: StoredPanel) => {
onDrop(itemToMove, dropAfterColumn)
},
[onDrop, dropAfterColumn],
),
)

return (
<>
<div
ref={dropBefore}
style={{
position: 'absolute',
pointerEvents: 'initial',
gridRowStart: 1,
gridRowEnd: -1,
gridColumn: `canvas / span 1`,
display: isDragActive && canDropBefore ? 'block' : 'none',
width: '50%',
height: '100%',
left: 0,
}}
>
<div
style={{
display: isOverBefore ? 'block' : 'none',
position: 'absolute',
left: -1,
width: 2,
height: '100%',
backgroundColor: colorTheme.primary.value,
}}
/>
</div>
<div
ref={dropAfter}
style={{
position: 'absolute',
pointerEvents: 'initial',
gridRowStart: 1,
gridRowEnd: -1,
gridColumn: `canvas / span 1`,
display: isDragActive && canDropAfter ? 'block' : 'none',
width: '50%',
height: '100%',
right: 0,
}}
>
<div
style={{
display: isOverAfter ? 'block' : 'none',
position: 'absolute',
right: -1,
width: 2,
height: '100%',
backgroundColor: colorTheme.primary.value,
}}
/>
</div>
</>
)
},
)

export const GridColumnResizeHandle = React.memo(
(props: {
columnIndex: number
Expand Down
86 changes: 73 additions & 13 deletions editor/src/components/canvas/grid-panels-state.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@ import {
} from '../inspector/common/inspector-utils'
import invariant from '../../third-party/remix/invariant'
import { useKeepShallowReferenceEquality } from '../../utils/react-performance'
import { atom, useAtom, useAtomValue } from 'jotai'
import { atom, useAtom, useAtomValue, useSetAtom, useStore } from 'jotai'
import immutableUpdate from 'immutability-helper'
import { deepFreeze } from '../../utils/deep-freeze'

export const GridMenuWidth = 268
export const GridMenuMinWidth = 200
Expand All @@ -23,9 +24,9 @@ export const NumberOfColumns = 4
export const IndexOfCanvas = 2

export const GridPanelVerticalGapHalf = 6
export const GridVerticalExtraPadding = 4
export const GridVerticalExtraPadding = -4
export const GridPanelHorizontalGapHalf = 6
export const GridHorizontalExtraPadding = 4
export const GridHorizontalExtraPadding = -4

export const ExtraHorizontalDropTargetPadding = 45

Expand Down Expand Up @@ -160,6 +161,8 @@ export function updateLayout(
const panelToInsert = storedPanel(paneToMove)

function insertPanel(layout: StoredLayout) {
deepFreeze(layout)

if (update.type === 'before-column' || update.type === 'after-column') {
const atLeastOneEmptyColumn = layout.some((col) => col.panels.length === 0)
if (!atLeastOneEmptyColumn) {
Expand Down Expand Up @@ -189,23 +192,21 @@ export function updateLayout(
const working = [...layout]

// insert
working[update.columnIndex].panels = insert(
update.indexInColumn,
panelToInsert,
working[update.columnIndex].panels,
)
working[update.columnIndex] = {
...working[update.columnIndex],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extracting out the existing value into a variable would probably make this a little cleaner.

panels: insert(update.indexInColumn, panelToInsert, working[update.columnIndex].panels),
}

return removeOldPanel(working)
}
if (update.type === 'after-index') {
const working = [...layout]

// insert
working[update.columnIndex].panels = insert(
update.indexInColumn + 1,
panelToInsert,
working[update.columnIndex].panels,
)
working[update.columnIndex] = {
...working[update.columnIndex],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extracting out the existing value into a variable would probably make this a little cleaner.

panels: insert(update.indexInColumn + 1, panelToInsert, working[update.columnIndex].panels),
}

return removeOldPanel(working)
}
Expand Down Expand Up @@ -259,6 +260,65 @@ export function updateLayout(
return withEmptyColumnsInMiddle
}

export function useUpdateGridPanelLayout(): (panelName: PanelName, update: LayoutUpdate) => void {
const setStoredState = useSetAtom(GridPanelsStateAtom)

return React.useCallback(
(panelName: PanelName, update: LayoutUpdate) => {
setStoredState((stored) => {
const paneToMove: StoredPanel = (() => {
for (const column of stored) {
for (const panel of column.panels) {
if (panel.name === panelName) {
return panel
}
}
}
throw new Error(`Invariant error: we should have found a panel by now: '${panelName}'`)
})()
return updateLayout(stored, paneToMove, update)
})
},
[setStoredState],
)
}

export function useUpdateGridPanelLayoutPutCodeEditorBelowNavigator(): () => void {
const setStoredState = useSetAtom(GridPanelsStateAtom)

return React.useCallback(() => {
setStoredState((stored) => {
const codeEditorPane: StoredPanel = (() => {
for (const column of stored) {
for (const panel of column.panels) {
if (panel.name === 'code-editor') {
return panel
}
}
}
throw new Error('Invariant error: we should have found a code-editor panel by now')
})()
const update: LayoutUpdate = (() => {
for (let columnIndex = 0; columnIndex < stored.length; columnIndex++) {
const column = stored[columnIndex]
for (let indexInColumn = 0; indexInColumn < column.panels.length; indexInColumn++) {
const panel = column.panels[indexInColumn]
if (panel.name === 'navigator') {
return {
type: 'after-index',
columnIndex: columnIndex,
indexInColumn: indexInColumn,
}
}
}
}
throw new Error('Invariant error: we should have found a navigator panel by now')
})()
return updateLayout(stored, codeEditorPane, update)
})
}, [setStoredState])
}

export function useColumnWidths(): [
Array<number>,
(columnIndex: number, newWidth: number) => void,
Expand Down
8 changes: 6 additions & 2 deletions editor/src/components/navigator/navigator-drag-layer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ import React from 'react'
import { useDragLayer } from 'react-dnd'
import type { RegularNavigatorEntry } from '../editor/store/editor-state'
import { navigatorEntryToKey, regularNavigatorEntry } from '../editor/store/editor-state'
import type { NavigatorItemDragAndDropWrapperProps } from './navigator-item/navigator-item-dnd-container'
import {
NavigatorItemDragType,
type NavigatorItemDragAndDropWrapperProps,
} from './navigator-item/navigator-item-dnd-container'
import type { WindowPoint } from '../../core/shared/math-utils'
import { windowPoint, zeroPoint } from '../../core/shared/math-utils'
import { ItemLabel } from './navigator-item/item-label'
Expand Down Expand Up @@ -35,7 +38,8 @@ export const NavigatorDragLayer = React.memo(() => {
[item?.elementPath],
)

const hidden = item == null
const draggedItemIsNavigatorItem = item != null && item.type === NavigatorItemDragType
const hidden = !draggedItemIsNavigatorItem

const entryNavigatorDepth = useEditorState(
Substores.metadata,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,10 @@ export interface DragSelection {
index: number
}

export const NavigatorItemDragType = 'navigator-item-drag-item' as const

export interface NavigatorItemDragAndDropWrapperPropsBase {
type: typeof NavigatorItemDragType
index: number
entryDepth: number
appropriateDropTargetHint: DropTargetHint | null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ import {
ConditionalClauseNavigatorItemContainer,
ErrorNavigatorItemContainer,
NavigatorItemContainer,
NavigatorItemDragType,
SyntheticNavigatorItemContainer,
} from './navigator-item-dnd-container'
import { navigatorDepth } from '../navigator-utils'
Expand Down Expand Up @@ -317,6 +318,7 @@ export const NavigatorItemWrapper: React.FunctionComponent<
)

const navigatorItemProps: NavigatorItemDragAndDropWrapperPropsBase = {
type: NavigatorItemDragType,
index: props.index,
editorDispatch: dispatch,
entryDepth: entryDepth,
Expand Down
Loading