Skip to main content
Glama
deleonio
by deleonio
text-formatter.tsx5.4 kB
import { KolForm, KolInputText } from '@public-ui/react-v19'; import React, { useMemo, useRef, type BaseSyntheticEvent } from 'react'; import { Controller, useForm } from 'react-hook-form'; import { SampleDescription } from '../SampleDescription'; type InputTextElementSelection = { setSelectionStart?: (position: number) => Promise<void>; selectionStart?: () => Promise<number | null>; }; type KolInputTextEvents = { onBlur?: (event: Event) => void; onChange?: (event: Event, value: unknown) => void; onFocus?: (event: Event) => void; onInput?: (event: Event, value: unknown) => void; }; type KolInputTextProps = Omit<React.ComponentProps<typeof KolInputText>, '_on' | '_value'> & { _on?: KolInputTextEvents; _value?: string; }; const NON_ALPHANUM = /[^a-zA-Z0-9]/g; const EVERY_FOUR_CHARS = /(.{4})(?!$)/g; class IbanFormatter { private electronicFormat(iban: string): string { return iban.replace(NON_ALPHANUM, '').toUpperCase(); } private printFormat(iban: string, separator?: string) { return this.electronicFormat(iban).replace(EVERY_FOUR_CHARS, '$1' + (separator || ' ')); } public parse(value: string): string { return this.electronicFormat(value); } public format(value: string, ref?: HTMLKolInputTextElement | null, selectionStart?: number | null): string { const setSelectionStart = (ref as InputTextElementSelection | null)?.setSelectionStart; if (selectionStart && setSelectionStart) { if (selectionStart % 5 === 0) selectionStart++; void setSelectionStart(selectionStart); } return this.printFormat(value); } } type IbanExampleFormValues = { iban: string; }; function FormattedKolInputText({ formatter, selectionStartRef, _on, _value, ...props }: KolInputTextProps & { formatter: IbanFormatter; selectionStartRef: React.MutableRefObject<number | null>; }) { const inputRef = useRef<HTMLKolInputTextElement | null>(null); const normalizedOn = _on && typeof _on === 'object' ? (_on as KolInputTextEvents) : undefined; const sanitizedSelectionRef = selectionStartRef as React.MutableRefObject<number | null>; const element = inputRef.current; const selectionStart = sanitizedSelectionRef.current; const sanitizedFormatter: IbanFormatter = formatter; return ( <KolInputText {...props} ref={inputRef} _value={sanitizedFormatter.format(_value ?? '', element, selectionStart)} _on={{ ...normalizedOn, onInput: (event: Event, value: unknown) => { const selectionStartGetter = (inputRef.current as InputTextElementSelection | null)?.selectionStart; selectionStartGetter?.().then((start) => { sanitizedSelectionRef.current = start ?? null; }); const parsedValue = sanitizedFormatter.parse(typeof value === 'string' ? value : ''); normalizedOn?.onInput?.(event, parsedValue); }, }} /> ); } function KolFormattedIbanController(props: any) { const { name, control, rules, defaultValue, shouldUnregister, disabled, formatter, selectionStartRef, ...componentProps } = props; return ( <Controller name={name} control={control} rules={rules} defaultValue={defaultValue} shouldUnregister={shouldUnregister} disabled={disabled} render={({ field, fieldState }) => { // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access const userHandlers = componentProps._on as KolInputTextEvents | undefined; return ( <FormattedKolInputText {...(componentProps as any)} formatter={formatter} selectionStartRef={selectionStartRef} _value={field.value} _touched={fieldState.isTouched} _msg={ fieldState.error ? { _type: 'error' as const, _description: fieldState.error.message || String(fieldState.error), } : undefined } _on={{ onInput: (event: Event, value: unknown) => { field.onChange(value); userHandlers?.onInput?.(event, value); }, onBlur: () => field.onBlur(), }} /> ); }} /> ); } export function InputTextFormatterDemo() { const formatter = useMemo(() => new IbanFormatter(), []); const textInput1SelectionStart = useRef<number | null>(null); const initialIbanExampleValues: IbanExampleFormValues = { iban: 'DE89370400440532013000', }; const ibanForm = useForm<IbanExampleFormValues>({ defaultValues: initialIbanExampleValues, mode: 'onTouched', }); const ibanValues = ibanForm.watch(); const handleIbanSubmit = (event: Event) => { void ibanForm.handleSubmit(async () => {})(event as unknown as BaseSyntheticEvent); }; return ( <> <SampleDescription> <p> This example demonstrates formatting a data value in an input field (example IBAN). The data value is formatted to the input field (print format) and vice versa the formatting is removed again (machine format) </p> </SampleDescription> <section className="w-full"> <div> <KolForm _on={{ onSubmit: handleIbanSubmit }}> <KolFormattedIbanController control={ibanForm.control as any} name="iban" id="field-iban" formatter={formatter} selectionStartRef={textInput1SelectionStart} rules={{ required: 'Please enter an IBAN.' }} _label="IBAN" _required /> </KolForm> <pre className="text-base mt-2">{JSON.stringify(ibanValues, null, 2)}</pre> </div> </section> </> ); }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/deleonio/public-ui-kolibri'

If you have feedback or need assistance with the MCP directory API, please join our Discord server