import { FC, useEffect, useId, useMemo, useState } from 'react'; import { CntrlColor } from '@cntrl-site/color'; import { getLayoutStyles, RichTextItem as TRichTextItem } from '@cntrl-site/sdk'; import JSXStyle from 'styled-jsx/style'; import { ItemProps } from '../Item'; import { useRichTextItem } from './useRichTextItem'; import { useCntrlContext } from '../../../provider/useCntrlContext'; import { useRichTextItemValues } from '../useRichTextItemValues'; import { useRegisterResize } from '../../../common/useRegisterResize'; import { getFontFamilyValue } from '../../../utils/getFontFamilyValue'; import { useExemplary } from '../../../common/useExemplary'; import { useItemAngle } from '../useItemAngle'; import { getStyleFromItemStateAndParams } from '../../../utils/getStyleFromItemStateAndParams'; import { useCurrentLayout } from '../../../common/useCurrentLayout'; import { useItemGeometry } from '../../../ItemGeometry/useItemGeometry'; import { RichTextGeometryController } from '../../../ItemGeometry/RichTextGeometryController'; import { RICH_TEXT_LAYOUT_PENDING_CLASS } from '../../../utils/RichTextConverter/RichTextConverter'; import { getHeadingTag } from '../../../utils/getHeadingTag'; export const RichTextItem: FC> = ({ item, sectionId, onResize, interactionCtrl, onVisibilityChange }) => { const reactId = useId(); const id = `${reactId}-richtext-${item.id}`; const [ref, setRef] = useState(null); const { layouts } = useCntrlContext(); const itemAngle = useItemAngle(item, sectionId); const { blur: itemBlur, wordSpacing: itemWordSpacing, letterSpacing: itemLetterSpacing, color: itemColor, fontSize, lineHeight, xSizing } = useRichTextItemValues(item, sectionId); const layoutValues: Record[] = [item.area, item.layoutParams]; const exemplary = useExemplary(); const { layoutId } = useCurrentLayout(); useRegisterResize(ref, onResize); const geometry = useItemGeometry(item.id, ref, RichTextGeometryController, { xSizing }); geometry?.setAngle(itemAngle!); const stateParams = interactionCtrl?.getState(['angle', 'blur', 'letterSpacing', 'wordSpacing', 'color']); const stateStyles = stateParams?.styles ?? {}; const transition = stateParams?.transition ?? 'none'; const textColor = useMemo(() => { const color = getStyleFromItemStateAndParams(stateParams?.styles?.color as string, itemColor); return color ? CntrlColor.parse(color) : undefined; }, [itemColor, stateStyles.color]); const angle = getStyleFromItemStateAndParams(stateStyles.angle, itemAngle); const blur = getStyleFromItemStateAndParams(stateStyles.blur, itemBlur); const letterSpacing = getStyleFromItemStateAndParams(stateStyles.letterSpacing, itemLetterSpacing); const wordSpacing = getStyleFromItemStateAndParams(stateStyles.wordSpacing, itemWordSpacing); const colorAlpha = textColor?.getAlpha(); const rangeStyles = layoutId ? item.layoutParams[layoutId]?.rangeStyles ?? [] : []; const rangeColors = rangeStyles.filter((style) => style.style === 'COLOR'); const hasVisibleRangeColors = rangeColors.some((color) => { const alpha = CntrlColor.parse(color.value!).getAlpha(); return alpha > 0; }); const isInteractive = colorAlpha !== 0 || hasVisibleRangeColors; const [content, styles] = useRichTextItem(item); const Wrapper = (getHeadingTag(item) ?? 'div') as 'div'; useEffect(() => { onVisibilityChange?.(isInteractive); }, [isInteractive, onVisibilityChange]); return ( <> {content} {styles} {`${getLayoutStyles(layouts, layoutValues, ([area, layoutParams]) => { const color = CntrlColor.parse(layoutParams.color); return (` .rich-text-wrapper-${item.id} { margin: 0; font-size: ${layoutParams.fontSize * 100}vw; line-height: ${layoutParams.lineHeight * 100}vw; letter-spacing: ${layoutParams.letterSpacing * 100}vw; word-spacing: ${layoutParams.wordSpacing * 100}vw; font-family: ${getFontFamilyValue(layoutParams.typeFace)}; font-weight: ${layoutParams.fontWeight}; font-style: ${layoutParams.fontStyle ? layoutParams.fontStyle : 'normal'}; vertical-align: ${layoutParams.verticalAlign}; font-variant: ${layoutParams.fontVariant}; color: ${color.fmt('rgba')}; transform: rotate(${area.angle}deg); filter: ${layoutParams.blur !== 0 ? `blur(${layoutParams.blur * 100}vw)` : 'unset'}; text-transform: ${layoutParams.textTransform}; ${layoutParams.blur !== 0 ? 'will-change: transform;' : ''} } @supports not (color: oklch(42% 0.3 90 / 1)) { .rich-text-wrapper-${item.id} { color: ${color.fmt('rgba')}; } } `); })}`} ); };