// The Chat widget behavior controls, with the Stand app's names and help text. // Shared by the Chat widget screen and the block editor's Stand Chat panel. import { SelectControl, TextControl, TextareaControl, ToggleControl } from '@wordpress/components'; import { useState } from '@wordpress/element'; import { __ } from '@wordpress/i18n'; import { clampDelaySeconds, clampScrollPercent, greetingMode, triggerMode, withGreetingMode, withOpenOnDesktop, withTriggerMode, type GreetingMode, type TriggerMode, } from '../../shared/behavior.ts'; import type { BehaviorRule } from '../../shared/types.ts'; export function triggerLabel(mode: TriggerMode): string { return { onLoad: __('On load', 'stand-chat'), time: __('Time', 'stand-chat'), scroll: __('Scroll', 'stand-chat'), none: __('None', 'stand-chat'), }[mode]; } export function greetingLabel(mode: GreetingMode): string { return { default: __('Default greeting', 'stand-chat'), none: __('No greeting', 'stand-chat'), custom: __('Custom greeting', 'stand-chat'), }[mode]; } /** "On load · Default greeting · Half-sized", for rule summaries. */ export function ruleSummary(rule: BehaviorRule): string { const parts: string[] = []; const mode = triggerMode(rule); if (mode === 'time') parts.push(`${triggerLabel(mode)} ${Math.round(rule.trigger.delayMs / 1000)} s`); else if (mode === 'scroll') parts.push(`${triggerLabel(mode)} ${rule.trigger.scrollPercent}%`); else parts.push(triggerLabel(mode)); parts.push(greetingLabel(greetingMode(rule))); if (rule.presentation.halfSize) parts.push(__('Half-sized', 'stand-chat')); if (rule.presentation.stepAside) parts.push(__('Step aside', 'stand-chat')); if (rule.action.type === 'openChatAfterGreeting') parts.push(__('Opens on desktop', 'stand-chat')); return parts.join(' · '); } export function RuleControls({ rule, onChange, disabled = false, }: { rule: BehaviorRule; onChange: (rule: BehaviorRule) => void; disabled?: boolean; }) { const [custom, setCustom] = useState>(new Set()); const mode = triggerMode(rule); const greeting = greetingMode(rule, custom); return (
{__('Widget show trigger', 'stand-chat')}
{(['onLoad', 'time', 'scroll', 'none'] as TriggerMode[]).map((option) => ( ))}

{__('On load shows the widget when someone can answer. Time waits for the delay, Scroll for the scroll depth. None keeps it hidden until a Stand button or card opens chat.', 'stand-chat')}

{mode === 'time' && ( onChange({ ...rule, trigger: { ...rule.trigger, delayMs: clampDelaySeconds(value) * 1000 } })} /> )} {mode === 'scroll' && ( onChange({ ...rule, trigger: { ...rule.trigger, type: 'scrollDepth', scrollPercent: clampScrollPercent(value) } })} /> )} ({ value, label: greetingLabel(value) }))} onChange={(value) => { const next = value as GreetingMode; setCustom((current) => { const copy = new Set(current); if (next === 'custom') copy.add(rule.ruleId); else copy.delete(rule.ruleId); return copy; }); onChange(withGreetingMode(rule, next)); }} /> {greeting === 'custom' && ( onChange({ ...rule, action: { ...rule.action, initialMessage: value } })} /> )} onChange({ ...rule, presentation: { ...rule.presentation, halfSize: checked } })} /> onChange({ ...rule, presentation: { ...rule.presentation, stepAside: checked } })} /> onChange(withOpenOnDesktop(rule, checked))} />
); }