Skip to content

Commit

Permalink
Multiplayer shadows (#4519)
Browse files Browse the repository at this point in the history
* fix user bar

* shadows (wip)

* readability

* better active frame, source shadow

* reuse

* zeroRectIfNullOrInfinity

* useSelectorWithCallback
  • Loading branch information
ruggi authored Nov 21, 2023
1 parent aca3ec6 commit 40ccc90
Show file tree
Hide file tree
Showing 14 changed files with 428 additions and 22 deletions.
13 changes: 10 additions & 3 deletions editor/liveblocks.config.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { LiveObject } from '@liveblocks/client'
import { createClient } from '@liveblocks/client'
import { LiveObject, createClient } from '@liveblocks/client'
import { createRoomContext } from '@liveblocks/react'
import type { CanvasVector, WindowPoint } from './src/core/shared/math-utils'
import { getProjectID } from './src/common/env-vars'
import type { ActiveFrameAction } from './src/components/canvas/commands/set-active-frames-command'
import type { CanvasRectangle, CanvasVector, WindowPoint } from './src/core/shared/math-utils'
import { projectIdToRoomId } from './src/core/shared/multiplayer'

export const liveblocksThrottle = 100 // ms
Expand All @@ -19,9 +19,16 @@ export type Presence = {
cursor: WindowPoint | null
canvasScale: number | null
canvasOffset: CanvasVector | null
activeFrames?: PresenceActiveFrame[]
following: string | null
}

export type PresenceActiveFrame = {
action: ActiveFrameAction
frame: CanvasRectangle
source: CanvasRectangle
}

export function initialPresence(): Presence {
return {
cursor: null,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import { EdgePositionLeft, EdgePositionTop, EdgePositionTopLeft } from '../../ca
import { isEdgePositionEqualTo } from '../../canvas-utils'
import { pushIntendedBoundsAndUpdateGroups } from '../../commands/push-intended-bounds-and-update-groups-command'
import { queueTrueUpElement } from '../../commands/queue-true-up-command'
import { activeFrameTargetRect, setActiveFrames } from '../../commands/set-active-frames-command'
import { setCursorCommand } from '../../commands/set-cursor-command'
import { setElementsToRerenderCommand } from '../../commands/set-elements-to-rerender-command'
import { setSnappingGuidelines } from '../../commands/set-snapping-guidelines-command'
Expand Down Expand Up @@ -263,6 +264,13 @@ export function absoluteResizeBoundingBoxStrategy(
'starting-metadata',
),
queueTrueUpElement(childGroups.map(trueUpGroupElementChanged)),
setActiveFrames([
{
action: 'resize',
target: activeFrameTargetRect(newFrame),
source: originalBoundingBox,
},
]),
]
})

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ import { MetadataUtils } from '../../../../core/model/element-metadata-utils'
import type { CanvasVector } from '../../../../core/shared/math-utils'
import {
canvasRectangle,
CanvasRectangle,
isInfinityRectangle,
offsetPoint,
rectContainsPoint,
zeroRectIfNullOrInfinity,
} from '../../../../core/shared/math-utils'
import { absolute } from '../../../../utils/utils'
import { CSSCursor } from '../../canvas-types'
Expand All @@ -20,13 +20,10 @@ import type {
InteractionCanvasState,
StrategyApplicationResult,
} from '../canvas-strategy-types'
import {
emptyStrategyApplicationResult,
getTargetPathsFromInteractionTarget,
strategyApplicationResult,
} from '../canvas-strategy-types'
import { emptyStrategyApplicationResult, strategyApplicationResult } from '../canvas-strategy-types'
import type { InteractionSession } from '../interaction-state'
import type { ElementInstanceMetadataMap } from '../../../../core/shared/element-template'
import { activeFrameTargetRect, setActiveFrames } from '../../commands/set-active-frames-command'

export function isReorderAllowed(siblings: Array<ElementPath>): boolean {
return siblings.every((sibling) => !isRootOfGeneratedElement(sibling))
Expand Down Expand Up @@ -81,12 +78,26 @@ export function applyReorderCommon(
isValidTarget,
)

const sourceFrame = zeroRectIfNullOrInfinity(
MetadataUtils.getFrameInCanvasCoords(target, canvasState.startingMetadata) ?? null,
)
const newIndexFound = newIndex > -1
const newResultOrLastIndex = newIndexFound ? newIndex : lastReorderIdx
const targetFrame = zeroRectIfNullOrInfinity(
newResultOrLastIndex > -1
? MetadataUtils.getFrameInCanvasCoords(
siblings[newResultOrLastIndex],
canvasState.startingMetadata,
)
: sourceFrame,
)

if (newResultOrLastIndex === unpatchedIndex) {
return strategyApplicationResult(
[
setActiveFrames([
{ action: 'reorder', target: activeFrameTargetRect(targetFrame), source: sourceFrame },
]),
updateHighlightedViews('mid-interaction', []),
setElementsToRerenderCommand(siblings),
setCursorCommand(CSSCursor.Move),
Expand All @@ -98,6 +109,9 @@ export function applyReorderCommon(
} else {
return strategyApplicationResult(
[
setActiveFrames([
{ action: 'reorder', target: activeFrameTargetRect(targetFrame), source: sourceFrame },
]),
reorderElement('always', target, absolute(newResultOrLastIndex)),
setElementsToRerenderCommand(siblings),
updateHighlightedViews('mid-interaction', []),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ import { withUnderlyingTarget } from '../../../editor/store/editor-state'
import type { ProjectContentTreeRoot } from '../../../assets'
import { getModifiableJSXAttributeAtPath } from '../../../../core/shared/jsx-attributes'
import { showToastCommand } from '../../commands/show-toast-command'
import { activeFrameTargetPath, setActiveFrames } from '../../commands/set-active-frames-command'

export const SetBorderRadiusStrategyId = 'SET_BORDER_RADIUS_STRATEGY'

Expand Down Expand Up @@ -157,6 +158,15 @@ export const setBorderRadiusStrategy: CanvasStrategyFactory = (
...commands(selectedElement),
...getAddOverflowHiddenCommands(selectedElement, canvasState.projectContents),
setElementsToRerenderCommand(selectedElements),
setActiveFrames(
selectedElements.map((path) => ({
action: 'set-radius',
target: activeFrameTargetPath(path),
source: zeroRectIfNullOrInfinity(
MetadataUtils.getFrameInCanvasCoords(path, canvasState.startingMetadata),
),
})),
),
]),
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import { styleStringInArray } from '../../../../utils/common-constants'
import { MetadataUtils } from '../../../../core/model/element-metadata-utils'
import type { CanvasVector } from '../../../../core/shared/math-utils'
import { canvasPoint, canvasVector } from '../../../../core/shared/math-utils'
import {
canvasPoint,
zeroRectIfNullOrInfinity,
canvasVector,
} from '../../../../core/shared/math-utils'
import { optionalMap } from '../../../../core/shared/optional-utils'
import { assertNever } from '../../../../core/shared/utils'
import type { Modifiers } from '../../../../utils/modifiers'
Expand Down Expand Up @@ -38,6 +42,7 @@ import {
import type { InteractionSession } from '../interaction-state'
import { areAllSiblingsInOneDimensionFlexOrFlow } from './flow-reorder-helpers'
import { colorTheme } from '../../../../uuiui'
import { activeFrameTargetPath, setActiveFrames } from '../../commands/set-active-frames-command'

export const SetFlexGapStrategyId = 'SET_FLEX_GAP_STRATEGY'

Expand Down Expand Up @@ -170,6 +175,15 @@ export const setFlexGapStrategy: CanvasStrategyFactory = (
),
setCursorCommand(cursorFromFlexDirection(flexGap.direction)),
setElementsToRerenderCommand([...selectedElements, ...children]),
setActiveFrames([
{
action: 'set-gap',
target: activeFrameTargetPath(selectedElement),
source: zeroRectIfNullOrInfinity(
MetadataUtils.getFrameInCanvasCoords(selectedElement, canvasState.startingMetadata),
),
},
]),
])
},
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ import {
adjustCssLengthProperties,
} from '../../commands/adjust-css-length-command'
import type { ElementPathTrees } from '../../../../core/shared/element-path-tree'
import { activeFrameTargetPath, setActiveFrames } from '../../commands/set-active-frames-command'

const StylePaddingProp = stylePropPathMappingFn('padding', styleStringInArray)
const IndividualPaddingProps: Array<CSSPaddingKey> = [
Expand Down Expand Up @@ -257,6 +258,15 @@ export const setPaddingStrategy: CanvasStrategyFactory = (canvasState, interacti
value,
),
),
setActiveFrames(
selectedElements.map((path) => ({
action: 'set-padding',
target: activeFrameTargetPath(path),
source: zeroRectIfNullOrInfinity(
MetadataUtils.getFrameInCanvasCoords(path, canvasState.startingMetadata),
),
})),
),
])
}

Expand All @@ -273,6 +283,15 @@ export const setPaddingStrategy: CanvasStrategyFactory = (canvasState, interacti
]),
),
setProperty('always', selectedElement, StylePaddingProp, paddingString),
setActiveFrames(
selectedElements.map((path) => ({
action: 'set-padding',
target: activeFrameTargetPath(path),
source: zeroRectIfNullOrInfinity(
MetadataUtils.getFrameInCanvasCoords(path, canvasState.startingMetadata),
),
})),
),
])
}

