@bpmn-io/form-js-viewer 1.7.0-alpha.0 → 1.7.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/dist/index.es.js CHANGED
@@ -1569,7 +1569,8 @@ function useCleanupMultiSelectValue(props) {
1569
1569
 
1570
1570
  function Description(props) {
1571
1571
  const {
1572
- description
1572
+ description,
1573
+ id
1573
1574
  } = props;
1574
1575
  const evaluatedDescription = useSingleLineTemplateEvaluation(description || '', {
1575
1576
  debug: true
@@ -1578,6 +1579,7 @@ function Description(props) {
1578
1579
  return null;
1579
1580
  }
1580
1581
  return jsx("div", {
1582
+ id: id,
1581
1583
  class: "fjs-form-field-description",
1582
1584
  children: evaluatedDescription
1583
1585
  });
@@ -1608,6 +1610,7 @@ function Errors(props) {
1608
1610
  function Label(props) {
1609
1611
  const {
1610
1612
  id,
1613
+ htmlFor,
1611
1614
  label,
1612
1615
  collapseOnEmpty = true,
1613
1616
  required = false
@@ -1616,12 +1619,14 @@ function Label(props) {
1616
1619
  debug: true
1617
1620
  });
1618
1621
  return jsxs("label", {
1619
- for: id,
1622
+ id: id,
1623
+ for: htmlFor,
1620
1624
  class: classNames('fjs-form-field-label', {
1621
1625
  'fjs-incollapsible-label': !collapseOnEmpty
1622
1626
  }, props['class']),
1623
1627
  children: [props.children, evaluatedLabel, required && jsx("span", {
1624
1628
  class: "fjs-asterix",
1629
+ "aria-hidden": true,
1625
1630
  children: "*"
1626
1631
  })]
1627
1632
  });
@@ -1632,7 +1637,6 @@ function Checkbox(props) {
1632
1637
  const {
1633
1638
  disabled,
1634
1639
  errors = [],
1635
- errorMessageId,
1636
1640
  domId,
1637
1641
  onBlur,
1638
1642
  onFocus,
@@ -1656,6 +1660,8 @@ function Checkbox(props) {
1656
1660
  value: target.checked
1657
1661
  });
1658
1662
  };
1663
+ const descriptionId = `${domId}-description`;
1664
+ const errorMessageId = `${domId}-error-message`;
1659
1665
  return jsxs("div", {
1660
1666
  class: classNames(formFieldClasses(type$f, {
1661
1667
  errors,
@@ -1665,7 +1671,7 @@ function Checkbox(props) {
1665
1671
  'fjs-checked': value
1666
1672
  }),
1667
1673
  children: [jsx(Label, {
1668
- id: domId,
1674
+ htmlFor: domId,
1669
1675
  label: label,
1670
1676
  required: required,
1671
1677
  children: jsx("input", {
@@ -1678,13 +1684,16 @@ function Checkbox(props) {
1678
1684
  onChange: onChange,
1679
1685
  onBlur: () => onBlur && onBlur(),
1680
1686
  onFocus: () => onFocus && onFocus(),
1681
- "aria-describedby": errorMessageId
1687
+ required: required,
1688
+ "aria-invalid": errors.length > 0,
1689
+ "aria-describedby": [descriptionId, errorMessageId].join(' ')
1682
1690
  })
1683
1691
  }), jsx(Description, {
1692
+ id: descriptionId,
1684
1693
  description: description
1685
1694
  }), jsx(Errors, {
1686
- errors: errors,
1687
- id: errorMessageId
1695
+ id: errorMessageId,
1696
+ errors: errors
1688
1697
  })]
1689
1698
  });
1690
1699
  }
@@ -1707,7 +1716,6 @@ function Checklist(props) {
1707
1716
  const {
1708
1717
  disabled,
1709
1718
  errors = [],
1710
- errorMessageId,
1711
1719
  domId,
1712
1720
  onBlur,
1713
1721
  onFocus,
@@ -1754,6 +1762,8 @@ function Checklist(props) {
1754
1762
  values,
1755
1763
  onChange: props.onChange
1756
1764
  });
1765
+ const descriptionId = `${domId}-description`;
1766
+ const errorMessageId = `${domId}-error-message`;
1757
1767
  return jsxs("div", {
1758
1768
  class: classNames(formFieldClasses(type$e, {
1759
1769
  errors,
@@ -1768,7 +1778,7 @@ function Checklist(props) {
1768
1778
  const itemDomId = `${domId}-${index}`;
1769
1779
  const isChecked = hasEqualValue(o.value, values);
1770
1780
  return jsx(Label, {
1771
- id: itemDomId,
1781
+ htmlFor: itemDomId,
1772
1782
  label: o.label,
1773
1783
  class: classNames({
1774
1784
  'fjs-checked': isChecked
@@ -1784,14 +1794,17 @@ function Checklist(props) {
1784
1794
  onClick: () => toggleCheckbox(o.value),
1785
1795
  onBlur: onCheckboxBlur,
1786
1796
  onFocus: onCheckboxFocus,
1787
- "aria-describedby": errorMessageId
1797
+ required: required,
1798
+ "aria-invalid": errors.length > 0,
1799
+ "aria-describedby": [descriptionId, errorMessageId].join(' ')
1788
1800
  })
1789
1801
  });
1790
1802
  }), jsx(Description, {
1803
+ id: descriptionId,
1791
1804
  description: description
1792
1805
  }), jsx(Errors, {
1793
- errors: errors,
1794
- id: errorMessageId
1806
+ id: errorMessageId,
1807
+ errors: errors
1795
1808
  })]
1796
1809
  });
1797
1810
  }
@@ -1831,6 +1844,10 @@ function FormField(props) {
1831
1844
  const {
1832
1845
  formId
1833
1846
  } = useContext(FormContext);
1847
+
1848
+ // track whether we should trigger initial validation on certain actions, e.g. field blur
1849
+ // disabled straight away, if viewerCommands are not available
1850
+ const [initialValidationTrigger, setInitialValidationTrigger] = useState(!!viewerCommands);
1834
1851
  const FormFieldComponent = formFields.get(field.type);
1835
1852
  if (!FormFieldComponent) {
1836
1853
  throw new Error(`cannot render field <${field.type}>`);
@@ -1844,26 +1861,48 @@ function FormField(props) {
1844
1861
 
1845
1862
  // add precedence: global readonly > form field disabled
1846
1863
  const disabled = !properties.readOnly && (properties.disabled || field.disabled || false);
1864
+
1865
+ // ensures the initial validation behavior can be re-triggered upon form reset
1866
+ useEffect(() => {
1867
+ if (!viewerCommands) {
1868
+ return;
1869
+ }
1870
+ const resetValidation = () => {
1871
+ setInitialValidationTrigger(true);
1872
+ };
1873
+ eventBus.on('import.done', resetValidation);
1874
+ eventBus.on('reset', resetValidation);
1875
+ return () => {
1876
+ eventBus.off('import.done', resetValidation);
1877
+ eventBus.off('reset', resetValidation);
1878
+ };
1879
+ }, [eventBus, viewerCommands]);
1880
+ useEffect(() => {
1881
+ if (initialValidationTrigger && initialValue) {
1882
+ setInitialValidationTrigger(false);
1883
+ viewerCommands.updateFieldValidation(field, initialValue, indexes);
1884
+ }
1885
+ }, [viewerCommands, field, initialValue, initialValidationTrigger, indexes]);
1847
1886
  const onBlur = useCallback(() => {
1848
- if (viewerCommands) {
1887
+ const value = get(data, valuePath);
1888
+ if (initialValidationTrigger) {
1889
+ setInitialValidationTrigger(false);
1849
1890
  viewerCommands.updateFieldValidation(field, value, indexes);
1850
1891
  }
1851
1892
  eventBus.fire('formField.blur', {
1852
1893
  formField: field
1853
1894
  });
1854
- }, [eventBus, viewerCommands, field, value, indexes]);
1895
+ }, [eventBus, field, indexes, viewerCommands, initialValidationTrigger, data, valuePath]);
1855
1896
  const onFocus = useCallback(() => {
1856
1897
  eventBus.fire('formField.focus', {
1857
1898
  formField: field
1858
1899
  });
1859
1900
  }, [eventBus, field]);
1860
- useEffect(() => {
1861
- if (viewerCommands && initialValue) {
1862
- viewerCommands.updateFieldValidation(field, initialValue, indexes);
1863
- }
1864
- }, [viewerCommands, field, initialValue, indexes]);
1865
1901
  const hidden = useCondition(field.conditional && field.conditional.hide || null);
1866
1902
  const onChangeIndexed = useCallback(update => {
1903
+ // any data change will trigger validation
1904
+ setInitialValidationTrigger(false);
1905
+
1867
1906
  // add indexes of the keyed field to the update, if any
1868
1907
  onChange(FormFieldComponent.config.keyed ? {
1869
1908
  ...update,
@@ -1877,7 +1916,6 @@ function FormField(props) {
1877
1916
  }
1878
1917
  const domId = `${prefixId(field.id, formId, indexes)}`;
1879
1918
  const fieldErrors = get(errors, [field.id, ...Object.values(indexes || {})]) || [];
1880
- const errorMessageId = errors.length === 0 ? undefined : `${domId}-error-message`;
1881
1919
  return jsx(Column, {
1882
1920
  field: field,
1883
1921
  class: gridColumnClasses(field),
@@ -1888,7 +1926,6 @@ function FormField(props) {
1888
1926
  ...props,
1889
1927
  disabled: disabled,
1890
1928
  errors: fieldErrors,
1891
- errorMessageId: errorMessageId,
1892
1929
  domId: domId,
1893
1930
  onChange: disabled || readonly ? noop$1 : onChangeIndexed,
1894
1931
  onBlur: disabled || readonly ? noop$1 : onBlur,
@@ -2291,7 +2328,7 @@ function Datepicker(props) {
2291
2328
  return jsxs("div", {
2292
2329
  class: "fjs-datetime-subsection",
2293
2330
  children: [jsx(Label, {
2294
- id: domId,
2331
+ htmlFor: domId,
2295
2332
  label: label,
2296
2333
  collapseOnEmpty: collapseLabelOnEmpty,
2297
2334
  required: required
@@ -2563,7 +2600,7 @@ function Timepicker(props) {
2563
2600
  return jsxs("div", {
2564
2601
  class: "fjs-datetime-subsection",
2565
2602
  children: [jsx(Label, {
2566
- id: domId,
2603
+ htmlFor: domId,
2567
2604
  label: label,
2568
2605
  collapseOnEmpty: collapseLabelOnEmpty,
2569
2606
  required: required
@@ -2750,6 +2787,7 @@ function Datetime(props) {
2750
2787
  });
2751
2788
  }, []);
2752
2789
  const errorMessageId = allErrors.length === 0 ? undefined : `${prefixId(id, formId)}-error-message`;
2790
+ const descriptionId = `${prefixId(id, formId)}-description`;
2753
2791
  const datePickerProps = {
2754
2792
  label: dateLabel,
2755
2793
  collapseLabelOnEmpty: !timeLabel,
@@ -2762,7 +2800,7 @@ function Datetime(props) {
2762
2800
  date: dateTime.date,
2763
2801
  readonly,
2764
2802
  setDate,
2765
- 'aria-describedby': errorMessageId
2803
+ 'aria-describedby': [descriptionId, errorMessageId].join(' ')
2766
2804
  };
2767
2805
  const timePickerProps = {
2768
2806
  label: timeLabel,
@@ -2777,7 +2815,7 @@ function Datetime(props) {
2777
2815
  timeInterval,
2778
2816
  time: dateTime.time,
2779
2817
  setTime,
2780
- 'aria-describedby': errorMessageId
2818
+ 'aria-describedby': [descriptionId, errorMessageId].join(' ')
2781
2819
  };
2782
2820
  return jsxs("div", {
2783
2821
  class: formFieldClasses(type$d, {
@@ -2796,6 +2834,7 @@ function Datetime(props) {
2796
2834
  ...timePickerProps
2797
2835
  })]
2798
2836
  }), jsx(Description, {
2837
+ id: descriptionId,
2799
2838
  description: description
2800
2839
  }), jsx(Errors, {
2801
2840
  errors: allErrors,
@@ -2899,7 +2938,7 @@ function IFrame(props) {
2899
2938
  readonly
2900
2939
  }),
2901
2940
  children: [jsx(Label, {
2902
- id: domId,
2941
+ htmlFor: domId,
2903
2942
  label: evaluatedLabel
2904
2943
  }), !evaluatedUrl && jsx(IFramePlaceholder, {
2905
2944
  text: "No content to show."
@@ -3445,7 +3484,6 @@ function Numberfield(props) {
3445
3484
  const {
3446
3485
  disabled,
3447
3486
  errors = [],
3448
- errorMessageId,
3449
3487
  domId,
3450
3488
  onBlur,
3451
3489
  onFocus,
@@ -3583,6 +3621,8 @@ function Numberfield(props) {
3583
3621
  e.preventDefault();
3584
3622
  }
3585
3623
  };
3624
+ const descriptionId = `${domId}-description`;
3625
+ const errorMessageId = `${domId}-error-message`;
3586
3626
  return jsxs("div", {
3587
3627
  class: formFieldClasses(type$a, {
3588
3628
  errors,
@@ -3590,7 +3630,7 @@ function Numberfield(props) {
3590
3630
  readonly
3591
3631
  }),
3592
3632
  children: [jsx(Label, {
3593
- id: domId,
3633
+ htmlFor: domId,
3594
3634
  label: label,
3595
3635
  required: required
3596
3636
  }), jsx(TemplatedInputAdorner, {
@@ -3624,7 +3664,9 @@ function Numberfield(props) {
3624
3664
  autoComplete: "off",
3625
3665
  step: incrementAmount,
3626
3666
  value: displayValue,
3627
- "aria-describedby": errorMessageId
3667
+ "aria-describedby": [descriptionId, errorMessageId].join(' '),
3668
+ required: required,
3669
+ "aria-invalid": errors.length > 0
3628
3670
  }), jsxs("div", {
3629
3671
  class: classNames('fjs-number-arrow-container', {
3630
3672
  'fjs-disabled': disabled,
@@ -3650,10 +3692,11 @@ function Numberfield(props) {
3650
3692
  })]
3651
3693
  })
3652
3694
  }), jsx(Description, {
3695
+ id: descriptionId,
3653
3696
  description: description
3654
3697
  }), jsx(Errors, {
3655
- errors: errors,
3656
- id: errorMessageId
3698
+ id: errorMessageId,
3699
+ errors: errors
3657
3700
  })]
3658
3701
  });
3659
3702
  }
@@ -3683,7 +3726,6 @@ function Radio(props) {
3683
3726
  const {
3684
3727
  disabled,
3685
3728
  errors = [],
3686
- errorMessageId,
3687
3729
  domId,
3688
3730
  onBlur,
3689
3731
  onFocus,
@@ -3729,6 +3771,8 @@ function Radio(props) {
3729
3771
  value,
3730
3772
  onChange: props.onChange
3731
3773
  });
3774
+ const descriptionId = `${domId}-description`;
3775
+ const errorMessageId = `${domId}-error-message`;
3732
3776
  return jsxs("div", {
3733
3777
  class: formFieldClasses(type$9, {
3734
3778
  errors,
@@ -3743,7 +3787,7 @@ function Radio(props) {
3743
3787
  const itemDomId = `${domId}-${index}`;
3744
3788
  const isChecked = isEqual(option.value, value);
3745
3789
  return jsx(Label, {
3746
- id: itemDomId,
3790
+ htmlFor: itemDomId,
3747
3791
  label: option.label,
3748
3792
  class: classNames({
3749
3793
  'fjs-checked': isChecked
@@ -3759,14 +3803,17 @@ function Radio(props) {
3759
3803
  onClick: () => onChange(option.value),
3760
3804
  onBlur: onRadioBlur,
3761
3805
  onFocus: onRadioFocus,
3762
- "aria-describedby": errorMessageId
3806
+ "aria-describedby": [descriptionId, errorMessageId].join(' '),
3807
+ required: required,
3808
+ "aria-invalid": errors.length > 0
3763
3809
  })
3764
3810
  }, index);
3765
3811
  }), jsx(Description, {
3812
+ id: descriptionId,
3766
3813
  description: description
3767
3814
  }), jsx(Errors, {
3768
- errors: errors,
3769
- id: errorMessageId
3815
+ id: errorMessageId,
3816
+ errors: errors
3770
3817
  })]
3771
3818
  });
3772
3819
  }
@@ -3831,7 +3878,7 @@ function SearchableSelect(props) {
3831
3878
 
3832
3879
  // whenever we change the underlying value, set the label to it
3833
3880
  useEffect(() => {
3834
- setFilter(label);
3881
+ setFilter(label || '');
3835
3882
  }, [label]);
3836
3883
  const filteredOptions = useMemo(() => {
3837
3884
  if (loadState !== LOAD_STATES.LOADED) {
@@ -3911,7 +3958,7 @@ function SearchableSelect(props) {
3911
3958
  }, [onFocus]);
3912
3959
  const onInputBlur = useCallback(() => {
3913
3960
  setIsDropdownExpanded(false);
3914
- setFilter(label);
3961
+ setFilter(label || '');
3915
3962
  onBlur && onBlur();
3916
3963
  }, [onBlur, label]);
3917
3964
  return jsxs(Fragment, {
@@ -4007,6 +4054,9 @@ function SimpleSelect(props) {
4007
4054
  }, [disabled, isDropdownExpanded, loadState, readonly, value]);
4008
4055
  const onMouseDown = useCallback(e => {
4009
4056
  const input = inputRef.current;
4057
+ if (disabled || !input) {
4058
+ return;
4059
+ }
4010
4060
  setIsDropdownExpanded(!isDropdownExpanded);
4011
4061
  if (isDropdownExpanded) {
4012
4062
  input.blur();
@@ -4014,7 +4064,7 @@ function SimpleSelect(props) {
4014
4064
  input.focus();
4015
4065
  }
4016
4066
  e.preventDefault();
4017
- }, [isDropdownExpanded]);
4067
+ }, [disabled, isDropdownExpanded]);
4018
4068
  const initialFocusIndex = useMemo(() => value && findIndex(options, o => o.value === value) || 0, [options, value]);
4019
4069
  const onInputFocus = useCallback(() => {
4020
4070
  if (!readonly) {
@@ -4086,7 +4136,6 @@ function Select(props) {
4086
4136
  const {
4087
4137
  disabled,
4088
4138
  errors = [],
4089
- errorMessageId,
4090
4139
  domId,
4091
4140
  onBlur,
4092
4141
  onFocus,
@@ -4104,6 +4153,8 @@ function Select(props) {
4104
4153
  const {
4105
4154
  required
4106
4155
  } = validate;
4156
+ const descriptionId = `${domId}-description`;
4157
+ const errorMessageId = `${domId}-error-message`;
4107
4158
  const selectProps = {
4108
4159
  domId,
4109
4160
  disabled,
@@ -4114,7 +4165,9 @@ function Select(props) {
4114
4165
  value,
4115
4166
  onChange,
4116
4167
  readonly,
4117
- 'aria-describedby': errorMessageId
4168
+ required,
4169
+ 'aria-invalid': errors.length > 0,
4170
+ 'aria-describedby': [descriptionId, errorMessageId].join(' ')
4118
4171
  };
4119
4172
  return jsxs("div", {
4120
4173
  class: formFieldClasses(type$8, {
@@ -4129,7 +4182,7 @@ function Select(props) {
4129
4182
  }
4130
4183
  },
4131
4184
  children: [jsx(Label, {
4132
- id: domId,
4185
+ htmlFor: domId,
4133
4186
  label: label,
4134
4187
  required: required
4135
4188
  }), searchable ? jsx(SearchableSelect, {
@@ -4137,10 +4190,11 @@ function Select(props) {
4137
4190
  }) : jsx(SimpleSelect, {
4138
4191
  ...selectProps
4139
4192
  }), jsx(Description, {
4193
+ id: descriptionId,
4140
4194
  description: description
4141
4195
  }), jsx(Errors, {
4142
- errors: errors,
4143
- id: errorMessageId
4196
+ id: errorMessageId,
4197
+ errors: errors
4144
4198
  })]
4145
4199
  });
4146
4200
  }
@@ -4273,7 +4327,6 @@ function Taglist(props) {
4273
4327
  const {
4274
4328
  disabled,
4275
4329
  errors = [],
4276
- errorMessageId,
4277
4330
  onFocus,
4278
4331
  domId,
4279
4332
  onBlur,
@@ -4409,6 +4462,8 @@ function Taglist(props) {
4409
4462
  inputRef.current.focus();
4410
4463
  };
4411
4464
  const shouldDisplayDropdown = useMemo(() => !disabled && loadState === LOAD_STATES.LOADED && isDropdownExpanded && !isEscapeClosed, [disabled, isDropdownExpanded, isEscapeClosed, loadState]);
4465
+ const descriptionId = `${domId}-description`;
4466
+ const errorMessageId = `${domId}-error-message`;
4412
4467
  return jsxs("div", {
4413
4468
  ref: focusScopeRef,
4414
4469
  class: formFieldClasses(type$5, {
@@ -4425,7 +4480,7 @@ function Taglist(props) {
4425
4480
  children: [jsx(Label, {
4426
4481
  label: label,
4427
4482
  required: required,
4428
- id: domId
4483
+ htmlFor: domId
4429
4484
  }), !disabled && !readonly && !!values.length && jsx(SkipLink, {
4430
4485
  className: "fjs-taglist-skip-link",
4431
4486
  label: "Skip to search",
@@ -4473,7 +4528,9 @@ function Taglist(props) {
4473
4528
  onMouseDown: () => setIsEscapeClose(false),
4474
4529
  onFocus: onInputFocus,
4475
4530
  onBlur: onInputBlur,
4476
- "aria-describedby": errorMessageId
4531
+ "aria-describedby": [descriptionId, errorMessageId].join(' '),
4532
+ required: required,
4533
+ "aria-invalid": errors.length > 0
4477
4534
  })]
4478
4535
  }), jsx("div", {
4479
4536
  class: "fjs-taglist-anchor",
@@ -4485,10 +4542,11 @@ function Taglist(props) {
4485
4542
  listenerElement: inputRef.current
4486
4543
  })
4487
4544
  }), jsx(Description, {
4545
+ id: descriptionId,
4488
4546
  description: description
4489
4547
  }), jsx(Errors, {
4490
- errors: errors,
4491
- id: errorMessageId
4548
+ id: errorMessageId,
4549
+ errors: errors
4492
4550
  })]
4493
4551
  });
4494
4552
  }
@@ -4805,7 +4863,6 @@ function Textfield(props) {
4805
4863
  const {
4806
4864
  disabled,
4807
4865
  errors = [],
4808
- errorMessageId,
4809
4866
  domId,
4810
4867
  onBlur,
4811
4868
  onFocus,
@@ -4841,6 +4898,8 @@ function Textfield(props) {
4841
4898
  const onInputFocus = () => {
4842
4899
  onFocus && onFocus();
4843
4900
  };
4901
+ const descriptionId = `${domId}-description`;
4902
+ const errorMessageId = `${domId}-error-message`;
4844
4903
  return jsxs("div", {
4845
4904
  class: formFieldClasses(type$2, {
4846
4905
  errors,
@@ -4848,7 +4907,7 @@ function Textfield(props) {
4848
4907
  readonly
4849
4908
  }),
4850
4909
  children: [jsx(Label, {
4851
- id: domId,
4910
+ htmlFor: domId,
4852
4911
  label: label,
4853
4912
  required: required
4854
4913
  }), jsx(TemplatedInputAdorner, {
@@ -4866,13 +4925,16 @@ function Textfield(props) {
4866
4925
  onFocus: onInputFocus,
4867
4926
  type: "text",
4868
4927
  value: value,
4869
- "aria-describedby": errorMessageId
4928
+ "aria-describedby": [descriptionId, errorMessageId].join(' '),
4929
+ required: required,
4930
+ "aria-invalid": errors.length > 0
4870
4931
  })
4871
4932
  }), jsx(Description, {
4933
+ id: descriptionId,
4872
4934
  description: description
4873
4935
  }), jsx(Errors, {
4874
- errors: errors,
4875
- id: errorMessageId
4936
+ id: errorMessageId,
4937
+ errors: errors
4876
4938
  })]
4877
4939
  });
4878
4940
  }
@@ -4905,7 +4967,6 @@ function Textarea(props) {
4905
4967
  const {
4906
4968
  disabled,
4907
4969
  errors = [],
4908
- errorMessageId,
4909
4970
  domId,
4910
4971
  onBlur,
4911
4972
  onFocus,
@@ -4922,7 +4983,7 @@ function Textarea(props) {
4922
4983
  required
4923
4984
  } = validate;
4924
4985
  const textareaRef = useRef();
4925
- const [onInputChange, flushOnChange] = useFlushDebounce(({
4986
+ const [onChange, flushOnChange] = useFlushDebounce(({
4926
4987
  target
4927
4988
  }) => {
4928
4989
  props.onChange({
@@ -4937,12 +4998,20 @@ function Textarea(props) {
4937
4998
  const onInputFocus = () => {
4938
4999
  onFocus && onFocus();
4939
5000
  };
5001
+ const onInputChange = event => {
5002
+ onChange({
5003
+ target: event.target
5004
+ });
5005
+ autoSizeTextarea(textareaRef.current);
5006
+ };
4940
5007
  useLayoutEffect(() => {
4941
5008
  autoSizeTextarea(textareaRef.current);
4942
5009
  }, [value]);
4943
5010
  useEffect(() => {
4944
5011
  autoSizeTextarea(textareaRef.current);
4945
5012
  }, []);
5013
+ const descriptionId = `${domId}-description`;
5014
+ const errorMessageId = `${domId}-error-message`;
4946
5015
  return jsxs("div", {
4947
5016
  class: formFieldClasses(type$1, {
4948
5017
  errors,
@@ -4950,7 +5019,7 @@ function Textarea(props) {
4950
5019
  readonly
4951
5020
  }),
4952
5021
  children: [jsx(Label, {
4953
- id: domId,
5022
+ htmlFor: domId,
4954
5023
  label: label,
4955
5024
  required: required
4956
5025
  }), jsx("textarea", {
@@ -4963,12 +5032,15 @@ function Textarea(props) {
4963
5032
  onFocus: onInputFocus,
4964
5033
  value: value,
4965
5034
  ref: textareaRef,
4966
- "aria-describedby": errorMessageId
5035
+ "aria-describedby": [descriptionId, errorMessageId].join(' '),
5036
+ required: required,
5037
+ "aria-invalid": errors.length > 0
4967
5038
  }), jsx(Description, {
5039
+ id: descriptionId,
4968
5040
  description: description
4969
5041
  }), jsx(Errors, {
4970
- errors: errors,
4971
- id: errorMessageId
5042
+ id: errorMessageId,
5043
+ errors: errors
4972
5044
  })]
4973
5045
  });
4974
5046
  }
@@ -5137,7 +5209,7 @@ function Table(props) {
5137
5209
  return jsxs("div", {
5138
5210
  class: formFieldClasses(type),
5139
5211
  children: [jsx(Label, {
5140
- id: prefixId(id),
5212
+ htmlFor: prefixId(id),
5141
5213
  label: label
5142
5214
  }), jsxs("div", {
5143
5215
  class: classNames('fjs-table-middle-container', {
@@ -5537,7 +5609,7 @@ class FormFields {
5537
5609
  }
5538
5610
 
5539
5611
  const EXPRESSION_PROPERTIES = ['alt', 'appearance.prefixAdorner', 'appearance.suffixAdorner', 'conditional.hide', 'description', 'label', 'source', 'readonly', 'text', 'validate.min', 'validate.max', 'validate.minLength', 'validate.maxLength', 'valuesExpression', 'url', 'dataSource', 'columnsExpression'];
5540
- const TEMPLATE_PROPERTIES = ['alt', 'appearance.prefixAdorner', 'appearance.suffixAdorner', 'description', 'label', 'source', 'text', 'url'];
5612
+ const TEMPLATE_PROPERTIES = ['alt', 'appearance.prefixAdorner', 'appearance.suffixAdorner', 'description', 'label', 'source', 'text', 'content', 'url'];
5541
5613
 
5542
5614
  /**
5543
5615
  * @typedef { import('../types').Schema } Schema
@@ -6523,47 +6595,17 @@ class RepeatRenderManager {
6523
6595
  };
6524
6596
  const parentExpressionContextInfo = useContext(LocalExpressionContext);
6525
6597
  return jsx(Fragment, {
6526
- children: displayValues.map((value, index) => {
6527
- const elementProps = useMemo(() => ({
6528
- ...restProps,
6529
- indexes: {
6530
- ...(indexes || {}),
6531
- [repeaterField.id]: index
6532
- }
6533
- }), [index]);
6534
- const localExpressionContextInfo = useMemo(() => ({
6535
- data: parentExpressionContextInfo.data,
6536
- this: value,
6537
- parent: buildExpressionContext(parentExpressionContextInfo),
6538
- i: [...parentExpressionContextInfo.i, index + 1]
6539
- }), [index, value]);
6540
- return !showRemove ? jsx(LocalExpressionContext.Provider, {
6541
- value: localExpressionContextInfo,
6542
- children: jsx(RowsRenderer, {
6543
- ...elementProps
6544
- })
6545
- }) : jsxs("div", {
6546
- class: "fjs-repeat-row-container",
6547
- children: [jsx("div", {
6548
- class: "fjs-repeat-row-rows",
6549
- children: jsx(LocalExpressionContext.Provider, {
6550
- value: localExpressionContextInfo,
6551
- children: jsx(RowsRenderer, {
6552
- ...elementProps
6553
- })
6554
- })
6555
- }), jsx("button", {
6556
- class: "fjs-repeat-row-remove",
6557
- type: "button",
6558
- "aria-label": `Remove list item ${index + 1}`,
6559
- onClick: () => onDeleteItem(index),
6560
- children: jsx("div", {
6561
- class: "fjs-repeat-row-remove-icon-container",
6562
- children: jsx(DeleteSvg, {})
6563
- })
6564
- })]
6565
- });
6566
- })
6598
+ children: displayValues.map((value, index) => jsx(RepetitionScaffold, {
6599
+ index: index,
6600
+ value: value,
6601
+ parentExpressionContextInfo: parentExpressionContextInfo,
6602
+ repeaterField: repeaterField,
6603
+ RowsRenderer: RowsRenderer,
6604
+ indexes: indexes,
6605
+ onDeleteItem: onDeleteItem,
6606
+ showRemove: showRemove,
6607
+ ...restProps
6608
+ }, index))
6567
6609
  });
6568
6610
  }
6569
6611
  RepeatFooter(props) {
@@ -6655,6 +6697,73 @@ class RepeatRenderManager {
6655
6697
  return nonCollapsedItems ? nonCollapsedItems : DEFAULT_NON_COLLAPSED_ITEMS;
6656
6698
  }
6657
6699
  }
6700
+
6701
+ /**
6702
+ * Individual repetition of a repeated field and context scaffolding.
6703
+ *
6704
+ * @param {Object} props
6705
+ * @param {number} props.index
6706
+ * @param {Object} props.value
6707
+ * @param {Object} props.parentExpressionContextInfo
6708
+ * @param {Object} props.repeaterField
6709
+ * @param {Function} props.RowsRenderer
6710
+ * @param {Object} props.indexes
6711
+ * @param {Function} props.onDeleteItem
6712
+ * @param {boolean} props.showRemove
6713
+ */
6714
+
6715
+ const RepetitionScaffold = props => {
6716
+ const {
6717
+ index,
6718
+ value,
6719
+ parentExpressionContextInfo,
6720
+ repeaterField,
6721
+ RowsRenderer,
6722
+ indexes,
6723
+ onDeleteItem,
6724
+ showRemove,
6725
+ ...restProps
6726
+ } = props;
6727
+ const elementProps = useMemo(() => ({
6728
+ ...restProps,
6729
+ indexes: {
6730
+ ...(indexes || {}),
6731
+ [repeaterField.id]: index
6732
+ }
6733
+ }), [index, indexes, repeaterField.id, restProps]);
6734
+ const localExpressionContextInfo = useMemo(() => ({
6735
+ data: parentExpressionContextInfo.data,
6736
+ this: value,
6737
+ parent: buildExpressionContext(parentExpressionContextInfo),
6738
+ i: [...parentExpressionContextInfo.i, index + 1]
6739
+ }), [index, parentExpressionContextInfo, value]);
6740
+ return !showRemove ? jsx(LocalExpressionContext.Provider, {
6741
+ value: localExpressionContextInfo,
6742
+ children: jsx(RowsRenderer, {
6743
+ ...elementProps
6744
+ })
6745
+ }) : jsxs("div", {
6746
+ class: "fjs-repeat-row-container",
6747
+ children: [jsx("div", {
6748
+ class: "fjs-repeat-row-rows",
6749
+ children: jsx(LocalExpressionContext.Provider, {
6750
+ value: localExpressionContextInfo,
6751
+ children: jsx(RowsRenderer, {
6752
+ ...elementProps
6753
+ })
6754
+ })
6755
+ }), jsx("button", {
6756
+ class: "fjs-repeat-row-remove",
6757
+ type: "button",
6758
+ "aria-label": `Remove list item ${index + 1}`,
6759
+ onClick: () => onDeleteItem(index),
6760
+ children: jsx("div", {
6761
+ class: "fjs-repeat-row-remove-icon-container",
6762
+ children: jsx(DeleteSvg, {})
6763
+ })
6764
+ })]
6765
+ });
6766
+ };
6658
6767
  RepeatRenderManager.$inject = ['form', 'formFields', 'formFieldRegistry', 'pathRegistry'];
6659
6768
 
6660
6769
  const RepeatRenderModule = {
@@ -8092,10 +8201,10 @@ class Form {
8092
8201
  }
8093
8202
  }
8094
8203
  clear() {
8095
- // clear form services
8204
+ // clear diagram services (e.g. EventBus)
8096
8205
  this._emit('diagram.clear');
8097
8206
 
8098
- // clear diagram services (e.g. EventBus)
8207
+ // clear form services
8099
8208
  this._emit('form.clear');
8100
8209
  }
8101
8210