@bpmn-io/properties-panel 3.18.1 → 3.19.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
@@ -988,6 +988,7 @@ const useBufferedFocus = function (editor, ref) {
988
988
  };
989
989
  const CodeEditor = compat.forwardRef((props, ref) => {
990
990
  const {
991
+ contentAttributes,
991
992
  enableGutters,
992
993
  value,
993
994
  onInput,
@@ -1033,7 +1034,8 @@ const CodeEditor = compat.forwardRef((props, ref) => {
1033
1034
  tooltipContainer: tooltipContainer,
1034
1035
  value: localValue,
1035
1036
  variables: variables,
1036
- extensions: [...(enableGutters ? [view.lineNumbers()] : []), view.EditorView.lineWrapping]
1037
+ extensions: [...(enableGutters ? [view.lineNumbers()] : []), view.EditorView.lineWrapping],
1038
+ contentAttributes
1037
1039
  });
1038
1040
  setEditor(editor);
1039
1041
  return () => {
@@ -2123,9 +2125,12 @@ function FeelTextfieldComponent(props) {
2123
2125
  disabled: feel !== 'optional' || disabled,
2124
2126
  onClick: handleFeelToggle
2125
2127
  }), feelActive ? jsxRuntime.jsx(CodeEditor, {
2126
- id: prefixId$5(id),
2127
2128
  name: id,
2128
2129
  onInput: handleLocalInput,
2130
+ contentAttributes: {
2131
+ 'id': prefixId$5(id),
2132
+ 'aria-label': label
2133
+ },
2129
2134
  disabled: disabled,
2130
2135
  popupOpen: popuOpen,
2131
2136
  onFeelToggle: () => {
@@ -2682,7 +2687,6 @@ const DEFAULT_TOOLTIP = {};
2682
2687
  * id: String,
2683
2688
  * items: Array<ListItemDefinition>,
2684
2689
  * label: String,
2685
- * shouldSort?: Boolean,
2686
2690
  * shouldOpen?: Boolean
2687
2691
  * } } ListGroupDefinition
2688
2692
  *
@@ -3115,6 +3119,7 @@ function ListItem(props) {
3115
3119
  } else if (minDash.isFunction(focusableInput.focus)) {
3116
3120
  focusableInput.focus();
3117
3121
  }
3122
+ focusableInput.scrollIntoView();
3118
3123
  }
3119
3124
  }
3120
3125
  }, [autoOpen, autoFocusEntry]);
@@ -3139,97 +3144,61 @@ function ListGroup(props) {
3139
3144
  id,
3140
3145
  items,
3141
3146
  label,
3142
- shouldOpen = true,
3143
- shouldSort = true
3147
+ shouldOpen = true
3144
3148
  } = props;
3149
+ hooks.useEffect(() => {
3150
+ if (props.shouldSort != undefined) {
3151
+ console.warn('the property \'shouldSort\' is no longer supported');
3152
+ }
3153
+ }, [props.shouldSort]);
3145
3154
  const groupRef = hooks.useRef(null);
3146
3155
  const [open, setOpen] = useLayoutState(['groups', id, 'open'], false);
3147
3156
  const [sticky, setSticky] = hooks.useState(false);
3148
3157
  const onShow = hooks.useCallback(() => setOpen(true), [setOpen]);
3149
- const [ordering, setOrdering] = hooks.useState([]);
3150
- const [newItemAdded, setNewItemAdded] = hooks.useState(false);
3158
+ const [localItems, setLocalItems] = hooks.useState([]);
3159
+ const [newlyAddedItemIds, setNewlyAddedItemIds] = hooks.useState([]);
3151
3160
 
3152
3161
  // Flag to mark that add button was clicked in the last render cycle
3153
3162
  const [addTriggered, setAddTriggered] = hooks.useState(false);
3154
- const prevItems = usePrevious(items);
3155
3163
  const prevElement = usePrevious(element);
3156
3164
  const elementChanged = element !== prevElement;
