@chris-c-brine/rhf-mui-kit 0.5.3 → 0.5.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -133,7 +133,7 @@ export const ObjectElementDisplay = ({ options, autocompleteProps, getItemKey, g
133
133
  }
134
134
  // Handle regular option
135
135
  return (_createElement(ListItem, { ...itemProps, key: `${name}-option-${getItemKey(option)}` },
136
- (props?.showCheckbox && ownerState?.multiple) && (_jsx(Checkbox, { sx: { marginRight: 1 }, checked: selected })),
136
+ props?.showCheckbox && ownerState?.multiple && (_jsx(Checkbox, { sx: { marginRight: 1 }, checked: selected })),
137
137
  typeof option === "string" ? option : getItemLabel(option)));
138
138
  },
139
139
  onChange: (event, value, reason, details) => {
@@ -239,5 +239,15 @@ export const ObjectElementDisplay = ({ options, autocompleteProps, getItemKey, g
239
239
  : "";
240
240
  },
241
241
  ...autocompleteProps,
242
+ }, textFieldProps: {
243
+ /**
244
+ * Determines the placeholder value based on the `field.value` and `props.textFieldProps.placeholder`.
245
+ * If `field.value` is truthy, the placeholder will be an empty string.
246
+ * Otherwise, it uses `props.textFieldProps.placeholder` if available.
247
+ *
248
+ * @type {string}
249
+ */
250
+ placeholder: field.value ? "" : props?.textFieldProps?.placeholder,
251
+ ...props?.textFieldProps,
242
252
  } }));
243
253
  };
