@bpmn-io/properties-panel 3.18.2 → 3.20.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.js CHANGED
@@ -995,6 +995,7 @@ const CodeEditor = compat.forwardRef((props, ref) => {
995
995
  onFeelToggle = noop$5,
996
996
  onLint = noop$5,
997
997
  onPopupOpen = noop$5,
998
+ placeholder,
998
999
  popupOpen,
999
1000
  disabled,
1000
1001
  tooltipContainer,
@@ -1031,6 +1032,7 @@ const CodeEditor = compat.forwardRef((props, ref) => {
1031
1032
  onChange: handleInput,
1032
1033
  onKeyDown: onKeyDown,
1033
1034
  onLint: onLint,
1035
+ placeholder: placeholder,
1034
1036
  tooltipContainer: tooltipContainer,
1035
1037
  value: localValue,
1036
1038
  variables: variables,
@@ -1060,6 +1062,12 @@ const CodeEditor = compat.forwardRef((props, ref) => {
1060
1062
  }
1061
1063
  editor.setVariables(variables);
1062
1064
  }, [variables]);
1065
+ hooks.useEffect(() => {
1066
+ if (!editor) {
1067
+ return;
1068
+ }
1069
+ editor.setPlaceholder(placeholder);
1070
+ }, [placeholder]);
1063
1071
  const handleClick = () => {
1064
1072
  ref.current.focus();
1065
1073
  };
@@ -1965,6 +1973,7 @@ function FeelTextfieldComponent(props) {
1965
1973
  hostLanguage,
1966
1974
  onInput,
1967
1975
  onError,
1976
+ placeholder,
1968
1977
  feel,
1969
1978
  value = '',
1970
1979
  disabled = false,
@@ -2139,6 +2148,7 @@ function FeelTextfieldComponent(props) {
2139
2148
  },
2140
2149
  onLint: handleLint,
2141
2150
  onPopupOpen: handlePopupOpen,
2151
+ placeholder: placeholder,
2142
2152
  value: feelOnlyValue,
2143
2153
  variables: variables,
2144
2154
  ref: editorRef,
@@ -2167,7 +2177,8 @@ const OptionalFeelInput = compat.forwardRef((props, ref) => {
2167
2177
  onInput,
2168
2178
  value,
2169
2179
  onFocus,
2170
- onBlur
2180
+ onBlur,
2181
+ placeholder
2171
2182
  } = props;
2172
2183
  const inputRef = hooks.useRef();
2173
2184
 
@@ -2200,6 +2211,7 @@ const OptionalFeelInput = compat.forwardRef((props, ref) => {
2200
2211
  onInput: e => onInput(e.target.value),
2201
2212
  onFocus: onFocus,
2202
2213
  onBlur: onBlur,
2214
+ placeholder: placeholder,
2203
2215
  value: value || ''
2204
2216
  });
2205
2217
  });
@@ -2257,7 +2269,8 @@ const OptionalFeelTextArea = compat.forwardRef((props, ref) => {
2257
2269
  onInput,
2258
2270
  value,
2259
2271
  onFocus,
2260
- onBlur
2272
+ onBlur,
2273
+ placeholder
2261
2274
  } = props;
2262
2275
  const inputRef = hooks.useRef();
2263
2276
 
@@ -2285,6 +2298,7 @@ const OptionalFeelTextArea = compat.forwardRef((props, ref) => {
2285
2298
  onInput: e => onInput(e.target.value),
2286
2299
  onFocus: onFocus,
2287
2300
  onBlur: onBlur,
2301
+ placeholder: placeholder,
2288
2302
  value: value || '',
2289
2303
  "data-gramm": "false"
2290
2304
  });
@@ -2380,6 +2394,7 @@ const OptionalFeelCheckbox = compat.forwardRef((props, ref) => {
2380
2394
  * @param {Function} props.variables
2381
2395
  * @param {Function} props.onFocus
2382
2396
  * @param {Function} props.onBlur
2397
+ * @param {string} [props.placeholder]
2383
2398
  * @param {string|import('preact').Component} props.tooltip
2384
2399
  */
2385
2400
  function FeelEntry(props) {
@@ -2402,6 +2417,7 @@ function FeelEntry(props) {
2402
2417
  variables,
2403
2418
  onFocus,
2404
2419
  onBlur,
2420
+ placeholder,
2405
2421
  tooltip
2406
2422
  } = props;
2407
2423
  const [validationError, setValidationError] = hooks.useState(null);
@@ -2445,6 +2461,7 @@ function FeelEntry(props) {
2445
2461
  onError: onError,
2446
2462
  onFocus: onFocus,
2447
2463
  onBlur: onBlur,
2464
+ placeholder: placeholder,
2448
2465
  example: example,
2449
2466
  hostLanguage: hostLanguage,
2450
2467
  singleLine: singleLine,
@@ -2513,6 +2530,7 @@ function FeelNumberEntry(props) {
2513
2530
  * @param {Function} props.variables
2514
2531
  * @param {Function} props.onFocus
2515
2532
  * @param {Function} props.onBlur
2533
+ * @param {string} [props.placeholder]
2516
2534
  */
2517
2535
  function FeelTextAreaEntry(props) {
2518
2536
  return jsxRuntime.jsx(FeelEntry, {
@@ -2687,7 +2705,6 @@ const DEFAULT_TOOLTIP = {};
2687
2705
  * id: String,
2688
2706
  * items: Array<ListItemDefinition>,
2689
2707
  * label: String,
2690
- * shouldSort?: Boolean,
2691
2708
  * shouldOpen?: Boolean
2692
2709
  * } } ListGroupDefinition
2693
2710
  *
@@ -3120,6 +3137,7 @@ function ListItem(props) {
3120
3137
  } else if (minDash.isFunction(focusableInput.focus)) {
3121
3138
  focusableInput.focus();
3122
3139
  }
3140
+ focusableInput.scrollIntoView();
3123
3141
  }
3124
3142
  }
3125
3143
  }, [autoOpen, autoFocusEntry]);
@@ -3144,97 +3162,61 @@ function ListGroup(props) {
3144
3162
  id,
3145
3163
  items,
3146
3164
  label,
3147
- shouldOpen = true,
3148
- shouldSort = true
3165
+ shouldOpen = true
3149
3166
  } = props;
3167
+ hooks.useEffect(() => {
3168
+ if (props.shouldSort != undefined) {
3169
+ console.warn('the property \'shouldSort\' is no longer supported');
3170
+ }
3171
+ }, [props.shouldSort]);
3150
3172
  const groupRef = hooks.useRef(null);
3151
3173
  const [open, setOpen] = useLayoutState(['groups', id, 'open'], false);
3152
3174
  const [sticky, setSticky] = hooks.useState(false);
3153
3175
  const onShow = hooks.useCallback(() => setOpen(true), [setOpen]);
3154
- const [ordering, setOrdering] = hooks.useState([]);
3155
- const [newItemAdded, setNewItemAdded] = hooks.useState(false);
3176
+ const [localItems, setLocalItems] = hooks.useState([]);
3177
+ const [newlyAddedItemIds, setNewlyAddedItemIds] = hooks.useState([]);
3156
3178
 
3157
3179
  // Flag to mark that add button was clicked in the last render cycle
3158
3180
  const [addTriggered, setAddTriggered] = hooks.useState(false);
3159
- const prevItems = usePrevious(items);
3160
3181
  const prevElement = usePrevious(element);
3161
3182
  const elementChanged = element !== prevElement;
3162
- const shouldHandleEffects = !elementChanged && (shouldSort || shouldOpen);
3163
-
3164
- // reset initial ordering when element changes (before first render)
3165
- if (elementChanged) {
3166
- setOrdering(createOrdering(shouldSort ? sortItems(items) : items));
3167
- }
3168
-
3169
- // keep ordering in sync to items - and open changes
3170
-
3171
- // (0) set initial ordering from given items
3183
+ const shouldHandleEffects = !elementChanged && shouldOpen;
3184
+
3185
+ // (0) delay setting items
3186
+ //
3187
+ // We need to this to align the render cycles of items
3188
+ // with the detection of newly added items.
3189
+ // This is important, because the autoOpen property can
3190
+ // only set per list item on its very first render.
3172
3191
  hooks.useEffect(() => {
3173
- if (!prevItems || !shouldSort) {
3174
- setOrdering(createOrdering(items));
3175
- }
3176
- }, [items, element]);
3192
+ setLocalItems(items);
3193
+ }, [items]);
3177
3194
 
3178
- // (1) items were added
3195
+ // (1) handle auto opening when items were added
3179
3196
  hooks.useEffect(() => {
3180
3197
  // reset addTriggered flag
3181
3198
  setAddTriggered(false);
3182
- if (shouldHandleEffects && prevItems && items.length > prevItems.length) {
3183
- let add = [];
3184
- items.forEach(item => {
3185
- if (!ordering.includes(item.id)) {
3186
- add.push(item.id);
3199
+ if (shouldHandleEffects && localItems) {
3200
+ if (addTriggered) {
3201
+ const previousItemIds = localItems.map(item => item.id);
3202
+ const currentItemsIds = items.map(item => item.id);
3203
+ const newItemIds = currentItemsIds.filter(itemId => !previousItemIds.includes(itemId));
3204
+
3205
+ // open if not open, configured and triggered by add button
3206
+ //
3207
+ // TODO(marstamm): remove once we refactor layout handling for listGroups.
3208
+ // Ideally, opening should be handled as part of the `add` callback and
3209
+ // not be a concern for the ListGroup component.
3210
+ if (!open && shouldOpen && newItemIds.length > 0) {
3211
+ toggleOpen();
3187
3212
  }
3188
- });
3189
- let newOrdering = ordering;
3190
-
3191
- // open if not open, configured and triggered by add button
3192
- //
3193
- // TODO(marstamm): remove once we refactor layout handling for listGroups.
3194
- // Ideally, opening should be handled as part of the `add` callback and
3195
- // not be a concern for the ListGroup component.
3196
- if (addTriggered && !open && shouldOpen) {
3197
- toggleOpen();
3198
- }
3199
-
3200
- // filter when not open and configured
3201
- if (!open && shouldSort) {
3202
- newOrdering = createOrdering(sortItems(items));
3203
- }
3204
-
3205
- // add new items on top or bottom depending on sorting behavior
3206
- newOrdering = newOrdering.filter(item => !add.includes(item));
3207
- if (shouldSort) {
3208
- newOrdering.unshift(...add);
3213
+ setNewlyAddedItemIds(newItemIds);
3209
3214
  } else {
3210
- newOrdering.push(...add);
3215
+ // ignore newly added items that do not result from a triggered add
3216
+ setNewlyAddedItemIds([]);
3211
3217
  }
3212
- setOrdering(newOrdering);
3213
- setNewItemAdded(addTriggered);
3214
- } else {
3215
- setNewItemAdded(false);
3216
- }
3217
- }, [items, open, shouldHandleEffects, addTriggered]);
3218
-
3219
- // (2) sort items on open if shouldSort is set
3220
- hooks.useEffect(() => {
3221
- if (shouldSort && open && !newItemAdded) {
3222
- setOrdering(createOrdering(sortItems(items)));
3223
3218
  }
3224
- }, [open, shouldSort]);
3225
-
3226
- // (3) items were deleted
3227
- hooks.useEffect(() => {
3228
- if (shouldHandleEffects && prevItems && items.length < prevItems.length) {
3229
- let keep = [];
3230
- ordering.forEach(o => {
3231
- if (getItem(items, o)) {
3232
- keep.push(o);
3233
- }
3234
- });
3235
- setOrdering(keep);
3236
- }
3237
- }, [items, shouldHandleEffects]);
3219
+ }, [items, open, shouldHandleEffects, addTriggered, localItems]);
3238
3220
 
3239
3221
  // set css class when group is sticky to top
3240
3222
  useStickyIntersectionObserver(groupRef, 'div.bio-properties-panel-scroll-container', setSticky);
@@ -3306,8 +3288,7 @@ function ListGroup(props) {
3306
3288
  class: classnames('bio-properties-panel-list', open && hasItems ? 'open' : ''),
3307
3289
  children: jsxRuntime.jsx(LayoutContext.Provider, {
3308
3290
  value: propertiesPanelContext,
3309
- children: ordering.map((o, index) => {
3310
- const item = getItem(items, o);
3291
+ children: localItems.map((item, index) => {
3311
3292
  if (!item) {
3312
3293
  return;
3313
3294
  }
@@ -3317,7 +3298,7 @@ function ListGroup(props) {
3317
3298
 
3318
3299
  // if item was added, open it
3319
3300
  // Existing items will not be affected as autoOpen is only applied on first render
3320
- const autoOpen = newItemAdded;
3301
+ const autoOpen = newlyAddedItemIds.includes(item.id);
3321
3302
  return preact.createElement(ListItem, {
3322
3303
  ...item,
3323
3304
  autoOpen: autoOpen,
@@ -3331,21 +3312,6 @@ function ListGroup(props) {
3331
3312
  });
3332
3313
  }
3333
3314
 
3334
- // helpers ////////////////////
3335
-
3336
- /**
3337
- * Sorts given items alphanumeric by label
3338
- */
3339
- function sortItems(items) {
3340
- return minDash.sortBy(items, i => i.label.toLowerCase());
3341
- }
3342
- function getItem(items, id) {
3343
- return minDash.find(items, i => i.id === id);
3344
- }
3345
- function createOrdering(items) {
3346
- return items.map(i => i.id);
3347
- }
3348
-
3349
3315
  function Checkbox(props) {
3350
3316
  const {
3351
3317
  id,
@@ -3637,16 +3603,12 @@ function List(props) {
3637
3603
  onAdd,
3638
3604
  onRemove,
3639
3605
  autoFocusEntry,
3640
- compareFn,
3641
3606
  ...restProps
3642
3607
  } = props;
3643
3608
  const [open, setOpen] = hooks.useState(!!shouldOpen);
3644
3609
  const hasItems = !!items.length;
3645
3610
  const toggleOpen = () => hasItems && setOpen(!open);
3646
- const opening = !usePrevious(open) && open;
3647
3611
  const elementChanged = usePrevious(element) !== element;
3648
- const shouldReset = opening || elementChanged;
3649
- const sortedItems = useSortedItems(items, compareFn, shouldReset);
3650
3612
  const newItems = useNewItems(items, elementChanged);
3651
3613
  hooks.useEffect(() => {
3652
3614
  if (open && !hasItems) {
@@ -3704,7 +3666,7 @@ function List(props) {
3704
3666
  component: component,
3705
3667
  element: element,
3706
3668
  id: id,
3707
- items: sortedItems,
3669
+ items: items,
3708
3670
  newItems: newItems,
3709
3671
  onRemove: onRemove,
3710
3672
  open: open
@@ -3768,41 +3730,6 @@ function ItemsList(props) {
3768
3730
  })
3769
3731
  });
3770
3732
  }
3771
-
3772
- /**
3773
- * Place new items in the beginning of the list and sort the rest with provided function.
3774
- *
3775
- * @template Item
3776
- * @param {Item[]} currentItems
3777
- * @param {(a: Item, b: Item) => 0 | 1 | -1} [compareFn] function used to sort items
3778
- * @param {boolean} [shouldReset=false] set to `true` to reset state of the hook
3779
- * @returns {Item[]}
3780
- */
3781
- function useSortedItems(currentItems, compareFn, shouldReset = false) {
3782
- const itemsRef = hooks.useRef(currentItems.slice());
3783
-
3784
- // (1) Reset and optionally sort.
3785
- if (shouldReset) {
3786
- itemsRef.current = currentItems.slice();
3787
- if (compareFn) {
3788
- itemsRef.current.sort(compareFn);
3789
- }
3790
- } else {
3791
- const items = itemsRef.current;
3792
-
3793
- // (2) Add new item to the list.
3794
- for (const item of currentItems) {
3795
- if (!items.includes(item)) {
3796
- // Unshift or push depending on whether we have a compareFn
3797
- compareFn ? items.unshift(item) : items.push(item);
3798
- }
3799
- }
3800
-
3801
- // (3) Filter out removed items.
3802
- itemsRef.current = items.filter(item => currentItems.includes(item));
3803
- }
3804
- return itemsRef.current;
3805
- }
3806
3733
  function useNewItems(items = [], shouldReset) {
3807
3734
  const previousItems = usePrevious(items.slice()) || [];
3808
3735
  if (shouldReset) {
@@ -4038,6 +3965,7 @@ function TextArea(props) {
4038
3965
  onFocus,
4039
3966
  onBlur,
4040
3967
  autoResize,
3968
+ placeholder,
4041
3969
  rows = autoResize ? 1 : 2,
4042
3970
  tooltip
4043
3971
  } = props;
@@ -4080,6 +4008,7 @@ function TextArea(props) {
4080
4008
  onInput: handleInput,
4081
4009
  onFocus: onFocus,
4082
4010
  onBlur: onBlur,
4011
+ placeholder: placeholder,
4083
4012
  rows: rows,
4084
4013
  value: localValue,
4085
4014
  disabled: disabled,
@@ -4119,6 +4048,7 @@ function TextAreaEntry(props) {
4119
4048
  validate,
4120
4049
  onFocus,
4121
4050
  onBlur,
4051
+ placeholder,
4122
4052
  autoResize,
4123
4053
  tooltip
4124
4054
  } = props;
@@ -4154,6 +4084,7 @@ function TextAreaEntry(props) {
4154
4084
  debounce: debounce,
4155
4085
  monospace: monospace,
4156
4086
  disabled: disabled,
4087
+ placeholder: placeholder,
4157
4088
  autoResize: autoResize,
4158
4089
  tooltip: tooltip,
4159
4090
  element: element
@@ -4186,6 +4117,7 @@ function Textfield(props) {
4186
4117
  onInput,
4187
4118
  onFocus,
4188
4119
  onBlur,
4120
+ placeholder,
4189
4121
  value = '',
4190
4122
  tooltip
4191
4123
  } = props;
@@ -4227,6 +4159,7 @@ function Textfield(props) {
4227
4159
  onInput: handleInput,
4228
4160
  onFocus: onFocus,
4229
4161
  onBlur: onBlur,
4162
+ placeholder: placeholder,
4230
4163
  value: localValue
4231
4164
  })]
4232
4165
  });
@@ -4260,6 +4193,7 @@ function TextfieldEntry(props) {
4260
4193
  validate,
4261
4194
  onFocus,
4262
4195
  onBlur,
4196
+ placeholder,
4263
4197
  tooltip
4264
4198
  } = props;
4265
4199
  const globalError = useError(id);
@@ -4291,6 +4225,7 @@ function TextfieldEntry(props) {
4291
4225
  onInput: onInput,
4292
4226
  onFocus: onFocus,
4293
4227
  onBlur: onBlur,
4228
+ placeholder: placeholder,
4294
4229
  value: value,
4295
4230
  tooltip: tooltip,
4296
4231
  element: element