Skip to content

Commit

Permalink
Extract canvas prop instantiation to its own hook
Browse files Browse the repository at this point in the history
Now that we have components and slots, there's a bit more complexity
to how we handle things like canvas selection and rendering. So, this
breaks this logic out into a standalone hook to make things more clear
around what's happening.

Refactor to prep for #487
Related to #467
  • Loading branch information
johno committed Jul 15, 2022
1 parent 084d6bb commit e2bd4fb
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 61 deletions.
5 changes: 5 additions & 0 deletions .changeset/shy-adults-turn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@compai/css-gui': patch
---

Internal refactor for canvas prop instantiation
81 changes: 81 additions & 0 deletions packages/gui/src/components/html/CanvasProvider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { createContext, ReactNode, useContext } from 'react'
import { toCSSObject } from '../../lib/codegen/to-css-object'
import { toReactProps } from '../../lib/codegen/to-react-props'
import { useTheme } from '../providers/ThemeContext'
import { useHtmlEditor } from './Provider'
import { ElementPath, HtmlNode } from './types'
import { cleanAttributesForCanvas, isSamePath } from './util'

const DEFAULT_CANVAS_VALUE = {}
const DEFAULT_ELEMENT_STYLES_IN_CANVAS = {
cursor: 'default',
}

type CanvasProviderType = {
canvas?: boolean
}

export function useCanvas() {
const context = useContext(CanvasContext)
return context
}

type UseCanvasPropsArguments = {
path: ElementPath
value: HtmlNode
}

export function useCanvasProps({ path, value }: UseCanvasPropsArguments) {
const { canvas } = useContext(CanvasContext)
const { selected, setSelected } = useHtmlEditor()
const theme = useTheme()

const { attributes = {}, style = {} } = value

const sx = toCSSObject(
{
...(canvas ? DEFAULT_ELEMENT_STYLES_IN_CANVAS : {}),
...style,
},
theme
)

if (isSamePath(path, selected) && canvas) {
sx.outlineWidth = 'thin'
sx.outlineStyle = 'solid'
sx.outlineColor = 'primary'
sx.outlineOffset = '4px'
sx.userSelect = 'none'
}

const handleSelect = (e: MouseEvent) => {
if (!canvas) {
return
}

e.stopPropagation()
setSelected(path)
}

const props = toReactProps({
...(canvas ? cleanAttributesForCanvas(attributes) : attributes),
sx,
onClick: handleSelect,
})

return props
}

const CanvasContext = createContext<CanvasProviderType>(DEFAULT_CANVAS_VALUE)

type CanvasProviderProps = CanvasProviderType & {
children: ReactNode
}

export function CanvasProvider({ children, canvas }: CanvasProviderProps) {
return (
<CanvasContext.Provider value={{ canvas }}>
{children}
</CanvasContext.Provider>
)
}
75 changes: 14 additions & 61 deletions packages/gui/src/components/html/Renderer.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
import { toCSSObject } from '../../lib'
import { ElementPath, HtmlNode, Slot } from './types'
import { HTMLFontTags } from './FontTags'
import { useHtmlEditor } from './Provider'
import { isVoidElement } from '../../lib/elements'
import { isSamePath } from './util'
import { useTheme } from '../providers/ThemeContext'
import { transformValueToSchema } from '../../components/html/Provider'
import { toReactProps } from '../../lib/codegen/to-react-props'
import { ComponentProvider, useComponent } from './ComponentProvider'
import { CanvasProvider, useCanvasProps } from './CanvasProvider'

interface HtmlRendererProps {
value: HtmlNode
Expand All @@ -16,69 +12,36 @@ interface HtmlRendererProps {
}
export function HtmlRenderer({ value, canvas = true }: HtmlRendererProps) {
const transformedVal = transformValueToSchema(value)

return (
<>
<HTMLFontTags htmlTree={transformedVal} />
<ElementRenderer
value={transformedVal}
canvas={canvas}
path={[] as ElementPath}
/>
</>
<CanvasProvider canvas={canvas}>
<>
<HTMLFontTags htmlTree={transformedVal} />
<ElementRenderer
value={transformedVal}
canvas={canvas}
path={[] as ElementPath}
/>
</>
</CanvasProvider>
)
}

const DEFAULT_ELEMENT_STYLES_IN_CANVAS = {
cursor: 'default',
}

interface ElementRendererProps {
value: HtmlNode
path: ElementPath
canvas: boolean
}
function ElementRenderer({ value, canvas, path }: ElementRendererProps) {
const { selected, setSelected } = useHtmlEditor()
const theme = useTheme()
const props = useCanvasProps({ value, path })

if (value.type === 'slot') {
return <SlotRenderer value={value} path={path} canvas={canvas} />
}

const { attributes = {}, style = {}, children = [] } = value
const { children = [] } = value
const Tag: any = value.tagName || 'div'

const sx = toCSSObject(
{
...(canvas ? DEFAULT_ELEMENT_STYLES_IN_CANVAS : {}),
...style,
},
theme
)

if (isSamePath(path, selected) && canvas) {
sx.outlineWidth = 'thin'
sx.outlineStyle = 'solid'
sx.outlineColor = 'primary'
sx.outlineOffset = '4px'
sx.userSelect = 'none'
}

const handleSelect = (e: MouseEvent) => {
if (!canvas) {
return
}

e.stopPropagation()
setSelected(path)
}

const props = toReactProps({
...(canvas ? cleanAttributes(attributes) : attributes),
sx,
onClick: handleSelect,
})

if (value.type === 'component') {
const fullValue = {
...value.value,
Expand Down Expand Up @@ -154,13 +117,3 @@ function SlotRenderer({ value: providedValue, canvas }: SlotRendererProps) {

return <>{propValue}</>
}

const cleanAttributes = (attributes: Record<string, string>) => {
const newAttributes = { ...attributes }

if (newAttributes.href) {
newAttributes.href = '#!'
}

return newAttributes
}
12 changes: 12 additions & 0 deletions packages/gui/src/components/html/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,18 @@ export const isSamePath = (
return path1.join('-') === path2.join('-')
}

export const cleanAttributesForCanvas = (
attributes: Record<string, string>
) => {
const newAttributes = { ...attributes }

if (newAttributes.href) {
newAttributes.href = '#!'
}

return newAttributes
}

export function getChildAtPath(element: HtmlNode, path: ElementPath): HtmlNode {
if (path.length === 0) {
return element
Expand Down

0 comments on commit e2bd4fb

Please sign in to comment.