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

feat(*): add view connection #35

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 43 additions & 7 deletions app/View.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
import React, { useState, useRef, useMemo, useEffect } from 'react'
import React, {
useState,
useRef,
useMemo,
useEffect,
useReducer,
useCallback,
} from 'react'
import './style/view.scss'
import { View as ViewType, EditorState, Vector, Path, Component } from './types'
import { useSelector, useDispatch } from 'react-redux'
import { useGesture } from 'react-use-gesture'
Expand All @@ -11,14 +19,14 @@ import {
useIsSelectedPath,
rootTree,
} from './utils'
import { ResizableBox } from 'react-resizable'
import {
resizeView,
dragView,
dragToView,
modifyInput,
removeInput,
selectComponent,
connectRelation,
} from './appShell'
import { Box, Text, Input } from '@modulz/radix'
import EditingMould from './EditingMould'
Expand All @@ -45,9 +53,17 @@ const Moveable = dynamic(() => import('react-moveable'), {

const ViewContextProvider = ViewContext.Provider

export const View = ({ viewId }: { viewId: string }) => {
export const View = ({
viewId,
onMove,
}: {
viewId: string
onMove: ({ isMoving }) => void
}) => {
const dispatch = useDispatch()
const { views, testWorkspace } = useSelector((state: EditorState) => state)
const { views, testWorkspace, connectingRelation, selection } = useSelector(
(state: EditorState) => state
)
const view = views[viewId]
const { mouldId, state, x, y, width, height } = view
const { moulds } = useSelector((state: EditorState) => state)
Expand Down Expand Up @@ -126,6 +142,8 @@ export const View = ({ viewId }: { viewId: string }) => {
setReady(true)
}, [viewRef.current])

const relation = connectingRelation

return (
<>
{selected && ready && (
Expand Down Expand Up @@ -169,6 +187,9 @@ export const View = ({ viewId }: { viewId: string }) => {
})
)
}}
onDragStart={() => {
onMove({ isMoving: true })
}}
onDrag={({ target, left, top }) => {
target.style.left = left + 'px'
target.style.top = top + 'px'
Expand All @@ -181,13 +202,12 @@ export const View = ({ viewId }: { viewId: string }) => {
y: parseFloat(target.style.top),
})
)
onMove({ isMoving: false })
}}
elementGuidelines={otherViews.map((v) =>
document.getElementById(`view-${v}`)
)}
style={{
pointerEvents: !paused ? 'none' : 'auto',
}}
style={{ pointerEvents: !paused ? 'none' : 'auto' }}
></Moveable>
<DebugPanel.Source>
<div
Expand Down Expand Up @@ -351,6 +371,22 @@ export const View = ({ viewId }: { viewId: string }) => {
}
}}
>
{selection &&
['top', 'left', 'right', 'bottom'].map((position) => (
<div
className={`archer-trigger ${position} ${
relation[0].view === viewId &&
relation[0].position === position
? 'active'
: 'inactive'
} ${selected ? 'selected' : ''}`}
onClick={() => {
dispatch(
connectRelation({ viewId, position })
)
}}
></div>
))}
<div
style={{
cursor: 'grab',
Expand Down
131 changes: 97 additions & 34 deletions app/Workspaces.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import React, { useState, useRef, DOMElement, useEffect } from 'react'
import React, { useState } from 'react'
import { TransformComponent, TransformWrapper } from 'react-zoom-pan-pinch'
import { Box } from '@modulz/radix'
import { Workspace as WorkspaceType, EditorState, Vector } from './types'
import { ArcherContainer, ArcherElement } from 'react-archer'
import { createAction, handleAction } from 'redux-actions'
import { initialData } from './utils'
import { useDispatch, useSelector } from 'react-redux'
Expand Down Expand Up @@ -50,10 +51,9 @@ export const handleZoomWorkspace = handleAction<

export const Workspace = ({ views, x, y, id, zoom = 1 }: WorkspaceType) => {
const dispatch = useDispatch()
const creating = useSelector((state: EditorState) => {
return state.creating
})

const { views: viewMap, creating, viewRelationsMap } = useSelector(
(state: EditorState) => state
)
const creation = creating && creating.view
const [xy, setXY] = useState([x, y])
const bind = useGesture({
Expand Down Expand Up @@ -90,8 +90,61 @@ export const Workspace = ({ views, x, y, id, zoom = 1 }: WorkspaceType) => {

const [viewCacheKey, setViewCacheKey] = useState('')

const [archerStyleState, setArcherStyle] = useState({
display: 'block',
} as React.CSSProperties)

const getArcherStyle = ({ isMoving }) => {
const style = isMoving
? ({
display: 'none',
} as React.CSSProperties)
: ({
display: 'block',
} as React.CSSProperties)

setArcherStyle(style)
}

const vs = Object.values(views).map((viewId) => {
return <View key={`${viewId}-${viewCacheKey}`} viewId={viewId}></View>
const { width, height, x, y } = viewMap[viewId]
const relations = viewRelationsMap[viewId]

return (
<>
<div style={{ position: 'absolute', zIndex: 1 }}>
<ArcherElement
id={`archer-${viewId}`}
relations={relations}
style={{
position: 'absolute',
width,
height,
left: x,
top: y,
}}
>
<div
style={{
position: 'absolute',
width: 0,
height: 0,
left: -1 * x,
top: -1 * y,
}}
>
<View
onMove={({ isMoving }) =>
getArcherStyle({ isMoving })
}
key={`${viewId}-${viewCacheKey}`}
viewId={viewId}
></View>
</div>
</ArcherElement>
</div>
</>
)
})

return (
Expand All @@ -117,9 +170,13 @@ export const Workspace = ({ views, x, y, id, zoom = 1 }: WorkspaceType) => {
limitsOnWheel: false,
step: 30,
}}
onWheelStart={() => {
getArcherStyle({ isMoving: true })
}}
onWheelStop={(e) => {
const zoom = e.scale

getArcherStyle({ isMoving: false })
setViewCacheKey(zoom)
zoomWorkspace({ zoom })
}}
Expand All @@ -134,34 +191,40 @@ export const Workspace = ({ views, x, y, id, zoom = 1 }: WorkspaceType) => {
tick((data = []) => data)
}}
>
<TransformComponent>
<div
style={{
position: 'inherit',
width: '100vw',
height: '100vh',
top: 0,
left: 0,
transform: `translate(${xy[0]}px,${xy[1]}px)`,
}}
>
{vs}
{creation && (
<Box
position="absolute"
bg="white"
style={{
left: creation.x,
top: creation.y,
width: creation.width,
height: creation.height,
}}
>
{/* <Mould editable {...mould} currentState={state}></Mould> */}
</Box>
)}
</div>
</TransformComponent>
<ArcherContainer
strokeColor="#aaa"
strokeWidth={2}
arrowLength={8}
arrowThickness={3}
svgContainerStyle={archerStyleState}
>
<TransformComponent>
<div
style={{
position: 'inherit',
width: '100vw',
height: '100vh',
top: 0,
left: 0,
transform: `translate(${xy[0]}px,${xy[1]}px)`,
}}
>
{vs}
{creation && (
<div
style={{
position: 'absolute',
left: creation.x,
top: creation.y,
width: creation.width,
height: creation.height,
background: '#fff',
}}
></div>
)}
</div>
</TransformComponent>
</ArcherContainer>
</Box>
</TransformWrapper>
)
Expand Down
72 changes: 72 additions & 0 deletions app/appShell.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
Kit,
StateName,
InputConfig,
ViewRelaion,
} from './types'
import { initialData, pathToString, viewPathToString } from './utils'
import nanoid from 'nanoid'
Expand Down Expand Up @@ -962,3 +963,74 @@ export const handleToggleViews = handleAction<EditorState, ToggleViewsAction>(
},
initialData
)

type AddViewRelationAction = {
viewId: string
relation: ViewRelaion
}

const ADD_VIEW_RELATION = 'ADD_VIEW_RELATION'
export const addViewRelation = createAction<AddViewRelationAction>(
ADD_VIEW_RELATION
)
export const handleAddViewRelation = handleAction<
EditorState,
AddViewRelationAction
>(
ADD_VIEW_RELATION,
(state, { payload: { viewId, relation } }) => {
if (!state.viewRelationsMap[viewId]) {
state.viewRelationsMap[viewId] = []
} else {
state.viewRelationsMap[viewId].push(relation)
}
return state
},
initialData
)

type ConnectRelation = {
viewId: string
position: string
}

const CONNECT_RELATION = 'CONNECT_RELATION'
export const connectRelation = createAction<ConnectRelation>(CONNECT_RELATION)
export const handleConnectRelation = handleAction<EditorState, ConnectRelation>(
CONNECT_RELATION,
(state, { payload: { viewId, position } }) => {
const [from, to] = state.connectingRelation

if (!from.view) {
state.connectingRelation = [{ view: viewId, position }]
} else {
if (from.view === viewId) {
state.connectingRelation = [
{ view: '', position: '' },
{ view: '', position: '' },
]
} else {
state.connectingRelation = [
...state.connectingRelation,
{ view: viewId, position },
]

if (!state.viewRelationsMap[from.view]) {
state.viewRelationsMap[from.view] = []
}
state.viewRelationsMap[from.view].push({
targetId: `archer-${viewId}`,
sourceAnchor: from.position,
targetAnchor: position,
})

state.connectingRelation = [
{ view: '', position: '' },
{ view: '', position: '' },
]
}
}
return state
},
initialData
)
Loading