feat: WYSIWYG 빌더 1차 기능 완성 및 테스트 추가
Auto PR / open-pr (push) Successful in 20s
Auto Label PR / add-automerge-label (pull_request) Successful in 7s
CI / test (pull_request) Successful in 1m34s

This commit is contained in:
2025-11-17 10:04:01 +09:00
parent 9ced249015
commit 1c607f6331
13 changed files with 660 additions and 28 deletions
+41 -1
View File
@@ -1,4 +1,4 @@
import React, { useState } from 'react'
import React, { useEffect, useState } from 'react'
import type { WObject } from '@/lib/wysiwyg/schema'
export type PropsPanelProps = {
@@ -15,9 +15,21 @@ function isImage(o: WObject): o is Extract<WObject, { type: 'image' }> {
return o.type === 'image'
}
function isText(o: WObject): o is Extract<WObject, { type: 'text' }> {
return o.type === 'text'
}
function isButton(o: WObject): o is Extract<WObject, { type: 'button' }> {
return o.type === 'button'
}
export function PropsPanel({ object, onChange }: PropsPanelProps) {
const [model, setModel] = useState<WObject>(object)
useEffect(() => {
setModel(object)
}, [object])
const emit = (next: WObject) => {
setModel(next)
onChange?.(next)
@@ -32,6 +44,16 @@ export function PropsPanel({ object, onChange }: PropsPanelProps) {
const next: WObject = { ...model, props: { ...model.props, ...patch } }
emit(next)
}
const updateTextProps = (patch: Partial<{ text: string }>): void => {
if (!isText(model)) return
const next: WObject = { ...model, props: { ...model.props, ...patch } }
emit(next)
}
const updateButtonProps = (patch: Partial<{ label: string }>): void => {
if (!isButton(model)) return
const next: WObject = { ...model, props: { ...model.props, ...patch } }
emit(next)
}
return (
<div aria-label="Properties Panel">
@@ -58,6 +80,24 @@ export function PropsPanel({ object, onChange }: PropsPanelProps) {
</label>
</div>
{isText(model) && (
<div>
<label>
Text
<input aria-label="Text" type="text" value={model.props.text} onChange={(e) => updateTextProps({ text: e.target.value })} />
</label>
</div>
)}
{isButton(model) && (
<div>
<label>
Label
<input aria-label="Label" type="text" value={model.props.label} onChange={(e) => updateButtonProps({ label: e.target.value })} />
</label>
</div>
)}
{isImage(model) && (
<div>
<label>