package/dist/index.cjs CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const y=require("react/jsx-runtime"),T=require("react-hook-form-mui"),h=require("react"),g=require("lodash"),C=require("@mui/material"),B=require("react-hook-form"),{merge:R}=g;function L(e,n){return n?.multiple,n?.freeSolo,e}const S=(e,n=!1,r=!1)=>R(e,n?{disabled:!0,variant:"standard",sx:{"& .MuiAutocomplete-endAdornment":{display:"none"},...r&&{"& .MuiInput-underline:before":{borderBottom:"none"},"& .MuiInput-underline:after":{borderBottom:"none"},"& .MuiInput-underline:hover:not(.Mui-disabled):before":{borderBottom:"none"}}}}:{});function w(e){return e!=null&&typeof e=="string"}const{merge:z}=g,$=({viewOnly:e=void 0,disableUnderline:n,textFieldProps:r,autocompleteProps:c,...E})=>{const f=h.useMemo(()=>z({readOnly:e,disableClearable:c?.disableClearable||e,disabled:e},c,e?{sx:{".MuiAutocomplete-tag":{opacity:"1 !important"}}}:{}),[c,e]),A=h.useMemo(()=>S(r,e,n),[r,e,n]);return y.jsx(T.AutocompleteElement,{autocompleteProps:f,textFieldProps:A,...E})},G=({options:e,autocompleteProps:n,getItemKey:r,getItemLabel:c,getChipProps:E,stringToNewItem:f,transformValue:A,name:O,freeSolo:F,control:q,getOptionProps:_,...V})=>{const{field:a}=T.useController({name:O,control:q}),[b,k]=h.useState(()=>a.value?(Array.isArray(a.value)?a.value:[a.value]).filter(t=>typeof t!="string"&&!e.some(s=>r(s)===r(t))):[]);h.useEffect(()=>{if(!a.value)return;const t=(Array.isArray(a.value)?a.value:[a.value]).filter(s=>typeof s!="string"&&![...e,...b].some(u=>r(u)===r(s)));t.length>0&&k(s=>[...s,...t])},[a.value,e,b,r]);const H=h.useMemo(()=>{const i=new Set;return[...e,...b].filter(t=>{const s=r(t);return i.has(s)?!1:(i.add(s),!0)})},[e,b]);return y.jsx($,{name:O,control:q,options:H,...V,autocompleteProps:{isOptionEqualToValue:(i,t)=>r(i)===r(t),filterOptions:(i,{inputValue:t})=>{if(!t)return i;const s=t.toLowerCase(),u=i.filter(l=>{const d=r(l)?.toLowerCase(),j=String(c(l)).toLowerCase();return d?.includes(s)||j.includes(s)});return F&&f&&t.length>0&&!u.some(d=>String(c(d)).toLowerCase()===s)?[{__isAddOption:!0,inputValue:t,...f(t)},...u]:u},freeSolo:F,autoComplete:!0,autoHighlight:!0,openOnFocus:!0,renderOption:(i,t,{selected:s},u)=>{const l=g.merge(i,_?.(t)??{});if(u?.freeSolo&&typeof t=="object"&&t!==null&&"__isAddOption"in t){const d=t.inputValue;return h.createElement(C.ListItem,{...l,key:`${O}-add-option-${d}`},"Add: '",d,"'")}return h.createElement(C.ListItem,{...l,key:`${O}-option-${r(t)}`},V?.showCheckbox&&u?.multiple&&y.jsx(C.Checkbox,{sx:{marginRight:1},checked:s}),typeof t=="string"?t:c(t))},onChange:(i,t,s,u)=>{const l=o=>A&&o!==null?a.onChange(A(o)):a.onChange(o),d=o=>{const p=r(o);[...e,...b].some(x=>r(x)===p)||k(x=>[...x,o])},j=o=>typeof o=="string"&&o.length>0?o:typeof o=="object"&&o!==null&&"__isAddOption"in o?o.inputValue:null;if(F&&f){const o=j(t);if(o){const p=f(o);if(V.multiple){const x=[...Array.isArray(a.value)?a.value:[],p];l(x)}else l(p);d(p);return}if(Array.isArray(t)&&V.multiple){const p=t?.map(m=>{const D=j(m);return D?f(D):m})??[];l(p);const M=[...e,...b].map(m=>r(m)),x=p.filter(m=>typeof m!="string"&&!M.includes(r(m)));x.length>0&&k(m=>[...m,...x]);return}}A&&t!==null?l(t):n?.onChange?.(i,t,s,u)},renderValue:(i,t,s)=>{const u=L(i,s);return Array.isArray(u)?u.map((l,d)=>{const{key:j,...o}=t({index:d}),p=typeof l=="string"?l:c(l),M=typeof l!="string"&&E?E({value:l,index:d}):{};return y.jsx(C.Chip,{...o,...M,label:M?.label??p},`${O}-chip-${j}`)}):w(u)?u:u?c(u):""},...n}})},J=({viewOnly:e,disableUnderline:n,...r})=>{const c=h.useMemo(()=>S(r,e,n),[r,e,n]);return y.jsx(T.TextFieldElement,{...c})},{get:N}=g;function P(e,n){const r=N(e,n);return{error:!!r,helperText:r?.message||""}}function Q(e){const n=h.useRef(!1);h.useEffect(()=>(n.current||(e(),n.current=!0),()=>{n.current=!0}),[])}const W=({name:e,rules:n,formControlProps:r={}})=>{const{register:c,formState:{errors:E}}=B.useFormContext(),{error:f,helperText:A}=P(E,e);return y.jsxs(C.FormControl,{error:f,...r,children:[y.jsx("input",{type:"hidden",...c(e,n)}),f&&y.jsx(C.FormHelperText,{children:A})]})};exports.AutocompleteElementDisplay=$;exports.ObjectElementDisplay=G;exports.TextElementDisplay=J;exports.ValidationElement=W;exports.useFormError=P;exports.useOnMount=Q;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const y=require("react/jsx-runtime"),P=require("react-hook-form-mui"),h=require("react"),g=require("lodash"),O=require("@mui/material"),B=require("react-hook-form"),{merge:R}=g;function L(e,n){return n?.multiple,n?.freeSolo,e}const D=(e,n=!1,r=!1)=>R(e,n?{disabled:!0,variant:"standard",sx:{"& .MuiAutocomplete-endAdornment":{display:"none"},...r&&{"& .MuiInput-underline:before":{borderBottom:"none"},"& .MuiInput-underline:after":{borderBottom:"none"},"& .MuiInput-underline:hover:not(.Mui-disabled):before":{borderBottom:"none"}}}}:{});function w(e){return e!=null&&typeof e=="string"}const{merge:z}=g,S=({viewOnly:e=void 0,disableUnderline:n,textFieldProps:r,autocompleteProps:a,...E})=>{const f=h.useMemo(()=>z({readOnly:e,disableClearable:a?.disableClearable||e,disabled:e},a,e?{sx:{".MuiAutocomplete-tag":{opacity:"1 !important"}}}:{}),[a,e]),A=h.useMemo(()=>D(r,e,n),[r,e,n]);return y.jsx(P.AutocompleteElement,{autocompleteProps:f,textFieldProps:A,...E})},G=({options:e,autocompleteProps:n,getItemKey:r,getItemLabel:a,getChipProps:E,stringToNewItem:f,transformValue:A,name:V,freeSolo:F,control:T,getOptionProps:_,...b})=>{const{field:c}=P.useController({name:V,control:T}),[j,k]=h.useState(()=>c.value?(Array.isArray(c.value)?c.value:[c.value]).filter(t=>typeof t!="string"&&!e.some(s=>r(s)===r(t))):[]);h.useEffect(()=>{if(!c.value)return;const t=(Array.isArray(c.value)?c.value:[c.value]).filter(s=>typeof s!="string"&&![...e,...j].some(u=>r(u)===r(s)));t.length>0&&k(s=>[...s,...t])},[c.value,e,j,r]);const H=h.useMemo(()=>{const i=new Set;return[...e,...j].filter(t=>{const s=r(t);return i.has(s)?!1:(i.add(s),!0)})},[e,j]);return y.jsx(S,{name:V,control:T,options:H,...b,autocompleteProps:{isOptionEqualToValue:(i,t)=>r(i)===r(t),filterOptions:(i,{inputValue:t})=>{if(!t)return i;const s=t.toLowerCase(),u=i.filter(l=>{const d=r(l)?.toLowerCase(),M=String(a(l)).toLowerCase();return d?.includes(s)||M.includes(s)});return F&&f&&t.length>0&&!u.some(d=>String(a(d)).toLowerCase()===s)?[{__isAddOption:!0,inputValue:t,...f(t)},...u]:u},freeSolo:F,autoComplete:!0,autoHighlight:!0,openOnFocus:!0,renderOption:(i,t,{selected:s},u)=>{const l=g.merge(i,_?.(t)??{});if(u?.freeSolo&&typeof t=="object"&&t!==null&&"__isAddOption"in t){const d=t.inputValue;return h.createElement(O.ListItem,{...l,key:`${V}-add-option-${d}`},"Add: '",d,"'")}return h.createElement(O.ListItem,{...l,key:`${V}-option-${r(t)}`},b?.showCheckbox&&u?.multiple&&y.jsx(O.Checkbox,{sx:{marginRight:1},checked:s}),typeof t=="string"?t:a(t))},onChange:(i,t,s,u)=>{const l=o=>A&&o!==null?c.onChange(A(o)):c.onChange(o),d=o=>{const p=r(o);[...e,...j].some(x=>r(x)===p)||k(x=>[...x,o])},M=o=>typeof o=="string"&&o.length>0?o:typeof o=="object"&&o!==null&&"__isAddOption"in o?o.inputValue:null;if(F&&f){const o=M(t);if(o){const p=f(o);if(b.multiple){const x=[...Array.isArray(c.value)?c.value:[],p];l(x)}else l(p);d(p);return}if(Array.isArray(t)&&b.multiple){const p=t?.map(m=>{const q=M(m);return q?f(q):m})??[];l(p);const C=[...e,...j].map(m=>r(m)),x=p.filter(m=>typeof m!="string"&&!C.includes(r(m)));x.length>0&&k(m=>[...m,...x]);return}}A&&t!==null?l(t):n?.onChange?.(i,t,s,u)},renderValue:(i,t,s)=>{const u=L(i,s);return Array.isArray(u)?u.map((l,d)=>{const{key:M,...o}=t({index:d}),p=typeof l=="string"?l:a(l),C=typeof l!="string"&&E?E({value:l,index:d}):{};return y.jsx(O.Chip,{...o,...C,label:C?.label??p},`${V}-chip-${M}`)}):w(u)?u:u?a(u):""},...n},textFieldProps:{placeholder:c.value?"":b?.textFieldProps?.placeholder,...b?.textFieldProps}})},J=({viewOnly:e,disableUnderline:n,...r})=>{const a=h.useMemo(()=>D(r,e,n),[r,e,n]);return y.jsx(P.TextFieldElement,{...a})},{get:N}=g;function $(e,n){const r=N(e,n);return{error:!!r,helperText:r?.message||""}}function Q(e){const n=h.useRef(!1);h.useEffect(()=>(n.current||(e(),n.current=!0),()=>{n.current=!0}),[])}const W=({name:e,rules:n,formControlProps:r={}})=>{const{register:a,formState:{errors:E}}=B.useFormContext(),{error:f,helperText:A}=$(E,e);return y.jsxs(O.FormControl,{error:f,...r,children:[y.jsx("input",{type:"hidden",...a(e,n)}),f&&y.jsx(O.FormHelperText,{children:A})]})};exports.AutocompleteElementDisplay=S;exports.ObjectElementDisplay=G;exports.TextElementDisplay=J;exports.ValidationElement=W;exports.useFormError=$;exports.useOnMount=Q;
2
2
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../src/utils.ts","../src/components/AutocompleteElementDisplay.tsx","../src/components/ObjectElementDisplay.tsx","../src/components/TextElementDisplay.tsx","../src/hooks/useFormError.ts","../src/hooks/useOnMount.ts","../src/components/ValidationElement.tsx"],"sourcesContent":["import type {\r\n AutocompleteOwnerState,\r\n AutocompleteRenderValue,\r\n AutocompleteValue,\r\n ChipTypeMap,\r\n TextFieldProps,\r\n} from \"@mui/material\";\r\nimport { ElementType } from \"react\";\r\n\r\nimport lodash from \"lodash\";\r\n\r\nconst { merge } = lodash;\r\n\r\nexport function getAutocompleteTypedValue<\r\n TValue,\r\n Multiple extends boolean | undefined,\r\n DisableClearable extends boolean | undefined,\r\n FreeSolo extends boolean | undefined,\r\n ChipComponent extends ElementType = ChipTypeMap[\"defaultComponent\"],\r\n>(\r\n value:\r\n | AutocompleteRenderValue<TValue, Multiple, FreeSolo>\r\n | AutocompleteValue<TValue, Multiple, DisableClearable, FreeSolo>,\r\n ownerState?: AutocompleteOwnerState<TValue, Multiple, DisableClearable, FreeSolo, ChipComponent>,\r\n) {\r\n if (ownerState?.multiple) {\r\n if (ownerState?.freeSolo) return value as Array<TValue | string>;\r\n return value as TValue[];\r\n } else if (ownerState?.freeSolo) {\r\n return value as NonNullable<TValue | string>;\r\n }\r\n return value as NonNullable<TValue>;\r\n}\r\n\r\n// Apply view-only properties directly to the TextFieldElement props\r\nexport const getTextElementDisplayProps = <PropType>(\r\n props: PropType,\r\n viewOnly = false,\r\n disableUnderline = false,\r\n) =>\r\n merge<PropType, Partial<TextFieldProps>>(\r\n props,\r\n viewOnly\r\n ? {\r\n disabled: true,\r\n variant: \"standard\",\r\n sx: {\r\n \"& .MuiAutocomplete-endAdornment\": {\r\n display: \"none\",\r\n },\r\n // Hide the underline without using slotProps.input.disableUnderline which clears out chips\r\n ...(disableUnderline && {\r\n \"& .MuiInput-underline:before\": { borderBottom: \"none\" },\r\n \"& .MuiInput-underline:after\": { borderBottom: \"none\" },\r\n \"& .MuiInput-underline:hover:not(.Mui-disabled):before\": { borderBottom: \"none\" },\r\n }),\r\n },\r\n }\r\n : {},\r\n ) as PropType;\r\n\r\nexport function isNonNullableString(value: any): value is NonNullable<string> {\r\nreturn value != null && typeof value === 'string';\r\n}","import { AutocompleteElement, type AutocompleteElementProps } from \"react-hook-form-mui\";\r\nimport { type ChipTypeMap } from \"@mui/material\";\r\nimport type { FieldPath, FieldValues } from \"react-hook-form\";\r\nimport { type ElementType, useMemo } from \"react\";\r\nimport lodash from \"lodash\";\r\nimport { getTextElementDisplayProps } from \"../utils\";\r\n\r\nconst { merge } = lodash;\r\n\r\nexport type AutocompleteElementDisplayProps<\r\n TValue,\r\n Multiple extends boolean | undefined,\r\n DisableClearable extends boolean | undefined,\r\n FreeSolo extends boolean | undefined,\r\n ChipComponent extends ElementType = ChipTypeMap[\"defaultComponent\"],\r\n TFieldValues extends FieldValues = FieldValues,\r\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,\r\n> = AutocompleteElementProps<\r\n TValue,\r\n Multiple,\r\n DisableClearable,\r\n FreeSolo,\r\n ChipComponent,\r\n TFieldValues,\r\n TName\r\n> & {\r\n viewOnly?: boolean;\r\n disableUnderline?: boolean;\r\n}\r\n\r\nexport const AutocompleteElementDisplay = <\r\n TValue,\r\n Multiple extends boolean | undefined,\r\n DisableClearable extends boolean | undefined,\r\n FreeSolo extends boolean | undefined,\r\n ChipComponent extends ElementType = ChipTypeMap[\"defaultComponent\"],\r\n TFieldValues extends FieldValues = FieldValues,\r\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,\r\n>({\r\n viewOnly = undefined as boolean | undefined,\r\n disableUnderline,\r\n textFieldProps,\r\n autocompleteProps,\r\n ...props\r\n}: AutocompleteElementDisplayProps<\r\n TValue,\r\n Multiple,\r\n DisableClearable,\r\n FreeSolo,\r\n ChipComponent,\r\n TFieldValues,\r\n TName\r\n>) => {\r\n const autocompleteAdjustedProps: AutocompleteElementDisplayProps<\r\n TValue,\r\n Multiple,\r\n DisableClearable,\r\n FreeSolo,\r\n ChipComponent,\r\n TFieldValues,\r\n TName\r\n >[\"autocompleteProps\"] = useMemo(\r\n () =>\r\n merge<\r\n AutocompleteElementDisplayProps<TValue, Multiple, DisableClearable, FreeSolo, ChipComponent, TFieldValues, TName>[\"autocompleteProps\"],\r\n AutocompleteElementDisplayProps<TValue, Multiple, DisableClearable, FreeSolo, ChipComponent, TFieldValues, TName>[\"autocompleteProps\"],\r\n AutocompleteElementDisplayProps<TValue, Multiple, DisableClearable, FreeSolo, ChipComponent, TFieldValues, TName>[\"autocompleteProps\"]\r\n >(\r\n {\r\n readOnly: viewOnly,\r\n disableClearable: autocompleteProps?.disableClearable || viewOnly as DisableClearable,\r\n disabled: viewOnly,\r\n\r\n },\r\n autocompleteProps,\r\n viewOnly\r\n ? {\r\n sx: {\r\n \".MuiAutocomplete-tag\": {\r\n opacity: \"1 !important\",\r\n },\r\n },\r\n }\r\n : {},\r\n ),\r\n [autocompleteProps, viewOnly],\r\n );\r\n\r\n const textFieldAdjustedProps= useMemo(\r\n () => getTextElementDisplayProps(textFieldProps, viewOnly, disableUnderline),\r\n [textFieldProps, viewOnly, disableUnderline],\r\n );\r\n\r\n return (\r\n <AutocompleteElement\r\n autocompleteProps={autocompleteAdjustedProps}\r\n textFieldProps={textFieldAdjustedProps}\r\n {...props}\r\n />\r\n );\r\n};\r\n\r\n\r\n","import { type ElementType, type ReactNode, useMemo, useState, useEffect } from \"react\";\nimport {\n Checkbox,\n Chip,\n ListItem,\n type ChipProps,\n type ChipTypeMap,\n type ListItemProps,\n} from \"@mui/material\";\nimport type { FieldPath, FieldValue, FieldValues } from \"react-hook-form\";\nimport {\n AutocompleteElementDisplay,\n type AutocompleteElementDisplayProps,\n} from \"./AutocompleteElementDisplay\";\nimport { getAutocompleteTypedValue, isNonNullableString } from \"../utils\";\nimport { useController } from \"react-hook-form-mui\";\nimport { merge } from \"lodash\";\n\n/**\n * Interface for special \"add option\" objects used in freeSolo mode\n * These objects represent a new item that can be created from user input\n */\ninterface AddOptionType {\n __isAddOption: true;\n inputValue: string;\n\n [key: string]: any; // Allow for additional properties from stringToNewItem\n}\n\n/**\n * Extends AutocompleteElementDisplayProps with additional properties for handling object values.\n *\n * @template TValue - The type of the option values\n * @template Multiple - Boolean flag indicating if multiple selections are allowed\n * @template DisableClearable - Boolean flag indicating if clearing the selection is disabled\n * @template FreeSolo - Boolean flag indicating if free text input is allowed\n * @template ChipComponent - The component type used for rendering chips in multiple selection mode\n * @template TFieldValues - The type of the form values\n * @template TName - The type of the field name\n */\nexport type ObjectElementDisplayProps<\n TValue,\n Multiple extends boolean | undefined,\n DisableClearable extends boolean | undefined,\n FreeSolo extends boolean | undefined,\n ChipComponent extends ElementType = ChipTypeMap[\"defaultComponent\"],\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,\n> = AutocompleteElementDisplayProps<\n TValue,\n Multiple,\n DisableClearable,\n FreeSolo,\n ChipComponent,\n TFieldValues,\n TName\n> & {\n /**\n * Function to extract a unique key from an option value.\n * Used for option comparison and deduplication.\n *\n * @param value - The option value or null\n * @returns A unique string key for the value\n */\n getItemKey: (value: TValue | null) => string | null;\n\n /**\n * Function to generate a display label for an option value.\n * Can return any ReactNode for custom rendering.\n *\n * @param value - The option value or null\n * @returns An option to show for the value\n */\n getItemLabel: (value: TValue | null) => ReactNode;\n\n /**\n * Function to get additional props for an option list item.\n * Used for customizing the rendering of the option.\n *\n * @param value - The option value or null\n * @returns Additional props to apply to the list item\n */\n getOptionProps?: (value: TValue | null) => ListItemProps;\n\n /**\n * Function to convert a free text input string to a TValue object.\n * Required when freeSolo is true to create new items from text input.\n *\n * @param value - The string value entered by the user\n * @returns A new TValue object created from the string\n */\n stringToNewItem?: (value: string) => TValue;\n\n /**\n * Whether the input allows free text entry.\n * When true, users can enter values that are not in the options.\n */\n freeSolo?: FreeSolo;\n\n /**\n * Optional function that returns additional chip props based on the value.\n * This allows for customizing chip appearance and behavior based on the value it represents.\n *\n * @param value - The option value being rendered as a chip\n * @returns Additional props to apply to the Chip component\n */\n getChipProps?: (props: { value: TValue; index: number }) => Partial<ChipProps> | undefined;\n\n /**\n * Optional function to transform the value before it's updated in the form.\n * This allows for custom processing or enrichment of the selected value.\n *\n * @param value - The value that would normally be sent to the form\n * @returns The transformed value to be stored in the form\n */\n transformValue?: (\n value: Multiple extends true ? TValue[] : TValue | null\n ) => FieldValue<FieldValues>;\n};\n\n/**\n * A form component that displays a searchable dropdown for selecting object values.\n * Extends AutocompleteElementDisplay with object-specific functionality.\n *\n * Features:\n * - Works with complex object values instead of just primitive types\n * - Supports both single and multiple selection modes\n * - Supports free-solo mode for creating new items from text input\n * - Handles initial values that aren't in the default options\n * - Deduplicates options based on item keys\n *\n * @template TValue - The type of the option values\n * @template Multiple - Boolean flag indicating if multiple selections are allowed\n * @template DisableClearable - Boolean flag indicating if clearing the selection is disabled\n * @template FreeSolo - Boolean flag indicating if free text input is allowed\n * @template ChipComponent - The component type used for rendering chips in multiple selection mode\n * @template TFieldValues - The type of the form values\n * @template TName - The type of the field name\n *\n * @returns A React component for selecting object values\n */\nexport const ObjectElementDisplay = <\n TValue,\n Multiple extends boolean | undefined,\n DisableClearable extends boolean | undefined,\n FreeSolo extends boolean | undefined,\n ChipComponent extends ElementType = ChipTypeMap[\"defaultComponent\"],\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,\n>({\n options,\n autocompleteProps,\n getItemKey,\n getItemLabel,\n getChipProps,\n stringToNewItem,\n transformValue,\n name,\n freeSolo,\n control,\n getOptionProps,\n ...props\n}: ObjectElementDisplayProps<\n TValue,\n Multiple,\n DisableClearable,\n FreeSolo,\n ChipComponent,\n TFieldValues,\n TName\n>) => {\n /**\n * Access to the form field controller\n */\n const { field } = useController({ name, control });\n\n /**\n * State for storing dynamically added options that aren't in the original options list\n * Includes both default values and values added during freeSolo mode\n */\n const [newOptions, setNewOptions] = useState<TValue[]>(() => {\n if (!field.value) return [];\n\n // Convert field value to array for consistent handling\n const fieldValues: TValue[] = Array.isArray(field.value) ? field.value : [field.value];\n\n // Keep only object values that don't exist in the options array\n return fieldValues.filter(\n (value) =>\n typeof value !== \"string\" &&\n !options.some((option) => getItemKey(option) === getItemKey(value)),\n );\n });\n\n /**\n * Update newOptions when field.value changes\n * This ensures that any new values added to the field after rendering\n * are properly included in newOptions and displayed\n */\n useEffect(() => {\n if (!field.value) return;\n\n const fieldValues: TValue[] = Array.isArray(field.value) ? field.value : [field.value];\n const newFieldOptions = fieldValues.filter(\n (value) =>\n typeof value !== \"string\" &&\n ![...options, ...newOptions].some((option) => getItemKey(option) === getItemKey(value)),\n );\n\n // Only update newOptions if there are new values to add\n if (newFieldOptions.length > 0) {\n setNewOptions((prevOptions) => [...prevOptions, ...newFieldOptions]);\n }\n }, [field.value, options, newOptions, getItemKey]);\n\n /**\n * Combined list of all available options (original + dynamically added)\n */\n const allOptions = useMemo(() => {\n const seen = new Set();\n return [...options, ...newOptions].filter((option) => {\n const key = getItemKey(option);\n if (seen.has(key)) return false;\n seen.add(key);\n return true;\n })\n }, [options, newOptions]);\n\n return (\n <AutocompleteElementDisplay\n name={name}\n control={control}\n options={allOptions}\n {...props}\n autocompleteProps={{\n /**\n * Determines if two options should be considered equal\n * Uses the getItemKey function to compare option values\n */\n isOptionEqualToValue: (o, v) => getItemKey(o) === getItemKey(v),\n\n /**\n * Filters options based on the input value\n * Checks if the option key or label contains the input value (case-insensitive)\n * For freeSolo mode, adds a special \"Add [value]\" option when there's no exact match\n */\n filterOptions: (options, { inputValue }) => {\n if (!inputValue) return options;\n\n const searchValue = inputValue.toLowerCase();\n\n // Filter options that match the input value (by key or label)\n const filteredOptions = options.filter((option) => {\n const key = getItemKey(option)?.toLowerCase();\n const label = String(getItemLabel(option)).toLowerCase();\n return key?.includes(searchValue) || label.includes(searchValue);\n });\n\n // For freeSolo mode, add \"Add [value]\" option if no exact match exists\n if (freeSolo && stringToNewItem && inputValue.length > 0) {\n const hasExactMatch = filteredOptions.some(\n (option) => String(getItemLabel(option)).toLowerCase() === searchValue,\n );\n\n if (!hasExactMatch) {\n // Create a special option with a __isAddOption flag\n const addOption: AddOptionType = {\n __isAddOption: true,\n inputValue,\n ...stringToNewItem(inputValue), // Include properties for type compatibility\n };\n\n return [addOption as unknown as TValue, ...filteredOptions];\n }\n }\n\n return filteredOptions;\n },\n freeSolo, // Allowed to enter own string value\n autoComplete: true,\n autoHighlight: true, // The first option is highlighted by default\n openOnFocus: true, // Opens the menu when tabbed into\n\n /**\n * Custom rendering for each option in the dropdown list\n * Handles both regular options and special \"Add\" options in freeSolo mode\n */\n renderOption: (liProps, option, { selected }, ownerState) => {\n const itemProps = merge(liProps, getOptionProps?.(option) ?? {});\n\n // Handles the special \"Add\" option in freeSolo mode\n if (\n ownerState?.freeSolo &&\n typeof option === \"object\" &&\n option !== null &&\n \"__isAddOption\" in option\n ) {\n const inputValue = (option as unknown as AddOptionType).inputValue;\n return (\n <ListItem {...itemProps} key={`${name}-add-option-${inputValue}`}>\n Add: '{inputValue}'\n </ListItem>\n );\n }\n\n // Handle regular option\n return (\n <ListItem {...itemProps} key={`${name}-option-${getItemKey(option)}`}>\n {(props?.showCheckbox && ownerState?.multiple) && (\n <Checkbox sx={{ marginRight: 1 }} checked={selected} />\n )}\n {typeof option === \"string\" ? option : getItemLabel(option)}\n </ListItem>\n );\n },\n\n onChange: (event, value, reason, details) => {\n /**\n * Helper function to apply transformValue if provided, otherwise return the original value\n */\n const applyTransform = (val: any) => {\n return transformValue && val !== null\n ? field.onChange(transformValue(val))\n : field.onChange(val);\n };\n\n /**\n * Helper function to add a new item to newOptions if it doesn't exist already\n */\n const addToNewOptions = (item: TValue) => {\n const itemKey = getItemKey(item);\n const itemExists = [...options, ...newOptions].some(\n (option) => getItemKey(option) === itemKey,\n );\n\n if (!itemExists) {\n setNewOptions((prev) => [...prev, item]);\n }\n };\n\n /**\n * Helper function to extract input value from string or AddOption\n */\n const getInputValue = (item: any): string | null => {\n if (typeof item === \"string\" && item.length > 0) {\n return item;\n }\n if (typeof item === \"object\" && item !== null && \"__isAddOption\" in item) {\n return (item as unknown as AddOptionType).inputValue;\n }\n return null;\n };\n\n // Handle freeSolo mode with stringToNewItem function\n if (freeSolo && stringToNewItem) {\n // Handle special add option selection or string input\n const inputValue = getInputValue(value);\n\n if (inputValue) {\n const newItem = stringToNewItem(inputValue);\n\n if (props.multiple) {\n // For multiple selection, add the new item to the current values\n const currentValues = Array.isArray(field.value) ? field.value : [];\n const newValues = [...currentValues, newItem];\n applyTransform(newValues);\n } else {\n // For single selection, just use the new item\n applyTransform(newItem);\n }\n\n addToNewOptions(newItem);\n return;\n }\n\n // Handle array values (multiple selection)\n if (Array.isArray(value) && props.multiple) {\n // Convert any string values to objects and handle special add options\n const newValues =\n value?.map((item) => {\n const inputVal = getInputValue(item);\n return inputVal ? stringToNewItem(inputVal) : item;\n }) ?? [];\n\n applyTransform(newValues);\n\n // Add any new items to newOptions\n const allOptionsKeys = [...options, ...newOptions].map((option) =>\n getItemKey(option),\n );\n const newItems = newValues.filter(\n (item) => typeof item !== \"string\" && !allOptionsKeys.includes(getItemKey(item)),\n );\n\n if (newItems.length > 0) {\n setNewOptions((prev) => [...prev, ...newItems]);\n }\n return;\n }\n }\n\n // Default behavior for non-freeSolo cases\n if (transformValue && value !== null) {\n applyTransform(value as TValue | TValue[]);\n } else {\n autocompleteProps?.onChange?.(event, value, reason, details);\n }\n },\n\n /**\n * Custom rendering for the selected value(s)\n * For multiple selection, renders a Chip for each selected value\n * For single selection, renders the value as text\n * Uses getItemLabel to render the value labels\n */\n renderValue: (value, getItemProps, ownerState) => {\n const typedValue = getAutocompleteTypedValue(value, ownerState);\n\n // Handle array values (multiple selection)\n if (Array.isArray(typedValue)) {\n return typedValue.map((v, index) => {\n // @ts-expect-error a key is returned, and the linter doesn't pick this up\n const { key, ...chipProps } = getItemProps({ index });\n\n // Get the label - use string directly or extract from object\n const label = typeof v === \"string\" ? v : getItemLabel(v);\n\n // Get additional chip props if available\n const valueSpecificProps =\n typeof v !== \"string\" && getChipProps ? getChipProps({ value: v, index }) : {};\n\n return (\n <Chip\n key={`${name}-chip-${key}`}\n {...chipProps}\n {...valueSpecificProps}\n label={valueSpecificProps?.label ?? label}\n />\n );\n });\n }\n\n // Handles single value - return string or extracted label\n return isNonNullableString(typedValue)\n ? typedValue\n : typedValue\n ? getItemLabel(typedValue as NonNullable<TValue>)\n : \"\";\n },\n ...autocompleteProps,\n }}\n />\n );\n};\n","import { TextFieldElement, type TextFieldElementProps } from \"react-hook-form-mui\";\nimport { type FieldPath, type FieldValues } from \"react-hook-form\";\nimport { useMemo } from \"react\";\nimport { getTextElementDisplayProps } from \"../utils\";\n\nexport type TextElementDisplayProps<\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>\n> = TextFieldElementProps<TFieldValues, TName> & Viewable;\n\n/**\n * A form component that displays a text field with view-only capabilities.\n * Extends TextFieldElement with view-only functionality.\n *\n * @template TFieldValues - The type of the form values\n * @template TName - The type of the field name\n *\n * @returns A React component for text input with view-only support\n */\nexport const TextElementDisplay = <\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,\n>({\n viewOnly,\n disableUnderline,\n ...props\n}: TextElementDisplayProps<TFieldValues, TName>) => {\n\n const adjustedProps = useMemo(\n () => getTextElementDisplayProps(props, viewOnly, disableUnderline),\n [props, viewOnly, disableUnderline],\n );\n\n return <TextFieldElement {...adjustedProps} />;\n};\n\ntype Viewable = {\n viewOnly?: boolean;\n disableUnderline?: boolean;\n};\n","import { FieldError, FieldErrors, FieldValues } from 'react-hook-form';\r\nimport lodash from 'lodash';\r\nconst { get } = lodash;\r\n\r\n/**\r\n * A hook to get the error message for a field from react-hook-form\r\n * @param errors The errors object from react-hook-form\r\n * @param name The name of the field (supports dot notation for nested fields)\r\n * @returns An object with error and helperText properties\r\n */\r\nexport function useFormError<T extends FieldValues>(\r\n errors: FieldErrors<T>,\r\n name: string\r\n): { error: boolean; helperText: string } {\r\n // Get the error for the field, supporting nested paths with dot notation\r\n const fieldError = get(errors, name) as FieldError | undefined;\r\n\r\n // Return error state and helper text\r\n return {\r\n error: !!fieldError,\r\n helperText: fieldError?.message || '',\r\n };\r\n}\r\n","// src/hooks/useOnMount.ts\r\nimport { useEffect, useRef } from \"react\";\r\n\r\n/**\r\n * Runs a provided callback function once on the first component mount.\r\n *\r\n * @param callback - The function to run on first mount.\r\n */\r\nexport function useOnMount(callback: () => void): void {\r\n const hasMounted = useRef(false);\r\n\r\n useEffect(() => {\r\n if (!hasMounted.current) {\r\n callback();\r\n hasMounted.current = true;\r\n }\r\n\r\n // Cleanup to prevent callback logic from running during cleanup\r\n return () => {\r\n hasMounted.current = true;\r\n };\r\n \r\n // eslint-disable-next-line react-hooks/exhaustive-deps\r\n }, []);\r\n}\r\n\r\n","import type { JSX } from \"react\";\r\nimport { FormControl, FormHelperText } from \"@mui/material\";\r\nimport type { FormControlProps } from \"@mui/material\";\r\nimport { useFormContext, type RegisterOptions, type FieldValues, type Path } from \"react-hook-form\";\r\nimport { useFormError } from \"../hooks\";\r\n\r\n/**\r\n * Props for the RHFHiddenInput component\r\n */\r\nexport interface ValidationElementProps<TFieldValues extends FieldValues> {\r\n /**\r\n * Name of the field in the form\r\n */\r\n name: Path<TFieldValues>;\r\n /**\r\n * Optional validation rules\r\n */\r\n rules: RegisterOptions<TFieldValues>;\r\n /**\r\n * Props to pass to the FormControl component\r\n */\r\n formControlProps?: Omit<FormControlProps, \"error\">;\r\n}\r\n\r\nexport const ValidationElement = <TFieldValues extends FieldValues = FieldValues>({\r\n name,\r\n rules,\r\n formControlProps = {},\r\n}: ValidationElementProps<TFieldValues>): JSX.Element => {\r\n const {\r\n register,\r\n formState: { errors },\r\n } = useFormContext<TFieldValues>();\r\n\r\n const { error, helperText } = useFormError(errors, name);\r\n\r\n return (\r\n <FormControl error={error} {...formControlProps}>\r\n <input type=\"hidden\" {...register(name, rules)} />\r\n {error && <FormHelperText>{helperText}</FormHelperText>}\r\n </FormControl>\r\n );\r\n};\r\n"],"names":["merge","lodash","getAutocompleteTypedValue","value","ownerState","getTextElementDisplayProps","props","viewOnly","disableUnderline","isNonNullableString","AutocompleteElementDisplay","textFieldProps","autocompleteProps","autocompleteAdjustedProps","useMemo","textFieldAdjustedProps","jsx","AutocompleteElement","ObjectElementDisplay","options","getItemKey","getItemLabel","getChipProps","stringToNewItem","transformValue","name","freeSolo","control","getOptionProps","field","useController","newOptions","setNewOptions","useState","option","useEffect","newFieldOptions","prevOptions","allOptions","seen","key","o","v","inputValue","searchValue","filteredOptions","label","liProps","selected","itemProps","createElement","ListItem","Checkbox","event","reason","details","applyTransform","val","addToNewOptions","item","itemKey","prev","getInputValue","newItem","newValues","inputVal","allOptionsKeys","newItems","getItemProps","typedValue","index","chipProps","valueSpecificProps","Chip","TextElementDisplay","adjustedProps","TextFieldElement","get","useFormError","errors","fieldError","useOnMount","callback","hasMounted","useRef","ValidationElement","rules","formControlProps","register","useFormContext","error","helperText","jsxs","FormControl","FormHelperText"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","sources":["../src/utils.ts","../src/components/AutocompleteElementDisplay.tsx","../src/components/ObjectElementDisplay.tsx","../src/components/TextElementDisplay.tsx","../src/hooks/useFormError.ts","../src/hooks/useOnMount.ts","../src/components/ValidationElement.tsx"],"sourcesContent":["import type {\r\n AutocompleteOwnerState,\r\n AutocompleteRenderValue,\r\n AutocompleteValue,\r\n ChipTypeMap,\r\n TextFieldProps,\r\n} from \"@mui/material\";\r\nimport { ElementType } from \"react\";\r\n\r\nimport lodash from \"lodash\";\r\n\r\nconst { merge } = lodash;\r\n\r\nexport function getAutocompleteTypedValue<\r\n TValue,\r\n Multiple extends boolean | undefined,\r\n DisableClearable extends boolean | undefined,\r\n FreeSolo extends boolean | undefined,\r\n ChipComponent extends ElementType = ChipTypeMap[\"defaultComponent\"],\r\n>(\r\n value:\r\n | AutocompleteRenderValue<TValue, Multiple, FreeSolo>\r\n | AutocompleteValue<TValue, Multiple, DisableClearable, FreeSolo>,\r\n ownerState?: AutocompleteOwnerState<TValue, Multiple, DisableClearable, FreeSolo, ChipComponent>,\r\n) {\r\n if (ownerState?.multiple) {\r\n if (ownerState?.freeSolo) return value as Array<TValue | string>;\r\n return value as TValue[];\r\n } else if (ownerState?.freeSolo) {\r\n return value as NonNullable<TValue | string>;\r\n }\r\n return value as NonNullable<TValue>;\r\n}\r\n\r\n// Apply view-only properties directly to the TextFieldElement props\r\nexport const getTextElementDisplayProps = <PropType>(\r\n props: PropType,\r\n viewOnly = false,\r\n disableUnderline = false,\r\n) =>\r\n merge<PropType, Partial<TextFieldProps>>(\r\n props,\r\n viewOnly\r\n ? {\r\n disabled: true,\r\n variant: \"standard\",\r\n sx: {\r\n \"& .MuiAutocomplete-endAdornment\": {\r\n display: \"none\",\r\n },\r\n // Hide the underline without using slotProps.input.disableUnderline which clears out chips\r\n ...(disableUnderline && {\r\n \"& .MuiInput-underline:before\": { borderBottom: \"none\" },\r\n \"& .MuiInput-underline:after\": { borderBottom: \"none\" },\r\n \"& .MuiInput-underline:hover:not(.Mui-disabled):before\": { borderBottom: \"none\" },\r\n }),\r\n },\r\n }\r\n : {},\r\n ) as PropType;\r\n\r\nexport function isNonNullableString(value: any): value is NonNullable<string> {\r\nreturn value != null && typeof value === 'string';\r\n}","import { AutocompleteElement, type AutocompleteElementProps } from \"react-hook-form-mui\";\r\nimport { type ChipTypeMap } from \"@mui/material\";\r\nimport type { FieldPath, FieldValues } from \"react-hook-form\";\r\nimport { type ElementType, useMemo } from \"react\";\r\nimport lodash from \"lodash\";\r\nimport { getTextElementDisplayProps } from \"../utils\";\r\n\r\nconst { merge } = lodash;\r\n\r\nexport type AutocompleteElementDisplayProps<\r\n TValue,\r\n Multiple extends boolean | undefined,\r\n DisableClearable extends boolean | undefined,\r\n FreeSolo extends boolean | undefined,\r\n ChipComponent extends ElementType = ChipTypeMap[\"defaultComponent\"],\r\n TFieldValues extends FieldValues = FieldValues,\r\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,\r\n> = AutocompleteElementProps<\r\n TValue,\r\n Multiple,\r\n DisableClearable,\r\n FreeSolo,\r\n ChipComponent,\r\n TFieldValues,\r\n TName\r\n> & {\r\n viewOnly?: boolean;\r\n disableUnderline?: boolean;\r\n}\r\n\r\nexport const AutocompleteElementDisplay = <\r\n TValue,\r\n Multiple extends boolean | undefined,\r\n DisableClearable extends boolean | undefined,\r\n FreeSolo extends boolean | undefined,\r\n ChipComponent extends ElementType = ChipTypeMap[\"defaultComponent\"],\r\n TFieldValues extends FieldValues = FieldValues,\r\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,\r\n>({\r\n viewOnly = undefined as boolean | undefined,\r\n disableUnderline,\r\n textFieldProps,\r\n autocompleteProps,\r\n ...props\r\n}: AutocompleteElementDisplayProps<\r\n TValue,\r\n Multiple,\r\n DisableClearable,\r\n FreeSolo,\r\n ChipComponent,\r\n TFieldValues,\r\n TName\r\n>) => {\r\n const autocompleteAdjustedProps: AutocompleteElementDisplayProps<\r\n TValue,\r\n Multiple,\r\n DisableClearable,\r\n FreeSolo,\r\n ChipComponent,\r\n TFieldValues,\r\n TName\r\n >[\"autocompleteProps\"] = useMemo(\r\n () =>\r\n merge<\r\n AutocompleteElementDisplayProps<TValue, Multiple, DisableClearable, FreeSolo, ChipComponent, TFieldValues, TName>[\"autocompleteProps\"],\r\n AutocompleteElementDisplayProps<TValue, Multiple, DisableClearable, FreeSolo, ChipComponent, TFieldValues, TName>[\"autocompleteProps\"],\r\n AutocompleteElementDisplayProps<TValue, Multiple, DisableClearable, FreeSolo, ChipComponent, TFieldValues, TName>[\"autocompleteProps\"]\r\n >(\r\n {\r\n readOnly: viewOnly,\r\n disableClearable: autocompleteProps?.disableClearable || viewOnly as DisableClearable,\r\n disabled: viewOnly,\r\n\r\n },\r\n autocompleteProps,\r\n viewOnly\r\n ? {\r\n sx: {\r\n \".MuiAutocomplete-tag\": {\r\n opacity: \"1 !important\",\r\n },\r\n },\r\n }\r\n : {},\r\n ),\r\n [autocompleteProps, viewOnly],\r\n );\r\n\r\n const textFieldAdjustedProps= useMemo(\r\n () => getTextElementDisplayProps(textFieldProps, viewOnly, disableUnderline),\r\n [textFieldProps, viewOnly, disableUnderline],\r\n );\r\n\r\n return (\r\n <AutocompleteElement\r\n autocompleteProps={autocompleteAdjustedProps}\r\n textFieldProps={textFieldAdjustedProps}\r\n {...props}\r\n />\r\n );\r\n};\r\n\r\n\r\n","import { type ElementType, type ReactNode, useMemo, useState, useEffect } from \"react\";\nimport {\n Checkbox,\n Chip,\n ListItem,\n type ChipProps,\n type ChipTypeMap,\n type ListItemProps,\n} from \"@mui/material\";\nimport type { FieldPath, FieldValue, FieldValues } from \"react-hook-form\";\nimport {\n AutocompleteElementDisplay,\n type AutocompleteElementDisplayProps,\n} from \"./AutocompleteElementDisplay\";\nimport { getAutocompleteTypedValue, isNonNullableString } from \"../utils\";\nimport { useController } from \"react-hook-form-mui\";\nimport { merge } from \"lodash\";\n\n/**\n * Interface for special \"add option\" objects used in freeSolo mode\n * These objects represent a new item that can be created from user input\n */\ninterface AddOptionType {\n __isAddOption: true;\n inputValue: string;\n\n [key: string]: any; // Allow for additional properties from stringToNewItem\n}\n\n/**\n * Extends AutocompleteElementDisplayProps with additional properties for handling object values.\n *\n * @template TValue - The type of the option values\n * @template Multiple - Boolean flag indicating if multiple selections are allowed\n * @template DisableClearable - Boolean flag indicating if clearing the selection is disabled\n * @template FreeSolo - Boolean flag indicating if free text input is allowed\n * @template ChipComponent - The component type used for rendering chips in multiple selection mode\n * @template TFieldValues - The type of the form values\n * @template TName - The type of the field name\n */\nexport type ObjectElementDisplayProps<\n TValue,\n Multiple extends boolean | undefined,\n DisableClearable extends boolean | undefined,\n FreeSolo extends boolean | undefined,\n ChipComponent extends ElementType = ChipTypeMap[\"defaultComponent\"],\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,\n> = AutocompleteElementDisplayProps<\n TValue,\n Multiple,\n DisableClearable,\n FreeSolo,\n ChipComponent,\n TFieldValues,\n TName\n> & {\n /**\n * Function to extract a unique key from an option value.\n * Used for option comparison and deduplication.\n *\n * @param value - The option value or null\n * @returns A unique string key for the value\n */\n getItemKey: (value: TValue | null) => string | null;\n\n /**\n * Function to generate a display label for an option value.\n * Can return any ReactNode for custom rendering.\n *\n * @param value - The option value or null\n * @returns An option to show for the value\n */\n getItemLabel: (value: TValue | null) => ReactNode;\n\n /**\n * Function to get additional props for an option list item.\n * Used for customizing the rendering of the option.\n *\n * @param value - The option value or null\n * @returns Additional props to apply to the list item\n */\n getOptionProps?: (value: TValue | null) => ListItemProps;\n\n /**\n * Function to convert a free text input string to a TValue object.\n * Required when freeSolo is true to create new items from text input.\n *\n * @param value - The string value entered by the user\n * @returns A new TValue object created from the string\n */\n stringToNewItem?: (value: string) => TValue;\n\n /**\n * Whether the input allows free text entry.\n * When true, users can enter values that are not in the options.\n */\n freeSolo?: FreeSolo;\n\n /**\n * Optional function that returns additional chip props based on the value.\n * This allows for customizing chip appearance and behavior based on the value it represents.\n *\n * @param value - The option value being rendered as a chip\n * @returns Additional props to apply to the Chip component\n */\n getChipProps?: (props: { value: TValue; index: number }) => Partial<ChipProps> | undefined;\n\n /**\n * Optional function to transform the value before it's updated in the form.\n * This allows for custom processing or enrichment of the selected value.\n *\n * @param value - The value that would normally be sent to the form\n * @returns The transformed value to be stored in the form\n */\n transformValue?: (\n value: Multiple extends true ? TValue[] : TValue | null\n ) => FieldValue<FieldValues>;\n};\n\n/**\n * A form component that displays a searchable dropdown for selecting object values.\n * Extends AutocompleteElementDisplay with object-specific functionality.\n *\n * Features:\n * - Works with complex object values instead of just primitive types\n * - Supports both single and multiple selection modes\n * - Supports free-solo mode for creating new items from text input\n * - Handles initial values that aren't in the default options\n * - Deduplicates options based on item keys\n *\n * @template TValue - The type of the option values\n * @template Multiple - Boolean flag indicating if multiple selections are allowed\n * @template DisableClearable - Boolean flag indicating if clearing the selection is disabled\n * @template FreeSolo - Boolean flag indicating if free text input is allowed\n * @template ChipComponent - The component type used for rendering chips in multiple selection mode\n * @template TFieldValues - The type of the form values\n * @template TName - The type of the field name\n *\n * @returns A React component for selecting object values\n */\nexport const ObjectElementDisplay = <\n TValue,\n Multiple extends boolean | undefined,\n DisableClearable extends boolean | undefined,\n FreeSolo extends boolean | undefined,\n ChipComponent extends ElementType = ChipTypeMap[\"defaultComponent\"],\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,\n>({\n options,\n autocompleteProps,\n getItemKey,\n getItemLabel,\n getChipProps,\n stringToNewItem,\n transformValue,\n name,\n freeSolo,\n control,\n getOptionProps,\n ...props\n}: ObjectElementDisplayProps<\n TValue,\n Multiple,\n DisableClearable,\n FreeSolo,\n ChipComponent,\n TFieldValues,\n TName\n>) => {\n /**\n * Access to the form field controller\n */\n const { field } = useController({ name, control });\n\n /**\n * State for storing dynamically added options that aren't in the original options list\n * Includes both default values and values added during freeSolo mode\n */\n const [newOptions, setNewOptions] = useState<TValue[]>(() => {\n if (!field.value) return [];\n\n // Convert field value to array for consistent handling\n const fieldValues: TValue[] = Array.isArray(field.value) ? field.value : [field.value];\n\n // Keep only object values that don't exist in the options array\n return fieldValues.filter(\n (value) =>\n typeof value !== \"string\" &&\n !options.some((option) => getItemKey(option) === getItemKey(value)),\n );\n });\n\n /**\n * Update newOptions when field.value changes\n * This ensures that any new values added to the field after rendering\n * are properly included in newOptions and displayed\n */\n useEffect(() => {\n if (!field.value) return;\n\n const fieldValues: TValue[] = Array.isArray(field.value) ? field.value : [field.value];\n const newFieldOptions = fieldValues.filter(\n (value) =>\n typeof value !== \"string\" &&\n ![...options, ...newOptions].some((option) => getItemKey(option) === getItemKey(value)),\n );\n\n // Only update newOptions if there are new values to add\n if (newFieldOptions.length > 0) {\n setNewOptions((prevOptions) => [...prevOptions, ...newFieldOptions]);\n }\n }, [field.value, options, newOptions, getItemKey]);\n\n /**\n * Combined list of all available options (original + dynamically added)\n */\n const allOptions = useMemo(() => {\n const seen = new Set();\n return [...options, ...newOptions].filter((option) => {\n const key = getItemKey(option);\n if (seen.has(key)) return false;\n seen.add(key);\n return true;\n })\n }, [options, newOptions]);\n\n return (\n <AutocompleteElementDisplay\n name={name}\n control={control}\n options={allOptions}\n {...props}\n autocompleteProps={{\n /**\n * Determines if two options should be considered equal\n * Uses the getItemKey function to compare option values\n */\n isOptionEqualToValue: (o, v) => getItemKey(o) === getItemKey(v),\n\n /**\n * Filters options based on the input value\n * Checks if the option key or label contains the input value (case-insensitive)\n * For freeSolo mode, adds a special \"Add [value]\" option when there's no exact match\n */\n filterOptions: (options, { inputValue }) => {\n if (!inputValue) return options;\n\n const searchValue = inputValue.toLowerCase();\n\n // Filter options that match the input value (by key or label)\n const filteredOptions = options.filter((option) => {\n const key = getItemKey(option)?.toLowerCase();\n const label = String(getItemLabel(option)).toLowerCase();\n return key?.includes(searchValue) || label.includes(searchValue);\n });\n\n // For freeSolo mode, add \"Add [value]\" option if no exact match exists\n if (freeSolo && stringToNewItem && inputValue.length > 0) {\n const hasExactMatch = filteredOptions.some(\n (option) => String(getItemLabel(option)).toLowerCase() === searchValue,\n );\n\n if (!hasExactMatch) {\n // Create a special option with a __isAddOption flag\n const addOption: AddOptionType = {\n __isAddOption: true,\n inputValue,\n ...stringToNewItem(inputValue), // Include properties for type compatibility\n };\n\n return [addOption as unknown as TValue, ...filteredOptions];\n }\n }\n\n return filteredOptions;\n },\n freeSolo, // Allowed to enter own string value\n autoComplete: true,\n autoHighlight: true, // The first option is highlighted by default\n openOnFocus: true, // Opens the menu when tabbed into\n\n /**\n * Custom rendering for each option in the dropdown list\n * Handles both regular options and special \"Add\" options in freeSolo mode\n */\n renderOption: (liProps, option, { selected }, ownerState) => {\n const itemProps = merge(liProps, getOptionProps?.(option) ?? {});\n\n // Handles the special \"Add\" option in freeSolo mode\n if (\n ownerState?.freeSolo &&\n typeof option === \"object\" &&\n option !== null &&\n \"__isAddOption\" in option\n ) {\n const inputValue = (option as unknown as AddOptionType).inputValue;\n return (\n <ListItem {...itemProps} key={`${name}-add-option-${inputValue}`}>\n Add: '{inputValue}'\n </ListItem>\n );\n }\n\n // Handle regular option\n return (\n <ListItem {...itemProps} key={`${name}-option-${getItemKey(option)}`}>\n {props?.showCheckbox && ownerState?.multiple && (\n <Checkbox sx={{ marginRight: 1 }} checked={selected} />\n )}\n {typeof option === \"string\" ? option : getItemLabel(option)}\n </ListItem>\n );\n },\n\n onChange: (event, value, reason, details) => {\n /**\n * Helper function to apply transformValue if provided, otherwise return the original value\n */\n const applyTransform = (val: any) => {\n return transformValue && val !== null\n ? field.onChange(transformValue(val))\n : field.onChange(val);\n };\n\n /**\n * Helper function to add a new item to newOptions if it doesn't exist already\n */\n const addToNewOptions = (item: TValue) => {\n const itemKey = getItemKey(item);\n const itemExists = [...options, ...newOptions].some(\n (option) => getItemKey(option) === itemKey,\n );\n\n if (!itemExists) {\n setNewOptions((prev) => [...prev, item]);\n }\n };\n\n /**\n * Helper function to extract input value from string or AddOption\n */\n const getInputValue = (item: any): string | null => {\n if (typeof item === \"string\" && item.length > 0) {\n return item;\n }\n if (typeof item === \"object\" && item !== null && \"__isAddOption\" in item) {\n return (item as unknown as AddOptionType).inputValue;\n }\n return null;\n };\n\n // Handle freeSolo mode with stringToNewItem function\n if (freeSolo && stringToNewItem) {\n // Handle special add option selection or string input\n const inputValue = getInputValue(value);\n\n if (inputValue) {\n const newItem = stringToNewItem(inputValue);\n\n if (props.multiple) {\n // For multiple selection, add the new item to the current values\n const currentValues = Array.isArray(field.value) ? field.value : [];\n const newValues = [...currentValues, newItem];\n applyTransform(newValues);\n } else {\n // For single selection, just use the new item\n applyTransform(newItem);\n }\n\n addToNewOptions(newItem);\n return;\n }\n\n // Handle array values (multiple selection)\n if (Array.isArray(value) && props.multiple) {\n // Convert any string values to objects and handle special add options\n const newValues =\n value?.map((item) => {\n const inputVal = getInputValue(item);\n return inputVal ? stringToNewItem(inputVal) : item;\n }) ?? [];\n\n applyTransform(newValues);\n\n // Add any new items to newOptions\n const allOptionsKeys = [...options, ...newOptions].map((option) =>\n getItemKey(option),\n );\n const newItems = newValues.filter(\n (item) => typeof item !== \"string\" && !allOptionsKeys.includes(getItemKey(item)),\n );\n\n if (newItems.length > 0) {\n setNewOptions((prev) => [...prev, ...newItems]);\n }\n return;\n }\n }\n\n // Default behavior for non-freeSolo cases\n if (transformValue && value !== null) {\n applyTransform(value as TValue | TValue[]);\n } else {\n autocompleteProps?.onChange?.(event, value, reason, details);\n }\n },\n\n /**\n * Custom rendering for the selected value(s)\n * For multiple selection, renders a Chip for each selected value\n * For single selection, renders the value as text\n * Uses getItemLabel to render the value labels\n */\n renderValue: (value, getItemProps, ownerState) => {\n const typedValue = getAutocompleteTypedValue(value, ownerState);\n\n // Handle array values (multiple selection)\n if (Array.isArray(typedValue)) {\n return typedValue.map((v, index) => {\n // @ts-expect-error a key is returned, and the linter doesn't pick this up\n const { key, ...chipProps } = getItemProps({ index });\n\n // Get the label - use string directly or extract from object\n const label = typeof v === \"string\" ? v : getItemLabel(v);\n\n // Get additional chip props if available\n const valueSpecificProps =\n typeof v !== \"string\" && getChipProps ? getChipProps({ value: v, index }) : {};\n\n return (\n <Chip\n key={`${name}-chip-${key}`}\n {...chipProps}\n {...valueSpecificProps}\n label={valueSpecificProps?.label ?? label}\n />\n );\n });\n }\n\n // Handles single value - return string or extracted label\n return isNonNullableString(typedValue)\n ? typedValue\n : typedValue\n ? getItemLabel(typedValue as NonNullable<TValue>)\n : \"\";\n },\n ...autocompleteProps,\n }}\n textFieldProps={{\n /**\n * Determines the placeholder value based on the `field.value` and `props.textFieldProps.placeholder`.\n * If `field.value` is truthy, the placeholder will be an empty string.\n * Otherwise, it uses `props.textFieldProps.placeholder` if available.\n *\n * @type {string}\n */\n placeholder: field.value ? \"\" : props?.textFieldProps?.placeholder,\n ...props?.textFieldProps,\n }}\n />\n );\n};\n","import { TextFieldElement, type TextFieldElementProps } from \"react-hook-form-mui\";\nimport { type FieldPath, type FieldValues } from \"react-hook-form\";\nimport { useMemo } from \"react\";\nimport { getTextElementDisplayProps } from \"../utils\";\n\nexport type TextElementDisplayProps<\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>\n> = TextFieldElementProps<TFieldValues, TName> & Viewable;\n\n/**\n * A form component that displays a text field with view-only capabilities.\n * Extends TextFieldElement with view-only functionality.\n *\n * @template TFieldValues - The type of the form values\n * @template TName - The type of the field name\n *\n * @returns A React component for text input with view-only support\n */\nexport const TextElementDisplay = <\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,\n>({\n viewOnly,\n disableUnderline,\n ...props\n}: TextElementDisplayProps<TFieldValues, TName>) => {\n\n const adjustedProps = useMemo(\n () => getTextElementDisplayProps(props, viewOnly, disableUnderline),\n [props, viewOnly, disableUnderline],\n );\n\n return <TextFieldElement {...adjustedProps} />;\n};\n\ntype Viewable = {\n viewOnly?: boolean;\n disableUnderline?: boolean;\n};\n","import { FieldError, FieldErrors, FieldValues } from 'react-hook-form';\r\nimport lodash from 'lodash';\r\nconst { get } = lodash;\r\n\r\n/**\r\n * A hook to get the error message for a field from react-hook-form\r\n * @param errors The errors object from react-hook-form\r\n * @param name The name of the field (supports dot notation for nested fields)\r\n * @returns An object with error and helperText properties\r\n */\r\nexport function useFormError<T extends FieldValues>(\r\n errors: FieldErrors<T>,\r\n name: string\r\n): { error: boolean; helperText: string } {\r\n // Get the error for the field, supporting nested paths with dot notation\r\n const fieldError = get(errors, name) as FieldError | undefined;\r\n\r\n // Return error state and helper text\r\n return {\r\n error: !!fieldError,\r\n helperText: fieldError?.message || '',\r\n };\r\n}\r\n","// src/hooks/useOnMount.ts\r\nimport { useEffect, useRef } from \"react\";\r\n\r\n/**\r\n * Runs a provided callback function once on the first component mount.\r\n *\r\n * @param callback - The function to run on first mount.\r\n */\r\nexport function useOnMount(callback: () => void): void {\r\n const hasMounted = useRef(false);\r\n\r\n useEffect(() => {\r\n if (!hasMounted.current) {\r\n callback();\r\n hasMounted.current = true;\r\n }\r\n\r\n // Cleanup to prevent callback logic from running during cleanup\r\n return () => {\r\n hasMounted.current = true;\r\n };\r\n \r\n // eslint-disable-next-line react-hooks/exhaustive-deps\r\n }, []);\r\n}\r\n\r\n","import type { JSX } from \"react\";\r\nimport { FormControl, FormHelperText } from \"@mui/material\";\r\nimport type { FormControlProps } from \"@mui/material\";\r\nimport { useFormContext, type RegisterOptions, type FieldValues, type Path } from \"react-hook-form\";\r\nimport { useFormError } from \"../hooks\";\r\n\r\n/**\r\n * Props for the RHFHiddenInput component\r\n */\r\nexport interface ValidationElementProps<TFieldValues extends FieldValues> {\r\n /**\r\n * Name of the field in the form\r\n */\r\n name: Path<TFieldValues>;\r\n /**\r\n * Optional validation rules\r\n */\r\n rules: RegisterOptions<TFieldValues>;\r\n /**\r\n * Props to pass to the FormControl component\r\n */\r\n formControlProps?: Omit<FormControlProps, \"error\">;\r\n}\r\n\r\nexport const ValidationElement = <TFieldValues extends FieldValues = FieldValues>({\r\n name,\r\n rules,\r\n formControlProps = {},\r\n}: ValidationElementProps<TFieldValues>): JSX.Element => {\r\n const {\r\n register,\r\n formState: { errors },\r\n } = useFormContext<TFieldValues>();\r\n\r\n const { error, helperText } = useFormError(errors, name);\r\n\r\n return (\r\n <FormControl error={error} {...formControlProps}>\r\n <input type=\"hidden\" {...register(name, rules)} />\r\n {error && <FormHelperText>{helperText}</FormHelperText>}\r\n </FormControl>\r\n );\r\n};\r\n"],"names":["merge","lodash","getAutocompleteTypedValue","value","ownerState","getTextElementDisplayProps","props","viewOnly","disableUnderline","isNonNullableString","AutocompleteElementDisplay","textFieldProps","autocompleteProps","autocompleteAdjustedProps","useMemo","textFieldAdjustedProps","jsx","AutocompleteElement","ObjectElementDisplay","options","getItemKey","getItemLabel","getChipProps","stringToNewItem","transformValue","name","freeSolo","control","getOptionProps","field","useController","newOptions","setNewOptions","useState","option","useEffect","newFieldOptions","prevOptions","allOptions","seen","key","o","v","inputValue","searchValue","filteredOptions","label","liProps","selected","itemProps","createElement","ListItem","Checkbox","event","reason","details","applyTransform","val","addToNewOptions","item","itemKey","prev","getInputValue","newItem","newValues","inputVal","allOptionsKeys","newItems","getItemProps","typedValue","index","chipProps","valueSpecificProps","Chip","TextElementDisplay","adjustedProps","TextFieldElement","get","useFormError","errors","fieldError","useOnMount","callback","hasMounted","useRef","ValidationElement","rules","formControlProps","register","useFormContext","error","helperText","jsxs","FormControl","FormHelperText"],"mappings":"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"}
package/dist/index.js CHANGED
@@ -1,10 +1,10 @@
1
- import { jsx as x, jsxs as H } from "react/jsx-runtime";
1
+ import { jsx as A, jsxs as H } from "react/jsx-runtime";
2
2
  import { AutocompleteElement as R, useController as q, TextFieldElement as L } from "react-hook-form-mui";
