import React, { CSSProperties } from 'react'; import { useNode, UserComponent } from '@craftjs/core'; import { cssPropsToString } from '../../utils/style-helpers'; import { escapeHtml } from '../../utils/escape'; import { resolveInlineHtml } from '../../utils/inline-html'; import { useInlineEditable } from './useInlineEditable'; interface TextBlockProps { text?: string; /** Sanitised inline rich text (#46); '' = plain `text` only. */ html?: string; style?: CSSProperties; cssId?: string; cssClass?: string; hideOnDesktop?: boolean; hideOnTablet?: boolean; hideOnMobile?: boolean; animation?: string; animationDelay?: string; } export const TextBlock: UserComponent = ({ text = 'Start typing here...', html = '', style = {}, }) => { const { connectors: { connect, drag }, selected, actions: { setProp }, } = useNode((node) => ({ selected: node.events.selected, })); const { elRef, onBlur, onInput, onKeyDown } = useInlineEditable(text, html, selected, setProp); return (

{ elRef.current = ref; if (ref) connect(drag(ref)); }} contentEditable={selected} suppressContentEditableWarning onBlur={onBlur} onInput={onInput} onKeyDown={onKeyDown} style={{ outline: 'none', cursor: selected ? 'text' : 'pointer', minHeight: '1em', ...style, }} /> ); }; /* ---------- Craft config ---------- */ TextBlock.craft = { displayName: 'Text', props: { text: 'Start typing here...', html: '', style: { fontSize: '16px', lineHeight: '1.6', color: '#3f3f46', letterSpacing: '', textTransform: '' as CSSProperties['textTransform'], fontStyle: '' as CSSProperties['fontStyle'], textDecoration: '', marginTop: '', marginRight: '', marginBottom: '', marginLeft: '', paddingTop: '', paddingRight: '', paddingBottom: '', paddingLeft: '', border: 'none', boxShadow: 'none', opacity: '1', }, animation: '', animationDelay: '0', hideOnDesktop: false, hideOnTablet: false, hideOnMobile: false, }, rules: { canDrag: () => true, canMoveIn: () => false, canMoveOut: () => true, }, }; /* ---------- HTML export ---------- */ (TextBlock as any).toHtml = (props: TextBlockProps, _childrenHtml: string) => { const styleStr = cssPropsToString(props.style); const escapedText = resolveInlineHtml(props.text, props.html) ?? escapeHtml(props.text || ''); return { html: `${escapedText}

` }; };