@abgov/jsonforms-components 2.71.0 → 2.71.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
@@ -7767,10 +7767,14 @@ const stepperReducer = (state, action) => {
7767
7767
  // (page/next, page/prev, or setVisited previously marked it visited).
7768
7768
  // Preserve any previously-tracked isVisited=true so navigation history
7769
7769
  // isn't lost whenever unrelated form data changes trigger this recompute.
7770
+ // isNavigatedAway is tracked here and never recomputed, so the merge is the only thing
7771
+ // carrying it across a recompute. Seeding it from the recomputed state instead would let
7772
+ // data presence mark a step navigated, which is the whole thing it exists to avoid.
7770
7773
  const mergedCategories = newState.categories.map(newCategory => {
7771
7774
  const previousCategory = categories.find(c => c.id === newCategory.id);
7772
7775
  return Object.assign({}, newCategory, {
7773
- isVisited: (previousCategory == null ? void 0 : previousCategory.isVisited) || newCategory.isVisited
7776
+ isVisited: (previousCategory == null ? void 0 : previousCategory.isVisited) || newCategory.isVisited,
7777
+ isNavigatedAway: (previousCategory == null ? void 0 : previousCategory.isNavigatedAway) === true
7774
7778
  });
7775
7779
  });
7776
7780
  return Object.assign({}, newState, {
@@ -7781,7 +7785,8 @@ const stepperReducer = (state, action) => {
7781
7785
  {
7782
7786
  const newActive = activeId + 1;
7783
7787
  const newCategories = categories.map((c, idx) => idx === activeId ? Object.assign({}, c, {
7784
- isVisited: true
7788
+ isVisited: true,
7789
+ isNavigatedAway: true
7785
7790
  }) : c);
7786
7791
  const isOnReview = newActive === lastId + 1;
7787
7792
  return Object.assign({}, state, {
@@ -7797,7 +7802,8 @@ const stepperReducer = (state, action) => {
7797
7802
  {
7798
7803
  const newActive = Math.max(0, activeId - 1);
7799
7804
  const newCategories = categories.map((c, idx) => idx === activeId ? Object.assign({}, c, {
7800
- isVisited: true
7805
+ isVisited: true,
7806
+ isNavigatedAway: true
7801
7807
  }) : c);
7802
7808
  return Object.assign({}, state, {
7803
7809
  activeId: newActive,
@@ -7868,7 +7874,8 @@ const stepperReducer = (state, action) => {
7868
7874
  id
7869
7875
  } = action.payload;
7870
7876
  const newCategories = state.categories.map(cat => cat.id === id ? Object.assign({}, cat, {
7871
- isVisited: true
7877
+ isVisited: true,
7878
+ isNavigatedAway: true
7872
7879
  }) : cat);
7873
7880
  return Object.assign({}, state, {
7874
7881
  categories: newCategories
@@ -8546,6 +8553,10 @@ const createStepperContextInitData = (props, options) => {
8546
8553
  isCompleted: status === StepStatus.COMPLETED || visited && !hasRequiredFields,
8547
8554
  isValid: status === StepStatus.COMPLETED || visited && !hasRequiredFields,
8548
8555
  isVisited: [StepStatus.COMPLETED, StepStatus.IN_PROGRESS].includes(status),
8556
+ // Navigation is tracked by the reducer, which merges this value forward on every recompute.
8557
+ // It starts false so a freshly opened form shows no validation messages until the user has
8558
+ // actually worked through a step; deriving it here from data would defeat the point.
8559
+ isNavigatedAway: false,
8549
8560
  status,
8550
8561
  uischema: c,
8551
8562
  isEnabled: isEnabled(c, data, '', ajv, undefined),
@@ -8895,7 +8906,7 @@ const GoAInputBaseControl = props => {
8895
8906
  id: isStepperReview === true ? `review-base-${path}-element-wrapper` : `${path}-element-wrapper`,
8896
8907
  children: jsx(GoabFormItem, {
8897
8908
  requirement: (_uischema$options$com = uischema == null || (_uischema$options = uischema.options) == null || (_uischema$options = _uischema$options.componentProps) == null ? void 0 : _uischema$options.requirement) != null ? _uischema$options$com : requiredNow ? 'required' : undefined,
8898
- error: (currentCategory == null ? void 0 : currentCategory.isVisited) === true || isVisited || hasValue ? modifiedErrors : undefined,
8909
+ error: (currentCategory == null ? void 0 : currentCategory.isNavigatedAway) === true || isVisited || hasValue ? modifiedErrors : undefined,
8899
8910
  testId: isStepperReview === true ? `review-base-${path}` : path,
8900
8911
  label: getFormItemLabel(labelToUpdate, props == null ? void 0 : props.noLabel),
8901
8912
  helpText: typeof (uischema == null || (_uischema$options2 = uischema.options) == null ? void 0 : _uischema$options2.help) === 'string' && !isStepperReview ? uischema == null || (_uischema$options3 = uischema.options) == null ? void 0 : _uischema$options3.help : '',
@@ -10017,7 +10028,9 @@ const EnumSelect = props => {
10017
10028
  options,
10018
10029
  uischema,
10019
10030
  schema,
10020
- errors
10031
+ errors,
10032
+ isVisited,
10033
+ setIsVisited
10021
10034
  } = props;
10022
10035
  const registerCtx = useContext(JsonFormsRegisterContext);
10023
10036
  const registerConfig = fetchRegisterConfigFromOptions((_props$uischema = props.uischema) == null || (_props$uischema = _props$uischema.options) == null ? void 0 : _props$uischema.register);
@@ -10075,6 +10088,12 @@ const EnumSelect = props => {
10075
10088
  id: `jsonforms-${path}-dropdown`,
10076
10089
  filterable: autoCompletion,
10077
10090
  onChange: detail => {
10091
+ // goa-dropdown exposes no blur event, so a selection is the only interaction available
10092
+ // to mark visited on. This is what surfaces the error when the user picks the empty
10093
+ // placeholder on a required control, which leaves no value to fall back on.
10094
+ if (isVisited === false && setIsVisited) {
10095
+ setIsVisited();
10096
+ }
10078
10097
  if (expectsObjectValue(schema)) {
10079
10098
  handleChange(path, registerData.find(o => {
10080
10099
  return ___default.get(o, valuePath) === detail.value;
@@ -10121,6 +10140,7 @@ const RadioGroup = props => {
10121
10140
  config,
10122
10141
  label,
10123
10142
  isVisited,
10143
+ setIsVisited,
10124
10144
  errors
10125
10145
  } = props;
10126
10146
  const oneOF = (schema == null ? void 0 : schema.oneOf) || [];
@@ -10146,7 +10166,15 @@ const RadioGroup = props => {
10146
10166
  value: data,
10147
10167
  disabled: !enabled
10148
10168
  }, appliedUiSchemaOptions, {
10149
- onChange: detail => handleChange(path, detail.value)
10169
+ onChange: detail => {
10170
+ // goa-radio-group exposes no blur event, so selecting an option is the only interaction we
10171
+ // can mark visited on. Without this the group never reports its own error state, and on a
10172
+ // non stepper form a required control the user cleared would stay silent.
10173
+ if (isVisited === false && setIsVisited) {
10174
+ setIsVisited();
10175
+ }
10176
+ handleChange(path, detail.value);
10177
+ }
10150
10178
  }, uischema == null || (_uischema$options = uischema.options) == null ? void 0 : _uischema$options.componentProps, {
10151
10179
  children: items.map((item, index) => jsx(GoabRadioItem$1, {
10152
10180
  name: item.value,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abgov/jsonforms-components",
3
- "version": "2.71.0",
3
+ "version": "2.71.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-08-04T16:45:42.802Z",
4
- "sourceCommit": "a30b2d185c20480fc9d22daa6bcd39656cb4085e",
3
+ "generatedAt": "2026-08-07T16:31:58.685Z",
4
+ "sourceCommit": "ba35318b425d06f6d8b272e81da892659e240d0e",
5
5
  "sourcePath": "libs/jsonforms-components/src/index.ts",
6
6
  "rendererCount": 33,
7
7
  "renderers": [
@@ -3,6 +3,7 @@ import { StepStatusType } from '../../../common/Constants';
3
3
  export interface CategoryInternalState {
4
4
  isCompleted?: boolean;
5
5
  isVisited?: boolean;
6
+ isNavigatedAway?: boolean;
6
7
  isValid?: boolean;
7
8
  showReviewPageLink?: boolean;
8
9
  id: number;