3157
- const shouldHandleEffects = !elementChanged && (shouldSort || shouldOpen);
3158
-
3159
- // reset initial ordering when element changes (before first render)
3160
- if (elementChanged) {
3161
- setOrdering(createOrdering(shouldSort ? sortItems(items) : items));
3162
- }
3163
-
3164
- // keep ordering in sync to items - and open changes
3165
-
3166
- // (0) set initial ordering from given items
3165
+ const shouldHandleEffects = !elementChanged && shouldOpen;
3166
+
3167
+ // (0) delay setting items
3168
+ //
3169
+ // We need to this to align the render cycles of items
3170
+ // with the detection of newly added items.
3171
+ // This is important, because the autoOpen property can
3172
+ // only set per list item on its very first render.
3167
3173
  hooks.useEffect(() => {
3168
- if (!prevItems || !shouldSort) {
3169
- setOrdering(createOrdering(items));
3170
- }
3171
- }, [items, element]);
3174
+ setLocalItems(items);
3175
+ }, [items]);
3172
3176
 
3173
- // (1) items were added
3177
+ // (1) handle auto opening when items were added
3174
3178
  hooks.useEffect(() => {
3175
3179
  // reset addTriggered flag
3176
3180
  setAddTriggered(false);
3177
- if (shouldHandleEffects && prevItems && items.length > prevItems.length) {
3178
- let add = [];
3179
- items.forEach(item => {
3180
- if (!ordering.includes(item.id)) {
3181
- add.push(item.id);
3181
+ if (shouldHandleEffects && localItems) {
3182
+ if (addTriggered) {
3183
+ const previousItemIds = localItems.map(item => item.id);
3184
+ const currentItemsIds = items.map(item => item.id);
3185
+ const newItemIds = currentItemsIds.filter(itemId => !previousItemIds.includes(itemId));
3186
+
3187
+ // open if not open, configured and triggered by add button
3188
+ //
3189
+ // TODO(marstamm): remove once we refactor layout handling for listGroups.
3190
+ // Ideally, opening should be handled as part of the `add` callback and
3191
+ // not be a concern for the ListGroup component.
3192
+ if (!open && shouldOpen && newItemIds.length > 0) {
3193
+ toggleOpen();
3182
3194
  }
3183
- });
3184
- let newOrdering = ordering;
3185
-
3186
- // open if not open, configured and triggered by add button
3187
- //
3188
- // TODO(marstamm): remove once we refactor layout handling for listGroups.
3189
- // Ideally, opening should be handled as part of the `add` callback and
3190
- // not be a concern for the ListGroup component.
3191
- if (addTriggered && !open && shouldOpen) {
3192
- toggleOpen();
3193
- }
3194
-
3195
- // filter when not open and configured
3196
- if (!open && shouldSort) {
3197
- newOrdering = createOrdering(sortItems(items));
3198
- }
3199
-
3200
- // add new items on top or bottom depending on sorting behavior
3201
- newOrdering = newOrdering.filter(item => !add.includes(item));
3202
- if (shouldSort) {
3203
- newOrdering.unshift(...add);
3195
+ setNewlyAddedItemIds(newItemIds);
3204
3196
  } else {
3205
- newOrdering.push(...add);
3197
+ // ignore newly added items that do not result from a triggered add
3198
+ setNewlyAddedItemIds([]);
3206
3199
  }
3207
- setOrdering(newOrdering);
3208
- setNewItemAdded(addTriggered);
3209
- } else {
3210
- setNewItemAdded(false);
3211
- }
3212
- }, [items, open, shouldHandleEffects, addTriggered]);
3213
-
3214
- // (2) sort items on open if shouldSort is set
3215
- hooks.useEffect(() => {
3216
- if (shouldSort && open && !newItemAdded) {
3217
- setOrdering(createOrdering(sortItems(items)));
3218
- }
3219
- }, [open, shouldSort]);
3220
-
3221
- // (3) items were deleted
3222
- hooks.useEffect(() => {
3223
- if (shouldHandleEffects && prevItems && items.length < prevItems.length) {
3224
- let keep = [];
3225
- ordering.forEach(o => {
3226
- if (getItem(items, o)) {
3227
- keep.push(o);
3228
- }
3229
- });
3230
- setOrdering(keep);
3231
3200
  }
3232
- }, [items, shouldHandleEffects]);
3201
+ }, [items, open, shouldHandleEffects, addTriggered, localItems]);
3233
3202
 
3234
3203
  // set css class when group is sticky to top
3235
3204
  useStickyIntersectionObserver(groupRef, 'div.bio-properties-panel-scroll-container', setSticky);
@@ -3301,8 +3270,7 @@ function ListGroup(props) {
3301
3270
  class: classnames('bio-properties-panel-list', open && hasItems ? 'open' : ''),
3302
3271
  children: jsxRuntime.jsx(LayoutContext.Provider, {
3303
3272
  value: propertiesPanelContext,
3304
- children: ordering.map((o, index) => {
3305
- const item = getItem(items, o);
3273
+ children: localItems.map((item, index) => {
3306
3274
  if (!item) {
3307
3275
  return;
3308
3276
  }
@@ -3312,7 +3280,7 @@ function ListGroup(props) {
3312
3280
 
3313
3281
  // if item was added, open it
3314
3282
  // Existing items will not be affected as autoOpen is only applied on first render
3315
- const autoOpen = newItemAdded;
3283
+ const autoOpen = newlyAddedItemIds.includes(item.id);
3316
3284
  return preact.createElement(ListItem, {
3317
3285
  ...item,
3318
3286
  autoOpen: autoOpen,
@@ -3326,21 +3294,6 @@ function ListGroup(props) {
3326
3294
  });
3327
3295
  }
3328
3296
 
3329
- // helpers ////////////////////
3330
-
3331
- /**
3332
- * Sorts given items alphanumeric by label
3333
- */
3334
- function sortItems(items) {
3335
- return minDash.sortBy(items, i => i.label.toLowerCase());
3336
- }
3337
- function getItem(items, id) {
3338
- return minDash.find(items, i => i.id === id);
3339
- }
3340
- function createOrdering(items) {
3341
- return items.map(i => i.id);
3342
- }
3343
-
3344
3297
  function Checkbox(props) {
3345
3298
  const {
3346
3299
  id,
@@ -3632,16 +3585,12 @@ function List(props) {
3632
3585
  onAdd,
3633
3586
  onRemove,
3634
3587
  autoFocusEntry,
3635
- compareFn,
3636
3588
  ...restProps
3637
3589
  } = props;
3638
3590
  const [open, setOpen] = hooks.useState(!!shouldOpen);
3639
3591
  const hasItems = !!items.length;
3640
3592
  const toggleOpen = () => hasItems && setOpen(!open);
3641
- const opening = !usePrevious(open) && open;
3642
3593
  const elementChanged = usePrevious(element) !== element;
3643
- const shouldReset = opening || elementChanged;
3644
- const sortedItems = useSortedItems(items, compareFn, shouldReset);
3645
3594
  const newItems = useNewItems(items, elementChanged);
3646
3595
  hooks.useEffect(() => {
3647
3596
  if (open && !hasItems) {
@@ -3699,7 +3648,7 @@ function List(props) {
3699
3648
  component: component,
3700
3649
  element: element,
3701
3650
  id: id,
3702
- items: sortedItems,
3651
+ items: items,
3703
3652
  newItems: newItems,
3704
3653
  onRemove: onRemove,
3705
3654
  open: open
@@ -3763,41 +3712,6 @@ function ItemsList(props) {
3763
3712
  })
3764
3713
  });
3765
3714
  }
3766
-
3767
- /**
3768
- * Place new items in the beginning of the list and sort the rest with provided function.
3769
- *
3770
- * @template Item
3771
- * @param {Item[]} currentItems
3772
- * @param {(a: Item, b: Item) => 0 | 1 | -1} [compareFn] function used to sort items
3773
- * @param {boolean} [shouldReset=false] set to `true` to reset state of the hook
3774
- * @returns {Item[]}
3775
- */
3776
- function useSortedItems(currentItems, compareFn, shouldReset = false) {
3777
- const itemsRef = hooks.useRef(currentItems.slice());
3778
-
3779
- // (1) Reset and optionally sort.
3780
- if (shouldReset) {
3781
- itemsRef.current = currentItems.slice();
3782
- if (compareFn) {
3783
- itemsRef.current.sort(compareFn);
3784
- }
3785
- } else {
3786
- const items = itemsRef.current;
3787
-
3788
- // (2) Add new item to the list.
3789
- for (const item of currentItems) {
3790
- if (!items.includes(item)) {
3791
- // Unshift or push depending on whether we have a compareFn
3792
- compareFn ? items.unshift(item) : items.push(item);
3793
- }
3794
- }
3795
-
3796
- // (3) Filter out removed items.
3797
- itemsRef.current = items.filter(item => currentItems.includes(item));
3798
- }
3799
- return itemsRef.current;
3800
- }
3801
3715
  function useNewItems(items = [], shouldReset) {
3802
3716
  const previousItems = usePrevious(items.slice()) || [];
3803
3717
  if (shouldReset) {