@bpmn-io/properties-panel 3.44.0 → 3.45.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.
@@ -44,6 +44,8 @@
44
44
  --description-code-border-color: var(--color-grey-225-10-85);
45
45
  --description-list-item-color: var(--color-grey-225-10-35);
46
46
 
47
+ --tooltip-underline-color: var(--color-grey-225-10-55);
48
+
47
49
  --placeholder-color: var(--color-grey-225-10-35);
48
50
  --placeholder-background-color: var(--color-grey-225-10-95);
49
51
 
@@ -1182,7 +1184,7 @@ textarea.bio-properties-panel-input {
1182
1184
  text-decoration: underline;
1183
1185
  text-decoration-style: dotted;
1184
1186
  text-underline-offset: 2px;
1185
- text-decoration-color: var(--color-grey-225-10-55);
1187
+ text-decoration-color: var(--tooltip-underline-color);
1186
1188
  font: inherit;
1187
1189
  display: flex;
1188
1190
  justify-content: center;
@@ -1196,7 +1198,6 @@ textarea.bio-properties-panel-input {
1196
1198
  }
1197
1199
 
1198
1200
  .bio-properties-panel-tooltip {
1199
- --tooltip-underline-color: var(--color-blue-219-99-53);
1200
1201
  --tooltip-background-color: var(--color-grey-0-0-22);
1201
1202
  --tooltip-link: var(--color-blue-218-100-74);
1202
1203
  --tooltip-code-background-color: var(--color-grey-225-10-97);
package/dist/index.esm.js CHANGED
@@ -12,7 +12,7 @@ import { closeBrackets, closeBracketsKeymap } from '@codemirror/autocomplete';
12
12
  import { history, defaultKeymap, historyKeymap } from '@codemirror/commands';
13
13
  import { jsonParseLinter, json } from '@codemirror/lang-json';
14
14
  import { linter } from '@codemirror/lint';
15
- import { FeelersEditor } from 'feelers';
15
+ import { FeelersEditor } from '@bpmn-io/feelers-editor';
16
16
  import Editor from '@bpmn-io/feel-editor';
17
17
  import * as focusTrap from 'focus-trap';
18
18
 
@@ -159,6 +159,28 @@ OpenPopupIcon.defaultProps = {
159
159
  viewBox: "0 0 16 16"
160
160
  };
161
161
 
162
+ /**
163
+ * @typedef { {
164
+ * [key: string]: string;
165
+ * } } TranslateReplacements
166
+ */
167
+
168
+ /**
169
+ * A simple translation stub to be used for multi-language support.
170
+ * Can be easily replaced with a more sophisticated solution.
171
+ *
172
+ * @param {string} template to interpolate
173
+ * @param {TranslateReplacements} [replacements] a map with substitutes
174
+ *
175
+ * @return {string} the translated string
176
+ */
177
+ function translateFallback(template, replacements) {
178
+ replacements = replacements || {};
179
+ return template.replace(/{([^}]+)}/g, function (_, key) {
180
+ return replacements[key] || '{' + key + '}';
181
+ });
182
+ }
183
+
162
184
  /**
163
185
  * @typedef { {
164
186
  * getElementLabel: (element: object) => string,
@@ -170,13 +192,15 @@ OpenPopupIcon.defaultProps = {
170
192
 
171
193
  /**
172
194
  * @param {Object} props
173
- * @param {Object} props.element,
195
+ * @param {Object} props.element
174
196
  * @param {HeaderProvider} props.headerProvider
197
+ * @param {Function} [props.translate]
175
198
  */
176
199
  function Header(props) {
177
200
  const {
178
201
  element,
179
- headerProvider
202
+ headerProvider,
203
+ translate = translateFallback
180
204
  } = props;
181
205
  const {
182
206
  getElementIcon,
@@ -212,7 +236,7 @@ function Header(props) {
212
236
  rel: "noreferrer",
213
237
  class: "bio-properties-panel-header-link",
214
238
  href: documentationRef,
215
- title: "Open documentation",
239
+ title: translate('Open documentation'),
216
240
  target: "_blank",
217
241
  children: jsx(ExternalLinkIcon, {})
218
242
  }) : null
@@ -842,7 +866,8 @@ function Group(props) {
842
866
  entries = [],
843
867
  id,
844
868
  label,
845
- shouldOpen = false
869
+ shouldOpen = false,
870
+ translate = translateFallback
846
871
  } = props;
847
872
  const groupRef = useRef(null);
848
873
  const [open, setOpen] = useLayoutState(['groups', id, 'open'], shouldOpen);
@@ -901,10 +926,11 @@ function Group(props) {
901
926
  class: "bio-properties-panel-group-header-buttons",
902
927
  children: [jsx(DataMarker, {
903
928
  edited: edited,
904
- hasErrors: hasErrors
929
+ hasErrors: hasErrors,
930
+ translate: translate
905
931
  }), jsx("button", {
906
932
  type: "button",
907
- title: "Toggle section",
933
+ title: translate('Toggle section'),
908
934
  class: "bio-properties-panel-group-header-button bio-properties-panel-arrow",
909
935
  children: jsx(ArrowIcon, {
910
936
  class: open ? 'bio-properties-panel-arrow-down' : 'bio-properties-panel-arrow-right'
@@ -933,17 +959,18 @@ function Group(props) {
933
959
  function DataMarker(props) {
934
960
  const {
935
961
  edited,
936
- hasErrors
962
+ hasErrors,
963
+ translate = translateFallback
937
964
  } = props;
938
965
  if (hasErrors) {
939
966
  return jsx("div", {
940
- title: "Section contains an error",
967
+ title: translate('Section contains an error'),
941
968
  class: "bio-properties-panel-dot bio-properties-panel-dot--error"
942
969
  });
943
970
  }
944
971
  if (edited) {
945
972
  return jsx("div", {
946
- title: "Section contains edits",
973
+ title: translate('Section contains edits'),
947
974
  class: "bio-properties-panel-dot"
948
975
  });
949
976
  }
@@ -1004,7 +1031,8 @@ const DEFAULT_TOOLTIP = {};
1004
1031
  * id: String,
1005
1032
  * items: Array<ListItemDefinition>,
1006
1033
  * label: String,
1007
- * shouldOpen?: Boolean
1034
+ * shouldOpen?: Boolean,
1035
+ * translate?: Function
1008
1036
  * } } ListGroupDefinition
1009
1037
  *
1010
1038
  * @typedef { {
@@ -1012,7 +1040,8 @@ const DEFAULT_TOOLTIP = {};
1012
1040
  * entries: Array<EntryDefinition>,
1013
1041
  * id: String,
1014
1042
  * label: String,
1015
- * shouldOpen?: Boolean
1043
+ * shouldOpen?: Boolean,
1044
+ * translate?: Function
1016
1045
  * } } GroupDefinition
1017
1046
  *
1018
1047
  * @typedef { {
@@ -1356,28 +1385,6 @@ function HeaderButton(props) {
1356
1385
  });
1357
1386
  }
1358
1387
 
1359
- /**
1360
- * @typedef { {
1361
- * [key: string]: string;
1362
- * } } TranslateReplacements
1363
- */
1364
-
1365
- /**
1366
- * A simple translation stub to be used for multi-language support.
1367
- * Can be easily replaced with a more sophisticated solution.
1368
- *
1369
- * @param {string} template to interpolate
1370
- * @param {TranslateReplacements} [replacements] a map with substitutes
1371
- *
1372
- * @return {string} the translated string
1373
- */
1374
- function translateFallback(template, replacements) {
1375
- replacements = replacements || {};
1376
- return template.replace(/{([^}]+)}/g, function (_, key) {
1377
- return replacements[key] || '{' + key + '}';
1378
- });
1379
- }
1380
-
1381
1388
  function CollapsibleEntry(props) {
1382
1389
  const {
1383
1390
  element,
@@ -1945,6 +1952,7 @@ function JsonEditor(props) {
1945
1952
  * @param {string} [props.placeholder]
1946
1953
  * @param {string} [props.tooltip]
1947
1954
  * @param {Function} [props.validate]
1955
+ * @param {Function} [props.translate]
1948
1956
  */
1949
1957
  function JsonEditorEntry(props) {
1950
1958
  const {
@@ -1958,24 +1966,25 @@ function JsonEditorEntry(props) {
1958
1966
  disabled,
1959
1967
  placeholder,
1960
1968
  tooltip,
1961
- validate
1969
+ validate,
1970
+ translate = translateFallback
1962
1971
  } = props;
1963
1972
  const globalError = useError(id);
1964
1973
  let value = getValue(element);
1965
- const [localError, setLocalError] = useState(() => computeError(validate, value));
1974
+ const [localError, setLocalError] = useState(() => computeError(validate, value, translate));
1966
1975
  const [editorValue, setEditorValue] = useState(value);
1967
1976
  useEffect(() => {
1968
1977
  if (value === editorValue) {
1969
1978
  return;
1970
1979
  }
1971
1980
  setEditorValue(value);
1972
- setLocalError(computeError(validate, value));
1981
+ setLocalError(computeError(validate, value, translate));
1973
1982
  }, [value, validate]);
1974
1983
  const onInput = useStaticCallback(newValue => {
1975
1984
  setEditorValue(newValue);
1976
1985
  const currentValue = getValue(element);
1977
1986
  if (newValue !== currentValue) {
1978
- const newValidationError = computeError(validate, newValue);
1987
+ const newValidationError = computeError(validate, newValue, translate);
1979
1988
  setValue(newValue, newValidationError);
1980
1989
  setLocalError(newValidationError);
1981
1990
  }
@@ -2014,15 +2023,15 @@ function isEdited$8(node) {
2014
2023
 
2015
2024
  // helpers /////////////////
2016
2025
 
2017
- function computeError(validate, value) {
2018
- return (isFunction(validate) ? validate(value) : null) || validateJson(value);
2026
+ function computeError(validate, value, translate) {
2027
+ return (isFunction(validate) ? validate(value) : null) || validateJson(value, translate);
2019
2028
  }
2020
- function validateJson(value) {
2029
+ function validateJson(value, translate = translateFallback) {
2021
2030
  if (!value || !value.trim()) return null;
2022
2031
  try {
2023
- return isObject(JSON.parse(value)) ? null : 'JSON contains errors';
2032
+ return isObject(JSON.parse(value)) ? null : translate('JSON contains errors');
2024
2033
  } catch (e) {
2025
- return 'JSON contains errors';
2034
+ return translate('JSON contains errors');
2026
2035
  }
2027
2036
  }
2028
2037
 
@@ -2032,13 +2041,14 @@ function validateJson(value) {
2032
2041
  * @param {Object} props
2033
2042
  * @param {Function} props.onClick - Callback to trigger when the button is clicked.
2034
2043
  * @param {string} [props.title] - Tooltip text for the button.
2035
- * @param {boolean} [props.disabled] - Whether the button is disabled.
2036
- * @param {string} [props.className] - Additional class names for the button.
2044
+ * @param {Function} [props.translate] - Translation function for built-in strings.
2037
2045
  */
2038
2046
  function OpenPopupButton({
2039
2047
  onClick,
2040
- title = 'Open pop-up editor'
2048
+ title,
2049
+ translate = translateFallback
2041
2050
  }) {
2051
+ title = title ?? translate('Open pop-up editor');
2042
2052
  return jsx("button", {
2043
2053
  type: "button",
2044
2054
  title: title,
@@ -2190,7 +2200,8 @@ const FeelEditor = forwardRef((props, ref) => {
2190
2200
  disabled,
2191
2201
  tooltipContainer,
2192
2202
  variables,
2193
- feelLanguageContext
2203
+ feelLanguageContext,
2204
+ translate = translateFallback
2194
2205
  } = props;
2195
2206
  const inputRef = useRef();
2196
2207
  const [editor, setEditor] = useState();
@@ -2282,14 +2293,15 @@ const FeelEditor = forwardRef((props, ref) => {
2282
2293
  class: classnames('bio-properties-panel-feel-editor-container', disabled ? 'disabled' : null, popupOpen ? 'popupOpen' : null),
2283
2294
  children: [popupOpen && jsx("div", {
2284
2295
  class: "bio-properties-panel-feel-editor__open-popup-placeholder",
2285
- children: "Opened in editor"
2296
+ children: translate('Opened in editor')
2286
2297
  }), jsx("div", {
2287
2298
  name: props.name,
2288
2299
  class: classnames('bio-properties-panel-input', localValue ? 'edited' : null),
2289
2300
  ref: inputRef,
2290
2301
  onClick: handleClick
2291
2302
  }), !disabled && jsx(OpenPopupButton, {
2292
- onClick: () => onOpenPopup('feel')
2303
+ onClick: () => onOpenPopup('feel'),
2304
+ translate: translate
2293
2305
  })]
2294
2306
  });
2295
2307
  });
@@ -2313,16 +2325,22 @@ const noop$3 = () => {};
2313
2325
  * @param {Object} props
2314
2326
  * @param {Object} props.label
2315
2327
  * @param {String} props.feel
2328
+ * @param {boolean} props.active
2329
+ * @param {boolean} props.disabled
2330
+ * @param {Function} props.onClick
2331
+ * @param {Function} props.translate
2332
+ * @returns {import('preact').Component}
2316
2333
  */
2317
2334
  function FeelIcon(props) {
2318
2335
  const {
2319
2336
  feel = false,
2320
2337
  active,
2321
2338
  disabled = false,
2322
- onClick = noop$3
2339
+ onClick = noop$3,
2340
+ translate = translateFallback
2323
2341
  } = props;
2324
- const feelRequiredLabel = 'FEEL expression is mandatory';
2325
- const feelOptionalLabel = `Click to ${active ? 'remove' : 'set a'} dynamic value with FEEL expression`;
2342
+ const feelRequiredLabel = translate('FEEL expression is mandatory');
2343
+ const feelOptionalLabel = translate(`Click to ${active ? 'remove' : 'set a'} dynamic value with FEEL expression`);
2326
2344
  const handleClick = e => {
2327
2345
  onClick(e);
2328
2346
 
@@ -2664,6 +2682,7 @@ const noop$2 = () => {};
2664
2682
  * @param {Array} props.variables
2665
2683
  * @param {string} [props.placeholder]
2666
2684
  * @param {string | import('preact').Component} props.tooltip
2685
+ * @param {Function} props.translate
2667
2686
  */
2668
2687
  function FeelTextfield(props) {
2669
2688
  const {
@@ -2683,7 +2702,8 @@ function FeelTextfield(props) {
2683
2702
  singleLine,
2684
2703
  tooltipContainer,
2685
2704
  OptionalComponent = OptionalFeelInput,
2686
- tooltip
2705
+ tooltip,
2706
+ translate
2687
2707
  } = props;
2688
2708
  const [localValue, setLocalValue] = useState(getInitialFeelLocalValue(feel, value));
2689
2709
  const editorRef = useShowEntryEvent(id);
@@ -2772,7 +2792,7 @@ function FeelTextfield(props) {
2772
2792
  const handleLint = useStaticCallback((lint = []) => {
2773
2793
  const syntaxError = lint.some(report => report.type === 'Syntax Error');
2774
2794
  if (syntaxError) {
2775
- onError('Unparsable FEEL expression.');
2795
+ onError(translate('Unparsable FEEL expression.'));
2776
2796
  } else {
2777
2797
  onError(undefined);
2778
2798
  }
@@ -2843,9 +2863,14 @@ function FeelTextfield(props) {
2843
2863
  });
2844
2864
  return;
2845
2865
  }
2846
- const input = event.target;
2847
- const isFieldEmpty = !input.value;
2848
- const isAllSelected = input.selectionStart === 0 && input.selectionEnd === input.value.length;
2866
+ const target = event.target;
2867
+
2868
+ // Skip for non-input/textArea elements (e.g. CodeMirror contenteditable)
2869
+ if (!(target instanceof HTMLInputElement) && !(target instanceof HTMLTextAreaElement)) {
2870
+ return;
2871
+ }
2872
+ const isFieldEmpty = !target.value;
2873
+ const isAllSelected = target.selectionStart === 0 && target.selectionEnd === target.value.length;
2849
2874
  if (isFieldEmpty || isAllSelected) {
2850
2875
  const textData = event.clipboardData.getData('text');
2851
2876
  const trimmedValue = textData.trim();
@@ -2882,7 +2907,8 @@ function FeelTextfield(props) {
2882
2907
  label: label,
2883
2908
  feel: feel,
2884
2909
  onClick: handleFeelToggle,
2885
- active: feelActive
2910
+ active: feelActive,
2911
+ translate: translate
2886
2912
  })]
2887
2913
  }), jsxs("div", {
2888
2914
  class: "bio-properties-panel-feel-container",
@@ -2913,7 +2939,8 @@ function FeelTextfield(props) {
2913
2939
  variables: variables,
2914
2940
  feelLanguageContext: feelLanguageContext,
2915
2941
  ref: editorRef,
2916
- tooltipContainer: tooltipContainer
2942
+ tooltipContainer: tooltipContainer,
2943
+ translate: translate
2917
2944
  }) : jsx(OptionalComponent, {
2918
2945
  ...props,
2919
2946
  popupOpen: isPopupOpen,
@@ -3182,7 +3209,8 @@ function FeelEntry(props) {
3182
3209
  onFocus,
3183
3210
  onBlur,
3184
3211
  placeholder,
3185
- tooltip
3212
+ tooltip,
3213
+ translate = translateFallback
3186
3214
  } = props;
3187
3215
  const [validationError, setValidationError] = useState(null);
3188
3216
  const [localError, setLocalError] = useState(null);
@@ -3231,6 +3259,7 @@ function FeelEntry(props) {
3231
3259
  hostLanguage: hostLanguage,
3232
3260
  singleLine: singleLine,
3233
3261
  show: show,
3262
+ translate: translate,
3234
3263
  value: value,
3235
3264
  variables: variables,
3236
3265
  tooltipContainer: tooltipContainer,
@@ -3644,6 +3673,7 @@ function prefixIdLabel(id) {
3644
3673
  * @param {Item[]} [props.items]
3645
3674
  * @param {boolean} [props.open]
3646
3675
  * @param {string|boolean} [props.autoFocusEntry] either a custom selector string or true to focus the first input
3676
+ * @param {Function} [props.translate]
3647
3677
  * @returns
3648
3678
  */
3649
3679
  function List(props) {
@@ -3657,6 +3687,7 @@ function List(props) {
3657
3687
  onAdd,
3658
3688
  onRemove,
3659
3689
  autoFocusEntry,
3690
+ translate = translateFallback,
3660
3691
  ...restProps
3661
3692
  } = props;
3662
3693
  const entryRef = useRef(null);
@@ -3699,20 +3730,22 @@ function List(props) {
3699
3730
  class: "bio-properties-panel-list-entry-header-buttons",
3700
3731
  children: [jsxs("button", {
3701
3732
  type: "button",
3702
- title: "Create new list item",
3733
+ title: translate('Create new list item'),
3703
3734
  onClick: addItem,
3704
3735
  class: "bio-properties-panel-add-entry",
3705
3736
  children: [jsx(CreateIcon, {}), !hasItems ? jsx("span", {
3706
3737
  class: "bio-properties-panel-add-entry-label",
3707
- children: "Create"
3738
+ children: translate('Create')
3708
3739
  }) : null]
3709
3740
  }), hasItems && jsx("div", {
3710
- title: `List contains ${items.length} item${items.length != 1 ? 's' : ''}`,
3741
+ title: translate(`List contains {numOfItems} item${items.length != 1 ? 's' : ''}`, {
3742
+ numOfItems: items.length
3743
+ }),
3711
3744
  class: "bio-properties-panel-list-badge",
3712
3745
  children: items.length
3713
3746
  }), hasItems && jsx("button", {
3714
3747
  type: "button",
3715
- title: "Toggle list item",
3748
+ title: translate('Toggle list item'),
3716
3749
  class: "bio-properties-panel-arrow",
3717
3750
  children: jsx(ArrowIcon, {
3718
3751
  class: open ? 'bio-properties-panel-arrow-down' : 'bio-properties-panel-arrow-right'
@@ -3728,7 +3761,8 @@ function List(props) {
3728
3761
  items: items,
3729
3762
  newItems: newItems,
3730
3763
  onRemove: onRemove,
3731
- open: open
3764
+ open: open,
3765
+ translate: translate
3732
3766
  })]
3733
3767
  });
3734
3768
  }
@@ -3742,6 +3776,7 @@ function ItemsList(props) {
3742
3776
  newItems,
3743
3777
  onRemove,
3744
3778
  open,
3779
+ translate,
3745
3780
  ...restProps
3746
3781
  } = props;
3747
3782
  const getKey = useKeyFactory();
@@ -3780,7 +3815,7 @@ function ItemsList(props) {
3780
3815
  open: item === newItem
3781
3816
  }), onRemove && jsx("button", {
3782
3817
  type: "button",
3783
- title: "Delete item",
3818
+ title: translate('Delete item'),
3784
3819
  class: "bio-properties-panel-remove-entry bio-properties-panel-remove-list-entry",
3785
3820
  onClick: () => onRemove && onRemove(item),
3786
3821
  children: jsx(DeleteIcon, {})
@@ -3981,6 +4016,7 @@ function prefixId$4(id) {
3981
4016
  * @param {Function} [props.onBlur]
3982
4017
  * @param {Function} [props.onFocus]
3983
4018
  * @param {Function} props.setValue
4019
+ * @param {Function} [props.translate]
3984
4020
  */
3985
4021
  function Simple(props) {
3986
4022
  const {
@@ -3991,7 +4027,8 @@ function Simple(props) {
3991
4027
  id,
3992
4028
  onBlur,
3993
4029
  onFocus,
3994
- setValue
4030
+ setValue,
4031
+ translate = translateFallback
3995
4032
  } = props;
3996
4033
  const value = getValue(element);
3997
4034
  const [localValue, setLocalValue] = useState(value);
@@ -4019,7 +4056,7 @@ function Simple(props) {
4019
4056
  disabled: disabled,
4020
4057
  class: "bio-properties-panel-input",
4021
4058
  onInput: handleInput,
4022
- "aria-label": localValue || '<empty>',
4059
+ "aria-label": localValue || translate('<empty>'),
4023
4060
  onFocus: onFocus,
4024
4061
  onBlur: onBlur,
4025
4062
  value: localValue