3
- import { useMemo as O, useState as w, useEffect as P, createElement as T, useRef as z } from "react";
4
- import k, { merge as G } from "lodash";
5
- import { Chip as J, ListItem as _, Checkbox as N, FormControl as Q, FormHelperText as W } from "@mui/material";
3
+ import { useMemo as O, useState as w, useEffect as _, createElement as $, useRef as z } from "react";
4
+ import j, { merge as G } from "lodash";
5
+ import { Chip as J, ListItem as T, Checkbox as N, FormControl as Q, FormHelperText as W } from "@mui/material";
6
6
  import { useFormContext as X } from "react-hook-form";
7
- const { merge: Y } = k;
7
+ const { merge: Y } = j;
8
8
  function Z(e, n) {
9
9
  return n?.multiple, n?.freeSolo, e;
10
10
  }
@@ -29,21 +29,21 @@ const S = (e, n = !1, t = !1) => Y(
29
29
  function U(e) {
30
30
  return e != null && typeof e == "string";
31
31
  }
32
- const { merge: v } = k, K = ({
32
+ const { merge: v } = j, K = ({
33
33
  viewOnly: e = void 0,
34
34
  disableUnderline: n,
35
35
  textFieldProps: t,
36
- autocompleteProps: c,
36
+ autocompleteProps: a,
37
37
  ...y
38
38
  }) => {
39
- const d = O(
39
+ const f = O(
40
40
  () => v(
41
41
  {
42
42
  readOnly: e,
43
- disableClearable: c?.disableClearable || e,
43
+ disableClearable: a?.disableClearable || e,
44
44
  disabled: e
45
45
  },
46
- c,
46
+ a,
47
47
  e ? {
48
48
  sx: {
49
49
  ".MuiAutocomplete-tag": {
@@ -52,57 +52,57 @@ const { merge: v } = k, K = ({
52
52
  }
53
53
  } : {}
54
54
  ),
55
- [c, e]
56
- ), A = O(
55
+ [a, e]
56
+ ), x = O(
57
57
  () => S(t, e, n),
58
58
  [t, e, n]
59
59
  );
60
- return /* @__PURE__ */ x(
60
+ return /* @__PURE__ */ A(
61
61
  R,
62
62
  {
63
- autocompleteProps: d,
64
- textFieldProps: A,
63
+ autocompleteProps: f,
64
+ textFieldProps: x,
65
65
  ...y
66
66
  }
67
67
  );
68
- }, le = ({
68
+ }, ue = ({
69
69
  options: e,
70
70
  autocompleteProps: n,
71
71
  getItemKey: t,
72
- getItemLabel: c,
72
+ getItemLabel: a,
73
73
  getChipProps: y,
74
- stringToNewItem: d,
75
- transformValue: A,
76
- name: V,
77
- freeSolo: M,
78
- control: F,
74
+ stringToNewItem: f,
75
+ transformValue: x,
76
+ name: g,
77
+ freeSolo: F,
78
+ control: k,
79
79
  getOptionProps: D,
80
- ...g
80
+ ...b
81
81
  }) => {
82
- const { field: a } = q({ name: V, control: F }), [b, j] = w(() => a.value ? (Array.isArray(a.value) ? a.value : [a.value]).filter(
83
- (r) => typeof r != "string" && !e.some((s) => t(s) === t(r))
82
+ const { field: c } = q({ name: g, control: k }), [C, M] = w(() => c.value ? (Array.isArray(c.value) ? c.value : [c.value]).filter(
83
+ (r) => typeof r != "string" && !e.some((o) => t(o) === t(r))
84
84
  ) : []);
85
- P(() => {
86
- if (!a.value) return;
87
- const r = (Array.isArray(a.value) ? a.value : [a.value]).filter(
88
- (s) => typeof s != "string" && ![...e, ...b].some((u) => t(u) === t(s))
85
+ _(() => {
86
+ if (!c.value) return;
87
+ const r = (Array.isArray(c.value) ? c.value : [c.value]).filter(
88
+ (o) => typeof o != "string" && ![...e, ...C].some((l) => t(l) === t(o))
89
89
  );
90
- r.length > 0 && j((s) => [...s, ...r]);
91
- }, [a.value, e, b, t]);
90
+ r.length > 0 && M((o) => [...o, ...r]);
91
+ }, [c.value, e, C, t]);
92
92
  const B = O(() => {
93
93
  const i = /* @__PURE__ */ new Set();
94
- return [...e, ...b].filter((r) => {
95
- const s = t(r);
96
- return i.has(s) ? !1 : (i.add(s), !0);
94
+ return [...e, ...C].filter((r) => {
95
+ const o = t(r);
96
+ return i.has(o) ? !1 : (i.add(o), !0);
97
97
  });
98
- }, [e, b]);
99
- return /* @__PURE__ */ x(
98
+ }, [e, C]);
99
+ return /* @__PURE__ */ A(
100
100
  K,
101
101
  {
102
- name: V,
103
- control: F,
102
+ name: g,
103
+ control: k,
104
104
  options: B,
105
- ...g,
105
+ ...b,
106
106
  autocompleteProps: {
107
107
  /**
108
108
  * Determines if two options should be considered equal
@@ -116,20 +116,20 @@ const { merge: v } = k, K = ({
116
116
  */
117
117
  filterOptions: (i, { inputValue: r }) => {
118
118
  if (!r) return i;
119
- const s = r.toLowerCase(), u = i.filter((l) => {
120
- const f = t(l)?.toLowerCase(), C = String(c(l)).toLowerCase();
121
- return f?.includes(s) || C.includes(s);
119
+ const o = r.toLowerCase(), l = i.filter((u) => {
120
+ const d = t(u)?.toLowerCase(), E = String(a(u)).toLowerCase();
121
+ return d?.includes(o) || E.includes(o);
122
122
  });
123
- return M && d && r.length > 0 && !u.some(
124
- (f) => String(c(f)).toLowerCase() === s
123
+ return F && f && r.length > 0 && !l.some(
124
+ (d) => String(a(d)).toLowerCase() === o
125
125
  ) ? [{
126
126
  __isAddOption: !0,
127
127
  inputValue: r,
128
- ...d(r)
128
+ ...f(r)
129
129
  // Include properties for type compatibility
130
- }, ...u] : u;
130
+ }, ...l] : l;
131
131
  },
132
- freeSolo: M,
132
+ freeSolo: F,
133
133
  // Allowed to enter own string value
134
134
  autoComplete: !0,
135
135
  autoHighlight: !0,
@@ -140,49 +140,49 @@ const { merge: v } = k, K = ({
140
140
  * Custom rendering for each option in the dropdown list
141
141
  * Handles both regular options and special "Add" options in freeSolo mode
142
142
  */
143
- renderOption: (i, r, { selected: s }, u) => {
144
- const l = G(i, D?.(r) ?? {});
145
- if (u?.freeSolo && typeof r == "object" && r !== null && "__isAddOption" in r) {
146
- const f = r.inputValue;
147
- return /* @__PURE__ */ T(_, { ...l, key: `${V}-add-option-${f}` }, "Add: '", f, "'");
143
+ renderOption: (i, r, { selected: o }, l) => {
144
+ const u = G(i, D?.(r) ?? {});
145
+ if (l?.freeSolo && typeof r == "object" && r !== null && "__isAddOption" in r) {
146
+ const d = r.inputValue;
147
+ return /* @__PURE__ */ $(T, { ...u, key: `${g}-add-option-${d}` }, "Add: '", d, "'");
148
148
  }
149
- return /* @__PURE__ */ T(_, { ...l, key: `${V}-option-${t(r)}` }, g?.showCheckbox && u?.multiple && /* @__PURE__ */ x(N, { sx: { marginRight: 1 }, checked: s }), typeof r == "string" ? r : c(r));
149
+ return /* @__PURE__ */ $(T, { ...u, key: `${g}-option-${t(r)}` }, b?.showCheckbox && l?.multiple && /* @__PURE__ */ A(N, { sx: { marginRight: 1 }, checked: o }), typeof r == "string" ? r : a(r));
150
150
  },
151
- onChange: (i, r, s, u) => {
152
- const l = (o) => A && o !== null ? a.onChange(A(o)) : a.onChange(o), f = (o) => {
153
- const p = t(o);
154
- [...e, ...b].some(
151
+ onChange: (i, r, o, l) => {
152
+ const u = (s) => x && s !== null ? c.onChange(x(s)) : c.onChange(s), d = (s) => {
153
+ const p = t(s);
154
+ [...e, ...C].some(
155
155
  (m) => t(m) === p
156
- ) || j((m) => [...m, o]);
157
- }, C = (o) => typeof o == "string" && o.length > 0 ? o : typeof o == "object" && o !== null && "__isAddOption" in o ? o.inputValue : null;
158
- if (M && d) {
159
- const o = C(r);
160
- if (o) {
161
- const p = d(o);
162
- if (g.multiple) {
163
- const m = [...Array.isArray(a.value) ? a.value : [], p];
164
- l(m);
156
+ ) || M((m) => [...m, s]);
157
+ }, E = (s) => typeof s == "string" && s.length > 0 ? s : typeof s == "object" && s !== null && "__isAddOption" in s ? s.inputValue : null;
158
+ if (F && f) {
159
+ const s = E(r);
160
+ if (s) {
161
+ const p = f(s);
162
+ if (b.multiple) {
163
+ const m = [...Array.isArray(c.value) ? c.value : [], p];
164
+ u(m);
165
165
  } else
166
- l(p);
167
- f(p);
166
+ u(p);
167
+ d(p);
168
168
  return;
169
169
  }
170
- if (Array.isArray(r) && g.multiple) {
170
+ if (Array.isArray(r) && b.multiple) {
171
171
  const p = r?.map((h) => {
172
- const $ = C(h);
173
- return $ ? d($) : h;
172
+ const P = E(h);
173
+ return P ? f(P) : h;
174
174
  }) ?? [];
175
- l(p);
176
- const E = [...e, ...b].map(
175
+ u(p);
176
+ const V = [...e, ...C].map(
177
177
  (h) => t(h)
178
178
  ), m = p.filter(
179
- (h) => typeof h != "string" && !E.includes(t(h))
179
+ (h) => typeof h != "string" && !V.includes(t(h))
180
180
  );
181
- m.length > 0 && j((h) => [...h, ...m]);
181
+ m.length > 0 && M((h) => [...h, ...m]);
182
182
  return;
183
183
  }
184
184
  }
185
- A && r !== null ? l(r) : n?.onChange?.(i, r, s, u);
185
+ x && r !== null ? u(r) : n?.onChange?.(i, r, o, l);
186
186
  },
187
187
  /**
188
188
  * Custom rendering for the selected value(s)
@@ -190,22 +190,33 @@ const { merge: v } = k, K = ({
190
190
  * For single selection, renders the value as text
191
191
  * Uses getItemLabel to render the value labels
192
192
  */
193
- renderValue: (i, r, s) => {
194
- const u = Z(i, s);
195
- return Array.isArray(u) ? u.map((l, f) => {
196
- const { key: C, ...o } = r({ index: f }), p = typeof l == "string" ? l : c(l), E = typeof l != "string" && y ? y({ value: l, index: f }) : {};
197
- return /* @__PURE__ */ x(
193
+ renderValue: (i, r, o) => {
194
+ const l = Z(i, o);
195
+ return Array.isArray(l) ? l.map((u, d) => {
196
+ const { key: E, ...s } = r({ index: d }), p = typeof u == "string" ? u : a(u), V = typeof u != "string" && y ? y({ value: u, index: d }) : {};
197
+ return /* @__PURE__ */ A(
198
198
  J,
199
199
  {
200
- ...o,
201
- ...E,
202
- label: E?.label ?? p
200
+ ...s,
201
+ ...V,
202
+ label: V?.label ?? p
203
203
  },
204
- `${V}-chip-${C}`
204
+ `${g}-chip-${E}`
205
205
  );
206
- }) : U(u) ? u : u ? c(u) : "";
206
+ }) : U(l) ? l : l ? a(l) : "";
207
207
  },
208
208
  ...n
209
+ },
210
+ textFieldProps: {
211
+ /**
212
+ * Determines the placeholder value based on the `field.value` and `props.textFieldProps.placeholder`.
213
+ * If `field.value` is truthy, the placeholder will be an empty string.
214
+ * Otherwise, it uses `props.textFieldProps.placeholder` if available.
215
+ *
216
+ * @type {string}
217
+ */
218
+ placeholder: c.value ? "" : b?.textFieldProps?.placeholder,
219
+ ...b?.textFieldProps
209
220
  }
210
221
  }
211
222
  );
@@ -214,12 +225,12 @@ const { merge: v } = k, K = ({
214
225
  disableUnderline: n,
215
226
  ...t
216
227
  }) => {
217
- const c = O(
228
+ const a = O(
218
229
  () => S(t, e, n),
219
230
  [t, e, n]
220
231
  );
221
- return /* @__PURE__ */ x(L, { ...c });
222
- }, { get: I } = k;
232
+ return /* @__PURE__ */ A(L, { ...a });
233
+ }, { get: I } = j;
223
234
  function ee(e, n) {
224
235
  const t = I(e, n);
225
236
  return {
@@ -229,7 +240,7 @@ function ee(e, n) {
229
240
  }
230
241
  function ce(e) {
231
242
  const n = z(!1);
232
- P(() => (n.current || (e(), n.current = !0), () => {
243
+ _(() => (n.current || (e(), n.current = !0), () => {
233
244
  n.current = !0;
234
245
  }), []);
235
246
  }
@@ -239,17 +250,17 @@ const ae = ({
239
250
  formControlProps: t = {}
240
251
  }) => {
241
252
  const {
242
- register: c,
253
+ register: a,
243
254
  formState: { errors: y }
244
- } = X(), { error: d, helperText: A } = ee(y, e);
245
- return /* @__PURE__ */ H(Q, { error: d, ...t, children: [
246
- /* @__PURE__ */ x("input", { type: "hidden", ...c(e, n) }),
247
- d && /* @__PURE__ */ x(W, { children: A })
255
+ } = X(), { error: f, helperText: x } = ee(y, e);
256
+ return /* @__PURE__ */ H(Q, { error: f, ...t, children: [
257
+ /* @__PURE__ */ A("input", { type: "hidden", ...a(e, n) }),
258
+ f && /* @__PURE__ */ A(W, { children: x })
248
259
  ] });
249
260
  };
250
261
  export {
251
262
  K as AutocompleteElementDisplay,
252
- le as ObjectElementDisplay,
263
+ ue as ObjectElementDisplay,
253
264
  ie as TextElementDisplay,
254
265
  ae as ValidationElement,
255
266
  ee as useFormError,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/utils.ts","../src/components/AutocompleteElementDisplay.tsx","../src/components/ObjectElementDisplay.tsx","../src/components/TextElementDisplay.tsx","../src/hooks/useFormError.ts","../src/hooks/useOnMount.ts","../src/components/ValidationElement.tsx"],"sourcesContent":["import type {\r\n AutocompleteOwnerState,\r\n AutocompleteRenderValue,\r\n AutocompleteValue,\r\n ChipTypeMap,\r\n TextFieldProps,\r\n} from \"@mui/material\";\r\nimport { ElementType } from \"react\";\r\n\r\nimport lodash from \"lodash\";\r\n\r\nconst { merge } = lodash;\r\n\r\nexport function getAutocompleteTypedValue<\r\n TValue,\r\n Multiple extends boolean | undefined,\r\n DisableClearable extends boolean | undefined,\r\n FreeSolo extends boolean | undefined,\r\n ChipComponent extends ElementType = ChipTypeMap[\"defaultComponent\"],\r\n>(\r\n value:\r\n | AutocompleteRenderValue<TValue, Multiple, FreeSolo>\r\n | AutocompleteValue<TValue, Multiple, DisableClearable, FreeSolo>,\r\n ownerState?: AutocompleteOwnerState<TValue, Multiple, DisableClearable, FreeSolo, ChipComponent>,\r\n) {\r\n if (ownerState?.multiple) {\r\n if (ownerState?.freeSolo) return value as Array<TValue | string>;\r\n return value as TValue[];\r\n } else if (ownerState?.freeSolo) {\r\n return value as NonNullable<TValue | string>;\r\n }\r\n return value as NonNullable<TValue>;\r\n}\r\n\r\n// Apply view-only properties directly to the TextFieldElement props\r\nexport const getTextElementDisplayProps = <PropType>(\r\n props: PropType,\r\n viewOnly = false,\r\n disableUnderline = false,\r\n) =>\r\n merge<PropType, Partial<TextFieldProps>>(\r\n props,\r\n viewOnly\r\n ? {\r\n disabled: true,\r\n variant: \"standard\",\r\n sx: {\r\n \"& .MuiAutocomplete-endAdornment\": {\r\n display: \"none\",\r\n },\r\n // Hide the underline without using slotProps.input.disableUnderline which clears out chips\r\n ...(disableUnderline && {\r\n \"& .MuiInput-underline:before\": { borderBottom: \"none\" },\r\n \"& .MuiInput-underline:after\": { borderBottom: \"none\" },\r\n \"& .MuiInput-underline:hover:not(.Mui-disabled):before\": { borderBottom: \"none\" },\r\n }),\r\n },\r\n }\r\n : {},\r\n ) as PropType;\r\n\r\nexport function isNonNullableString(value: any): value is NonNullable<string> {\r\nreturn value != null && typeof value === 'string';\r\n}","import { AutocompleteElement, type AutocompleteElementProps } from \"react-hook-form-mui\";\r\nimport { type ChipTypeMap } from \"@mui/material\";\r\nimport type { FieldPath, FieldValues } from \"react-hook-form\";\r\nimport { type ElementType, useMemo } from \"react\";\r\nimport lodash from \"lodash\";\r\nimport { getTextElementDisplayProps } from \"../utils\";\r\n\r\nconst { merge } = lodash;\r\n\r\nexport type AutocompleteElementDisplayProps<\r\n TValue,\r\n Multiple extends boolean | undefined,\r\n DisableClearable extends boolean | undefined,\r\n FreeSolo extends boolean | undefined,\r\n ChipComponent extends ElementType = ChipTypeMap[\"defaultComponent\"],\r\n TFieldValues extends FieldValues = FieldValues,\r\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,\r\n> = AutocompleteElementProps<\r\n TValue,\r\n Multiple,\r\n DisableClearable,\r\n FreeSolo,\r\n ChipComponent,\r\n TFieldValues,\r\n TName\r\n> & {\r\n viewOnly?: boolean;\r\n disableUnderline?: boolean;\r\n}\r\n\r\nexport const AutocompleteElementDisplay = <\r\n TValue,\r\n Multiple extends boolean | undefined,\r\n DisableClearable extends boolean | undefined,\r\n FreeSolo extends boolean | undefined,\r\n ChipComponent extends ElementType = ChipTypeMap[\"defaultComponent\"],\r\n TFieldValues extends FieldValues = FieldValues,\r\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,\r\n>({\r\n viewOnly = undefined as boolean | undefined,\r\n disableUnderline,\r\n textFieldProps,\r\n autocompleteProps,\r\n ...props\r\n}: AutocompleteElementDisplayProps<\r\n TValue,\r\n Multiple,\r\n DisableClearable,\r\n FreeSolo,\r\n ChipComponent,\r\n TFieldValues,\r\n TName\r\n>) => {\r\n const autocompleteAdjustedProps: AutocompleteElementDisplayProps<\r\n TValue,\r\n Multiple,\r\n DisableClearable,\r\n FreeSolo,\r\n ChipComponent,\r\n TFieldValues,\r\n TName\r\n >[\"autocompleteProps\"] = useMemo(\r\n () =>\r\n merge<\r\n AutocompleteElementDisplayProps<TValue, Multiple, DisableClearable, FreeSolo, ChipComponent, TFieldValues, TName>[\"autocompleteProps\"],\r\n AutocompleteElementDisplayProps<TValue, Multiple, DisableClearable, FreeSolo, ChipComponent, TFieldValues, TName>[\"autocompleteProps\"],\r\n AutocompleteElementDisplayProps<TValue, Multiple, DisableClearable, FreeSolo, ChipComponent, TFieldValues, TName>[\"autocompleteProps\"]\r\n >(\r\n {\r\n readOnly: viewOnly,\r\n disableClearable: autocompleteProps?.disableClearable || viewOnly as DisableClearable,\r\n disabled: viewOnly,\r\n\r\n },\r\n autocompleteProps,\r\n viewOnly\r\n ? {\r\n sx: {\r\n \".MuiAutocomplete-tag\": {\r\n opacity: \"1 !important\",\r\n },\r\n },\r\n }\r\n : {},\r\n ),\r\n [autocompleteProps, viewOnly],\r\n );\r\n\r\n const textFieldAdjustedProps= useMemo(\r\n () => getTextElementDisplayProps(textFieldProps, viewOnly, disableUnderline),\r\n [textFieldProps, viewOnly, disableUnderline],\r\n );\r\n\r\n return (\r\n <AutocompleteElement\r\n autocompleteProps={autocompleteAdjustedProps}\r\n textFieldProps={textFieldAdjustedProps}\r\n {...props}\r\n />\r\n );\r\n};\r\n\r\n\r\n","import { type ElementType, type ReactNode, useMemo, useState, useEffect } from \"react\";\nimport {\n Checkbox,\n Chip,\n ListItem,\n type ChipProps,\n type ChipTypeMap,\n type ListItemProps,\n} from \"@mui/material\";\nimport type { FieldPath, FieldValue, FieldValues } from \"react-hook-form\";\nimport {\n AutocompleteElementDisplay,\n type AutocompleteElementDisplayProps,\n} from \"./AutocompleteElementDisplay\";\nimport { getAutocompleteTypedValue, isNonNullableString } from \"../utils\";\nimport { useController } from \"react-hook-form-mui\";\nimport { merge } from \"lodash\";\n\n/**\n * Interface for special \"add option\" objects used in freeSolo mode\n * These objects represent a new item that can be created from user input\n */\ninterface AddOptionType {\n __isAddOption: true;\n inputValue: string;\n\n [key: string]: any; // Allow for additional properties from stringToNewItem\n}\n\n/**\n * Extends AutocompleteElementDisplayProps with additional properties for handling object values.\n *\n * @template TValue - The type of the option values\n * @template Multiple - Boolean flag indicating if multiple selections are allowed\n * @template DisableClearable - Boolean flag indicating if clearing the selection is disabled\n * @template FreeSolo - Boolean flag indicating if free text input is allowed\n * @template ChipComponent - The component type used for rendering chips in multiple selection mode\n * @template TFieldValues - The type of the form values\n * @template TName - The type of the field name\n */\nexport type ObjectElementDisplayProps<\n TValue,\n Multiple extends boolean | undefined,\n DisableClearable extends boolean | undefined,\n FreeSolo extends boolean | undefined,\n ChipComponent extends ElementType = ChipTypeMap[\"defaultComponent\"],\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,\n> = AutocompleteElementDisplayProps<\n TValue,\n Multiple,\n DisableClearable,\n FreeSolo,\n ChipComponent,\n TFieldValues,\n TName\n> & {\n /**\n * Function to extract a unique key from an option value.\n * Used for option comparison and deduplication.\n *\n * @param value - The option value or null\n * @returns A unique string key for the value\n */\n getItemKey: (value: TValue | null) => string | null;\n\n /**\n * Function to generate a display label for an option value.\n * Can return any ReactNode for custom rendering.\n *\n * @param value - The option value or null\n * @returns An option to show for the value\n */\n getItemLabel: (value: TValue | null) => ReactNode;\n\n /**\n * Function to get additional props for an option list item.\n * Used for customizing the rendering of the option.\n *\n * @param value - The option value or null\n * @returns Additional props to apply to the list item\n */\n getOptionProps?: (value: TValue | null) => ListItemProps;\n\n /**\n * Function to convert a free text input string to a TValue object.\n * Required when freeSolo is true to create new items from text input.\n *\n * @param value - The string value entered by the user\n * @returns A new TValue object created from the string\n */\n stringToNewItem?: (value: string) => TValue;\n\n /**\n * Whether the input allows free text entry.\n * When true, users can enter values that are not in the options.\n */\n freeSolo?: FreeSolo;\n\n /**\n * Optional function that returns additional chip props based on the value.\n * This allows for customizing chip appearance and behavior based on the value it represents.\n *\n * @param value - The option value being rendered as a chip\n * @returns Additional props to apply to the Chip component\n */\n getChipProps?: (props: { value: TValue; index: number }) => Partial<ChipProps> | undefined;\n\n /**\n * Optional function to transform the value before it's updated in the form.\n * This allows for custom processing or enrichment of the selected value.\n *\n * @param value - The value that would normally be sent to the form\n * @returns The transformed value to be stored in the form\n */\n transformValue?: (\n value: Multiple extends true ? TValue[] : TValue | null\n ) => FieldValue<FieldValues>;\n};\n\n/**\n * A form component that displays a searchable dropdown for selecting object values.\n * Extends AutocompleteElementDisplay with object-specific functionality.\n *\n * Features:\n * - Works with complex object values instead of just primitive types\n * - Supports both single and multiple selection modes\n * - Supports free-solo mode for creating new items from text input\n * - Handles initial values that aren't in the default options\n * - Deduplicates options based on item keys\n *\n * @template TValue - The type of the option values\n * @template Multiple - Boolean flag indicating if multiple selections are allowed\n * @template DisableClearable - Boolean flag indicating if clearing the selection is disabled\n * @template FreeSolo - Boolean flag indicating if free text input is allowed\n * @template ChipComponent - The component type used for rendering chips in multiple selection mode\n * @template TFieldValues - The type of the form values\n * @template TName - The type of the field name\n *\n * @returns A React component for selecting object values\n */\nexport const ObjectElementDisplay = <\n TValue,\n Multiple extends boolean | undefined,\n DisableClearable extends boolean | undefined,\n FreeSolo extends boolean | undefined,\n ChipComponent extends ElementType = ChipTypeMap[\"defaultComponent\"],\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,\n>({\n options,\n autocompleteProps,\n getItemKey,\n getItemLabel,\n getChipProps,\n stringToNewItem,\n transformValue,\n name,\n freeSolo,\n control,\n getOptionProps,\n ...props\n}: ObjectElementDisplayProps<\n TValue,\n Multiple,\n DisableClearable,\n FreeSolo,\n ChipComponent,\n TFieldValues,\n TName\n>) => {\n /**\n * Access to the form field controller\n */\n const { field } = useController({ name, control });\n\n /**\n * State for storing dynamically added options that aren't in the original options list\n * Includes both default values and values added during freeSolo mode\n */\n const [newOptions, setNewOptions] = useState<TValue[]>(() => {\n if (!field.value) return [];\n\n // Convert field value to array for consistent handling\n const fieldValues: TValue[] = Array.isArray(field.value) ? field.value : [field.value];\n\n // Keep only object values that don't exist in the options array\n return fieldValues.filter(\n (value) =>\n typeof value !== \"string\" &&\n !options.some((option) => getItemKey(option) === getItemKey(value)),\n );\n });\n\n /**\n * Update newOptions when field.value changes\n * This ensures that any new values added to the field after rendering\n * are properly included in newOptions and displayed\n */\n useEffect(() => {\n if (!field.value) return;\n\n const fieldValues: TValue[] = Array.isArray(field.value) ? field.value : [field.value];\n const newFieldOptions = fieldValues.filter(\n (value) =>\n typeof value !== \"string\" &&\n ![...options, ...newOptions].some((option) => getItemKey(option) === getItemKey(value)),\n );\n\n // Only update newOptions if there are new values to add\n if (newFieldOptions.length > 0) {\n setNewOptions((prevOptions) => [...prevOptions, ...newFieldOptions]);\n }\n }, [field.value, options, newOptions, getItemKey]);\n\n /**\n * Combined list of all available options (original + dynamically added)\n */\n const allOptions = useMemo(() => {\n const seen = new Set();\n return [...options, ...newOptions].filter((option) => {\n const key = getItemKey(option);\n if (seen.has(key)) return false;\n seen.add(key);\n return true;\n })\n }, [options, newOptions]);\n\n return (\n <AutocompleteElementDisplay\n name={name}\n control={control}\n options={allOptions}\n {...props}\n autocompleteProps={{\n /**\n * Determines if two options should be considered equal\n * Uses the getItemKey function to compare option values\n */\n isOptionEqualToValue: (o, v) => getItemKey(o) === getItemKey(v),\n\n /**\n * Filters options based on the input value\n * Checks if the option key or label contains the input value (case-insensitive)\n * For freeSolo mode, adds a special \"Add [value]\" option when there's no exact match\n */\n filterOptions: (options, { inputValue }) => {\n if (!inputValue) return options;\n\n const searchValue = inputValue.toLowerCase();\n\n // Filter options that match the input value (by key or label)\n const filteredOptions = options.filter((option) => {\n const key = getItemKey(option)?.toLowerCase();\n const label = String(getItemLabel(option)).toLowerCase();\n return key?.includes(searchValue) || label.includes(searchValue);\n });\n\n // For freeSolo mode, add \"Add [value]\" option if no exact match exists\n if (freeSolo && stringToNewItem && inputValue.length > 0) {\n const hasExactMatch = filteredOptions.some(\n (option) => String(getItemLabel(option)).toLowerCase() === searchValue,\n );\n\n if (!hasExactMatch) {\n // Create a special option with a __isAddOption flag\n const addOption: AddOptionType = {\n __isAddOption: true,\n inputValue,\n ...stringToNewItem(inputValue), // Include properties for type compatibility\n };\n\n return [addOption as unknown as TValue, ...filteredOptions];\n }\n }\n\n return filteredOptions;\n },\n freeSolo, // Allowed to enter own string value\n autoComplete: true,\n autoHighlight: true, // The first option is highlighted by default\n openOnFocus: true, // Opens the menu when tabbed into\n\n /**\n * Custom rendering for each option in the dropdown list\n * Handles both regular options and special \"Add\" options in freeSolo mode\n */\n renderOption: (liProps, option, { selected }, ownerState) => {\n const itemProps = merge(liProps, getOptionProps?.(option) ?? {});\n\n // Handles the special \"Add\" option in freeSolo mode\n if (\n ownerState?.freeSolo &&\n typeof option === \"object\" &&\n option !== null &&\n \"__isAddOption\" in option\n ) {\n const inputValue = (option as unknown as AddOptionType).inputValue;\n return (\n <ListItem {...itemProps} key={`${name}-add-option-${inputValue}`}>\n Add: '{inputValue}'\n </ListItem>\n );\n }\n\n // Handle regular option\n return (\n <ListItem {...itemProps} key={`${name}-option-${getItemKey(option)}`}>\n {(props?.showCheckbox && ownerState?.multiple) && (\n <Checkbox sx={{ marginRight: 1 }} checked={selected} />\n )}\n {typeof option === \"string\" ? option : getItemLabel(option)}\n </ListItem>\n );\n },\n\n onChange: (event, value, reason, details) => {\n /**\n * Helper function to apply transformValue if provided, otherwise return the original value\n */\n const applyTransform = (val: any) => {\n return transformValue && val !== null\n ? field.onChange(transformValue(val))\n : field.onChange(val);\n };\n\n /**\n * Helper function to add a new item to newOptions if it doesn't exist already\n */\n const addToNewOptions = (item: TValue) => {\n const itemKey = getItemKey(item);\n const itemExists = [...options, ...newOptions].some(\n (option) => getItemKey(option) === itemKey,\n );\n\n if (!itemExists) {\n setNewOptions((prev) => [...prev, item]);\n }\n };\n\n /**\n * Helper function to extract input value from string or AddOption\n */\n const getInputValue = (item: any): string | null => {\n if (typeof item === \"string\" && item.length > 0) {\n return item;\n }\n if (typeof item === \"object\" && item !== null && \"__isAddOption\" in item) {\n return (item as unknown as AddOptionType).inputValue;\n }\n return null;\n };\n\n // Handle freeSolo mode with stringToNewItem function\n if (freeSolo && stringToNewItem) {\n // Handle special add option selection or string input\n const inputValue = getInputValue(value);\n\n if (inputValue) {\n const newItem = stringToNewItem(inputValue);\n\n if (props.multiple) {\n // For multiple selection, add the new item to the current values\n const currentValues = Array.isArray(field.value) ? field.value : [];\n const newValues = [...currentValues, newItem];\n applyTransform(newValues);\n } else {\n // For single selection, just use the new item\n applyTransform(newItem);\n }\n\n addToNewOptions(newItem);\n return;\n }\n\n // Handle array values (multiple selection)\n if (Array.isArray(value) && props.multiple) {\n // Convert any string values to objects and handle special add options\n const newValues =\n value?.map((item) => {\n const inputVal = getInputValue(item);\n return inputVal ? stringToNewItem(inputVal) : item;\n }) ?? [];\n\n applyTransform(newValues);\n\n // Add any new items to newOptions\n const allOptionsKeys = [...options, ...newOptions].map((option) =>\n getItemKey(option),\n );\n const newItems = newValues.filter(\n (item) => typeof item !== \"string\" && !allOptionsKeys.includes(getItemKey(item)),\n );\n\n if (newItems.length > 0) {\n setNewOptions((prev) => [...prev, ...newItems]);\n }\n return;\n }\n }\n\n // Default behavior for non-freeSolo cases\n if (transformValue && value !== null) {\n applyTransform(value as TValue | TValue[]);\n } else {\n autocompleteProps?.onChange?.(event, value, reason, details);\n }\n },\n\n /**\n * Custom rendering for the selected value(s)\n * For multiple selection, renders a Chip for each selected value\n * For single selection, renders the value as text\n * Uses getItemLabel to render the value labels\n */\n renderValue: (value, getItemProps, ownerState) => {\n const typedValue = getAutocompleteTypedValue(value, ownerState);\n\n // Handle array values (multiple selection)\n if (Array.isArray(typedValue)) {\n return typedValue.map((v, index) => {\n // @ts-expect-error a key is returned, and the linter doesn't pick this up\n const { key, ...chipProps } = getItemProps({ index });\n\n // Get the label - use string directly or extract from object\n const label = typeof v === \"string\" ? v : getItemLabel(v);\n\n // Get additional chip props if available\n const valueSpecificProps =\n typeof v !== \"string\" && getChipProps ? getChipProps({ value: v, index }) : {};\n\n return (\n <Chip\n key={`${name}-chip-${key}`}\n {...chipProps}\n {...valueSpecificProps}\n label={valueSpecificProps?.label ?? label}\n />\n );\n });\n }\n\n // Handles single value - return string or extracted label\n return isNonNullableString(typedValue)\n ? typedValue\n : typedValue\n ? getItemLabel(typedValue as NonNullable<TValue>)\n : \"\";\n },\n ...autocompleteProps,\n }}\n />\n );\n};\n","import { TextFieldElement, type TextFieldElementProps } from \"react-hook-form-mui\";\nimport { type FieldPath, type FieldValues } from \"react-hook-form\";\nimport { useMemo } from \"react\";\nimport { getTextElementDisplayProps } from \"../utils\";\n\nexport type TextElementDisplayProps<\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>\n> = TextFieldElementProps<TFieldValues, TName> & Viewable;\n\n/**\n * A form component that displays a text field with view-only capabilities.\n * Extends TextFieldElement with view-only functionality.\n *\n * @template TFieldValues - The type of the form values\n * @template TName - The type of the field name\n *\n * @returns A React component for text input with view-only support\n */\nexport const TextElementDisplay = <\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,\n>({\n viewOnly,\n disableUnderline,\n ...props\n}: TextElementDisplayProps<TFieldValues, TName>) => {\n\n const adjustedProps = useMemo(\n () => getTextElementDisplayProps(props, viewOnly, disableUnderline),\n [props, viewOnly, disableUnderline],\n );\n\n return <TextFieldElement {...adjustedProps} />;\n};\n\ntype Viewable = {\n viewOnly?: boolean;\n disableUnderline?: boolean;\n};\n","import { FieldError, FieldErrors, FieldValues } from 'react-hook-form';\r\nimport lodash from 'lodash';\r\nconst { get } = lodash;\r\n\r\n/**\r\n * A hook to get the error message for a field from react-hook-form\r\n * @param errors The errors object from react-hook-form\r\n * @param name The name of the field (supports dot notation for nested fields)\r\n * @returns An object with error and helperText properties\r\n */\r\nexport function useFormError<T extends FieldValues>(\r\n errors: FieldErrors<T>,\r\n name: string\r\n): { error: boolean; helperText: string } {\r\n // Get the error for the field, supporting nested paths with dot notation\r\n const fieldError = get(errors, name) as FieldError | undefined;\r\n\r\n // Return error state and helper text\r\n return {\r\n error: !!fieldError,\r\n helperText: fieldError?.message || '',\r\n };\r\n}\r\n","// src/hooks/useOnMount.ts\r\nimport { useEffect, useRef } from \"react\";\r\n\r\n/**\r\n * Runs a provided callback function once on the first component mount.\r\n *\r\n * @param callback - The function to run on first mount.\r\n */\r\nexport function useOnMount(callback: () => void): void {\r\n const hasMounted = useRef(false);\r\n\r\n useEffect(() => {\r\n if (!hasMounted.current) {\r\n callback();\r\n hasMounted.current = true;\r\n }\r\n\r\n // Cleanup to prevent callback logic from running during cleanup\r\n return () => {\r\n hasMounted.current = true;\r\n };\r\n \r\n // eslint-disable-next-line react-hooks/exhaustive-deps\r\n }, []);\r\n}\r\n\r\n","import type { JSX } from \"react\";\r\nimport { FormControl, FormHelperText } from \"@mui/material\";\r\nimport type { FormControlProps } from \"@mui/material\";\r\nimport { useFormContext, type RegisterOptions, type FieldValues, type Path } from \"react-hook-form\";\r\nimport { useFormError } from \"../hooks\";\r\n\r\n/**\r\n * Props for the RHFHiddenInput component\r\n */\r\nexport interface ValidationElementProps<TFieldValues extends FieldValues> {\r\n /**\r\n * Name of the field in the form\r\n */\r\n name: Path<TFieldValues>;\r\n /**\r\n * Optional validation rules\r\n */\r\n rules: RegisterOptions<TFieldValues>;\r\n /**\r\n * Props to pass to the FormControl component\r\n */\r\n formControlProps?: Omit<FormControlProps, \"error\">;\r\n}\r\n\r\nexport const ValidationElement = <TFieldValues extends FieldValues = FieldValues>({\r\n name,\r\n rules,\r\n formControlProps = {},\r\n}: ValidationElementProps<TFieldValues>): JSX.Element => {\r\n const {\r\n register,\r\n formState: { errors },\r\n } = useFormContext<TFieldValues>();\r\n\r\n const { error, helperText } = useFormError(errors, name);\r\n\r\n return (\r\n <FormControl error={error} {...formControlProps}>\r\n <input type=\"hidden\" {...register(name, rules)} />\r\n {error && <FormHelperText>{helperText}</FormHelperText>}\r\n </FormControl>\r\n );\r\n};\r\n"],"names":["merge","lodash","getAutocompleteTypedValue","value","ownerState","getTextElementDisplayProps","props","viewOnly","disableUnderline","isNonNullableString","AutocompleteElementDisplay","textFieldProps","autocompleteProps","autocompleteAdjustedProps","useMemo","textFieldAdjustedProps","jsx","AutocompleteElement","ObjectElementDisplay","options","getItemKey","getItemLabel","getChipProps","stringToNewItem","transformValue","name","freeSolo","control","getOptionProps","field","useController","newOptions","setNewOptions","useState","option","useEffect","newFieldOptions","prevOptions","allOptions","seen","key","o","v","inputValue","searchValue","filteredOptions","label","liProps","selected","itemProps","createElement","ListItem","Checkbox","event","reason","details","applyTransform","val","addToNewOptions","item","itemKey","prev","getInputValue","newItem","newValues","inputVal","allOptionsKeys","newItems","getItemProps","typedValue","index","chipProps","valueSpecificProps","Chip","TextElementDisplay","adjustedProps","TextFieldElement","get","useFormError","errors","fieldError","useOnMount","callback","hasMounted","useRef","ValidationElement","rules","formControlProps","register","useFormContext","error","helperText","jsxs","FormControl","FormHelperText"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../src/utils.ts","../src/components/AutocompleteElementDisplay.tsx","../src/components/ObjectElementDisplay.tsx","../src/components/TextElementDisplay.tsx","../src/hooks/useFormError.ts","../src/hooks/useOnMount.ts","../src/components/ValidationElement.tsx"],"sourcesContent":["import type {\r\n AutocompleteOwnerState,\r\n AutocompleteRenderValue,\r\n AutocompleteValue,\r\n ChipTypeMap,\r\n TextFieldProps,\r\n} from \"@mui/material\";\r\nimport { ElementType } from \"react\";\r\n\r\nimport lodash from \"lodash\";\r\n\r\nconst { merge } = lodash;\r\n\r\nexport function getAutocompleteTypedValue<\r\n TValue,\r\n Multiple extends boolean | undefined,\r\n DisableClearable extends boolean | undefined,\r\n FreeSolo extends boolean | undefined,\r\n ChipComponent extends ElementType = ChipTypeMap[\"defaultComponent\"],\r\n>(\r\n value:\r\n | AutocompleteRenderValue<TValue, Multiple, FreeSolo>\r\n | AutocompleteValue<TValue, Multiple, DisableClearable, FreeSolo>,\r\n ownerState?: AutocompleteOwnerState<TValue, Multiple, DisableClearable, FreeSolo, ChipComponent>,\r\n) {\r\n if (ownerState?.multiple) {\r\n if (ownerState?.freeSolo) return value as Array<TValue | string>;\r\n return value as TValue[];\r\n } else if (ownerState?.freeSolo) {\r\n return value as NonNullable<TValue | string>;\r\n }\r\n return value as NonNullable<TValue>;\r\n}\r\n\r\n// Apply view-only properties directly to the TextFieldElement props\r\nexport const getTextElementDisplayProps = <PropType>(\r\n props: PropType,\r\n viewOnly = false,\r\n disableUnderline = false,\r\n) =>\r\n merge<PropType, Partial<TextFieldProps>>(\r\n props,\r\n viewOnly\r\n ? {\r\n disabled: true,\r\n variant: \"standard\",\r\n sx: {\r\n \"& .MuiAutocomplete-endAdornment\": {\r\n display: \"none\",\r\n },\r\n // Hide the underline without using slotProps.input.disableUnderline which clears out chips\r\n ...(disableUnderline && {\r\n \"& .MuiInput-underline:before\": { borderBottom: \"none\" },\r\n \"& .MuiInput-underline:after\": { borderBottom: \"none\" },\r\n \"& .MuiInput-underline:hover:not(.Mui-disabled):before\": { borderBottom: \"none\" },\r\n }),\r\n },\r\n }\r\n : {},\r\n ) as PropType;\r\n\r\nexport function isNonNullableString(value: any): value is NonNullable<string> {\r\nreturn value != null && typeof value === 'string';\r\n}","import { AutocompleteElement, type AutocompleteElementProps } from \"react-hook-form-mui\";\r\nimport { type ChipTypeMap } from \"@mui/material\";\r\nimport type { FieldPath, FieldValues } from \"react-hook-form\";\r\nimport { type ElementType, useMemo } from \"react\";\r\nimport lodash from \"lodash\";\r\nimport { getTextElementDisplayProps } from \"../utils\";\r\n\r\nconst { merge } = lodash;\r\n\r\nexport type AutocompleteElementDisplayProps<\r\n TValue,\r\n Multiple extends boolean | undefined,\r\n DisableClearable extends boolean | undefined,\r\n FreeSolo extends boolean | undefined,\r\n ChipComponent extends ElementType = ChipTypeMap[\"defaultComponent\"],\r\n TFieldValues extends FieldValues = FieldValues,\r\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,\r\n> = AutocompleteElementProps<\r\n TValue,\r\n Multiple,\r\n DisableClearable,\r\n FreeSolo,\r\n ChipComponent,\r\n TFieldValues,\r\n TName\r\n> & {\r\n viewOnly?: boolean;\r\n disableUnderline?: boolean;\r\n}\r\n\r\nexport const AutocompleteElementDisplay = <\r\n TValue,\r\n Multiple extends boolean | undefined,\r\n DisableClearable extends boolean | undefined,\r\n FreeSolo extends boolean | undefined,\r\n ChipComponent extends ElementType = ChipTypeMap[\"defaultComponent\"],\r\n TFieldValues extends FieldValues = FieldValues,\r\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,\r\n>({\r\n viewOnly = undefined as boolean | undefined,\r\n disableUnderline,\r\n textFieldProps,\r\n autocompleteProps,\r\n ...props\r\n}: AutocompleteElementDisplayProps<\r\n TValue,\r\n Multiple,\r\n DisableClearable,\r\n FreeSolo,\r\n ChipComponent,\r\n TFieldValues,\r\n TName\r\n>) => {\r\n const autocompleteAdjustedProps: AutocompleteElementDisplayProps<\r\n TValue,\r\n Multiple,\r\n DisableClearable,\r\n FreeSolo,\r\n ChipComponent,\r\n TFieldValues,\r\n TName\r\n >[\"autocompleteProps\"] = useMemo(\r\n () =>\r\n merge<\r\n AutocompleteElementDisplayProps<TValue, Multiple, DisableClearable, FreeSolo, ChipComponent, TFieldValues, TName>[\"autocompleteProps\"],\r\n AutocompleteElementDisplayProps<TValue, Multiple, DisableClearable, FreeSolo, ChipComponent, TFieldValues, TName>[\"autocompleteProps\"],\r\n AutocompleteElementDisplayProps<TValue, Multiple, DisableClearable, FreeSolo, ChipComponent, TFieldValues, TName>[\"autocompleteProps\"]\r\n >(\r\n {\r\n readOnly: viewOnly,\r\n disableClearable: autocompleteProps?.disableClearable || viewOnly as DisableClearable,\r\n disabled: viewOnly,\r\n\r\n },\r\n autocompleteProps,\r\n viewOnly\r\n ? {\r\n sx: {\r\n \".MuiAutocomplete-tag\": {\r\n opacity: \"1 !important\",\r\n },\r\n },\r\n }\r\n : {},\r\n ),\r\n [autocompleteProps, viewOnly],\r\n );\r\n\r\n const textFieldAdjustedProps= useMemo(\r\n () => getTextElementDisplayProps(textFieldProps, viewOnly, disableUnderline),\r\n [textFieldProps, viewOnly, disableUnderline],\r\n );\r\n\r\n return (\r\n <AutocompleteElement\r\n autocompleteProps={autocompleteAdjustedProps}\r\n textFieldProps={textFieldAdjustedProps}\r\n {...props}\r\n />\r\n );\r\n};\r\n\r\n\r\n","import { type ElementType, type ReactNode, useMemo, useState, useEffect } from \"react\";\nimport {\n Checkbox,\n Chip,\n ListItem,\n type ChipProps,\n type ChipTypeMap,\n type ListItemProps,\n} from \"@mui/material\";\nimport type { FieldPath, FieldValue, FieldValues } from \"react-hook-form\";\nimport {\n AutocompleteElementDisplay,\n type AutocompleteElementDisplayProps,\n} from \"./AutocompleteElementDisplay\";\nimport { getAutocompleteTypedValue, isNonNullableString } from \"../utils\";\nimport { useController } from \"react-hook-form-mui\";\nimport { merge } from \"lodash\";\n\n/**\n * Interface for special \"add option\" objects used in freeSolo mode\n * These objects represent a new item that can be created from user input\n */\ninterface AddOptionType {\n __isAddOption: true;\n inputValue: string;\n\n [key: string]: any; // Allow for additional properties from stringToNewItem\n}\n\n/**\n * Extends AutocompleteElementDisplayProps with additional properties for handling object values.\n *\n * @template TValue - The type of the option values\n * @template Multiple - Boolean flag indicating if multiple selections are allowed\n * @template DisableClearable - Boolean flag indicating if clearing the selection is disabled\n * @template FreeSolo - Boolean flag indicating if free text input is allowed\n * @template ChipComponent - The component type used for rendering chips in multiple selection mode\n * @template TFieldValues - The type of the form values\n * @template TName - The type of the field name\n */\nexport type ObjectElementDisplayProps<\n TValue,\n Multiple extends boolean | undefined,\n DisableClearable extends boolean | undefined,\n FreeSolo extends boolean | undefined,\n ChipComponent extends ElementType = ChipTypeMap[\"defaultComponent\"],\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,\n> = AutocompleteElementDisplayProps<\n TValue,\n Multiple,\n DisableClearable,\n FreeSolo,\n ChipComponent,\n TFieldValues,\n TName\n> & {\n /**\n * Function to extract a unique key from an option value.\n * Used for option comparison and deduplication.\n *\n * @param value - The option value or null\n * @returns A unique string key for the value\n */\n getItemKey: (value: TValue | null) => string | null;\n\n /**\n * Function to generate a display label for an option value.\n * Can return any ReactNode for custom rendering.\n *\n * @param value - The option value or null\n * @returns An option to show for the value\n */\n getItemLabel: (value: TValue | null) => ReactNode;\n\n /**\n * Function to get additional props for an option list item.\n * Used for customizing the rendering of the option.\n *\n * @param value - The option value or null\n * @returns Additional props to apply to the list item\n */\n getOptionProps?: (value: TValue | null) => ListItemProps;\n\n /**\n * Function to convert a free text input string to a TValue object.\n * Required when freeSolo is true to create new items from text input.\n *\n * @param value - The string value entered by the user\n * @returns A new TValue object created from the string\n */\n stringToNewItem?: (value: string) => TValue;\n\n /**\n * Whether the input allows free text entry.\n * When true, users can enter values that are not in the options.\n */\n freeSolo?: FreeSolo;\n\n /**\n * Optional function that returns additional chip props based on the value.\n * This allows for customizing chip appearance and behavior based on the value it represents.\n *\n * @param value - The option value being rendered as a chip\n * @returns Additional props to apply to the Chip component\n */\n getChipProps?: (props: { value: TValue; index: number }) => Partial<ChipProps> | undefined;\n\n /**\n * Optional function to transform the value before it's updated in the form.\n * This allows for custom processing or enrichment of the selected value.\n *\n * @param value - The value that would normally be sent to the form\n * @returns The transformed value to be stored in the form\n */\n transformValue?: (\n value: Multiple extends true ? TValue[] : TValue | null\n ) => FieldValue<FieldValues>;\n};\n\n/**\n * A form component that displays a searchable dropdown for selecting object values.\n * Extends AutocompleteElementDisplay with object-specific functionality.\n *\n * Features:\n * - Works with complex object values instead of just primitive types\n * - Supports both single and multiple selection modes\n * - Supports free-solo mode for creating new items from text input\n * - Handles initial values that aren't in the default options\n * - Deduplicates options based on item keys\n *\n * @template TValue - The type of the option values\n * @template Multiple - Boolean flag indicating if multiple selections are allowed\n * @template DisableClearable - Boolean flag indicating if clearing the selection is disabled\n * @template FreeSolo - Boolean flag indicating if free text input is allowed\n * @template ChipComponent - The component type used for rendering chips in multiple selection mode\n * @template TFieldValues - The type of the form values\n * @template TName - The type of the field name\n *\n * @returns A React component for selecting object values\n */\nexport const ObjectElementDisplay = <\n TValue,\n Multiple extends boolean | undefined,\n DisableClearable extends boolean | undefined,\n FreeSolo extends boolean | undefined,\n ChipComponent extends ElementType = ChipTypeMap[\"defaultComponent\"],\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,\n>({\n options,\n autocompleteProps,\n getItemKey,\n getItemLabel,\n getChipProps,\n stringToNewItem,\n transformValue,\n name,\n freeSolo,\n control,\n getOptionProps,\n ...props\n}: ObjectElementDisplayProps<\n TValue,\n Multiple,\n DisableClearable,\n FreeSolo,\n ChipComponent,\n TFieldValues,\n TName\n>) => {\n /**\n * Access to the form field controller\n */\n const { field } = useController({ name, control });\n\n /**\n * State for storing dynamically added options that aren't in the original options list\n * Includes both default values and values added during freeSolo mode\n */\n const [newOptions, setNewOptions] = useState<TValue[]>(() => {\n if (!field.value) return [];\n\n // Convert field value to array for consistent handling\n const fieldValues: TValue[] = Array.isArray(field.value) ? field.value : [field.value];\n\n // Keep only object values that don't exist in the options array\n return fieldValues.filter(\n (value) =>\n typeof value !== \"string\" &&\n !options.some((option) => getItemKey(option) === getItemKey(value)),\n );\n });\n\n /**\n * Update newOptions when field.value changes\n * This ensures that any new values added to the field after rendering\n * are properly included in newOptions and displayed\n */\n useEffect(() => {\n if (!field.value) return;\n\n const fieldValues: TValue[] = Array.isArray(field.value) ? field.value : [field.value];\n const newFieldOptions = fieldValues.filter(\n (value) =>\n typeof value !== \"string\" &&\n ![...options, ...newOptions].some((option) => getItemKey(option) === getItemKey(value)),\n );\n\n // Only update newOptions if there are new values to add\n if (newFieldOptions.length > 0) {\n setNewOptions((prevOptions) => [...prevOptions, ...newFieldOptions]);\n }\n }, [field.value, options, newOptions, getItemKey]);\n\n /**\n * Combined list of all available options (original + dynamically added)\n */\n const allOptions = useMemo(() => {\n const seen = new Set();\n return [...options, ...newOptions].filter((option) => {\n const key = getItemKey(option);\n if (seen.has(key)) return false;\n seen.add(key);\n return true;\n })\n }, [options, newOptions]);\n\n return (\n <AutocompleteElementDisplay\n name={name}\n control={control}\n options={allOptions}\n {...props}\n autocompleteProps={{\n /**\n * Determines if two options should be considered equal\n * Uses the getItemKey function to compare option values\n */\n isOptionEqualToValue: (o, v) => getItemKey(o) === getItemKey(v),\n\n /**\n * Filters options based on the input value\n * Checks if the option key or label contains the input value (case-insensitive)\n * For freeSolo mode, adds a special \"Add [value]\" option when there's no exact match\n */\n filterOptions: (options, { inputValue }) => {\n if (!inputValue) return options;\n\n const searchValue = inputValue.toLowerCase();\n\n // Filter options that match the input value (by key or label)\n const filteredOptions = options.filter((option) => {\n const key = getItemKey(option)?.toLowerCase();\n const label = String(getItemLabel(option)).toLowerCase();\n return key?.includes(searchValue) || label.includes(searchValue);\n });\n\n // For freeSolo mode, add \"Add [value]\" option if no exact match exists\n if (freeSolo && stringToNewItem && inputValue.length > 0) {\n const hasExactMatch = filteredOptions.some(\n (option) => String(getItemLabel(option)).toLowerCase() === searchValue,\n );\n\n if (!hasExactMatch) {\n // Create a special option with a __isAddOption flag\n const addOption: AddOptionType = {\n __isAddOption: true,\n inputValue,\n ...stringToNewItem(inputValue), // Include properties for type compatibility\n };\n\n return [addOption as unknown as TValue, ...filteredOptions];\n }\n }\n\n return filteredOptions;\n },\n freeSolo, // Allowed to enter own string value\n autoComplete: true,\n autoHighlight: true, // The first option is highlighted by default\n openOnFocus: true, // Opens the menu when tabbed into\n\n /**\n * Custom rendering for each option in the dropdown list\n * Handles both regular options and special \"Add\" options in freeSolo mode\n */\n renderOption: (liProps, option, { selected }, ownerState) => {\n const itemProps = merge(liProps, getOptionProps?.(option) ?? {});\n\n // Handles the special \"Add\" option in freeSolo mode\n if (\n ownerState?.freeSolo &&\n typeof option === \"object\" &&\n option !== null &&\n \"__isAddOption\" in option\n ) {\n const inputValue = (option as unknown as AddOptionType).inputValue;\n return (\n <ListItem {...itemProps} key={`${name}-add-option-${inputValue}`}>\n Add: '{inputValue}'\n </ListItem>\n );\n }\n\n // Handle regular option\n return (\n <ListItem {...itemProps} key={`${name}-option-${getItemKey(option)}`}>\n {props?.showCheckbox && ownerState?.multiple && (\n <Checkbox sx={{ marginRight: 1 }} checked={selected} />\n )}\n {typeof option === \"string\" ? option : getItemLabel(option)}\n </ListItem>\n );\n },\n\n onChange: (event, value, reason, details) => {\n /**\n * Helper function to apply transformValue if provided, otherwise return the original value\n */\n const applyTransform = (val: any) => {\n return transformValue && val !== null\n ? field.onChange(transformValue(val))\n : field.onChange(val);\n };\n\n /**\n * Helper function to add a new item to newOptions if it doesn't exist already\n */\n const addToNewOptions = (item: TValue) => {\n const itemKey = getItemKey(item);\n const itemExists = [...options, ...newOptions].some(\n (option) => getItemKey(option) === itemKey,\n );\n\n if (!itemExists) {\n setNewOptions((prev) => [...prev, item]);\n }\n };\n\n /**\n * Helper function to extract input value from string or AddOption\n */\n const getInputValue = (item: any): string | null => {\n if (typeof item === \"string\" && item.length > 0) {\n return item;\n }\n if (typeof item === \"object\" && item !== null && \"__isAddOption\" in item) {\n return (item as unknown as AddOptionType).inputValue;\n }\n return null;\n };\n\n // Handle freeSolo mode with stringToNewItem function\n if (freeSolo && stringToNewItem) {\n // Handle special add option selection or string input\n const inputValue = getInputValue(value);\n\n if (inputValue) {\n const newItem = stringToNewItem(inputValue);\n\n if (props.multiple) {\n // For multiple selection, add the new item to the current values\n const currentValues = Array.isArray(field.value) ? field.value : [];\n const newValues = [...currentValues, newItem];\n applyTransform(newValues);\n } else {\n // For single selection, just use the new item\n applyTransform(newItem);\n }\n\n addToNewOptions(newItem);\n return;\n }\n\n // Handle array values (multiple selection)\n if (Array.isArray(value) && props.multiple) {\n // Convert any string values to objects and handle special add options\n const newValues =\n value?.map((item) => {\n const inputVal = getInputValue(item);\n return inputVal ? stringToNewItem(inputVal) : item;\n }) ?? [];\n\n applyTransform(newValues);\n\n // Add any new items to newOptions\n const allOptionsKeys = [...options, ...newOptions].map((option) =>\n getItemKey(option),\n );\n const newItems = newValues.filter(\n (item) => typeof item !== \"string\" && !allOptionsKeys.includes(getItemKey(item)),\n );\n\n if (newItems.length > 0) {\n setNewOptions((prev) => [...prev, ...newItems]);\n }\n return;\n }\n }\n\n // Default behavior for non-freeSolo cases\n if (transformValue && value !== null) {\n applyTransform(value as TValue | TValue[]);\n } else {\n autocompleteProps?.onChange?.(event, value, reason, details);\n }\n },\n\n /**\n * Custom rendering for the selected value(s)\n * For multiple selection, renders a Chip for each selected value\n * For single selection, renders the value as text\n * Uses getItemLabel to render the value labels\n */\n renderValue: (value, getItemProps, ownerState) => {\n const typedValue = getAutocompleteTypedValue(value, ownerState);\n\n // Handle array values (multiple selection)\n if (Array.isArray(typedValue)) {\n return typedValue.map((v, index) => {\n // @ts-expect-error a key is returned, and the linter doesn't pick this up\n const { key, ...chipProps } = getItemProps({ index });\n\n // Get the label - use string directly or extract from object\n const label = typeof v === \"string\" ? v : getItemLabel(v);\n\n // Get additional chip props if available\n const valueSpecificProps =\n typeof v !== \"string\" && getChipProps ? getChipProps({ value: v, index }) : {};\n\n return (\n <Chip\n key={`${name}-chip-${key}`}\n {...chipProps}\n {...valueSpecificProps}\n label={valueSpecificProps?.label ?? label}\n />\n );\n });\n }\n\n // Handles single value - return string or extracted label\n return isNonNullableString(typedValue)\n ? typedValue\n : typedValue\n ? getItemLabel(typedValue as NonNullable<TValue>)\n : \"\";\n },\n ...autocompleteProps,\n }}\n textFieldProps={{\n /**\n * Determines the placeholder value based on the `field.value` and `props.textFieldProps.placeholder`.\n * If `field.value` is truthy, the placeholder will be an empty string.\n * Otherwise, it uses `props.textFieldProps.placeholder` if available.\n *\n * @type {string}\n */\n placeholder: field.value ? \"\" : props?.textFieldProps?.placeholder,\n ...props?.textFieldProps,\n }}\n />\n );\n};\n","import { TextFieldElement, type TextFieldElementProps } from \"react-hook-form-mui\";\nimport { type FieldPath, type FieldValues } from \"react-hook-form\";\nimport { useMemo } from \"react\";\nimport { getTextElementDisplayProps } from \"../utils\";\n\nexport type TextElementDisplayProps<\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>\n> = TextFieldElementProps<TFieldValues, TName> & Viewable;\n\n/**\n * A form component that displays a text field with view-only capabilities.\n * Extends TextFieldElement with view-only functionality.\n *\n * @template TFieldValues - The type of the form values\n * @template TName - The type of the field name\n *\n * @returns A React component for text input with view-only support\n */\nexport const TextElementDisplay = <\n TFieldValues extends FieldValues = FieldValues,\n TName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,\n>({\n viewOnly,\n disableUnderline,\n ...props\n}: TextElementDisplayProps<TFieldValues, TName>) => {\n\n const adjustedProps = useMemo(\n () => getTextElementDisplayProps(props, viewOnly, disableUnderline),\n [props, viewOnly, disableUnderline],\n );\n\n return <TextFieldElement {...adjustedProps} />;\n};\n\ntype Viewable = {\n viewOnly?: boolean;\n disableUnderline?: boolean;\n};\n","import { FieldError, FieldErrors, FieldValues } from 'react-hook-form';\r\nimport lodash from 'lodash';\r\nconst { get } = lodash;\r\n\r\n/**\r\n * A hook to get the error message for a field from react-hook-form\r\n * @param errors The errors object from react-hook-form\r\n * @param name The name of the field (supports dot notation for nested fields)\r\n * @returns An object with error and helperText properties\r\n */\r\nexport function useFormError<T extends FieldValues>(\r\n errors: FieldErrors<T>,\r\n name: string\r\n): { error: boolean; helperText: string } {\r\n // Get the error for the field, supporting nested paths with dot notation\r\n const fieldError = get(errors, name) as FieldError | undefined;\r\n\r\n // Return error state and helper text\r\n return {\r\n error: !!fieldError,\r\n helperText: fieldError?.message || '',\r\n };\r\n}\r\n","// src/hooks/useOnMount.ts\r\nimport { useEffect, useRef } from \"react\";\r\n\r\n/**\r\n * Runs a provided callback function once on the first component mount.\r\n *\r\n * @param callback - The function to run on first mount.\r\n */\r\nexport function useOnMount(callback: () => void): void {\r\n const hasMounted = useRef(false);\r\n\r\n useEffect(() => {\r\n if (!hasMounted.current) {\r\n callback();\r\n hasMounted.current = true;\r\n }\r\n\r\n // Cleanup to prevent callback logic from running during cleanup\r\n return () => {\r\n hasMounted.current = true;\r\n };\r\n \r\n // eslint-disable-next-line react-hooks/exhaustive-deps\r\n }, []);\r\n}\r\n\r\n","import type { JSX } from \"react\";\r\nimport { FormControl, FormHelperText } from \"@mui/material\";\r\nimport type { FormControlProps } from \"@mui/material\";\r\nimport { useFormContext, type RegisterOptions, type FieldValues, type Path } from \"react-hook-form\";\r\nimport { useFormError } from \"../hooks\";\r\n\r\n/**\r\n * Props for the RHFHiddenInput component\r\n */\r\nexport interface ValidationElementProps<TFieldValues extends FieldValues> {\r\n /**\r\n * Name of the field in the form\r\n */\r\n name: Path<TFieldValues>;\r\n /**\r\n * Optional validation rules\r\n */\r\n rules: RegisterOptions<TFieldValues>;\r\n /**\r\n * Props to pass to the FormControl component\r\n */\r\n formControlProps?: Omit<FormControlProps, \"error\">;\r\n}\r\n\r\nexport const ValidationElement = <TFieldValues extends FieldValues = FieldValues>({\r\n name,\r\n rules,\r\n formControlProps = {},\r\n}: ValidationElementProps<TFieldValues>): JSX.Element => {\r\n const {\r\n register,\r\n formState: { errors },\r\n } = useFormContext<TFieldValues>();\r\n\r\n const { error, helperText } = useFormError(errors, name);\r\n\r\n return (\r\n <FormControl error={error} {...formControlProps}>\r\n <input type=\"hidden\" {...register(name, rules)} />\r\n {error && <FormHelperText>{helperText}</FormHelperText>}\r\n </FormControl>\r\n );\r\n};\r\n"],"names":["merge","lodash","getAutocompleteTypedValue","value","ownerState","getTextElementDisplayProps","props","viewOnly","disableUnderline","isNonNullableString","AutocompleteElementDisplay","textFieldProps","autocompleteProps","autocompleteAdjustedProps","useMemo","textFieldAdjustedProps","jsx","AutocompleteElement","ObjectElementDisplay","options","getItemKey","getItemLabel","getChipProps","stringToNewItem","transformValue","name","freeSolo","control","getOptionProps","field","useController","newOptions","setNewOptions","useState","option","useEffect","newFieldOptions","prevOptions","allOptions","seen","key","o","v","inputValue","searchValue","filteredOptions","label","liProps","selected","itemProps","createElement","ListItem","Checkbox","event","reason","details","applyTransform","val","addToNewOptions","item","itemKey","prev","getInputValue","newItem","newValues","inputVal","allOptionsKeys","newItems","getItemProps","typedValue","index","chipProps","valueSpecificProps","Chip","TextElementDisplay","adjustedProps","TextFieldElement","get","useFormError","errors","fieldError","useOnMount","callback","hasMounted","useRef","ValidationElement","rules","formControlProps","register","useFormContext","error","helperText","jsxs","FormControl","FormHelperText"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chris-c-brine/rhf-mui-kit",
3
- "version": "0.5.3",
3
+ "version": "0.5.4",
4
4
  "description": "React Hook Form components with Material UI integration",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",