@abgov/jsonforms-components 2.75.3 → 2.76.1

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
@@ -5003,6 +5003,11 @@ const checkFieldValidity = (props, rootData) => {
5003
5003
  if (isRegisterBackedEnum) {
5004
5004
  return '';
5005
5005
  }
5006
+ const isSinField = resolveFormatConfig(schema) === DEFAULT_PATTERNS.sin;
5007
+ const hasSinFormat = isSinField && typeof data === 'string' && DEFAULT_PATTERNS.sin.pattern.test(data);
5008
+ if (hasSinFormat && !validateSinWithLuhn(data)) {
5009
+ return invalidSin;
5010
+ }
5006
5011
  if (!ajvErrors || ajvErrors === invalidSin) {
5007
5012
  return ajvErrors;
5008
5013
  }
@@ -10066,14 +10071,26 @@ const resetInputValue = (detail, value) => {
10066
10071
  target.value = value;
10067
10072
  }
10068
10073
  };
10074
+ const resolveTextMaskOptions = (schema, uischema) => {
10075
+ var _formatConfig$mask, _uischema$options, _uischema$options2;
10076
+ const formatConfig = resolveFormatConfig(schema);
10077
+ const mask = (_formatConfig$mask = formatConfig == null ? void 0 : formatConfig.mask) != null ? _formatConfig$mask : uischema == null || (_uischema$options = uischema.options) == null ? void 0 : _uischema$options.mask;
10078
+ // In-place shows the fill-in template and keeps the caret in place while editing.
10079
+ const inPlace = !!mask && (uischema == null || (_uischema$options2 = uischema.options) == null ? void 0 : _uischema$options2.inPlace) === true;
10080
+ return {
10081
+ formatConfig,
10082
+ mask,
10083
+ inPlace
10084
+ };
10085
+ };
10069
10086
  const GoAInputText = props => {
10070
- return jsxs(JsonFormRegisterProvider, {
10087
+ return jsx(JsonFormRegisterProvider, {
10071
10088
  defaultRegisters: undefined,
10072
- children: [jsx(InnerGoAInputText, Object.assign({}, props)), ' ']
10089
+ children: jsx(InnerGoAInputText, Object.assign({}, props))
10073
10090
  });
10074
10091
  };
10075
10092
  const InnerGoAInputText = props => {
10076
- var _formatConfig$mask, _uischema$options, _uischema$options2, _uischema$options$com, _uischema$options3, _props$uischema, _uischema$options4, _uischema$options5, _uischema$options$pla, _uischema$options6, _props$uischema2, _uischema$options7, _uischema$options8, _uischema$options$com2, _uischema$options9, _uischema$options0, _uischema$options1, _uischema$options10;
10093
+ var _uischema$options$com, _uischema$options3, _props$uischema, _uischema$options4, _uischema$options5, _uischema$options$pla, _uischema$options6, _props$uischema2, _uischema$options7, _uischema$options8, _uischema$options$com2, _uischema$options9, _uischema$options0, _uischema$options1, _uischema$options10;
10077
10094
  const {
10078
10095
  data,
10079
10096
  config,
@@ -10089,11 +10106,12 @@ const InnerGoAInputText = props => {
10089
10106
  setIsVisited
10090
10107
  } = props;
10091
10108
  // Detect the mask format from the JSON schema `format` (with the SIN title kept for backward compatibility).
10092
- const formatConfig = resolveFormatConfig(schema);
10093
- const mask = (_formatConfig$mask = formatConfig == null ? void 0 : formatConfig.mask) != null ? _formatConfig$mask : uischema == null || (_uischema$options = uischema.options) == null ? void 0 : _uischema$options.mask;
10109
+ const {
10110
+ formatConfig,
10111
+ mask,
10112
+ inPlace
10113
+ } = resolveTextMaskOptions(schema, uischema);
10094
10114
  const allowedKeys = formatConfig == null ? void 0 : formatConfig.allowedKeys;
10095
- // In-place shows the fill-in template and keeps the caret in place while editing.
10096
- const inPlace = !!mask && (uischema == null || (_uischema$options2 = uischema.options) == null ? void 0 : _uischema$options2.inPlace) === true;
10097
10115
  const toDisplay = value => {
10098
10116
  if (!mask) {
10099
10117
  return value;
@@ -10114,11 +10132,15 @@ const InnerGoAInputText = props => {
10114
10132
  const hasDefault = Object.prototype.hasOwnProperty.call(schema, 'default');
10115
10133
  useEffect(() => {
10116
10134
  if (data === undefined || data === null) {
10135
+ if (!mask) {
10136
+ return;
10137
+ }
10138
+ setLocalValue(toDisplay(''));
10117
10139
  return;
10118
10140
  }
10119
10141
  setLocalValue(toDisplay(data));
10120
10142
  // eslint-disable-next-line react-hooks/exhaustive-deps
10121
- }, [data, mask]);
10143
+ }, [data, mask, inPlace]);
10122
10144
  useEffect(() => {
10123
10145
  if (typeof handleChange === 'function' && hasDefault && data === undefined && !manualInput) {
10124
10146
  handleChange(props.path, schema.default);
@@ -10280,7 +10302,7 @@ const InnerGoAInputText = props => {
10280
10302
  }
10281
10303
  }
10282
10304
  }
10283
- }, uischema == null || (_uischema$options10 = uischema.options) == null ? void 0 : _uischema$options10.componentProps))
10305
+ }, uischema == null || (_uischema$options10 = uischema.options) == null ? void 0 : _uischema$options10.componentProps), `${mask != null ? mask : ''}:${inPlace}`)
10284
10306
  });
