/** @jsxImportSource react */ import { VDOM } from "../../ui/VDOM"; import type { Instance } from "../../ui/Instance"; import type { RenderingContext } from "../../ui/RenderingContext"; import { Widget, getContent } from "../../ui/Widget"; import { stopPropagation } from "../../util/eventCallbacks"; import { KeyCode } from "../../util/KeyCode"; import CheckIcon from "../icons/check"; import SquareIcon from "../icons/square"; import { tooltipMouseLeave, tooltipMouseMove } from "../overlay/tooltip-ops"; import { Field, FieldConfig, getFieldTooltip, FieldInstance } from "./Field"; import { BooleanProp, Prop, StringProp } from "../../ui/Prop"; export interface CheckboxConfig extends FieldConfig { /** Value of the checkbox. */ value?: Prop; /** Set to `true` to make the checkbox read-only. */ readOnly?: BooleanProp; /** Base CSS class to be applied to the element. Defaults to `checkbox`. */ baseClass?: string; /** Use native checkbox HTML element. */ native?: boolean; /** Set to `true` to display a square icon to indicate `null` or `undefined` value. */ indeterminate?: boolean; /** Checked value alias for `value`. */ checked?: Prop; /** Text description. */ text?: StringProp; /** Set to true to disable focusing on the checkbox. Used in grids to avoid conflicts. */ unfocusable?: boolean; /** View mode text. */ viewText?: StringProp; /** Custom validation function. */ onValidate?: | string | (( value: boolean, instance: Instance, validationParams: Record, ) => unknown); } export class Checkbox extends Field { declare public baseClass: string; declare public checked?: unknown; declare public value?: unknown; declare public indeterminate?: boolean; declare public unfocusable?: boolean; declare public native?: boolean; constructor(config?: CheckboxConfig) { super(config); } init(): void { if (this.checked) this.value = this.checked; super.init(); } declareData(...args: Record[]): void { super.declareData( { value: !this.indeterminate ? false : undefined, text: undefined, readOnly: undefined, disabled: undefined, enabled: undefined, required: undefined, viewText: undefined, }, ...args, ); } renderWrap( context: RenderingContext, instance: FieldInstance, key: string, content: React.ReactNode, ): React.ReactElement { let { data } = instance; return ( ); } validateRequired( context: RenderingContext, instance: FieldInstance, ): string | undefined { let { data } = instance; if (!data.value) return this.requiredText; } renderNativeCheck( context: RenderingContext, instance: FieldInstance, ): React.ReactElement { let { CSS, baseClass } = this; let { data } = instance; return ( { this.handleChange( e, instance, (e.target as HTMLInputElement).checked, ); }} /> ); } renderCheck( context: RenderingContext, instance: FieldInstance, ): React.ReactElement { return ; } renderInput( context: RenderingContext, instance: FieldInstance, key: string, ): React.ReactElement { let { data } = instance; let text = data.text || this.renderChildren?.(context, instance); let { CSS, baseClass } = this; return this.renderWrap(context, instance, key, [ this.native ? this.renderNativeCheck(context, instance) : this.renderCheck(context, instance), text ? (
{text}
) : (   ), ]); } renderValue( context: RenderingContext, instance: FieldInstance, ): React.ReactNode { let { data } = instance; if (!data.viewText) return super.renderValue(context, instance, undefined); return ( {data.viewText} ); } formatValue( context: RenderingContext, instance: Instance, ): React.ReactNode | string { let { data } = instance; return ( data.value && (data.text || this.renderChildren?.(context, instance)) ); } handleClick(e: React.MouseEvent, instance: Instance): void { if (this.native) e.stopPropagation(); else { var el = document.getElementById(instance.data.id); if (el) el.focus(); if (!instance.data.viewMode) { e.preventDefault(); e.stopPropagation(); this.handleChange(e, instance, !instance.data.value); } } } handleChange( e: React.ChangeEvent | React.MouseEvent, instance: Instance, checked?: boolean, ): void { let { data } = instance; if (data.readOnly || data.disabled || data.viewMode) return; instance.set( "value", checked != null ? checked : (e.target as HTMLInputElement).checked, ); } } Checkbox.prototype.baseClass = "checkbox"; Checkbox.prototype.native = false; Checkbox.prototype.indeterminate = false; Checkbox.prototype.unfocusable = false; Widget.alias("checkbox", Checkbox); interface CheckboxCmpProps { key?: string; instance: FieldInstance; data: Record; } interface CheckboxCmpState { value: unknown; } class CheckboxCmp extends VDOM.Component { constructor(props: CheckboxCmpProps) { super(props); this.state = { value: props.data.value, }; } UNSAFE_componentWillReceiveProps(props: CheckboxCmpProps) { this.setState({ value: props.data.value, }); } render(): React.ReactElement { let { instance, data } = this.props; let { widget } = instance; let { baseClass, CSS } = widget; let check: string | boolean = false; if (this.state.value == null && widget.indeterminate) check = "indeterminate"; else if (this.state.value) check = "check"; return ( {check == "check" && ( )} {check == "indeterminate" && ( )} ); } onClick(e: React.MouseEvent): void { let { instance, data } = this.props; let { widget } = instance; if (!data.disabled && !data.readOnly) { e.stopPropagation(); e.preventDefault(); this.setState({ value: !this.state.value }); widget.handleChange(e, instance, !this.state.value); } } onKeyDown(e: React.KeyboardEvent): void { let { instance } = this.props; const { widget } = instance; if ( widget.handleKeyDown && widget.handleKeyDown( e as unknown as React.KeyboardEvent, instance, ) === false ) return; switch (e.keyCode) { case KeyCode.space: this.onClick(e as unknown as React.MouseEvent); break; } } }