@abgov/jsonforms-components 2.60.16 → 2.60.18

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.
package/index.esm.js CHANGED
@@ -3786,6 +3786,19 @@ const validateSinWithLuhn = input => {
3786
3786
  }
3787
3787
  return sum % 10 === 0;
3788
3788
  };
3789
+ const getSinValidationError = (data, schema) => {
3790
+ const extraSchema = schema;
3791
+ if (!extraSchema || extraSchema.title !== sinTitle || typeof data !== 'string') {
3792
+ return undefined;
3793
+ }
3794
+ if (data.length === 11 && !validateSinWithLuhn(Number(data.replace(/\D/g, '')))) {
3795
+ return data === '' ? '' : invalidSin;
3796
+ }
3797
+ if (data.length > 0 && data.length < 11) {
3798
+ return extraSchema.errorMessage;
3799
+ }
3800
+ return undefined;
3801
+ };
3789
3802
  /**
3790
3803
  * Gets the required fields in the If/Then/Else json schema condition.
3791
3804
  * @param props - ControlProps
@@ -3850,13 +3863,9 @@ const checkFieldValidity = (props, rootData) => {
3850
3863
  schema
3851
3864
  } = props;
3852
3865
  const labelToUpdate = getControlLabelText(props);
3853
- const extraSchema = schema;
3854
- if (extraSchema && data && (extraSchema == null ? void 0 : extraSchema.title) === sinTitle) {
3855
- if (data.length === 11 && !validateSinWithLuhn(data)) {
3856
- return data === '' ? '' : invalidSin;
3857
- } else if (data.length > 0 && data.length < 11) {
3858
- return extraSchema.errorMessage;
3859
- }
3866
+ const sinValidationError = getSinValidationError(data, schema);
3867
+ if (sinValidationError) {
3868
+ return sinValidationError;
3860
3869
  }
3861
3870
  const rootRequired = getRequiredIfThen(props);
3862
3871
  const requiredByCondition = isRequiredBySchema(props.rootSchema, rootData, props.path, {
@@ -10114,6 +10123,10 @@ const GoAInputBaseTableReview = props => {
10114
10123
  if (!activeError && typeof errors === 'string' && errors.trim() !== '') {
10115
10124
  activeError = errors;
10116
10125
  }
10126
+ const sinValidationError = getSinValidationError(data, schema);
10127
+ if (sinValidationError) {
10128
+ activeError = sinValidationError;
10129
+ }
10117
10130
  if (activeError && /\sis required$/i.test(activeError)) {
10118
10131
  activeError = `${labelToUpdate} is required`;
10119
10132
  }
@@ -17609,20 +17622,66 @@ const NameInputs = ({
17609
17622
  handleInputChange,
17610
17623
  data,
17611
17624
  requiredFields,
17612
- disabled
17625
+ disabled,
17626
+ errors,
17627
+ onFieldBlur
17613
17628
  }) => {
17614
- var _errors$firstName, _errors$lastName;
17615
- const [errors, setErrors] = useState({});
17629
+ var _displayedErrors$firs, _displayedErrors$last;
17630
+ const [internalErrors, setInternalErrors] = useState({});
17631
+ const currentValues = {
17632
+ firstName,
17633
+ middleName: middleName || '',
17634
+ lastName
17635
+ };
17636
+ useEffect(() => {
17637
+ const timeout = window.setTimeout(() => {
17638
+ ['firstName', 'middleName', 'lastName'].forEach(field => {
17639
+ var _input$value;
17640
+ const input = document.querySelector(`goa-input[name="${field}"]`);
17641
+ const liveValue = (input == null || (_input$value = input.value) == null ? void 0 : _input$value.trim()) || '';
17642
+ if (liveValue && !currentValues[field]) {
17643
+ handleInputChange(field, liveValue);
17644
+ }
17645
+ });
17646
+ }, 50);
17647
+ return () => window.clearTimeout(timeout);
17648
+ }, [firstName, middleName, lastName, handleInputChange]);
17649
+ useEffect(() => {
17650
+ if (errors) {
17651
+ return;
17652
+ }
17653
+ setInternalErrors(currentErrors => {
17654
+ const nextErrors = Object.assign({}, currentErrors);
17655
+ let hasChanges = false;
17656
+ Object.keys(currentErrors).forEach(name => {
17657
+ const currentValue = (currentValues[name] || '').trim();
17658
+ if (requiredFields != null && requiredFields.includes(name) && currentValue === '') {
17659
+ return;
17660
+ }
17661
+ delete nextErrors[name];
17662
+ hasChanges = true;
17663
+ });
17664
+ return hasChanges ? nextErrors : currentErrors;
17665
+ });
17666
+ }, [errors, firstName, middleName, lastName, requiredFields]);
17616
17667
  // eslint-disable-next-line
17617
17668
  const handleRequiredFieldBlur = (name, updatedData) => {
17618
- const err = Object.assign({}, errors);
17619
- if ((!(data != null && data[name]) || (data == null ? void 0 : data[name]) === '') && requiredFields.includes(name) && (true)) {
17669
+ const err = Object.assign({}, internalErrors);
17670
+ if ((!(data != null && data[name]) || (data == null ? void 0 : data[name]) === '') && requiredFields != null && requiredFields.includes(name) && (true)) {
17620
17671
  const modifiedName = name === 'firstName' ? 'First name' : name === 'lastName' ? 'Last name' : '';
17621
17672
  err[name] = `${modifiedName} is required`;
17622
17673
  } else {
17623
17674
  err[name] = '';
17624
17675
  }
17625
- setErrors(err);
17676
+ setInternalErrors(err);
17677
+ };
17678
+ const displayedErrors = errors != null ? errors : internalErrors;
17679
+ const handleBlur = name => {
17680
+ if (onFieldBlur) {
17681
+ onFieldBlur(name);
17682
+ } else {
17683
+ handleRequiredFieldBlur(name);
17684
+ }
17626
17685
  };
17627
17686
  return jsxs(GoabGrid, {
17628
17687
  minChildWidth: "0ch",
@@ -17633,7 +17692,7 @@ const NameInputs = ({
17633
17692
  testId: "form-item-first-name",
17634
17693
  label: "First name",
17635
17694
  requirement: requiredFields != null && requiredFields.includes('firstName') ? 'required' : undefined,
17636
- error: (_errors$firstName = errors == null ? void 0 : errors['firstName']) != null ? _errors$firstName : '',
17695
+ error: (_displayedErrors$firs = displayedErrors == null ? void 0 : displayedErrors['firstName']) != null ? _displayedErrors$firs : '',
17637
17696
  children: jsx(GoabInput, {
17638
17697
  type: "text",
17639
17698
  name: "firstName",
@@ -17643,7 +17702,7 @@ const NameInputs = ({
17643
17702
  value: firstName || '',
17644
17703
  onChange: detail => handleInputChange(detail.name, detail.value),
17645
17704
  onBlur: detail => {
17646
- handleRequiredFieldBlur(detail.name);
17705
+ handleBlur(detail.name);
17647
17706
  },
17648
17707
  width: "100%"
17649
17708
  })
@@ -17665,7 +17724,7 @@ const NameInputs = ({
17665
17724
  testId: "form-item-last-name",
17666
17725
  label: "Last name",
17667
17726
  requirement: requiredFields != null && requiredFields.includes('lastName') ? 'required' : undefined,
17668
- error: (_errors$lastName = errors == null ? void 0 : errors['lastName']) != null ? _errors$lastName : '',
17727
+ error: (_displayedErrors$last = displayedErrors == null ? void 0 : displayedErrors['lastName']) != null ? _displayedErrors$last : '',
17669
17728
  children: jsx(GoabInput, {
17670
17729
  type: "text",
17671
17730
  name: "lastName",
@@ -17675,7 +17734,7 @@ const NameInputs = ({
17675
17734
  value: lastName || '',
17676
17735
  onChange: detail => handleInputChange(detail.name, detail.value),
17677
17736
  onBlur: detail => {
17678
- handleRequiredFieldBlur(detail.name);
17737
+ handleBlur(detail.name);
17679
17738
  },
17680
17739
  width: "100%"
17681
17740
  })
@@ -17847,6 +17906,8 @@ handleRequiredFieldBlur) {
17847
17906
  }, [formData]);
17848
17907
  }
17849
17908
 
17909
+ const AUTOFILL_FIELDS = ['firstName', 'middleName', 'lastName', 'dateOfBirth'];
17910
+ const getRequiredLabel = name => name === 'firstName' ? 'First name' : name === 'lastName' ? 'Last name' : name === 'dateOfBirth' ? 'Date of birth' : name;
17850
17911
  const normalizeNameDobData = value => ({
17851
17912
  firstName: (value == null ? void 0 : value.firstName) || '',
17852
17913
  middleName: (value == null ? void 0 : value.middleName) || '',
@@ -17854,7 +17915,7 @@ const normalizeNameDobData = value => ({
17854
17915
  dateOfBirth: (value == null ? void 0 : value.dateOfBirth) || ''
17855
17916
  });
17856
17917
  const FullNameDobControl = props => {
17857
- var _schema$required, _errors$firstName, _schema$required2, _schema$required3, _errors$lastName, _errors$dateOfBirth;
17918
+ var _errors$dateOfBirth;
17858
17919
  const {
17859
17920
  data,
17860
17921
  path,
@@ -17864,7 +17925,7 @@ const FullNameDobControl = props => {
17864
17925
  visible,
17865
17926
  uischema
17866
17927
  } = props;
17867
- const requiredFields = schema.required;
17928
+ const requiredFields = schema.required || [];
17868
17929
  const [errors, setErrors] = useState({});
17869
17930
  const controlRef = useRef(null);
17870
17931
  const formStepperCtx = useContext(JsonFormsStepperContext);
@@ -17879,9 +17940,9 @@ const FullNameDobControl = props => {
17879
17940
  };
17880
17941
  const [formData, setFormData] = useState(normalizeNameDobData(data));
17881
17942
  const updateFormData = updatedData => {
17882
- updatedData = Object.fromEntries(Object.entries(updatedData).filter(([_, value]) => value !== ''));
17883
- setFormData(updatedData);
17884
- handleChange(path, updatedData);
17943
+ const nextData = Object.fromEntries(Object.entries(updatedData).filter(([_, value]) => value !== ''));
17944
+ setFormData(nextData);
17945
+ handleChange(path, nextData);
17885
17946
  };
17886
17947
  useEffect(() => {
17887
17948
  const nextData = normalizeNameDobData(data);
@@ -17899,14 +17960,13 @@ const FullNameDobControl = props => {
17899
17960
  const err = Object.assign({}, errors);
17900
17961
  const liveInputValue = (_ref = (_ref2 = (_updatedData$name = updatedData == null ? void 0 : updatedData[name]) != null ? _updatedData$name : data == null ? void 0 : data[name]) != null ? _ref2 : (_document$querySelect = document.querySelector(`goa-input[name="${name}"]`)) == null ? void 0 : _document$querySelect.value) != null ? _ref : '';
17901
17962
  if (requiredFields.includes(name) && liveInputValue.trim() === '') {
17902
- const modifiedName = name === 'firstName' ? 'First name' : name === 'lastName' ? 'Last name' : name === 'dateOfBirth' ? 'Date of birth' : name;
17903
- err[name] = `${modifiedName} is required`;
17963
+ err[name] = `${getRequiredLabel(name)} is required`;
17904
17964
  } else {
17905
17965
  delete err[name];
17906
17966
  }
17907
17967
  setErrors(err);
17908
17968
  };
17909
- useSyncAutofillFields(['firstName', 'middleName', 'lastName', 'dateOfBirth'], formData, updateFormData, handleRequiredFieldBlur);
17969
+ useSyncAutofillFields(AUTOFILL_FIELDS, formData, updateFormData, handleRequiredFieldBlur);
17910
17970
  useEffect(() => {
17911
17971
  var _controlRef$current$q, _controlRef$current, _host$shadowRoot;
17912
17972
  const host = (_controlRef$current$q = (_controlRef$current = controlRef.current) == null ? void 0 : _controlRef$current.querySelector('goa-input[type="date"]')) != null ? _controlRef$current$q : null;
@@ -17947,64 +18007,16 @@ const FullNameDobControl = props => {
17947
18007
  visible: visible,
17948
18008
  children: jsxs("div", {
17949
18009
  ref: controlRef,
17950
- children: [jsxs(GoabGrid, {
17951
- minChildWidth: "0ch",
17952
- gap: "s",
17953
- mb: "m",
17954
- children: [jsx(GoabFormItem, {
17955
- label: "First name",
17956
- requirement: schema != null && (_schema$required = schema.required) != null && _schema$required.includes('firstName') ? 'required' : undefined,
17957
- error: (_errors$firstName = errors == null ? void 0 : errors['firstName']) != null ? _errors$firstName : '',
17958
- testId: "form-item-first-name",
17959
- children: jsx(GoabInput, {
17960
- disabled: !enabled,
17961
- type: "text",
17962
- name: "firstName",
17963
- testId: "name-form-first-name",
17964
- ariaLabel: 'name-form-first-name',
17965
- value: formData.firstName,
17966
- onChange: detail => {
17967
- handleInputChange(detail.name, detail.value);
17968
- },
17969
- onBlur: detail => {
17970
- handleRequiredFieldBlur(detail.name);
17971
- },
17972
- width: "100%"
17973
- })
17974
- }), jsx(GoabFormItem, {
17975
- label: "Middle name",
17976
- requirement: schema != null && (_schema$required2 = schema.required) != null && _schema$required2.includes('middleName') ? 'required' : undefined,
17977
- children: jsx(GoabInput, {
17978
- type: "text",
17979
- name: "middleName",
17980
- disabled: !enabled,
17981
- testId: "name-form-middle-name",
17982
- ariaLabel: 'name-form-middle-name',
17983
- value: formData.middleName || '',
17984
- onChange: detail => handleInputChange(detail.name, detail.value),
17985
- width: "100%"
17986
- })
17987
- }), jsx(GoabFormItem, {
17988
- label: "Last name",
17989
- requirement: schema != null && (_schema$required3 = schema.required) != null && _schema$required3.includes('lastName') ? 'required' : undefined,
17990
- error: (_errors$lastName = errors == null ? void 0 : errors['lastName']) != null ? _errors$lastName : '',
17991
- testId: "form-item-last-name",
17992
- children: jsx(GoabInput, {
17993
- type: "text",
17994
- name: "lastName",
17995
- disabled: !enabled,
17996
- testId: "name-form-last-name",
17997
- ariaLabel: 'name-form-last-name',
17998
- value: formData.lastName || '',
17999
- onChange: detail => {
18000
- handleInputChange(detail.name, detail.value);
18001
- },
18002
- onBlur: detail => {
18003
- handleRequiredFieldBlur(detail.name);
18004
- },
18005
- width: "100%"
18006
- })
18007
- })]
18010
+ children: [jsx(NameInputs, {
18011
+ firstName: formData.firstName,
18012
+ middleName: formData.middleName,
18013
+ lastName: formData.lastName,
18014
+ handleInputChange: handleInputChange,
18015
+ data: formData,
18016
+ disabled: !enabled,
18017
+ requiredFields: requiredFields,
18018
+ errors: errors,
18019
+ onFieldBlur: handleRequiredFieldBlur
18008
18020
  }), jsx(GoabGrid, {
18009
18021
  minChildWidth: "0ch",
18010
18022
  gap: "s",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abgov/jsonforms-components",
3
- "version": "2.60.16",
3
+ "version": "2.60.18",
4
4
  "license": "Apache-2.0",
5
5
  "description": "Government of Alberta - React renderers for JSON Forms based on the design system.",
6
6
  "repository": "https://github.com/GovAlta/adsp-monorepo",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "schemaVersion": "1.0.0",
3
- "generatedAt": "2026-04-27T20:33:20.640Z",
4
- "sourceCommit": "39950b0288e24ea3e4d895bf4bbe2b79c542625f",
3
+ "generatedAt": "2026-04-30T19:54:34.313Z",
4
+ "sourceCommit": "4b89cb1336839f443d768c9688ad888bab4924e3",
5
5
  "sourcePath": "libs/jsonforms-components/src/index.ts",
6
6
  "rendererCount": 33,
7
7
  "renderers": [
@@ -5,8 +5,10 @@ interface NameInputsProps {
5
5
  lastName: string;
6
6
  isStepperReview?: boolean;
7
7
  disabled?: boolean;
8
- data: any;
9
- requiredFields: string[];
8
+ data?: any;
9
+ requiredFields?: string[];
10
+ errors?: Record<string, string>;
11
+ onFieldBlur?: (name: string) => void;
10
12
  handleInputChange: (field: string, value: string) => void;
11
13
  }
12
14
  export declare const NameInputs: React.FC<NameInputsProps>;
@@ -32,6 +32,7 @@ export declare const isNilOrEmptyString: (value: string | null | undefined) => b
32
32
  */
33
33
  export declare const isNilOrEmptyValue: (value: unknown, includeEmptyArray?: boolean) => boolean;
34
34
  export declare const validateSinWithLuhn: (input: number) => boolean;
35
+ export declare const getSinValidationError: (data: unknown, schema?: JsonSchema) => string | undefined;
35
36
  /**
36
37
  * Gets the required fields in the If/Then/Else json schema condition.
37
38
  * @param props - ControlProps