10285
10307
  };
10286
10308
  const GoATextControl = props => jsx(GoAInputBaseControl, Object.assign({}, props, {
@@ -13908,11 +13930,9 @@ const useMaskedInput = ({
13908
13930
  // In-place mounts empty then sets the template so the web component reflects it (a value change forces the paint).
13909
13931
  const [value, setValue] = useState(inPlace ? '' : initialDisplay);
13910
13932
  useEffect(() => {
13911
- if (inPlace) {
13912
- setValue(initialDisplay);
13913
- }
13933
+ setValue(format(typeof data === 'string' ? data : ''));
13914
13934
  // eslint-disable-next-line react-hooks/exhaustive-deps
13915
- }, []);
13935
+ }, [mask, inPlace]);
13916
13936
  const handleChange = detail => {
13917
13937
  var _target$selectionStar;
13918
13938
  const rawValue = detail.value;
@@ -14014,7 +14034,7 @@ const PhoneNumberControl = props => {
14014
14034
  onChange: detail => handleMaskChange(detail),
14015
14035
  onKeyPress: detail => handleKeyPress(detail),
14016
14036
  width: "100%"
14017
- })
14037
+ }, `${phoneMask}:${inPlace}`)
14018
14038
  })
14019
14039
  });
14020
14040
  };
@@ -20640,6 +20660,26 @@ var GoAErrorControl = withJsonFormsControlProps(ErrorControl);
20640
20660
 
20641
20661
  // Allow empty values so incomplete fields are not treated as format errors.
20642
20662
  const optionalFormat = pattern => input => !input || pattern.test(input);
20663
+ // format: sin still rejects a bad checksum so the field is invalid; the UI maps this
20664
+ // to "Social insurance number is invalid" once the pattern already matches.
20665
+ const optionalSinFormat = input => {
20666
+ if (!input) {
20667
+ return true;
20668
+ }
20669
+ if (!DEFAULT_PATTERNS.sin.pattern.test(input)) {
20670
+ return false;
20671
+ }
20672
+ return validateSinWithLuhn(input);
20673
+ };
20674
+ const isValidSinWhenComplete = data => {
20675
+ if (typeof data !== 'string' || data.length === 0) {
20676
+ return true;
20677
+ }
20678
+ if (!DEFAULT_PATTERNS.sin.pattern.test(data)) {
20679
+ return true;
20680
+ }
20681
+ return validateSinWithLuhn(data);
20682
+ };
20643
20683
  const createDefaultAjv = (...schemas) => {
20644
20684
  const ajv = new Ajv({
20645
20685
  allErrors: true,
@@ -20654,7 +20694,7 @@ const createDefaultAjv = (...schemas) => {
20654
20694
  addFormats(ajv);
20655
20695
  ajv.addFormat('time', /^([01]\d|2[0-3]):[0-5]\d(:[0-5]\d)?$/);
20656
20696
  Object.entries(DEFAULT_PATTERNS).forEach(([format, config]) => {
20657
- ajv.addFormat(format, optionalFormat(config.pattern));
20697
+ ajv.addFormat(format, format === 'sin' ? optionalSinFormat : optionalFormat(config.pattern));
20658
20698
  });
20659
20699
  ajv.addFormat('phone', PHONE_REGEX);
20660
20700
  ajv.addFormat('computed', /^[a-zA-Z0-9._-]+$/);
@@ -20676,14 +20716,10 @@ const createDefaultAjv = (...schemas) => {
20676
20716
  type: 'string',
20677
20717
  schemaType: 'boolean',
20678
20718
  validate: (shouldValidate, data) => {
20679
- if (!shouldValidate) return true;
20680
- if (typeof data !== 'string' || data.length === 0) {
20681
- return true;
20682
- }
20683
- if (!/^\d{3} \d{3} \d{3}$/.test(data)) {
20719
+ if (shouldValidate === false) {
20684
20720
  return true;
20685
20721
  }
20686
- return validateSinWithLuhn(data);
20722
+ return isValidSinWhenComplete(data);
20687
20723
  },
20688
20724
  error: {
20689
20725
  message: invalidSin
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abgov/jsonforms-components",
3
- "version": "2.75.3",
3
+ "version": "2.76.1",
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-09-10T20:48:43.882Z",
4
- "sourceCommit": "5a1d458e5df0177e45371e7770719fd29fb0b773",
3
+ "generatedAt": "2026-09-14T21:52:08.453Z",
4
+ "sourceCommit": "b562ac4773b80256cc170680e106826f7696b070",
5
5
  "sourcePath": "libs/jsonforms-components/src/index.ts",
6
6
  "rendererCount": 33,
7
7
  "renderers": [