import { msg, str } from "@lit/localize"; import type { SlInput, SlTextarea } from "@shoelace-style/shoelace"; import { getLocale } from "./localization"; // TODO listen for localize changes and update const numberFormatter = new Intl.NumberFormat(getLocale()); export type MaxLengthValidator = { helpText: string; validate: (e: CustomEvent) => void; }; export function getHelpText(maxLength: number, currentLength: number) { const helpText = msg( str`Maximum ${numberFormatter.format(maxLength)} characters`, ); if (currentLength > maxLength) { const overMax = currentLength - maxLength; return overMax === 1 ? msg(str`${numberFormatter.format(overMax)} character over limit`) : msg(str`${numberFormatter.format(overMax)} characters over limit`); } return helpText; } /** * Validate field max length and set custom message in Shoelace inputs. * Usage: * ``` * const { helpText, validate } = maxLengthValidator(10) * * * ``` */ export function maxLengthValidator(maxLength: number): MaxLengthValidator { const validityHelpText = msg(str`Maximum ${maxLength} characters`); let origHelpText: null | string = null; const validate = (e: CustomEvent) => { const el = e.target as SlTextarea | SlInput; if (origHelpText === null && el.helpText) { origHelpText = el.helpText; } const validityText = getHelpText(maxLength, el.value.length); const isInvalid = el.value.length > maxLength; el.setCustomValidity( isInvalid ? msg( str`Please shorten this text to ${maxLength} or fewer characters.`, ) : "", ); el.helpText = isInvalid ? validityText : origHelpText || validityHelpText; }; return { helpText: validityHelpText, validate }; }