Expand All @@ -291,6 +310,15 @@ export const setPaddingStrategy: CanvasStrategyFactory = (canvasState, interacti
value,
),
),
setActiveFrames(
selectedElements.map((path) => ({
action: 'set-padding',
target: activeFrameTargetPath(path),
source: zeroRectIfNullOrInfinity(
MetadataUtils.getFrameInCanvasCoords(path, canvasState.startingMetadata),
),
})),
),
])
},
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,10 @@ import type {
ElementInstanceMetadataMap,
JSXElement,
} from '../../../../core/shared/element-template'
import type {
CanvasPoint,
CanvasRectangle,
CanvasVector,
LocalRectangle,
} from '../../../../core/shared/math-utils'
import type { CanvasPoint, CanvasRectangle, CanvasVector } from '../../../../core/shared/math-utils'
import {
boundingRectangleArray,
zeroRectIfNullOrInfinity,
canvasRectangleToLocalRectangle,
canvasVector,
nullIfInfinity,
Expand Down Expand Up @@ -70,6 +66,7 @@ import {
setCssLengthProperty,
setValueKeepingOriginalUnit,
} from '../../commands/set-css-length-command'
import { activeFrameTargetRect, setActiveFrames } from '../../commands/set-active-frames-command'

export interface MoveCommandsOptions {
ignoreLocalFrame?: boolean
Expand Down Expand Up @@ -134,6 +131,15 @@ export function applyMoveCommon(
updateHighlightedViews('mid-interaction', []),
setElementsToRerenderCommand(targets),
setCursorCommand(CSSCursor.Select),
setActiveFrames(
commandsForSelectedElements.intendedBounds.map((b) => ({
action: 'move', // TODO this could also show "duplicate" when applicable
target: activeFrameTargetRect(b.frame),
source: zeroRectIfNullOrInfinity(
MetadataUtils.getFrameInCanvasCoords(b.target, canvasState.startingMetadata),
),
})),
),
])
} else {
const constrainedDragAxis =
Expand Down Expand Up @@ -171,6 +177,15 @@ export function applyMoveCommon(
),
setElementsToRerenderCommand([...targets, ...targetsForSnapping]),
setCursorCommand(CSSCursor.Select),
setActiveFrames(
commandsForSelectedElements.intendedBounds.map((b) => ({
action: 'move', // TODO this could also show "duplicate" when applicable
target: activeFrameTargetRect(b.frame),
source: zeroRectIfNullOrInfinity(
MetadataUtils.getFrameInCanvasCoords(b.target, canvasState.startingMetadata),
),
})),
),
])
}
} else {
Expand Down
4 changes: 4 additions & 0 deletions editor/src/components/canvas/commands/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ import type { PushIntendedBoundsAndUpdateGroups } from './push-intended-bounds-a
import { runPushIntendedBoundsAndUpdateGroups } from './push-intended-bounds-and-update-groups-command'
import type { PushIntendedBoundsAndUpdateHuggingElements } from './push-intended-bounds-and-update-hugging-elements-command'
import { runPushIntendedBoundsAndUpdateHuggingElements } from './push-intended-bounds-and-update-hugging-elements-command'
import { runSetActiveFrames, type SetActiveFrames } from './set-active-frames-command'

export interface CommandFunctionResult {
editorStatePatches: Array<EditorStatePatch>
Expand Down Expand Up @@ -137,6 +138,7 @@ export type CanvasCommand =
| DeleteElement
| WrapInContainerCommand
| QueueTrueUpElement
| SetActiveFrames

export function runCanvasCommand(
editorState: EditorState,
Expand Down Expand Up @@ -219,6 +221,8 @@ export function runCanvasCommand(
return runWrapInContainerCommand(editorState, command)
case 'QUEUE_TRUE_UP_ELEMENT':
return runQueueTrueUpElement(editorState, command)
case 'SET_ACTIVE_FRAMES':
return runSetActiveFrames(editorState, command)
default:
const _exhaustiveCheck: never = command
throw new Error(`Unhandled canvas command ${JSON.stringify(command)}`)
Expand Down
Loading

0 comments on commit 40ccc90

Please sign in to comment.