@bpmn-io/form-js-viewer 0.15.0-alpha.0 → 1.0.0-alpha.0

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.cjs CHANGED
@@ -1342,7 +1342,7 @@ function createFormContainer(prefix = 'fjs') {
1342
1342
  return container;
1343
1343
  }
1344
1344
 
1345
- const EXPRESSION_PROPERTIES = ['alt', 'source', 'text'];
1345
+ const EXPRESSION_PROPERTIES = ['alt', 'source', 'readonly', 'text'];
1346
1346
  const TEMPLATE_PROPERTIES = ['text'];
1347
1347
  function findErrors(errors, path) {
1348
1348
  return errors[pathStringify(path)];
@@ -1590,14 +1590,16 @@ var importModule = {
1590
1590
 
1591
1591
  function formFieldClasses(type, {
1592
1592
  errors = [],
1593
- disabled = false
1593
+ disabled = false,
1594
+ readonly = false
1594
1595
  } = {}) {
1595
1596
  if (!type) {
1596
1597
  throw new Error('type required');
1597
1598
  }
1598
1599
  return classNames('fjs-form-field', `fjs-form-field-${type}`, {
1599
1600
  'fjs-has-errors': errors.length > 0,
1600
- 'fjs-disabled': disabled
1601
+ 'fjs-disabled': disabled,
1602
+ 'fjs-readonly': readonly
1601
1603
  });
1602
1604
  }
1603
1605
  function gridColumnClasses(formField) {
@@ -1755,6 +1757,7 @@ function Checkbox(props) {
1755
1757
  disabled,
1756
1758
  errors = [],
1757
1759
  field,
1760
+ readonly,
1758
1761
  value = false
1759
1762
  } = props;
1760
1763
  const {
@@ -1781,7 +1784,8 @@ function Checkbox(props) {
1781
1784
  return jsxRuntime.jsxs("div", {
1782
1785
  class: classNames(formFieldClasses(type$a, {
1783
1786
  errors,
1784
- disabled
1787
+ disabled,
1788
+ readonly
1785
1789
  }), {
1786
1790
  'fjs-checked': value
1787
1791
  }),
@@ -1793,6 +1797,7 @@ function Checkbox(props) {
1793
1797
  checked: value,
1794
1798
  class: "fjs-input",
1795
1799
  disabled: disabled,
1800
+ readOnly: readonly,
1796
1801
  id: prefixId(id, formId),
1797
1802
  type: "checkbox",
1798
1803
  onChange: onChange,
@@ -2154,6 +2159,7 @@ function Checklist(props) {
2154
2159
  disabled,
2155
2160
  errors = [],
2156
2161
  field,
2162
+ readonly,
2157
2163
  value = []
2158
2164
  } = props;
2159
2165
  const {
@@ -2188,7 +2194,8 @@ function Checklist(props) {
2188
2194
  return jsxRuntime.jsxs("div", {
2189
2195
  class: classNames(formFieldClasses(type$9, {
2190
2196
  errors,
2191
- disabled
2197
+ disabled,
2198
+ readonly
2192
2199
  })),
2193
2200
  children: [jsxRuntime.jsx(Label, {
2194
2201
  label: label,
@@ -2205,6 +2212,7 @@ function Checklist(props) {
2205
2212
  checked: value.includes(v.value),
2206
2213
  class: "fjs-input",
2207
2214
  disabled: disabled,
2215
+ readOnly: readonly,
2208
2216
  id: prefixId(`${id}-${index}`, formId),
2209
2217
  type: "checkbox",
2210
2218
  onClick: () => toggleCheckbox(v.value),
@@ -2313,6 +2321,33 @@ function useKeyDownAction(targetKey, action, listenerElement = window) {
2313
2321
  });
2314
2322
  }
2315
2323
 
2324
+ /**
2325
+ * Retrieve readonly value of a form field, given it can be an
2326
+ * expression optionally or configured globally.
2327
+ *
2328
+ * @typedef { import('../../types').FormProperties } FormProperties
2329
+ *
2330
+ * @param {any} formField
2331
+ * @param {FormProperties} properties
2332
+ *
2333
+ * @returns {boolean}
2334
+ */
2335
+ function useReadonly(formField, properties = {}) {
2336
+ const expressionLanguage = useService('expressionLanguage');
2337
+ const conditionChecker = useService('conditionChecker', false);
2338
+ const filteredData = useFilteredFormData();
2339
+ const {
2340
+ readonly
2341
+ } = formField;
2342
+ if (properties.readOnly) {
2343
+ return true;
2344
+ }
2345
+ if (expressionLanguage && expressionLanguage.isExpression(readonly)) {
2346
+ return conditionChecker ? conditionChecker.check(readonly, filteredData) : false;
2347
+ }
2348
+ return readonly || false;
2349
+ }
2350
+
2316
2351
  /**
2317
2352
  * Template a string reactively based on form data. If the string is not a template, it is returned as is.
2318
2353
  * Memoised to minimize re-renders
@@ -2359,7 +2394,10 @@ function FormField(props) {
2359
2394
  }
2360
2395
  const value = minDash.get(data, field._path);
2361
2396
  const fieldErrors = findErrors(errors, field._path);
2362
- const disabled = properties.readOnly || field.disabled || false;
2397
+ const readonly = useReadonly(field, properties);
2398
+
2399
+ // add precedence: global readonly > form field disabled
2400
+ const disabled = !properties.readOnly && (properties.disabled || field.disabled || false);
2363
2401
  const hidden = useCondition(field.conditional && field.conditional.hide || null);
2364
2402
  if (hidden) {
2365
2403
  return jsxRuntime.jsx(Empty, {});
@@ -2374,7 +2412,8 @@ function FormField(props) {
2374
2412
  ...props,
2375
2413
  disabled: disabled,
2376
2414
  errors: fieldErrors,
2377
- onChange: disabled ? noop$1 : onChange,
2415
+ onChange: disabled || readonly ? noop$1 : onChange,
2416
+ readonly: readonly,
2378
2417
  value: value
2379
2418
  })
2380
2419
  })
@@ -2461,12 +2500,14 @@ function InputAdorner(props) {
2461
2500
  inputRef,
2462
2501
  children,
2463
2502
  disabled,
2503
+ readonly,
2464
2504
  hasErrors
2465
2505
  } = props;
2466
2506
  const onAdornmentClick = () => inputRef && inputRef.current && inputRef.current.focus();
2467
2507
  return jsxRuntime.jsxs("div", {
2468
2508
  class: classNames('fjs-input-group', {
2469
- 'fjs-disabled': disabled
2509
+ 'fjs-disabled': disabled,
2510
+ 'fjs-readonly': readonly
2470
2511
  }, {
2471
2512
  'hasErrors': hasErrors
2472
2513
  }),
@@ -2499,6 +2540,7 @@ function Datepicker(props) {
2499
2540
  disabled,
2500
2541
  disallowPassedDates,
2501
2542
  date,
2543
+ readonly,
2502
2544
  setDate
2503
2545
  } = props;
2504
2546
  const dateInputRef = hooks.useRef();
@@ -2578,9 +2620,9 @@ function Datepicker(props) {
2578
2620
  }
2579
2621
  }, [flatpickrInstance, isInputDirty]);
2580
2622
  const onInputFocus = hooks.useCallback(e => {
2581
- if (!flatpickrInstance || focusScopeRef.current.contains(e.relatedTarget)) return;
2623
+ if (!flatpickrInstance || focusScopeRef.current.contains(e.relatedTarget) || readonly) return;
2582
2624
  flatpickrInstance.open();
2583
- }, [flatpickrInstance]);
2625
+ }, [flatpickrInstance, readonly]);
2584
2626
 
2585
2627
  // simulate an enter press on blur to make sure the date value is submitted in all scenarios
2586
2628
  const onInputBlur = hooks.useCallback(e => {
@@ -2599,6 +2641,7 @@ function Datepicker(props) {
2599
2641
  }), jsxRuntime.jsx(InputAdorner, {
2600
2642
  pre: jsxRuntime.jsx(CalendarIcon, {}),
2601
2643
  disabled: disabled,
2644
+ readonly: readonly,
2602
2645
  rootRef: focusScopeRef,
2603
2646
  inputRef: dateInputRef,
2604
2647
  children: jsxRuntime.jsx("div", {
@@ -2612,11 +2655,12 @@ function Datepicker(props) {
2612
2655
  id: fullId,
2613
2656
  class: "fjs-input",
2614
2657
  disabled: disabled,
2658
+ readOnly: readonly,
2615
2659
  placeholder: "mm/dd/yyyy",
2616
2660
  autoComplete: "off",
2617
2661
  onFocus: onInputFocus,
2618
2662
  onKeyDown: onInputKeyDown,
2619
- onMouseDown: () => !flatpickrInstance.isOpen && flatpickrInstance.open(),
2663
+ onMouseDown: () => !flatpickrInstance.isOpen && !readonly && flatpickrInstance.open(),
2620
2664
  onBlur: onInputBlur,
2621
2665
  onInput: () => setIsInputDirty(true),
2622
2666
  "data-input": true,
@@ -2750,6 +2794,7 @@ function Timepicker(props) {
2750
2794
  formId,
2751
2795
  required,
2752
2796
  disabled,
2797
+ readonly,
2753
2798
  use24h = false,
2754
2799
  timeInterval,
2755
2800
  time,
@@ -2855,6 +2900,7 @@ function Timepicker(props) {
2855
2900
  pre: jsxRuntime.jsx(ClockIcon, {}),
2856
2901
  inputRef: timeInputRef,
2857
2902
  disabled: disabled,
2903
+ readonly: readonly,
2858
2904
  children: jsxRuntime.jsxs("div", {
2859
2905
  class: "fjs-timepicker fjs-timepicker-anchor",
2860
2906
  children: [jsxRuntime.jsx("input", {
@@ -2864,10 +2910,11 @@ function Timepicker(props) {
2864
2910
  class: "fjs-input",
2865
2911
  value: rawValue,
2866
2912
  disabled: disabled,
2913
+ readOnly: readonly,
2867
2914
  placeholder: use24h ? 'hh:mm' : 'hh:mm ?m',
2868
2915
  autoComplete: "off",
2869
- onFocus: () => useDropdown && setDropdownIsOpen(true),
2870
- onClick: () => useDropdown && setDropdownIsOpen(true)
2916
+ onFocus: () => !readonly && useDropdown && setDropdownIsOpen(true),
2917
+ onClick: () => !readonly && useDropdown && setDropdownIsOpen(true)
2871
2918
 
2872
2919
  // @ts-ignore
2873
2920
  ,
@@ -2898,6 +2945,7 @@ function Datetime(props) {
2898
2945
  errors = [],
2899
2946
  field,
2900
2947
  onChange,
2948
+ readonly,
2901
2949
  value = ''
2902
2950
  } = props;
2903
2951
  const {
@@ -3024,6 +3072,7 @@ function Datetime(props) {
3024
3072
  disabled,
3025
3073
  disallowPassedDates,
3026
3074
  date: dateTime.date,
3075
+ readonly,
3027
3076
  setDate,
3028
3077
  'aria-describedby': errorMessageId
3029
3078
  };
@@ -3034,6 +3083,7 @@ function Datetime(props) {
3034
3083
  formId,
3035
3084
  required,
3036
3085
  disabled,
3086
+ readonly,
3037
3087
  use24h,
3038
3088
  timeInterval,
3039
3089
  time: dateTime.time,
@@ -3043,7 +3093,8 @@ function Datetime(props) {
3043
3093
  return jsxRuntime.jsxs("div", {
3044
3094
  class: formFieldClasses(type$8, {
3045
3095
  errors: allErrors,
3046
- disabled
3096
+ disabled,
3097
+ readonly
3047
3098
  }),
3048
3099
  children: [jsxRuntime.jsxs("div", {
3049
3100
  class: classNames('fjs-vertical-group'),
@@ -3447,6 +3498,7 @@ function Numberfield(props) {
3447
3498
  errors = [],
3448
3499
  field,
3449
3500
  value,
3501
+ readonly,
3450
3502
  onChange
3451
3503
  } = props;
3452
3504
  const {
@@ -3519,6 +3571,9 @@ function Numberfield(props) {
3519
3571
  });
3520
3572
  }, [field, onChange, serializeToString]);
3521
3573
  const increment = () => {
3574
+ if (readonly) {
3575
+ return;
3576
+ }
3522
3577
  const base = isValidNumber(value) ? Big(value) : Big(0);
3523
3578
  const stepFlooredValue = base.minus(base.mod(arrowIncrementValue));
3524
3579
 
@@ -3526,6 +3581,9 @@ function Numberfield(props) {
3526
3581
  setValue(stepFlooredValue.plus(arrowIncrementValue).toFixed());
3527
3582
  };
3528
3583
  const decrement = () => {
3584
+ if (readonly) {
3585
+ return;
3586
+ }
3529
3587
  const base = isValidNumber(value) ? Big(value) : Big(0);
3530
3588
  const offset = base.mod(arrowIncrementValue);
3531
3589
  if (offset.cmp(0) === 0) {
@@ -3572,7 +3630,8 @@ function Numberfield(props) {
3572
3630
  return jsxRuntime.jsxs("div", {
3573
3631
  class: formFieldClasses(type$6, {
3574
3632
  errors,
3575
- disabled
3633
+ disabled,
3634
+ readonly
3576
3635
  }),
3577
3636
  children: [jsxRuntime.jsx(Label, {
3578
3637
  id: prefixId(id, formId),
@@ -3580,11 +3639,13 @@ function Numberfield(props) {
3580
3639
  required: required
3581
3640
  }), jsxRuntime.jsx(InputAdorner, {
3582
3641
  disabled: disabled,
3642
+ readonly: readonly,
3583
3643
  pre: prefixAdorner,
3584
3644
  post: suffixAdorner,
3585
3645
  children: jsxRuntime.jsxs("div", {
3586
3646
  class: classNames('fjs-vertical-group', {
3587
- 'fjs-disabled': disabled
3647
+ 'fjs-disabled': disabled,
3648
+ 'fjs-readonly': readonly
3588
3649
  }, {
3589
3650
  'hasErrors': errors.length
3590
3651
  }),
@@ -3592,6 +3653,7 @@ function Numberfield(props) {
3592
3653
  ref: inputRef,
3593
3654
  class: "fjs-input",
3594
3655
  disabled: disabled,
3656
+ readOnly: readonly,
3595
3657
  id: prefixId(id, formId),
3596
3658
  onKeyDown: onKeyDown,
3597
3659
  onKeyPress: onKeyPress
@@ -3606,7 +3668,8 @@ function Numberfield(props) {
3606
3668
  "aria-describedby": errorMessageId
3607
3669
  }), jsxRuntime.jsxs("div", {
3608
3670
  class: classNames('fjs-number-arrow-container', {
3609
- 'fjs-disabled': disabled
3671
+ 'fjs-disabled': disabled,
3672
+ 'fjs-readonly': readonly
3610
3673
  }),
3611
3674
  children: [jsxRuntime.jsx("button", {
3612
3675
  class: "fjs-number-arrow-up",
@@ -3665,6 +3728,7 @@ function Radio(props) {
3665
3728
  disabled,
3666
3729
  errors = [],
3667
3730
  field,
3731
+ readonly,
3668
3732
  value
3669
3733
  } = props;
3670
3734
  const {
@@ -3693,7 +3757,8 @@ function Radio(props) {
3693
3757
  return jsxRuntime.jsxs("div", {
3694
3758
  class: formFieldClasses(type$5, {
3695
3759
  errors,
3696
- disabled
3760
+ disabled,
3761
+ readonly
3697
3762
  }),
3698
3763
  children: [jsxRuntime.jsx(Label, {
3699
3764
  label: label,
@@ -3710,6 +3775,7 @@ function Radio(props) {
3710
3775
  checked: option.value === value,
3711
3776
  class: "fjs-input",
3712
3777
  disabled: disabled,
3778
+ readOnly: readonly,
3713
3779
  id: prefixId(`${id}-${index}`, formId),
3714
3780
  type: "radio",
3715
3781
  onClick: () => onChange(option.value),
@@ -3771,6 +3837,7 @@ function SearchableSelect(props) {
3771
3837
  disabled,
3772
3838
  errors,
3773
3839
  field,
3840
+ readonly,
3774
3841
  value
3775
3842
  } = props;
3776
3843
  const {
@@ -3843,11 +3910,11 @@ function SearchableSelect(props) {
3843
3910
  }, [isDropdownExpanded, isEscapeClosed]);
3844
3911
  const displayState = hooks.useMemo(() => {
3845
3912
  const ds = {};
3846
- ds.componentReady = !disabled && loadState === LOAD_STATES.LOADED;
3913
+ ds.componentReady = !disabled && !readonly && loadState === LOAD_STATES.LOADED;
3847
3914
  ds.displayCross = ds.componentReady && value !== null && value !== undefined;
3848
- ds.displayDropdown = !disabled && isDropdownExpanded && !isEscapeClosed;
3915
+ ds.displayDropdown = !disabled && !readonly && isDropdownExpanded && !isEscapeClosed;
3849
3916
  return ds;
3850
- }, [disabled, isDropdownExpanded, isEscapeClosed, loadState, value]);
3917
+ }, [disabled, isDropdownExpanded, isEscapeClosed, loadState, readonly, value]);
3851
3918
  const onAngelMouseDown = hooks.useCallback(e => {
3852
3919
  setIsEscapeClose(false);
3853
3920
  setIsDropdownExpanded(!isDropdownExpanded);
@@ -3859,12 +3926,14 @@ function SearchableSelect(props) {
3859
3926
  children: [jsxRuntime.jsxs("div", {
3860
3927
  id: prefixId(`${id}`, formId),
3861
3928
  class: classNames('fjs-input-group', {
3862
- 'disabled': disabled
3929
+ 'disabled': disabled,
3930
+ 'readonly': readonly
3863
3931
  }, {
3864
3932
  'hasErrors': errors.length
3865
3933
  }),
3866
3934
  children: [jsxRuntime.jsx("input", {
3867
3935
  disabled: disabled,
3936
+ readOnly: readonly,
3868
3937
  class: "fjs-input",
3869
3938
  ref: searchbarRef,
3870
3939
  id: prefixId(`${id}-search`, formId),
@@ -3921,6 +3990,7 @@ function SimpleSelect(props) {
3921
3990
  disabled,
3922
3991
  errors,
3923
3992
  field,
3993
+ readonly,
3924
3994
  value
3925
3995
  } = props;
3926
3996
  const {
@@ -3946,9 +4016,9 @@ function SimpleSelect(props) {
3946
4016
  }, [field, props]);
3947
4017
  const displayState = hooks.useMemo(() => {
3948
4018
  const ds = {};
3949
- ds.componentReady = !disabled && loadState === LOAD_STATES.LOADED;
4019
+ ds.componentReady = !disabled && !readonly && loadState === LOAD_STATES.LOADED;
3950
4020
  ds.displayCross = ds.componentReady && value !== null && value !== undefined;
3951
- ds.displayDropdown = !disabled && isDropdownExpanded;
4021
+ ds.displayDropdown = !disabled && !readonly && isDropdownExpanded;
3952
4022
  return ds;
3953
4023
  }, [disabled, isDropdownExpanded, loadState, value]);
3954
4024
  const onMouseDown = hooks.useCallback(e => {
@@ -3967,7 +4037,8 @@ function SimpleSelect(props) {
3967
4037
  ref: selectRef,
3968
4038
  id: prefixId(`${id}`, formId),
3969
4039
  class: classNames('fjs-input-group', {
3970
- 'disabled': disabled
4040
+ disabled,
4041
+ readonly
3971
4042
  }, {
3972
4043
  'hasErrors': errors.length
3973
4044
  }),
@@ -3984,8 +4055,8 @@ function SimpleSelect(props) {
3984
4055
  id: prefixId(`${id}-search`, formId),
3985
4056
  class: "fjs-select-hidden-input",
3986
4057
  value: valueLabel,
3987
- onFocus: () => setIsDropdownExpanded(true),
3988
- onBlur: () => setIsDropdownExpanded(false),
4058
+ onFocus: () => !readonly && setIsDropdownExpanded(true),
4059
+ onBlur: () => !readonly && setIsDropdownExpanded(false),
3989
4060
  "aria-describedby": props['aria-describedby']
3990
4061
  }), displayState.displayCross && jsxRuntime.jsx("span", {
3991
4062
  class: "fjs-select-cross",
@@ -4021,6 +4092,7 @@ function Select(props) {
4021
4092
  errors = [],
4022
4093
  field,
4023
4094
  onChange,
4095
+ readonly,
4024
4096
  value
4025
4097
  } = props;
4026
4098
  const {
@@ -4044,12 +4116,14 @@ function Select(props) {
4044
4116
  field,
4045
4117
  value,
4046
4118
  onChange,
4119
+ readonly,
4047
4120
  'aria-describedby': errorMessageId
4048
- }), [disabled, errors, field, id, value, onChange, errorMessageId]);
4121
+ }), [disabled, errors, field, id, value, onChange, readonly, errorMessageId]);
4049
4122
  return jsxRuntime.jsxs("div", {
4050
4123
  class: formFieldClasses(type$4, {
4051
4124
  errors,
4052
- disabled
4125
+ disabled,
4126
+ readonly
4053
4127
  }),
4054
4128
  onKeyDown: event => {
4055
4129
  if (event.key === 'Enter') {
@@ -4103,6 +4177,7 @@ function Taglist(props) {
4103
4177
  disabled,
4104
4178
  errors = [],
4105
4179
  field,
4180
+ readonly,
4106
4181
  value: values = []
4107
4182
  } = props;
4108
4183
  const {
@@ -4193,6 +4268,10 @@ function Taglist(props) {
4193
4268
  break;
4194
4269
  }
4195
4270
  };
4271
+ const onBlur = () => {
4272
+ setIsDropdownExpanded(false);
4273
+ setFilter('');
4274
+ };
4196
4275
  const onTagRemoveClick = (event, value) => {
4197
4276
  const {
4198
4277
  target
@@ -4209,7 +4288,8 @@ function Taglist(props) {
4209
4288
  return jsxRuntime.jsxs("div", {
4210
4289
  class: formFieldClasses(type$3, {
4211
4290
  errors,
4212
- disabled
4291
+ disabled,
4292
+ readonly
4213
4293
  }),
4214
4294
  onKeyDown: event => {
4215
4295
  if (event.key === 'Enter') {
@@ -4223,20 +4303,22 @@ function Taglist(props) {
4223
4303
  id: prefixId(`${id}-search`, formId)
4224
4304
  }), jsxRuntime.jsxs("div", {
4225
4305
  class: classNames('fjs-taglist', {
4226
- 'fjs-disabled': disabled
4306
+ 'fjs-disabled': disabled,
4307
+ 'fjs-readonly': readonly
4227
4308
  }),
4228
4309
  children: [loadState === LOAD_STATES.LOADED && jsxRuntime.jsx("div", {
4229
4310
  class: "fjs-taglist-tags",
4230
4311
  children: values.map(v => {
4231
4312
  return jsxRuntime.jsxs("div", {
4232
4313
  class: classNames('fjs-taglist-tag', {
4233
- 'fjs-disabled': disabled
4314
+ 'fjs-disabled': disabled,
4315
+ 'fjs-readonly': readonly
4234
4316
  }),
4235
4317
  onMouseDown: e => e.preventDefault(),
4236
4318
  children: [jsxRuntime.jsx("span", {
4237
4319
  class: "fjs-taglist-tag-label",
4238
4320
  children: valueToOptionMap[v] ? valueToOptionMap[v].label : `unexpected value{${v}}`
4239
- }), !disabled && jsxRuntime.jsx("button", {
4321
+ }), !disabled && !readonly && jsxRuntime.jsx("button", {
4240
4322
  type: "button",
4241
4323
  title: "Remove tag",
4242
4324
  class: "fjs-taglist-tag-remove",
@@ -4247,20 +4329,20 @@ function Taglist(props) {
4247
4329
  })
4248
4330
  }), jsxRuntime.jsx("input", {
4249
4331
  disabled: disabled,
4332
+ readOnly: readonly,
4250
4333
  class: "fjs-taglist-input",
4251
4334
  ref: searchbarRef,
4252
4335
  id: prefixId(`${id}-search`, formId),
4253
4336
  onChange: onFilterChange,
4254
4337
  type: "text",
4255
4338
  value: filter,
4256
- placeholder: disabled ? undefined : 'Search',
4339
+ placeholder: disabled || readonly ? undefined : 'Search',
4257
4340
  autoComplete: "off",
4258
4341
  onKeyDown: onInputKeyDown,
4259
4342
  onMouseDown: () => setIsEscapeClose(false),
4260
- onFocus: () => setIsDropdownExpanded(true),
4343
+ onFocus: () => !readonly && setIsDropdownExpanded(true),
4261
4344
  onBlur: () => {
4262
- setIsDropdownExpanded(false);
4263
- setFilter('');
4345
+ !readonly && onBlur();
4264
4346
  },
4265
4347
  "aria-describedby": errorMessageId
4266
4348
  })]
@@ -4395,6 +4477,7 @@ function Textfield(props) {
4395
4477
  disabled,
4396
4478
  errors = [],
4397
4479
  field,
4480
+ readonly,
4398
4481
  value = ''
4399
4482
  } = props;
4400
4483
  const {
@@ -4426,7 +4509,8 @@ function Textfield(props) {
4426
4509
  return jsxRuntime.jsxs("div", {
4427
4510
  class: formFieldClasses(type$1, {
4428
4511
  errors,
4429
- disabled
4512
+ disabled,
4513
+ readonly
4430
4514
  }),
4431
4515
  children: [jsxRuntime.jsx(Label, {
4432
4516
  id: prefixId(id, formId),
@@ -4434,11 +4518,13 @@ function Textfield(props) {
4434
4518
  required: required
4435
4519
  }), jsxRuntime.jsx(InputAdorner, {
4436
4520
  disabled: disabled,
4521
+ readonly: readonly,
4437
4522
  pre: prefixAdorner,
4438
4523
  post: suffixAdorner,
4439
4524
  children: jsxRuntime.jsx("input", {
4440
4525
  class: "fjs-input",
4441
4526
  disabled: disabled,
4527
+ readOnly: readonly,
4442
4528
  id: prefixId(id, formId),
4443
4529
  onInput: onChange,
4444
4530
  type: "text",
@@ -4483,6 +4569,7 @@ function Textarea(props) {
4483
4569
  disabled,
4484
4570
  errors = [],
4485
4571
  field,
4572
+ readonly,
4486
4573
  value = ''
4487
4574
  } = props;
4488
4575
  const {
@@ -4526,7 +4613,8 @@ function Textarea(props) {
4526
4613
  return jsxRuntime.jsxs("div", {
4527
4614
  class: formFieldClasses(type, {
4528
4615
  errors,
4529
- disabled
4616
+ disabled,
4617
+ readonly
4530
4618
  }),
4531
4619
  children: [jsxRuntime.jsx(Label, {
4532
4620
  id: prefixId(id, formId),
@@ -4535,6 +4623,7 @@ function Textarea(props) {
4535
4623
  }), jsxRuntime.jsx("textarea", {
4536
4624
  class: "fjs-textarea",
4537
4625
  disabled: disabled,
4626
+ readonly: readonly,
4538
4627
  id: prefixId(id, formId),
4539
4628
  onInput: onInput,
4540
4629
  value: value,
@@ -5048,7 +5137,7 @@ class Form {
5048
5137
  const {
5049
5138
  properties
5050
5139
  } = this._getState();
5051
- if (properties.readOnly) {
5140
+ if (properties.readOnly || properties.disabled) {
5052
5141
  throw new Error('form is read-only');
5053
5142
  }
5054
5143
  const data = this._getSubmitData();
@@ -5277,7 +5366,7 @@ class Form {
5277
5366
  }
5278
5367
  }
5279
5368
 
5280
- const schemaVersion = 8;
5369
+ const schemaVersion = 9;
5281
5370
 
5282
5371
  /**
5283
5372
  * @typedef { import('./types').CreateFormOptions } CreateFormOptions