Skip to content

Instantly share code, notes, and snippets.

@jacques-blom
Last active May 4, 2023 14:37
Show Gist options
  • Save jacques-blom/54bbc7773422c040f0ea218ef492eaca to your computer and use it in GitHub Desktop.
Save jacques-blom/54bbc7773422c040f0ea218ef492eaca to your computer and use it in GitHub Desktop.
Atom Families
import {createContext, useState} from 'react'
import {Element, Rectangle} from './components/Rectangle/Rectangle'
import {PageContainer} from './PageContainer'
import {Toolbar} from './Toolbar'
type ElementsContextType = {
elements: Element[]
addElement: () => void
setElement: SetElement
}
export const ElementsContext = createContext<ElementsContextType>({
elements: [],
addElement: () => {},
setElement: () => {},
})
type SelectedElementContextType = {
selectedElement: number | null
setSelectedElement: (index: number) => void
}
export const SelectedElementContext = createContext<SelectedElementContextType>({
selectedElement: null,
setSelectedElement: () => {},
})
export type SetElement = (indexToSet: number, newElement: Element) => void
function Canvas() {
const [elements, setElements] = useState<Element[]>([])
const [selectedElement, setSelectedElement] = useState<number | null>(null)
const setElement: SetElement = (indexToSet, newElement) => {
setElements(
elements.map((element, index) => {
if (indexToSet === index) return newElement
return element
}),
)
}
const addElement = () => {
setElements((elements) => {
return [
...elements,
{
style: {
position: {top: 100 + elements.length * 30, left: 100 + elements.length * 30},
size: {width: 100, height: 100},
},
},
]
})
}
return (
<SelectedElementContext.Provider value={{selectedElement, setSelectedElement}}>
<ElementsContext.Provider value={{elements, addElement, setElement}}>
<PageContainer
onClick={() => {
setSelectedElement(null)
}}
>
<Toolbar />
{elements.map((element, index) => (
<Rectangle key={index} element={element} index={index} />
))}
</PageContainer>
</ElementsContext.Provider>
</SelectedElementContext.Provider>
)
}
export default Canvas
import {useContext} from 'react'
import {ElementsContext, SelectedElementContext} from '../../Canvas'
import {Drag} from '../Drag'
import {RectangleContainer} from './RectangleContainer'
import {RectangleInner} from './RectangleInner'
export type ElementStyle = {
position: {top: number; left: number}
size: {width: number; height: number}
}
export type Element = {style: ElementStyle}
export const Rectangle = ({element, index}: {element: Element; index: number}) => {
const {selectedElement, setSelectedElement} = useContext(SelectedElementContext)
const {setElement} = useContext(ElementsContext)
return (
<Drag
position={element.style.position}
onDrag={(position) => {
setElement(index, {
style: {
...element.style,
position,
},
})
}}
>
<div>
<RectangleContainer
position={element.style.position}
size={element.style.size}
onSelect={() => {
setSelectedElement(index)
}}
>
<RectangleInner selected={index === selectedElement} />
</RectangleContainer>
</div>
</Drag>
)
}
import {Icon, IconButton, VStack} from '@chakra-ui/react'
import {useContext} from 'react'
import {Square} from 'react-feather'
import {ElementsContext} from './Canvas'
export const Toolbar = () => {
const {addElement} = useContext(ElementsContext)
return (
<VStack
position="absolute"
top="20px"
left="20px"
backgroundColor="white"
padding={2}
boxShadow="md"
borderRadius="md"
spacing={2}
>
<IconButton
onClick={addElement}
aria-label="Add rectangle"
icon={<Icon style={{width: 24, height: 24}} as={Square} />}
/>
</VStack>
)
}
@mahdisoultana
Copy link

thank you very much jackes for this help , really appreciate it !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment