From fb2e342e314f1403d89827d73efe42fe25396c65 Mon Sep 17 00:00:00 2001 From: Marie Chatfield Date: Wed, 3 Jun 2026 17:49:53 -0700 Subject: [PATCH 1/2] docs(SDK-971): tsdoc-directory src/helpers/ Co-Authored-By: Claude Sonnet 4.6 --- eslint.config.ts | 1 - src/helpers/LRUCache.ts | 9 ++ src/helpers/apiErrorToList.tsx | 22 +++- src/helpers/applyMissingDefaults.ts | 13 +- src/helpers/breadcrumbHelpers.ts | 89 +++++++++---- src/helpers/currencyHelpers.ts | 14 +++ src/helpers/dateFormatting.ts | 171 ++++++++++++++++++++++--- src/helpers/ensureRequired.ts | 12 ++ src/helpers/federalEin.ts | 28 ++++- src/helpers/formattedStrings.ts | 186 +++++++++++++++++++++++----- src/helpers/getDataProps.ts | 11 ++ src/helpers/mask.ts | 41 ++++-- src/helpers/payRateCalculator.ts | 23 +++- src/helpers/percentageConversion.ts | 36 ++++++ src/helpers/readableStreamToBlob.ts | 13 ++ src/helpers/rem.ts | 29 ++++- src/helpers/responsive.ts | 55 ++++++++ src/helpers/retryAsync.ts | 14 +++ src/helpers/ssn.ts | 26 +++- src/helpers/validations.ts | 38 ++++++ 20 files changed, 734 insertions(+), 97 deletions(-) diff --git a/eslint.config.ts b/eslint.config.ts index 01fd0b9c3..0e4fba5cf 100644 --- a/eslint.config.ts +++ b/eslint.config.ts @@ -177,7 +177,6 @@ export default [ // As we improve documentation, remove directories from the ignore path 'src/components/**', 'src/contexts/**', - 'src/helpers/**', 'src/partner-hook-utils/**', 'src/shared/**', 'src/types/**', diff --git a/src/helpers/LRUCache.ts b/src/helpers/LRUCache.ts index 4a6daa3c3..f1b54668e 100644 --- a/src/helpers/LRUCache.ts +++ b/src/helpers/LRUCache.ts @@ -1,3 +1,12 @@ +/** + * Least-recently-used cache keyed by string with thunk values producing translation tables. + * + * @remarks Backs the i18n translation cache so loaded language bundles can be evicted in + * insertion-recency order once the configured capacity is reached. Reading or writing a key + * promotes it to the most-recently-used position. + * + * @internal + */ export class LRUCache { capacity: number map: Map Record> diff --git a/src/helpers/apiErrorToList.tsx b/src/helpers/apiErrorToList.tsx index e72f9fd81..aad6a4afc 100644 --- a/src/helpers/apiErrorToList.tsx +++ b/src/helpers/apiErrorToList.tsx @@ -1,7 +1,13 @@ import type { EntityErrorObject } from '@gusto/embedded-api-v-2025-11-15/models/components/entityerrorobject' import { snakeCaseToCamelCase } from './formattedStrings' -/**Traverses errorList and finds items with message properties */ +/** + * Renders each error in the list that carries a `message` as a `` keyed by `errorKey`. + * + * @param errorList - Flat list of entity errors returned by the API. + * @returns React nodes for messaged entries; entries without a message yield `null`. + * @internal + */ export const renderErrorList = (errorList: Array): React.ReactNode[] => { return errorList.map(errorFromList => { if (errorFromList.message) { @@ -10,8 +16,18 @@ export const renderErrorList = (errorList: Array): React.Reac return null }) } -/**Recuresively parses error list and constructs an array of objects containing attribute value error messages associated with form fields. Nested errors construct '.' separated keys - * metadata.state is a special case for state taxes validation errors +/** + * Recursively flattens a nested API error tree into a list keyed for form-field display. + * + * @remarks Builds dot-separated `errorKey` paths from nested errors and converts each segment + * from snake_case to camelCase so the resulting keys match react-hook-form field names. + * `metadata.key` is used as the path segment for nested errors when present; `metadata.state` + * is a special case for state-tax validation errors, falling back to the node's own `errorKey`. + * + * @param error - The root entity error to flatten. + * @param parentKey - Accumulated dot-path prefix used during recursion. Omit at the top level. + * @returns A flat list of `{ errorKey, message, category }` entries ready to bind to form fields. + * @internal */ export const getFieldErrors = ( error: EntityErrorObject, diff --git a/src/helpers/applyMissingDefaults.ts b/src/helpers/applyMissingDefaults.ts index c7afc4f1b..b9a88564e 100644 --- a/src/helpers/applyMissingDefaults.ts +++ b/src/helpers/applyMissingDefaults.ts @@ -1,6 +1,15 @@ /** - * Applies default values only to properties that are undefined in the source object. - * This is more efficient than object spread as it only sets values that are actually missing. + * Returns a copy of `rawProps` with `defaults` filled in only where the source value is `undefined`. + * + * @remarks Cheaper than `{ ...defaults, ...rawProps }` because it copies the source once and only + * writes the keys that are actually missing. Properties explicitly set to `null` or `false` are + * preserved as-is. + * + * @typeParam T - Shape of the props object. + * @param rawProps - Caller-supplied props; values set here always win. + * @param defaults - Fallback values applied only when the corresponding `rawProps` value is `undefined`. + * @returns A new object combining `rawProps` with defaults filled in for missing keys. + * @internal */ export function applyMissingDefaults(rawProps: T, defaults: Partial): T { const result = { ...rawProps } diff --git a/src/helpers/breadcrumbHelpers.ts b/src/helpers/breadcrumbHelpers.ts index 2cd3740a2..36403d396 100644 --- a/src/helpers/breadcrumbHelpers.ts +++ b/src/helpers/breadcrumbHelpers.ts @@ -24,9 +24,14 @@ const getBreadcrumbsHeader = (header: FlowHeaderConfig | null | undefined): Brea /** * Builds a complete breadcrumb trail map from a hierarchical node structure. * - * Takes a tree structure of breadcrumb nodes and generates a map where each state - * has its complete breadcrumb trail from root to that state. This is useful for - * initializing breadcrumb navigation in state machines or multi-step flows. + * @remarks Walks each node's `parent` pointer to assemble a root-to-state trail, producing + * one entry per state. Use it to seed breadcrumb navigation when initializing a state + * machine or multi-step flow. + * + * @param nodes - Map of state names to breadcrumb nodes, each carrying an `item` and an + * optional `parent` state key. + * @returns A map from state name to its ordered breadcrumb trail. + * @internal */ export const buildBreadcrumbs = (nodes: BreadcrumbNodes): BreadcrumbTrail => { const map: Record = {} @@ -50,9 +55,16 @@ export const buildBreadcrumbs = (nodes: BreadcrumbNodes): BreadcrumbTrail => { /** * Resolves template variables in breadcrumb labels using values from a context object. * - * Supports Handlebars-style template syntax (`{{variableName}}`) for dynamic breadcrumb labels. - * Variables enclosed in double braces are replaced with their corresponding values from the context. - * Non-template strings are returned as-is. + * @remarks Supports Handlebars-style `{{variableName}}` syntax. Values enclosed in double + * braces are replaced with the corresponding key on `context`; missing keys resolve to an + * empty string. Strings without a template token are returned unchanged. + * + * @param variables - Map of variable names to either a literal or a `{{key}}` template. + * Pass `undefined` to skip resolution. + * @param context - Source values referenced by template tokens. + * @returns A map of variable names to resolved values, or an empty object when `variables` + * is `undefined`. + * @internal */ export const resolveBreadcrumbVariables = ( variables: Record | undefined, @@ -76,11 +88,18 @@ export const resolveBreadcrumbVariables = ( } /** - * Merges `patch` fields into the existing breadcrumbs header on a context, - * preserving the existing trails and CTA. If the context has no breadcrumbs - * header, a fresh one is created. Useful when a transition needs to flip - * breadcrumbs visibility (`currentBreadcrumbId`) without rebuilding any - * trails. + * Merges `patch` fields into the existing breadcrumbs header on a context. + * + * @remarks Preserves existing trails and CTA; if the context has no breadcrumbs header + * a fresh one is created. Use this when a transition needs to flip breadcrumb visibility + * (for example `currentBreadcrumbId`) without rebuilding any trails. + * + * @typeParam T - Context shape carrying an optional `header` of the discriminated union. + * @param context - The context whose breadcrumbs header should be patched. + * @param patch - Partial breadcrumbs-header fields to merge in. The `type` discriminator + * cannot be overridden. + * @returns A new context with the patched breadcrumbs header. + * @internal */ export const patchBreadcrumbsHeader = ( context: T, @@ -91,9 +110,16 @@ export const patchBreadcrumbsHeader = ( } /** - * Removes a breadcrumb from all trails in the context's breadcrumbs header. - * Use this in state machine reducers to hide a step entirely (e.g. after - * payroll submission). + * Removes a breadcrumb from every trail in the context's breadcrumbs header. + * + * @remarks Use in state machine reducers to hide a step entirely, for example after + * payroll submission when the step should no longer appear in any trail. + * + * @typeParam T - Context shape carrying an optional `header` of the discriminated union. + * @param breadcrumbId - Id of the breadcrumb to strip from every trail. + * @param context - The context whose breadcrumbs header should be updated. + * @returns A new context with the breadcrumb removed from all trails. + * @internal */ export const hideBreadcrumb = (breadcrumbId: string, context: T): T => { const breadcrumbsHeader = getBreadcrumbsHeader(context.header) @@ -111,9 +137,16 @@ export const hideBreadcrumb = (breadcrumbId: string, conte } /** - * Marks a breadcrumb as non-navigable across all trails in the context's - * breadcrumbs header. Use this in state machine reducers to disable backward - * navigation to a specific step. + * Marks a breadcrumb as non-navigable across every trail in the context's breadcrumbs header. + * + * @remarks Use in state machine reducers to disable backward navigation to a specific step + * while still showing it in the trail. + * + * @typeParam T - Context shape carrying an optional `header` of the discriminated union. + * @param breadcrumbId - Id of the breadcrumb to mark `isNavigable: false`. + * @param context - The context whose breadcrumbs header should be updated. + * @returns A new context with the breadcrumb locked in every trail. + * @internal */ export const lockBreadcrumb = (breadcrumbId: string, context: T): T => { const breadcrumbsHeader = getBreadcrumbsHeader(context.header) @@ -131,14 +164,22 @@ export const lockBreadcrumb = (breadcrumbId: string, conte } /** - * Updates the breadcrumb trail for a specific state with resolved variables - * and switches the active breadcrumb to that state. + * Updates the breadcrumb trail for a specific state with resolved variables and switches + * the active breadcrumb to that state. + * + * @remarks Typically called from state machine transitions to update breadcrumb navigation + * when moving between states. Existing trails for other states are preserved; only the trail + * for `stateName` is rewritten with `variables` resolved against the context. The resulting + * context's header is always of type `'breadcrumbs'`. * - * This function is typically used in state machine transitions to update - * breadcrumb navigation when moving between states. It preserves all existing - * breadcrumb trails for other states and only updates the trail for the - * specified state by resolving any template variables for that state's - * breadcrumb. The resulting context's header is always of type `'breadcrumbs'`. + * @typeParam T - Context shape carrying an optional `header` of the discriminated union. + * @param stateName - The state whose breadcrumb trail should be updated and made active. + * @param context - The context whose breadcrumbs header should be updated. + * @param variables - Optional template variables to resolve against the context for each + * breadcrumb in the target state's trail. + * @returns A new context with the trail for `stateName` updated and `currentBreadcrumbId` + * set to `stateName`. + * @internal */ export const updateBreadcrumbs = ( stateName: string, diff --git a/src/helpers/currencyHelpers.ts b/src/helpers/currencyHelpers.ts index 9577c1f9d..966751608 100644 --- a/src/helpers/currencyHelpers.ts +++ b/src/helpers/currencyHelpers.ts @@ -1,8 +1,22 @@ +/** + * Converts a dollar amount to whole cents, rounding to the nearest cent. + * + * @param dollars - Amount in dollars, or `null` to pass through. + * @returns The amount in cents, or `null` if the input was `null`. + * @internal + */ export const dollarsToCents = (dollars: number | null): number | null => { if (dollars === null) return null return Math.round(dollars * 100) } +/** + * Converts a cents amount to dollars without rounding. + * + * @param cents - Amount in cents, or `null` to pass through. + * @returns The amount in dollars as a floating-point number, or `null` if the input was `null`. + * @internal + */ export const centsToDollars = (cents: number | null): number | null => { if (cents === null) return null return cents / 100 diff --git a/src/helpers/dateFormatting.ts b/src/helpers/dateFormatting.ts index 81e2d5384..47c019a1b 100644 --- a/src/helpers/dateFormatting.ts +++ b/src/helpers/dateFormatting.ts @@ -1,8 +1,13 @@ /** * Normalizes any date input (string, Date, or undefined) to a Date object. - * Handles YYYY-MM-DD strings by parsing them in local timezone to avoid timezone issues. - * Also handles ISO timestamp strings for compatibility. - * Returns null for invalid inputs. + * + * @remarks Handles `YYYY-MM-DD` strings by parsing them in local time to avoid + * timezone drift. Also accepts ISO timestamp strings and existing `Date` + * instances. Returns `null` for nullish, empty, or unparseable input. + * + * @param dateInput - The date value to normalize. + * @returns A `Date` instance, or `null` if the input is missing or invalid. + * @internal */ export const normalizeToDate = (dateInput?: string | Date | null): Date | null => { if (!dateInput) return null @@ -57,12 +62,22 @@ const createDateFormatter = return date.toLocaleDateString(locale, options) } +/** + * Formats a date as a short weekday plus short month and day (e.g. `Mon, Jan 5`). + * + * @internal + */ export const formatDateShortWithWeekday = createDateFormatter({ weekday: 'short', month: 'short', day: 'numeric', }) +/** + * Formats a date as a short weekday, short month, day, and year (e.g. `Mon, Jan 5, 2025`). + * + * @internal + */ export const formatDateShortWithWeekdayAndYear = createDateFormatter({ weekday: 'short', month: 'short', @@ -70,28 +85,57 @@ export const formatDateShortWithWeekdayAndYear = createDateFormatter({ year: 'numeric', }) +/** + * Formats a date as a short month and day (e.g. `Jan 5`). + * + * @internal + */ export const formatDateShort = createDateFormatter({ month: 'short', day: 'numeric', }) +/** + * Formats a date as a short month, day, and year (e.g. `Jan 5, 2025`). + * + * @internal + */ export const formatDateShortWithYear = createDateFormatter({ month: 'short', day: 'numeric', year: 'numeric', }) +/** + * Formats a date as a long month and day (e.g. `January 5`). + * + * @internal + */ export const formatDateLong = createDateFormatter({ month: 'long', day: 'numeric', }) +/** + * Formats a date as a long month, day, and year (e.g. `January 5, 2025`). + * + * @internal + */ export const formatDateLongWithYear = createDateFormatter({ month: 'long', day: 'numeric', year: 'numeric', }) +/** + * Splits a date into separate locale-formatted time and date strings. + * + * @param dateInput - The date value to format. + * @param locale - Optional BCP 47 locale tag passed to `toLocaleString`. + * @returns An object with `time` (e.g. `3:45 PM EST`) and `date` (e.g. `Mon, Jan 5`). + * Both fields are empty strings when the input cannot be parsed. + * @internal + */ export const formatDateWithTime = ( dateInput?: string | Date | null, locale?: string, @@ -115,6 +159,19 @@ export const formatDateWithTime = ( return { time, date: dateString } } +/** + * Formats a pay period start and end date for display as separate fields. + * + * @remarks Start date renders with the long month and day; end date renders + * with the short month, day, and year. + * + * @param startDateInput - Pay period start date. + * @param endDateInput - Pay period end date. + * @param locale - Optional BCP 47 locale tag passed to `toLocaleDateString`. + * @returns Formatted `startDate` and `endDate` strings. Both fields are empty + * strings when either input cannot be parsed. + * @internal + */ export const formatPayPeriod = ( startDateInput?: string | Date | null, endDateInput?: string | Date | null, @@ -141,6 +198,18 @@ export const formatPayPeriod = ( return { startDate: startFormatted, endDate: endFormatted } } +/** + * Formats a pay period as a single en-dash–separated range string. + * + * @param startDateInput - Pay period start date. + * @param endDateInput - Pay period end date. + * @param locale - Optional BCP 47 locale tag passed to `toLocaleDateString`. + * @param options - When `useShortMonth` is true, both ends use short month names. + * Otherwise the start uses the long month name and the end uses short. + * @returns The formatted range (e.g. `January 1–Jan 15, 2025`), or an empty + * string when either input cannot be parsed. + * @internal + */ export const formatPayPeriodRange = ( startDateInput?: string | Date | null, endDateInput?: string | Date | null, @@ -168,6 +237,13 @@ export const formatPayPeriodRange = ( return `${startFormatted}–${endFormatted}` } +/** + * Formats a `Date` as a `YYYY-MM-DD` string using the local year, month, and day. + * + * @param date - The date to format. + * @returns A zero-padded `YYYY-MM-DD` string, or `null` when the input is an invalid date. + * @internal + */ export const formatDateToStringDate = (date: Date): string | null => { if (isNaN(date.getTime())) { return null @@ -179,15 +255,16 @@ export const formatDateToStringDate = (date: Date): string | null => { } /** - * Converts any parseable date string to a `YYYY-MM-DD` ISO string using local - * time, so the calendar date is preserved regardless of the runtime timezone. + * Converts any parseable date string to a `YYYY-MM-DD` ISO string using local time. * - * Unlike `formatDateToStringDate` (which reads UTC), this function reads the - * local year/month/day — safe for dates parsed from locale-format strings - * (e.g. "4/16/1998") or ISO strings, both of which `normalizeToDate` lands at - * local midnight. + * @remarks Reads the local year, month, and day so the calendar date is + * preserved regardless of the runtime timezone. Safe for dates parsed from + * locale-format strings (e.g. `4/16/1998`) or ISO strings, both of which land + * at local midnight when normalized. * - * Returns `''` for null, undefined, empty, or unparseable input. + * @param value - The date string to convert. + * @returns A `YYYY-MM-DD` string, or `''` for nullish, empty, or unparseable input. + * @internal */ export const normalizeToISOString = (value?: string | null): string => { if (!value) return '' @@ -200,7 +277,11 @@ export const normalizeToISOString = (value?: string | null): string => { } /** - * Normalizes Date to local midnight, handling timezone issues from any adapter. + * Normalizes a `Date` to local midnight, stripping any time-of-day component. + * + * @param date - The date to normalize, or `null`. + * @returns A new `Date` at local midnight, or `null` when the input is missing or invalid. + * @internal */ export const normalizeDateToLocal = (date: Date | null): Date | null => { if (!date || isNaN(date.getTime())) { @@ -209,9 +290,22 @@ export const normalizeDateToLocal = (date: Date | null): Date | null => { return new Date(date.getFullYear(), date.getMonth(), date.getDate()) } +/** + * Number of milliseconds in one hour. + * + * @internal + */ export const MS_PER_HOUR = 1000 * 60 * 60 const MS_PER_DAY = MS_PER_HOUR * 24 +/** + * Returns the number of hours from now until a deadline. + * + * @param deadline - Target date in the future (or past, for negative results). + * @returns Hours until `deadline` (fractional, negative if `deadline` is in + * the past), or `null` when the input cannot be parsed. + * @internal + */ export const getHoursUntil = (deadline?: Date | string | null): number | null => { const deadlineDate = normalizeToDate(deadline) if (!deadlineDate) return null @@ -221,6 +315,14 @@ export const getHoursUntil = (deadline?: Date | string | null): number | null => return timeDiffMs / MS_PER_HOUR } +/** + * Returns the number of days from now until a deadline. + * + * @param deadline - Target date in the future (or past, for negative results). + * @returns Days until `deadline` (fractional, negative if `deadline` is in + * the past), or `null` when the input cannot be parsed. + * @internal + */ export const getDaysUntil = (deadline?: Date | string | null): number | null => { const deadlineDate = normalizeToDate(deadline) if (!deadlineDate) return null @@ -230,17 +332,43 @@ export const getDaysUntil = (deadline?: Date | string | null): number | null => return timeDiffMs / MS_PER_DAY } -export const isWeekend = (date: Date): boolean => { +/** + * Returns whether a date falls on Saturday or Sunday. + * + * @param date - The date to test. + * @returns `true` if `date` is a weekend day. + * @internal + */ +const isWeekend = (date: Date): boolean => { const day = date.getDay() return day === 0 || day === 6 } +/** + * Returns a new `Date` offset from the input by a given number of days. + * + * @param date - The base date. Not mutated. + * @param days - Number of days to add (negative values subtract). + * @returns A new `Date` shifted by `days`. + * @internal + */ export const addDays = (date: Date, days: number): Date => { const result = new Date(date) result.setDate(result.getDate() + days) return result } +/** + * Returns a new `Date` offset by a given number of business days (Monday–Friday). + * + * @remarks Skips Saturdays and Sundays when counting. The result is normalized + * to local midnight. Does not account for holidays. + * + * @param startDate - The base date. Not mutated. + * @param businessDays - Number of business days to add. + * @returns A new `Date` shifted forward by `businessDays` weekdays. + * @internal + */ export const addBusinessDays = (startDate: Date, businessDays: number): Date => { let currentDate = new Date(startDate) currentDate.setHours(0, 0, 0, 0) @@ -256,13 +384,28 @@ export const addBusinessDays = (startDate: Date, businessDays: number): Date => return currentDate } -/** Formats numeric month and day as a zero-padded `MM-DD` string. */ +/** + * Formats numeric month and day as a zero-padded `MM-DD` string. + * + * @param month - Month number, 1–12. + * @param day - Day-of-month number, 1–31. + * @returns A `MM-DD` string, or `undefined` when either argument is missing. + * @internal + */ export function formatMonthDay(month?: number, day?: number): string | undefined { if (month == null || day == null) return undefined return `${String(month).padStart(2, '0')}-${String(day).padStart(2, '0')}` } -/** Returns the number of days in a given month (1-indexed). Uses a non-leap year so February always returns 28. */ +/** + * Returns the number of days in a given month (1-indexed). + * + * @remarks Uses a non-leap year, so February always returns 28. + * + * @param month - Month number, 1–12. + * @returns The number of days in that month. + * @internal + */ export function getDaysInMonth(month: number): number { return new Date(2023, month, 0).getDate() } diff --git a/src/helpers/ensureRequired.ts b/src/helpers/ensureRequired.ts index 7e553c912..507b72bfc 100644 --- a/src/helpers/ensureRequired.ts +++ b/src/helpers/ensureRequired.ts @@ -1,5 +1,17 @@ import { t } from 'i18next' +/** + * Asserts that a value is defined, throwing a translated error otherwise. + * + * @remarks Used to narrow `T | undefined` to `T` at call sites where the value + * is required by contract but the type system allows `undefined`. + * + * @typeParam T - The non-undefined value type. + * @param prop - The value to assert. + * @returns The same value with the `undefined` branch removed from its type. + * @throws Error when `prop` is `undefined`. + * @internal + */ export function ensureRequired(prop: T | undefined): T { if (prop === undefined) { throw new Error(t('errors.ensureRequired')) diff --git a/src/helpers/federalEin.ts b/src/helpers/federalEin.ts index 2ab6db425..c5da3e074 100644 --- a/src/helpers/federalEin.ts +++ b/src/helpers/federalEin.ts @@ -1,10 +1,15 @@ import { useTranslation } from 'react-i18next' /** - * Normalizes string input to a 9 digit EIN format with two leading digits, a dash, and 7 trailing digits removing any non-numeric characters. + * Normalizes a raw string to the federal EIN display format `NN-NNNNNNN`. * - * @param value - Raw string value to be formatted as a federal EIN - * @returns String in the federal EIN format with all invalid characters removed + * @remarks Strips non-numeric characters, then inserts a dash between the + * first two digits and the remaining seven. Returns an empty string when no + * digits are present. + * + * @param value - Raw string value to be formatted as a federal EIN. + * @returns A string in `NN-NNNNNNN` format with non-digit characters removed. + * @internal */ export const normalizeEin = (value: string) => value @@ -16,9 +21,24 @@ export const normalizeEin = (value: string) => .join('-') .substring(0, 10) || '' -export const createPlaceholderEin = (hasEin?: boolean, placeholderEin?: string) => +/** + * Returns the placeholder EIN to display when an EIN exists but is masked. + * + * @param hasEin - Whether the form currently has a stored EIN value. + * @param placeholderEin - The masked placeholder string to show. + * @returns The placeholder string when `hasEin` is true; otherwise an empty string. + * @internal + */ +const createPlaceholderEin = (hasEin?: boolean, placeholderEin?: string) => hasEin ? placeholderEin : '' +/** + * Hook that returns a translated placeholder string for a masked EIN field. + * + * @param hasEin - Whether the form currently has a stored EIN value. + * @returns The translated placeholder when `hasEin` is true; otherwise an empty string. + * @internal + */ export const usePlaceholderEin = (hasEin?: boolean) => { const { t } = useTranslation('common') return createPlaceholderEin(hasEin, t('inputs.ein.placeholder')) diff --git a/src/helpers/formattedStrings.ts b/src/helpers/formattedStrings.ts index 59456d748..bd438e3f5 100644 --- a/src/helpers/formattedStrings.ts +++ b/src/helpers/formattedStrings.ts @@ -8,6 +8,17 @@ import { useLocale } from '@/contexts/LocaleProvider/useLocale' const capitalize = (word: string) => word.charAt(0).toLocaleUpperCase() + word.slice(1) +/** + * Joins a first and last name into a single capitalized display string. + * + * @remarks Each name part is capitalized at its first character. A space is + * inserted between the parts only when the last name is present. Missing + * parts are treated as empty. + * + * @param name - Object with optional `first_name` and `last_name` fields. + * @returns The combined name, e.g. `Jane Doe`, `Jane`, or `''`. + * @internal + */ export const firstLastName = ({ first_name, last_name, @@ -21,6 +32,17 @@ const maybeString = (str: string | null | undefined) => { return str ? ` ${str}` : '' } +/** + * Combines an address's two street lines with a comma separator. + * + * @remarks Each line is prefixed with a leading space when present, producing + * a string like ` 123 Main St, Apt 4`. Prefer {@link formatStreetForDisplay} + * for new display code; this function is retained for legacy callers. + * + * @param address - Address whose `street1` and `street2` are joined. + * @returns The joined street string. + * @internal + */ export const getStreet = (address: EmployeeAddress | Location) => { const street1 = maybeString(address.street1) const street2 = maybeString(address.street2) @@ -28,7 +50,16 @@ export const getStreet = (address: EmployeeAddress | Location) => { return `${street1},${street2}` } -/** Joins street lines with a comma for display (avoids getStreet’s leading-space/comma quirks). */ +/** + * Joins an address's street lines with a comma for display. + * + * @remarks Trims each line and skips empty values, avoiding the leading-space + * and trailing-comma artifacts of {@link getStreet}. + * + * @param address - Address whose `street1` and `street2` are joined. + * @returns The display-formatted street string, e.g. `123 Main St, Apt 4`. + * @internal + */ export const formatStreetForDisplay = (address: EmployeeAddress | Location) => { const parts = [address.street1?.trim(), address.street2?.trim()].filter((part): part is string => Boolean(part), @@ -36,29 +67,46 @@ export const formatStreetForDisplay = (address: EmployeeAddress | Location) => { return parts.join(', ') } +/** + * Formats an address's city, state, and zip into a single display string. + * + * @param address - Address whose `city`, `state`, and `zip` are joined. + * @returns A `City, State Zip` string. Empty fields are skipped. + * @internal + */ export const getCityStateZip = (address: EmployeeAddress | Location) => `${maybeString(address.city)}, ${maybeString(address.state)} ${maybeString(address.zip)}` +/** + * Formats a full address as a single inline string. + * + * @param address - The address to format. + * @returns The combined street and city/state/zip string. + * @internal + */ export const addressInline = (address: EmployeeAddress | Location) => `${getStreet(address)} ${getCityStateZip(address)}` -export const currentDateString = () => { - const d = new Date() - const dateString = `${String(d.getFullYear())}-${('0' + String(d.getMonth() + 1)).slice(-2)}-${('0' + String(d.getDate())).slice(-2)}` - return dateString -} - -export function isNumberKey({ which, keyCode }: KeyboardEvent) { - const charCode = which ? which : keyCode - if (charCode > 31 && charCode != 46 && (charCode < 48 || charCode > 57)) return false - return true -} - -export const booleanToString = (value: boolean) => (value ? 'true' : 'false') - -export const amountStr = (amount: string, isPercentage: boolean) => +/** + * Wraps an amount string with a currency or percent symbol. + * + * @param amount - Pre-formatted numeric string. + * @param isPercentage - When `true`, appends `%`; otherwise prepends `$`. + * @returns The amount with the appropriate symbol. + * @internal + */ +const amountStr = (amount: string, isPercentage: boolean) => isPercentage ? `${amount}%` : `$${amount}` +/** + * Formats a number as a USD currency string with two decimal places. + * + * @param amount - The numeric value to format. + * @param locale - Optional BCP 47 locale tag passed to `toLocaleString`. + * Defaults to `en-US`. + * @returns A `$1,234.56` style currency string. + * @internal + */ export const formatNumberAsCurrency = (amount: number, locale: string = 'en-US') => { const formattedNumber = amount.toLocaleString(locale, { minimumFractionDigits: 2, @@ -67,6 +115,20 @@ export const formatNumberAsCurrency = (amount: number, locale: string = 'en-US') return amountStr(formattedNumber, false) } +/** + * Formats a pay rate with its payment unit, annualizing weekly and monthly values. + * + * @remarks Hourly, yearly, and paycheck rates are displayed at the input + * value. Weekly rates are multiplied by 52 and monthly rates by 12 to express + * an annualized amount. Unknown payment units render as the currency value + * alone. + * + * @param args - Formatting inputs: `rate` (numeric value), `paymentUnit` + * (`Hour`, `Week`, `Month`, `Year`, or `Paycheck`), `t` (i18next translation + * function), and optional `locale` (BCP 47 tag, default `en-US`). + * @returns The translated, formatted pay rate string. + * @internal + */ export const formatPayRate = ({ rate, paymentUnit, @@ -102,22 +164,18 @@ export const formatPayRate = ({ } } -export const useFormatPayRate = () => { - const { t } = useTranslation('common') - const { locale } = useLocale() - - return useCallback( - (rate: number, paymentUnit: string) => { - return formatPayRate({ rate, paymentUnit, t, locale }) - }, - [t, locale], - ) -} - /** - * Formats a compensation rate as-is, without annualizing weekly or monthly - * values. Use this for displaying compensation card data where the stored rate - * should be shown directly (e.g. "$950 per week", "$3,500 per month"). + * Formats a compensation rate as-is, without annualizing weekly or monthly values. + * + * @remarks Use for displaying compensation card data where the stored rate + * should be shown directly (e.g. `$950 per week`, `$3,500 per month`). + * Unknown payment units render as the currency value alone. + * + * @param args - Formatting inputs: `rate` (numeric value), `paymentUnit` + * (`Hour`, `Week`, `Month`, `Year`, or `Paycheck`), `t` (i18next translation + * function), and optional `locale` (BCP 47 tag, default `en-US`). + * @returns The translated, formatted compensation rate string. + * @internal */ export const formatCompensationRate = ({ rate, @@ -148,6 +206,12 @@ export const formatCompensationRate = ({ } } +/** + * Hook that returns a memoized {@link formatCompensationRate} bound to the active locale. + * + * @returns A callback `(rate, paymentUnit) => string`. + * @internal + */ export const useFormatCompensationRate = () => { const { t } = useTranslation('common') const { locale } = useLocale() @@ -161,22 +225,70 @@ export const useFormatCompensationRate = () => { } const dompurifyConfig = { ALLOWED_TAGS: ['a', 'b', 'strong'], ALLOWED_ATTR: ['href', 'target'] } +/** + * Sanitizes an HTML string for use with React's `dangerouslySetInnerHTML`. + * + * @remarks Only ``, ``, and `` tags are allowed, and `` + * elements may retain only `href` and `target` attributes. All other markup + * is stripped via DOMPurify. + * + * @param dirty - The raw HTML string to sanitize. + * @returns An object shaped for `dangerouslySetInnerHTML`. The `__html` + * field is `''` when the input is empty. + * @internal + */ export function createMarkup(dirty: string) { if (!dirty) return { __html: '' } return { __html: DOMPurify.sanitize(dirty, dompurifyConfig) } } +/** + * Removes all non-digit characters from a string. + * + * @param value - The string to filter. + * @returns The input with only the digit characters `0`–`9` retained. + * @internal + */ export const removeNonDigits = (value: string): string => { return value.replace(/\D/g, '') } +/** + * Strips the trailing `.value` segment from an API error path. + * + * @remarks API validation errors target a `.value` field on the inner + * object, but react-hook-form registers the field under its bare name. + * Stripping `.value` aligns the error path with the form field name. + * + * @param errorKey - The dotted error path returned by the API. + * @returns The error key without a trailing `.value`. + * @internal + */ export const normalizeErrorKeyForForm = (errorKey: string): string => errorKey.replace(/\.value$/, '') +/** + * Converts a `snake_case` string to `camelCase`. + * + * @param s - The snake_case string to convert. + * @returns The camelCase equivalent. + * @internal + */ export const snakeCaseToCamelCase = (s: string) => { return s.replace(/_([a-z])/g, (_: string, char: string) => char.toUpperCase()) } +/** + * Converts a `camelCase` or `PascalCase` string to `snake_case`. + * + * @remarks Handles consecutive uppercase letters by inserting a separator + * before the final letter of a run that is followed by a lowercase letter + * (e.g. `HTMLParser` becomes `html_parser`). + * + * @param s - The camelCase or PascalCase string to convert. + * @returns The snake_case equivalent in lower case. + * @internal + */ export const camelCaseToSnakeCase = (s: string) => { return s .replace( @@ -191,6 +303,18 @@ export const camelCaseToSnakeCase = (s: string) => { .toLowerCase() } +/** + * Formats a US phone number as `NNN-NNN-NNNN` for display. + * + * @remarks Strips non-digit characters before formatting. A leading `1` + * country code on 11-digit inputs is dropped. Inputs that are not 10 or 11 + * digits are returned as the raw digit string. Returns an empty string for + * nullish input. + * + * @param phoneNumber - The phone number to format. + * @returns The formatted phone number, the digit-only fallback, or `''`. + * @internal + */ export const formatPhoneNumber = (phoneNumber: string | number | null | undefined): string => { if (!phoneNumber) return '' diff --git a/src/helpers/getDataProps.ts b/src/helpers/getDataProps.ts index 861cce007..a9888fea7 100644 --- a/src/helpers/getDataProps.ts +++ b/src/helpers/getDataProps.ts @@ -10,6 +10,17 @@ const isDataProp = (entry: [string, unknown]): entry is DataAttributeEntry => { ) } +/** + * Extracts `data-*` attributes from a props object for forwarding to the DOM. + * + * @remarks Filters out any entry whose key does not begin with `data-` or + * whose value is not a string, number, or boolean — matching the runtime + * shape that React permits on host elements. + * + * @param props - The component props to filter. + * @returns An object containing only the `data-*` attributes from `props`. + * @internal + */ export function getDataProps(props: Record): DataAttributes { const result: DataAttributes = {} diff --git a/src/helpers/mask.ts b/src/helpers/mask.ts index c70f26603..d35e4e5ba 100644 --- a/src/helpers/mask.ts +++ b/src/helpers/mask.ts @@ -3,22 +3,27 @@ import type { Transform } from '@/components/Common/Fields/hooks/useField' /** * Formats a string according to a specified mask pattern. * + * @remarks + * Strips non-alphanumeric characters from the input before applying the mask. + * Mask pattern characters: + * - `#` matches a digit (`\d`) + * - `@` matches a letter (`[a-zA-Z]`) + * - `^` matches an uppercase letter (`[A-Z]`) + * - `%` matches a digit or uppercase letter (`[0-9A-Z]`) + * - any other character is emitted as a literal + * * @param value - The input string to format - * @param mask - The mask pattern where: - * `#` represents a digit (`\d`) - * `@` represents a letter (`[a-zA-Z]`) - * `^` represents an uppercase letter (`[A-Z]`) - * `%` represents a digit or uppercase letter (`[0-9A-Z]`) - * any other character represents the literal character - * @returns The formatted string according to the mask + * @param mask - The mask pattern, or `null` to pass the value through unchanged + * @returns The formatted string according to the mask, or the original value when `value` or `mask` is empty + * @internal * * @example * ```ts - * formatWithMask('123456789', '###-##-####') // returns '123-45-6789' - * formatWithMask('ABC123', '@@@-###') // returns 'ABC-123' - * formatWithMask('123456', '(###) ###-####') // returns '(123) 456' - * formatWithMask('ABC123', '^^^-###') // returns 'ABC-123' - * formatWithMask('A1B2C3', '%%%-%%%') // returns 'A1B-2C3' + * formatWithMask('123456789', '###-##-####') // '123-45-6789' + * formatWithMask('ABC123', '@@@-###') // 'ABC-123' + * formatWithMask('123456', '(###) ###-####') // '(123) 456' + * formatWithMask('ABC123', '^^^-###') // 'ABC-123' + * formatWithMask('A1B2C3', '%%%-%%%') // 'A1B-2C3' * ``` */ export const formatWithMask = (value: string, mask: string | null): string => { @@ -92,10 +97,22 @@ export const formatWithMask = (value: string, mask: string | null): string => { return result.trim() } +/** + * Builds a Field transform that applies a mask pattern to the input value on each change. + * + * @param mask - The mask pattern accepted by {@link formatWithMask}, or `null` to pass the value through unchanged + * @returns A transform function suitable for passing to a Field component's `transform` prop + * @internal + */ export const useMaskedTransform = (mask: string | null): Transform => { return (value: string) => formatWithMask(value, mask) } +/** + * Reusable mask patterns shared across Field components. + * + * @internal + */ export const commonMasks = { phoneMask: '(###) ###-####', } diff --git a/src/helpers/payRateCalculator.ts b/src/helpers/payRateCalculator.ts index db753a4ce..e25a01f37 100644 --- a/src/helpers/payRateCalculator.ts +++ b/src/helpers/payRateCalculator.ts @@ -4,7 +4,19 @@ import { HOURS_PER_PAY_PERIOD_WEEKLY, } from '@/shared/constants' -export const hourlyRate = ( +/** + * Converts a pay rate expressed in the given unit into an equivalent hourly rate. + * + * @remarks + * Uses the standard hours-per-pay-period constants for weekly, monthly, and annual conversions. + * Returns `0` for `Paycheck` since the hours-per-paycheck value is not fixed. + * + * @param amount - The pay amount expressed in `paymentUnit` + * @param paymentUnit - The unit the `amount` is expressed in + * @returns The equivalent hourly rate, or `0` when `paymentUnit` is `Paycheck` + * @internal + */ +const hourlyRate = ( amount: number, paymentUnit: 'Hour' | 'Week' | 'Month' | 'Year' | 'Paycheck', ) => { @@ -21,6 +33,15 @@ export const hourlyRate = ( return 0 } } +/** + * Converts a pay rate expressed in the given unit into an equivalent annual rate. + * + * @param amount - The pay amount expressed in `paymentUnit` + * @param paymentUnit - The unit the `amount` is expressed in + * @returns The equivalent annual rate, or `0` when `paymentUnit` is `Paycheck` + * @internal + * @see {@link hourlyRate} + */ export const yearlyRate = ( amount: number, paymentUnit: 'Hour' | 'Week' | 'Month' | 'Year' | 'Paycheck', diff --git a/src/helpers/percentageConversion.ts b/src/helpers/percentageConversion.ts index ec753d5fd..88af7745b 100644 --- a/src/helpers/percentageConversion.ts +++ b/src/helpers/percentageConversion.ts @@ -4,6 +4,18 @@ function toCleanNumber(value: number): number { return parseFloat(value.toPrecision(PRECISION_DIGITS)) } +/** + * Converts a decimal value into its percentage equivalent. + * + * @remarks + * Multiplies by 100 and rounds to 12 significant digits to avoid floating-point artifacts. + * Returns `undefined` for `null`, `undefined`, empty strings, booleans, or values that cannot + * be parsed as numbers, making it safe to call on raw form input. + * + * @param value - The decimal value to convert; strings are parsed as floats + * @returns The percentage (e.g. `0.0625` becomes `6.25`), or `undefined` when the input is not a usable number + * @internal + */ export function decimalToPercent( value: string | number | boolean | null | undefined, ): number | undefined { @@ -20,6 +32,18 @@ export function decimalToPercent( return toCleanNumber(numValue * 100) } +/** + * Converts a percentage value into its decimal equivalent serialized as a string. + * + * @remarks + * Divides by 100 and rounds to 12 significant digits to avoid floating-point artifacts. + * If `value` cannot be parsed as a number, it is returned as-is via `String(value)` so that + * partially-typed form input is preserved. + * + * @param value - The percentage value to convert; strings are parsed as floats + * @returns The decimal value as a string (e.g. `6.25` becomes `"0.0625"`) + * @internal + */ export function percentToDecimal(value: number | string): string { const numValue = typeof value === 'number' ? value : parseFloat(value) @@ -30,6 +54,18 @@ export function percentToDecimal(value: number | string): string { return String(toCleanNumber(numValue / 100)) } +/** + * Formats a decimal value as a localized percentage string with a trailing `%`. + * + * @remarks + * Uses `Intl.NumberFormat` with 1 to 4 fractional digits. If `decimalValue` cannot be converted + * to a percentage via {@link decimalToPercent}, the original string is returned unchanged. + * + * @param decimalValue - The decimal value to format, as a string + * @param locale - BCP 47 locale tag passed to `Intl.NumberFormat`. Defaults to `'en-US'`. + * @returns The localized percentage string, or `decimalValue` when it cannot be parsed + * @internal + */ export function formatPercentLabel(decimalValue: string, locale = 'en-US'): string { const percent = decimalToPercent(decimalValue) if (percent === undefined) return decimalValue diff --git a/src/helpers/readableStreamToBlob.ts b/src/helpers/readableStreamToBlob.ts index 583d5c5c7..155bfd294 100644 --- a/src/helpers/readableStreamToBlob.ts +++ b/src/helpers/readableStreamToBlob.ts @@ -1,3 +1,16 @@ +/** + * Drains a binary `ReadableStream` and packages the bytes into a `Blob`. + * + * @remarks + * Reads all chunks from the stream, concatenates them into a single `Uint8Array`, and wraps the + * result in a `Blob` tagged with `mimeType`. Used to materialize downloads returned by streaming + * API responses. + * + * @param stream - The byte stream to read to completion + * @param mimeType - The MIME type assigned to the resulting `Blob` + * @returns A `Blob` containing the full contents of the stream + * @internal + */ export async function readableStreamToBlob(stream: ReadableStream, mimeType: string) { const reader = stream.getReader() const chunks: Uint8Array[] = [] diff --git a/src/helpers/rem.ts b/src/helpers/rem.ts index 01e4b3186..77d4765e6 100644 --- a/src/helpers/rem.ts +++ b/src/helpers/rem.ts @@ -1,11 +1,16 @@ let cachedRootFontSize: string | null = null /** - * Detects font-size on the document root element with fallback to 16px which is the default browser setting. - * The value is cached after the first call to avoid repeated expensive getComputedStyle() calls. + * Reads the font size of the document root element, falling back to `'16'` when running outside the browser or when the value cannot be parsed. * - * @param options - Set `forceRefresh` to force a fresh detection instead of using the cached value - * @returns The root font size in pixels as a string + * @remarks + * The first call resolves the value via `getComputedStyle(document.documentElement)` and caches it + * for subsequent calls, since `getComputedStyle` triggers layout. Pass `forceRefresh: true` to + * recompute, e.g. after a theme change that adjusts the root font size. + * + * @param options - Optional flags. Set `forceRefresh` to `true` to bypass the cache and recompute the value. + * @returns The root font size in pixels as a numeric string (no `px` suffix) + * @internal */ export function getRootFontSize(options?: { forceRefresh?: boolean }) { if (cachedRootFontSize && !options?.forceRefresh) { @@ -28,10 +33,26 @@ export function getRootFontSize(options?: { forceRefresh?: boolean }) { return cachedRootFontSize } +/** + * Converts a pixel value into a `rem`-suffixed string relative to the document root font size. + * + * @param pxValue - The value in pixels + * @returns The equivalent value as a string ending in `rem` (e.g. `'1.5rem'`) + * @internal + * @see {@link getRootFontSize} + */ export function toRem(pxValue: number) { return String(pxValue / Number(getRootFontSize())) + 'rem' } +/** + * Converts a `rem` value into pixels relative to the document root font size. + * + * @param rem - The value in `rem`. Accepts either a number (interpreted as raw `rem`) or a string that may include the `rem` suffix (e.g. `'1.5rem'`). + * @returns The equivalent value in pixels as a number + * @internal + * @see {@link getRootFontSize} + */ export const remToPx = (rem: string | number) => typeof rem === 'number' ? Number(getRootFontSize()) * rem diff --git a/src/helpers/responsive.ts b/src/helpers/responsive.ts index 2ad3f0198..22eed28da 100644 --- a/src/helpers/responsive.ts +++ b/src/helpers/responsive.ts @@ -3,20 +3,48 @@ import { BREAKPOINTS } from '@/shared/constants' type BreakpointKey = (typeof BREAKPOINTS)[keyof typeof BREAKPOINTS] +/** + * A value that may be specified as a single value or as a partial map of breakpoints to values. + * + * @typeParam T - The underlying value type at each breakpoint. + * @internal + */ export type Responsive = | T | Partial<{ [K in BreakpointKey]: T }> +/** + * Value accepted for a CSS custom property — either a string token or a numeric pixel value. + * + * @internal + */ export type CustomPropertyValue = string | number +/** + * Returns true if the value is a breakpoint-keyed object rather than a single value. + * + * @param value - The value to inspect. + * @returns Whether the value is keyed by a known breakpoint. + * @internal + */ export function isResponsiveValue(value: Responsive) { return Object.values(BREAKPOINTS).some( breakpoint => typeof value === 'object' && breakpoint in value, ) } +/** + * Applies a transform to every breakpoint entry in a responsive value. + * + * Non-responsive values are treated as if specified at the `base` breakpoint. + * + * @param value - The responsive value to transform. + * @param transformValue - Function applied to each per-breakpoint value. + * @returns A map of breakpoint key to the transformed string value. + * @internal + */ export function transformResponsiveValue( value: Responsive, transformValue: (value: CustomPropertyValue | CustomPropertyValue[]) => string, @@ -32,10 +60,28 @@ export function transformResponsiveValue( return transformedResponsiveValue } +/** + * Converts numeric values to rem units and passes string values through unchanged. + * + * @param value - A pixel number or a pre-formatted CSS length string. + * @returns The value as a rem-unit string when numeric, otherwise the original string. + * @internal + */ export const toRemIfNumeric = (value: string | number) => { return typeof value === 'number' ? toRem(value) : value } +/** + * Builds a map of CSS custom properties for one property across breakpoints. + * + * Each entry is keyed `--g--` and numeric values are converted to rem. + * Array values are joined with spaces (for shorthand properties like margin). + * + * @param property - The base property name used to build custom property keys. + * @param value - The responsive value, or undefined to produce no properties. + * @returns A map of custom property names to string values. + * @internal + */ export function createResponsiveCustomProperties( property: string, value?: Responsive, @@ -56,6 +102,15 @@ export function createResponsiveCustomProperties( return properties } +/** + * Builds a flat map of CSS custom properties for multiple properties at once. + * + * Combines the output of {@link createResponsiveCustomProperties} for every entry in the input. + * + * @param properties - A map of property name to its responsive value. + * @returns A flat map of custom property names to string values suitable for a `style` prop. + * @internal + */ export function setResponsiveCustomProperties( properties?: Record | undefined>, ) { diff --git a/src/helpers/retryAsync.ts b/src/helpers/retryAsync.ts index b5f2ff24c..ad932c3e5 100644 --- a/src/helpers/retryAsync.ts +++ b/src/helpers/retryAsync.ts @@ -4,6 +4,20 @@ interface RetryAsyncOptions { shouldRetry: (error: unknown) => boolean } +/** + * Retries an async function up to a maximum number of attempts, with a fixed delay between tries. + * + * The function is invoked at least once. After a failure, `shouldRetry` decides whether to retry; + * if it returns false the error is rethrown immediately. Errors from the final attempt are always + * rethrown. + * + * @typeParam T - The resolved value type of the async function. + * @param fn - The async function to invoke. + * @param options - Retry configuration: `maxAttempts`, `delayMs` between attempts, and a `shouldRetry` predicate. + * @returns The resolved value from the first successful call. + * @throws The error from the final attempt, or the first error for which `shouldRetry` returns false. + * @internal + */ export async function retryAsync( fn: () => Promise, { maxAttempts, delayMs, shouldRetry }: RetryAsyncOptions, diff --git a/src/helpers/ssn.ts b/src/helpers/ssn.ts index b8d0f389f..88204d5e7 100644 --- a/src/helpers/ssn.ts +++ b/src/helpers/ssn.ts @@ -1,5 +1,14 @@ import { useTranslation } from 'react-i18next' +/** + * Formats an SSN-like input string as `XXX-XX-XXXX`, stripping non-digit characters. + * + * Excess digits beyond nine are truncated. + * + * @param value - Raw user input that may contain digits, spaces, or punctuation. + * @returns The dash-formatted SSN, or an empty string if no digits are present. + * @internal + */ export const normalizeSSN = (value: string) => value .match(/\d*/g) @@ -10,9 +19,24 @@ export const normalizeSSN = (value: string) => .join('-') .substring(0, 12) || '' -export const createPlaceholderSSN = (hasSSN?: boolean, placeholderSSN?: string) => +/** + * Returns the masked placeholder string when an SSN is already on file, otherwise an empty string. + * + * @param hasSSN - Whether the underlying record already has an SSN stored. + * @param placeholderSSN - The masked placeholder to display when an SSN exists. + * @returns The placeholder when `hasSSN` is true, otherwise an empty string. + * @internal + */ +const createPlaceholderSSN = (hasSSN?: boolean, placeholderSSN?: string) => hasSSN ? placeholderSSN : '' +/** + * Hook that returns the localized SSN placeholder when an SSN is already on file. + * + * @param hasSSN - Whether the underlying record already has an SSN stored. + * @returns The translated placeholder string, or an empty string when no SSN exists. + * @internal + */ export const usePlaceholderSSN = (hasSSN?: boolean) => { const { t } = useTranslation('common') return createPlaceholderSSN(hasSSN, t('inputs.ssn.placeholder')) diff --git a/src/helpers/validations.ts b/src/helpers/validations.ts index 607115083..01102ca9f 100644 --- a/src/helpers/validations.ts +++ b/src/helpers/validations.ts @@ -2,14 +2,42 @@ import { z } from 'zod' import { commonMasks, formatWithMask } from './mask' import { removeNonDigits } from '@/helpers/formattedStrings' +/** + * Regex matching personal names: one or two words composed of Latin or extended-Latin letters, + * with optional internal spaces, hyphens, or apostrophes, and an optional trailing period. + * + * @internal + */ export const NAME_REGEX = /^([a-zA-Z\xC0-\uFFFF]+([ \-']{0,1}[a-zA-Z\xC0-\uFFFF]+)*[.]{0,1}){1,2}$/ +/** + * Zod schema validating a non-empty personal name against {@link NAME_REGEX}. + * + * @internal + */ export const nameValidation = z.string().min(1).regex(NAME_REGEX) +/** + * Zod schema validating a US ZIP code in either 5-digit (`12345`) or ZIP+4 (`12345-6789`) form. + * + * @internal + */ export const zipValidation = z.string().refine(zip => /(^\d{5}$)|(^\d{5}-\d{4}$)/.test(zip)) +/** + * Regex matching a valid US Social Security Number. Rejects reserved area numbers (000, 666, 9xx), + * a group number of 00, and a serial number of 0000. + * + * @internal + */ export const SSN_REGEX = /^(?!(000|666|9))\d{3}(?!00)\d{2}(?!0000)\d{4}$/ +/** + * Zod schema validating a US phone number. Formats the input with the phone mask and accepts it + * only when the digit-only form is exactly ten digits. + * + * @internal + */ export const phoneValidation = z .string() .transform(value => formatWithMask(value, commonMasks.phoneMask)) @@ -18,5 +46,15 @@ export const phoneValidation = z return digits.length === 10 }) +/** + * Zod schema validating a bank routing number (exactly nine digits). + * + * @internal + */ export const routingNumberValidation = z.string().regex(/^[0-9]{9}$/) +/** + * Zod schema validating a bank account number (one to seventeen digits). + * + * @internal + */ export const accountNumberValidation = z.string().regex(/^[0-9]{1,17}$/) From e2556b953b7d7010c96f20ef35d7880b11827901 Mon Sep 17 00:00:00 2001 From: Marie Chatfield Date: Wed, 3 Jun 2026 18:11:49 -0700 Subject: [PATCH 2/2] docs(SDK-971): tsdoc-directory src/components/Common/Fields/ Co-Authored-By: Claude Sonnet 4.6 --- eslint.config.ts | 1 + .../Common/Fields/CheckboxField/CheckboxField.tsx | 2 ++ src/components/Common/Fields/CheckboxField/index.ts | 2 +- .../Common/Fields/CheckboxGroupField/CheckboxGroupField.tsx | 2 ++ src/components/Common/Fields/CheckboxGroupField/index.ts | 2 +- .../Common/Fields/ComboBoxField/ComboBoxField.tsx | 2 ++ src/components/Common/Fields/ComboBoxField/index.ts | 1 - .../Common/Fields/DatePickerField/DatePickerField.tsx | 2 ++ .../Common/Fields/FileInputField/FileInputField.tsx | 2 ++ src/components/Common/Fields/FileInputField/index.ts | 2 +- .../MultiSelectComboBoxField/MultiSelectComboBoxField.tsx | 2 ++ .../Common/Fields/MultiSelectComboBoxField/index.ts | 5 +---- .../Common/Fields/NumberInputField/NumberInputField.tsx | 2 ++ src/components/Common/Fields/NumberInputField/index.ts | 2 +- .../Common/Fields/PercentageField/PercentageField.tsx | 2 ++ src/components/Common/Fields/PercentageField/index.ts | 1 - .../Common/Fields/RadioGroupField/RadioGroupField.tsx | 2 ++ src/components/Common/Fields/RadioGroupField/index.ts | 1 - src/components/Common/Fields/SelectField/SelectField.tsx | 2 ++ src/components/Common/Fields/SelectField/index.ts | 1 - src/components/Common/Fields/SwitchField/SwitchField.tsx | 2 ++ .../Common/Fields/TextAreaField/TextAreaField.tsx | 2 ++ src/components/Common/Fields/TextAreaField/index.ts | 1 - .../Common/Fields/TextInputField/TextInputField.tsx | 2 ++ src/components/Common/Fields/TextInputField/index.ts | 2 +- .../Common/Fields/hooks/FieldElementRegistryProvider.tsx | 2 ++ src/components/Common/Fields/hooks/fieldElementRegistry.ts | 6 ++++++ src/components/Common/Fields/hooks/useField.ts | 3 +++ .../Common/Fields/hooks/useStringifyGenericFieldValue.ts | 4 ++++ 29 files changed, 48 insertions(+), 14 deletions(-) delete mode 100644 src/components/Common/Fields/PercentageField/index.ts diff --git a/eslint.config.ts b/eslint.config.ts index 0e4fba5cf..8e08ffb1f 100644 --- a/eslint.config.ts +++ b/eslint.config.ts @@ -190,6 +190,7 @@ export default [ { files: [ 'src/components/Base/**/*.{ts,tsx}', + 'src/components/Common/Fields/**/*.{ts,tsx}', 'src/components/Flow/**/*.{ts,tsx}', 'src/contexts/ApiProvider/**/*.{ts,tsx}', 'src/contexts/LocaleProvider/**/*.{ts,tsx}', diff --git a/src/components/Common/Fields/CheckboxField/CheckboxField.tsx b/src/components/Common/Fields/CheckboxField/CheckboxField.tsx index e94b18795..a193c3884 100644 --- a/src/components/Common/Fields/CheckboxField/CheckboxField.tsx +++ b/src/components/Common/Fields/CheckboxField/CheckboxField.tsx @@ -3,11 +3,13 @@ import { useField, type UseFieldProps } from '@/components/Common/Fields/hooks/u import type { CheckboxProps } from '@/components/Common/UI/Checkbox/CheckboxTypes' import { useComponentContext } from '@/contexts/ComponentAdapter/useComponentContext' +/** @internal */ export interface CheckboxFieldProps extends Omit, UseFieldProps { FieldComponent?: ComponentType } +/** @internal */ export const CheckboxField: React.FC = ({ rules, defaultValue, diff --git a/src/components/Common/Fields/CheckboxField/index.ts b/src/components/Common/Fields/CheckboxField/index.ts index 6b257d2b6..c249595b0 100644 --- a/src/components/Common/Fields/CheckboxField/index.ts +++ b/src/components/Common/Fields/CheckboxField/index.ts @@ -1 +1 @@ -export { CheckboxField, type CheckboxFieldProps } from './CheckboxField' +export { CheckboxField } from './CheckboxField' diff --git a/src/components/Common/Fields/CheckboxGroupField/CheckboxGroupField.tsx b/src/components/Common/Fields/CheckboxGroupField/CheckboxGroupField.tsx index 1b264b031..bb5e778c2 100644 --- a/src/components/Common/Fields/CheckboxGroupField/CheckboxGroupField.tsx +++ b/src/components/Common/Fields/CheckboxGroupField/CheckboxGroupField.tsx @@ -9,6 +9,7 @@ import { type GenericCheckboxGroupOption = OptionWithGenericValue +/** @internal */ export interface CheckboxGroupFieldProps extends Omit, @@ -17,6 +18,7 @@ export interface CheckboxGroupFieldProps convertValueToString?: (value: TValue) => string } +/** @internal */ export const CheckboxGroupField = ({ rules, defaultValue, diff --git a/src/components/Common/Fields/CheckboxGroupField/index.ts b/src/components/Common/Fields/CheckboxGroupField/index.ts index ed752c097..617d1b5bb 100644 --- a/src/components/Common/Fields/CheckboxGroupField/index.ts +++ b/src/components/Common/Fields/CheckboxGroupField/index.ts @@ -1 +1 @@ -export { CheckboxGroupField, type CheckboxGroupFieldProps } from './CheckboxGroupField' +export { CheckboxGroupField } from './CheckboxGroupField' diff --git a/src/components/Common/Fields/ComboBoxField/ComboBoxField.tsx b/src/components/Common/Fields/ComboBoxField/ComboBoxField.tsx index 33f1eb09e..6dceaf465 100644 --- a/src/components/Common/Fields/ComboBoxField/ComboBoxField.tsx +++ b/src/components/Common/Fields/ComboBoxField/ComboBoxField.tsx @@ -8,6 +8,7 @@ import { type GenericComboBoxOption = OptionWithGenericValue +/** @internal */ export interface ComboBoxFieldProps extends Omit< @@ -20,6 +21,7 @@ export interface ComboBoxFieldProps allowsCustomValue?: TValue extends string ? boolean : never } +/** @internal */ export const ComboBoxField = ({ rules, defaultValue, diff --git a/src/components/Common/Fields/ComboBoxField/index.ts b/src/components/Common/Fields/ComboBoxField/index.ts index 312bd73b8..dd10af003 100644 --- a/src/components/Common/Fields/ComboBoxField/index.ts +++ b/src/components/Common/Fields/ComboBoxField/index.ts @@ -1,2 +1 @@ export { ComboBoxField } from './ComboBoxField' -export type { ComboBoxFieldProps } from './ComboBoxField' diff --git a/src/components/Common/Fields/DatePickerField/DatePickerField.tsx b/src/components/Common/Fields/DatePickerField/DatePickerField.tsx index fa866ad83..dfadb032e 100644 --- a/src/components/Common/Fields/DatePickerField/DatePickerField.tsx +++ b/src/components/Common/Fields/DatePickerField/DatePickerField.tsx @@ -11,11 +11,13 @@ import { type DateFieldValue = string | Date | null +/** @internal */ export interface DatePickerFieldProps extends Omit, UseFieldProps { FieldComponent?: ComponentType } +/** @internal */ export const DatePickerField = ({ rules, defaultValue, diff --git a/src/components/Common/Fields/FileInputField/FileInputField.tsx b/src/components/Common/Fields/FileInputField/FileInputField.tsx index 08a80bd9f..d8116f683 100644 --- a/src/components/Common/Fields/FileInputField/FileInputField.tsx +++ b/src/components/Common/Fields/FileInputField/FileInputField.tsx @@ -2,11 +2,13 @@ import { useField, type UseFieldProps } from '@/components/Common/Fields/hooks/u import type { FileInputProps } from '@/components/Common/UI/FileInput/FileInputTypes' import { useComponentContext } from '@/contexts/ComponentAdapter/useComponentContext' +/** @internal */ export interface FileInputFieldProps extends Omit, UseFieldProps {} +/** @internal */ export const FileInputField: React.FC = ({ rules, defaultValue, diff --git a/src/components/Common/Fields/FileInputField/index.ts b/src/components/Common/Fields/FileInputField/index.ts index eeaf4d947..c4aa9af96 100644 --- a/src/components/Common/Fields/FileInputField/index.ts +++ b/src/components/Common/Fields/FileInputField/index.ts @@ -1 +1 @@ -export { FileInputField, type FileInputFieldProps } from './FileInputField' +export { FileInputField } from './FileInputField' diff --git a/src/components/Common/Fields/MultiSelectComboBoxField/MultiSelectComboBoxField.tsx b/src/components/Common/Fields/MultiSelectComboBoxField/MultiSelectComboBoxField.tsx index 253de5cbe..d09e2f41c 100644 --- a/src/components/Common/Fields/MultiSelectComboBoxField/MultiSelectComboBoxField.tsx +++ b/src/components/Common/Fields/MultiSelectComboBoxField/MultiSelectComboBoxField.tsx @@ -2,11 +2,13 @@ import { useField, type UseFieldProps } from '@/components/Common/Fields/hooks/u import type { MultiSelectComboBoxProps } from '@/components/Common/UI/MultiSelectComboBox/MultiSelectComboBoxTypes' import { useComponentContext } from '@/contexts/ComponentAdapter/useComponentContext' +/** @internal */ export interface MultiSelectComboBoxFieldProps extends Omit, UseFieldProps {} +/** @internal */ export const MultiSelectComboBoxField: React.FC = ({ rules, defaultValue, diff --git a/src/components/Common/Fields/MultiSelectComboBoxField/index.ts b/src/components/Common/Fields/MultiSelectComboBoxField/index.ts index 61f986c11..62165cdf6 100644 --- a/src/components/Common/Fields/MultiSelectComboBoxField/index.ts +++ b/src/components/Common/Fields/MultiSelectComboBoxField/index.ts @@ -1,4 +1 @@ -export { - MultiSelectComboBoxField, - type MultiSelectComboBoxFieldProps, -} from './MultiSelectComboBoxField' +export { MultiSelectComboBoxField } from './MultiSelectComboBoxField' diff --git a/src/components/Common/Fields/NumberInputField/NumberInputField.tsx b/src/components/Common/Fields/NumberInputField/NumberInputField.tsx index f8218e0ca..6ebb2aec2 100644 --- a/src/components/Common/Fields/NumberInputField/NumberInputField.tsx +++ b/src/components/Common/Fields/NumberInputField/NumberInputField.tsx @@ -3,11 +3,13 @@ import { useField, type UseFieldProps } from '@/components/Common/Fields/hooks/u import type { NumberInputProps } from '@/components/Common/UI/NumberInput/NumberInputTypes' import { useComponentContext } from '@/contexts/ComponentAdapter/useComponentContext' +/** @internal */ export interface NumberInputFieldProps extends Omit, UseFieldProps { FieldComponent?: ComponentType } +/** @internal */ export const NumberInputField: React.FC = ({ rules: providedRules, defaultValue, diff --git a/src/components/Common/Fields/NumberInputField/index.ts b/src/components/Common/Fields/NumberInputField/index.ts index 8f1f5bd00..88e547cad 100644 --- a/src/components/Common/Fields/NumberInputField/index.ts +++ b/src/components/Common/Fields/NumberInputField/index.ts @@ -1 +1 @@ -export { NumberInputField, type NumberInputFieldProps } from './NumberInputField' +export { NumberInputField } from './NumberInputField' diff --git a/src/components/Common/Fields/PercentageField/PercentageField.tsx b/src/components/Common/Fields/PercentageField/PercentageField.tsx index 22687a306..a8ae36707 100644 --- a/src/components/Common/Fields/PercentageField/PercentageField.tsx +++ b/src/components/Common/Fields/PercentageField/PercentageField.tsx @@ -5,6 +5,7 @@ import { useField } from '@/components/Common/Fields/hooks/useField' import { useComponentContext } from '@/contexts/ComponentAdapter/useComponentContext' import { decimalToPercent, percentToDecimal } from '@/helpers/percentageConversion' +/** @internal */ export interface PercentageFieldProps extends Pick< NumberInputProps, 'isDisabled' | 'className' | 'label' | 'isRequired' | 'description' | 'errorMessage' @@ -20,6 +21,7 @@ function toDefaultString(value?: string | number | boolean | null): string | und return String(value) } +/** @internal */ export function PercentageField({ decimalValue, decimalMin, diff --git a/src/components/Common/Fields/PercentageField/index.ts b/src/components/Common/Fields/PercentageField/index.ts deleted file mode 100644 index bf2f61b18..000000000 --- a/src/components/Common/Fields/PercentageField/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { PercentageField, type PercentageFieldProps } from './PercentageField' diff --git a/src/components/Common/Fields/RadioGroupField/RadioGroupField.tsx b/src/components/Common/Fields/RadioGroupField/RadioGroupField.tsx index 6425c865f..c8e9539a2 100644 --- a/src/components/Common/Fields/RadioGroupField/RadioGroupField.tsx +++ b/src/components/Common/Fields/RadioGroupField/RadioGroupField.tsx @@ -12,6 +12,7 @@ import { type GenericRadioGroupOption = OptionWithGenericValue +/** @internal */ export interface RadioGroupFieldProps extends Omit, @@ -21,6 +22,7 @@ export interface RadioGroupFieldProps FieldComponent?: ComponentType } +/** @internal */ export const RadioGroupField = ({ rules, defaultValue, diff --git a/src/components/Common/Fields/RadioGroupField/index.ts b/src/components/Common/Fields/RadioGroupField/index.ts index c9d80437a..36e3cb0c5 100644 --- a/src/components/Common/Fields/RadioGroupField/index.ts +++ b/src/components/Common/Fields/RadioGroupField/index.ts @@ -1,2 +1 @@ export { RadioGroupField } from './RadioGroupField' -export type { RadioGroupFieldProps } from './RadioGroupField' diff --git a/src/components/Common/Fields/SelectField/SelectField.tsx b/src/components/Common/Fields/SelectField/SelectField.tsx index 8c6fe6529..bb728c62c 100644 --- a/src/components/Common/Fields/SelectField/SelectField.tsx +++ b/src/components/Common/Fields/SelectField/SelectField.tsx @@ -9,6 +9,7 @@ import { type GenericSelectOption = OptionWithGenericValue +/** @internal */ export interface SelectFieldProps extends Omit, @@ -18,6 +19,7 @@ export interface SelectFieldProps FieldComponent?: ComponentType } +/** @internal */ export const SelectField = ({ rules, defaultValue, diff --git a/src/components/Common/Fields/SelectField/index.ts b/src/components/Common/Fields/SelectField/index.ts index 84796eede..467a6585d 100644 --- a/src/components/Common/Fields/SelectField/index.ts +++ b/src/components/Common/Fields/SelectField/index.ts @@ -1,2 +1 @@ export { SelectField } from './SelectField' -export type { SelectFieldProps } from './SelectField' diff --git a/src/components/Common/Fields/SwitchField/SwitchField.tsx b/src/components/Common/Fields/SwitchField/SwitchField.tsx index cbe6e7c83..302bb8b9d 100644 --- a/src/components/Common/Fields/SwitchField/SwitchField.tsx +++ b/src/components/Common/Fields/SwitchField/SwitchField.tsx @@ -2,11 +2,13 @@ import type { ComponentType } from 'react' import { useField, type UseFieldProps } from '@/components/Common/Fields/hooks/useField' import type { SwitchProps } from '@/components/Common/UI/Switch/SwitchTypes' import { useComponentContext } from '@/contexts/ComponentAdapter/useComponentContext' +/** @internal */ export interface SwitchFieldProps extends Omit, UseFieldProps { FieldComponent?: ComponentType } +/** @internal */ export const SwitchField: React.FC = ({ rules, defaultValue, diff --git a/src/components/Common/Fields/TextAreaField/TextAreaField.tsx b/src/components/Common/Fields/TextAreaField/TextAreaField.tsx index 8d2bee4c5..7b702ad7d 100644 --- a/src/components/Common/Fields/TextAreaField/TextAreaField.tsx +++ b/src/components/Common/Fields/TextAreaField/TextAreaField.tsx @@ -2,11 +2,13 @@ import { useField, type UseFieldProps } from '@/components/Common/Fields/hooks/u import type { TextAreaProps } from '@/components/Common/UI/TextArea/TextAreaTypes' import { useComponentContext } from '@/contexts/ComponentAdapter/useComponentContext' +/** @internal */ export interface TextAreaFieldProps extends Omit, UseFieldProps {} +/** @internal */ export const TextAreaField: React.FC = ({ rules, defaultValue, diff --git a/src/components/Common/Fields/TextAreaField/index.ts b/src/components/Common/Fields/TextAreaField/index.ts index a9f405781..da43d3b75 100644 --- a/src/components/Common/Fields/TextAreaField/index.ts +++ b/src/components/Common/Fields/TextAreaField/index.ts @@ -1,2 +1 @@ export { TextAreaField } from './TextAreaField' -export type { TextAreaFieldProps } from './TextAreaField' diff --git a/src/components/Common/Fields/TextInputField/TextInputField.tsx b/src/components/Common/Fields/TextInputField/TextInputField.tsx index 9f629c0b2..ae4445f0c 100644 --- a/src/components/Common/Fields/TextInputField/TextInputField.tsx +++ b/src/components/Common/Fields/TextInputField/TextInputField.tsx @@ -3,11 +3,13 @@ import { useField, type UseFieldProps } from '@/components/Common/Fields/hooks/u import type { TextInputProps } from '@/components/Common/UI/TextInput/TextInputTypes' import { useComponentContext } from '@/contexts/ComponentAdapter/useComponentContext' +/** @internal */ export interface TextInputFieldProps extends Omit, UseFieldProps { FieldComponent?: ComponentType } +/** @internal */ export const TextInputField: React.FC = ({ rules, defaultValue, diff --git a/src/components/Common/Fields/TextInputField/index.ts b/src/components/Common/Fields/TextInputField/index.ts index e18ddc895..a27811de8 100644 --- a/src/components/Common/Fields/TextInputField/index.ts +++ b/src/components/Common/Fields/TextInputField/index.ts @@ -1 +1 @@ -export { TextInputField, type TextInputFieldProps } from './TextInputField' +export { TextInputField } from './TextInputField' diff --git a/src/components/Common/Fields/hooks/FieldElementRegistryProvider.tsx b/src/components/Common/Fields/hooks/FieldElementRegistryProvider.tsx index 8ca2344a5..2ee7637a6 100644 --- a/src/components/Common/Fields/hooks/FieldElementRegistryProvider.tsx +++ b/src/components/Common/Fields/hooks/FieldElementRegistryProvider.tsx @@ -10,6 +10,8 @@ interface FieldElementRegistryProviderProps { * Publishes a `FieldElementRegistry` via context so `useField` can populate it. * `SDKFormProvider` wires this automatically; partners who build their own form * surface can wrap with this provider directly to opt into cross-form focus. + * + * @internal */ export function FieldElementRegistryProvider({ registry, diff --git a/src/components/Common/Fields/hooks/fieldElementRegistry.ts b/src/components/Common/Fields/hooks/fieldElementRegistry.ts index 0ff951612..6af41b2d4 100644 --- a/src/components/Common/Fields/hooks/fieldElementRegistry.ts +++ b/src/components/Common/Fields/hooks/fieldElementRegistry.ts @@ -8,6 +8,8 @@ import { createContext, useContext, useRef } from 'react' * Lives here (next to `useField`) rather than in `partner-hook-utils` so the * established module-boundary direction (`partner-hook-utils` → `Common`) is * preserved. Partner code consumes it via re-exports from `partner-hook-utils/form`. + * + * @internal */ export interface FieldElementRegistry { register: (name: string, element: HTMLElement | null) => void @@ -37,6 +39,8 @@ function createFieldElementRegistry(): FieldElementRegistry { /** * Creates a stable `FieldElementRegistry` scoped to the caller's lifetime. * Intended to be called once per form hook (via `useHookFormInternals`). + * + * @internal */ export function useFieldElementRegistry(): FieldElementRegistry { const ref = useRef(null) @@ -46,8 +50,10 @@ export function useFieldElementRegistry(): FieldElementRegistry { return ref.current } +/** @internal */ export const FieldElementRegistryContext = createContext(null) +/** @internal */ export function useFieldElementRegistryContext(): FieldElementRegistry | null { return useContext(FieldElementRegistryContext) } diff --git a/src/components/Common/Fields/hooks/useField.ts b/src/components/Common/Fields/hooks/useField.ts index d1f2da7a1..fa091bed6 100644 --- a/src/components/Common/Fields/hooks/useField.ts +++ b/src/components/Common/Fields/hooks/useField.ts @@ -5,8 +5,10 @@ import { useFieldElementRegistryContext } from './fieldElementRegistry' import { createMarkup } from '@/helpers/formattedStrings' import { useForkRef } from '@/hooks/useForkRef/useForkRef' +/** @internal */ export type Transform = (value: TValue) => TValue +/** @internal */ export interface UseFieldProps { name: string control?: Control @@ -32,6 +34,7 @@ const processDescription = (description: React.ReactNode): React.ReactNode => { }) } +/** @internal */ export function useField({ name, control: controlProp, diff --git a/src/components/Common/Fields/hooks/useStringifyGenericFieldValue.ts b/src/components/Common/Fields/hooks/useStringifyGenericFieldValue.ts index a3218c9e2..be9479bd2 100644 --- a/src/components/Common/Fields/hooks/useStringifyGenericFieldValue.ts +++ b/src/components/Common/Fields/hooks/useStringifyGenericFieldValue.ts @@ -1,7 +1,9 @@ import { useCallback, useMemo } from 'react' +/** @internal */ export type ConvertValueToString = (value: TValue) => string +/** @internal */ export type OptionWithGenericValue = Omit & { value: TValue } @@ -43,6 +45,7 @@ interface UseStringifyGenericFieldValueProps { convertValueToString?: ConvertValueToString } +/** @internal */ export function useStringifyGenericFieldValue({ options, value, @@ -81,6 +84,7 @@ interface UseStringifyGenericFieldValueArrayProps { convertValueToString?: ConvertValueToString } +/** @internal */ export function useStringifyGenericFieldValueArray({ options, value,