@bpmn-io/properties-panel 0.13.0 → 0.14.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
@@ -161,6 +161,7 @@ function Header(props) {
161
161
  rel: "noopener",
162
162
  class: "bio-properties-panel-header-link",
163
163
  href: documentationRef,
164
+ title: "Open documentation",
164
165
  target: "_blank",
165
166
  children: jsxRuntime.jsx(ExternalLinkIcon, {})
166
167
  }) : null
@@ -173,480 +174,6 @@ const DescriptionContext = preact.createContext({
173
174
  getDescriptionForId: () => {}
174
175
  });
175
176
 
176
- var FN_REF = '__fn';
177
- var DEFAULT_PRIORITY$1 = 1000;
178
- var slice = Array.prototype.slice;
179
- /**
180
- * A general purpose event bus.
181
- *
182
- * This component is used to communicate across a diagram instance.
183
- * Other parts of a diagram can use it to listen to and broadcast events.
184
- *
185
- *
186
- * ## Registering for Events
187
- *
188
- * The event bus provides the {@link EventBus#on} and {@link EventBus#once}
189
- * methods to register for events. {@link EventBus#off} can be used to
190
- * remove event registrations. Listeners receive an instance of {@link Event}
191
- * as the first argument. It allows them to hook into the event execution.
192
- *
193
- * ```javascript
194
- *
195
- * // listen for event
196
- * eventBus.on('foo', function(event) {
197
- *
198
- * // access event type
199
- * event.type; // 'foo'
200
- *
201
- * // stop propagation to other listeners
202
- * event.stopPropagation();
203
- *
204
- * // prevent event default
205
- * event.preventDefault();
206
- * });
207
- *
208
- * // listen for event with custom payload
209
- * eventBus.on('bar', function(event, payload) {
210
- * console.log(payload);
211
- * });
212
- *
213
- * // listen for event returning value
214
- * eventBus.on('foobar', function(event) {
215
- *
216
- * // stop event propagation + prevent default
217
- * return false;
218
- *
219
- * // stop event propagation + return custom result
220
- * return {
221
- * complex: 'listening result'
222
- * };
223
- * });
224
- *
225
- *
226
- * // listen with custom priority (default=1000, higher is better)
227
- * eventBus.on('priorityfoo', 1500, function(event) {
228
- * console.log('invoked first!');
229
- * });
230
- *
231
- *
232
- * // listen for event and pass the context (`this`)
233
- * eventBus.on('foobar', function(event) {
234
- * this.foo();
235
- * }, this);
236
- * ```
237
- *
238
- *
239
- * ## Emitting Events
240
- *
241
- * Events can be emitted via the event bus using {@link EventBus#fire}.
242
- *
243
- * ```javascript
244
- *
245
- * // false indicates that the default action
246
- * // was prevented by listeners
247
- * if (eventBus.fire('foo') === false) {
248
- * console.log('default has been prevented!');
249
- * };
250
- *
251
- *
252
- * // custom args + return value listener
253
- * eventBus.on('sum', function(event, a, b) {
254
- * return a + b;
255
- * });
256
- *
257
- * // you can pass custom arguments + retrieve result values.
258
- * var sum = eventBus.fire('sum', 1, 2);
259
- * console.log(sum); // 3
260
- * ```
261
- */
262
-
263
- function EventBus() {
264
- this._listeners = {}; // cleanup on destroy on lowest priority to allow
265
- // message passing until the bitter end
266
-
267
- this.on('diagram.destroy', 1, this._destroy, this);
268
- }
269
- /**
270
- * Register an event listener for events with the given name.
271
- *
272
- * The callback will be invoked with `event, ...additionalArguments`
273
- * that have been passed to {@link EventBus#fire}.
274
- *
275
- * Returning false from a listener will prevent the events default action
276
- * (if any is specified). To stop an event from being processed further in
277
- * other listeners execute {@link Event#stopPropagation}.
278
- *
279
- * Returning anything but `undefined` from a listener will stop the listener propagation.
280
- *
281
- * @param {string|Array<string>} events
282
- * @param {number} [priority=1000] the priority in which this listener is called, larger is higher
283
- * @param {Function} callback
284
- * @param {Object} [that] Pass context (`this`) to the callback
285
- */
286
-
287
- EventBus.prototype.on = function (events, priority, callback, that) {
288
- events = minDash.isArray(events) ? events : [events];
289
-
290
- if (minDash.isFunction(priority)) {
291
- that = callback;
292
- callback = priority;
293
- priority = DEFAULT_PRIORITY$1;
294
- }
295
-
296
- if (!minDash.isNumber(priority)) {
297
- throw new Error('priority must be a number');
298
- }
299
-
300
- var actualCallback = callback;
301
-
302
- if (that) {
303
- actualCallback = minDash.bind(callback, that); // make sure we remember and are able to remove
304
- // bound callbacks via {@link #off} using the original
305
- // callback
306
-
307
- actualCallback[FN_REF] = callback[FN_REF] || callback;
308
- }
309
-
310
- var self = this;
311
- events.forEach(function (e) {
312
- self._addListener(e, {
313
- priority: priority,
314
- callback: actualCallback,
315
- next: null
316
- });
317
- });
318
- };
319
- /**
320
- * Register an event listener that is executed only once.
321
- *
322
- * @param {string} event the event name to register for
323
- * @param {number} [priority=1000] the priority in which this listener is called, larger is higher
324
- * @param {Function} callback the callback to execute
325
- * @param {Object} [that] Pass context (`this`) to the callback
326
- */
327
-
328
-
329
- EventBus.prototype.once = function (event, priority, callback, that) {
330
- var self = this;
331
-
332
- if (minDash.isFunction(priority)) {
333
- that = callback;
334
- callback = priority;
335
- priority = DEFAULT_PRIORITY$1;
336
- }
337
-
338
- if (!minDash.isNumber(priority)) {
339
- throw new Error('priority must be a number');
340
- }
341
-
342
- function wrappedCallback() {
343
- wrappedCallback.__isTomb = true;
344
- var result = callback.apply(that, arguments);
345
- self.off(event, wrappedCallback);
346
- return result;
347
- } // make sure we remember and are able to remove
348
- // bound callbacks via {@link #off} using the original
349
- // callback
350
-
351
-
352
- wrappedCallback[FN_REF] = callback;
353
- this.on(event, priority, wrappedCallback);
354
- };
355
- /**
356
- * Removes event listeners by event and callback.
357
- *
358
- * If no callback is given, all listeners for a given event name are being removed.
359
- *
360
- * @param {string|Array<string>} events
361
- * @param {Function} [callback]
362
- */
363
-
364
-
365
- EventBus.prototype.off = function (events, callback) {
366
- events = minDash.isArray(events) ? events : [events];
367
- var self = this;
368
- events.forEach(function (event) {
369
- self._removeListener(event, callback);
370
- });
371
- };
372
- /**
373
- * Create an EventBus event.
374
- *
375
- * @param {Object} data
376
- *
377
- * @return {Object} event, recognized by the eventBus
378
- */
379
-
380
-
381
- EventBus.prototype.createEvent = function (data) {
382
- var event = new InternalEvent();
383
- event.init(data);
384
- return event;
385
- };
386
- /**
387
- * Fires a named event.
388
- *
389
- * @example
390
- *
391
- * // fire event by name
392
- * events.fire('foo');
393
- *
394
- * // fire event object with nested type
395
- * var event = { type: 'foo' };
396
- * events.fire(event);
397
- *
398
- * // fire event with explicit type
399
- * var event = { x: 10, y: 20 };
400
- * events.fire('element.moved', event);
401
- *
402
- * // pass additional arguments to the event
403
- * events.on('foo', function(event, bar) {
404
- * alert(bar);
405
- * });
406
- *
407
- * events.fire({ type: 'foo' }, 'I am bar!');
408
- *
409
- * @param {string} [name] the optional event name
410
- * @param {Object} [event] the event object
411
- * @param {...Object} additional arguments to be passed to the callback functions
412
- *
413
- * @return {boolean} the events return value, if specified or false if the
414
- * default action was prevented by listeners
415
- */
416
-
417
-
418
- EventBus.prototype.fire = function (type, data) {
419
- var event, firstListener, returnValue, args;
420
- args = slice.call(arguments);
421
-
422
- if (typeof type === 'object') {
423
- data = type;
424
- type = data.type;
425
- }
426
-
427
- if (!type) {
428
- throw new Error('no event type specified');
429
- }
430
-
431
- firstListener = this._listeners[type];
432
-
433
- if (!firstListener) {
434
- return;
435
- } // we make sure we fire instances of our home made
436
- // events here. We wrap them only once, though
437
-
438
-
439
- if (data instanceof InternalEvent) {
440
- // we are fine, we alread have an event
441
- event = data;
442
- } else {
443
- event = this.createEvent(data);
444
- } // ensure we pass the event as the first parameter
445
-
446
-
447
- args[0] = event; // original event type (in case we delegate)
448
-
449
- var originalType = event.type; // update event type before delegation
450
-
451
- if (type !== originalType) {
452
- event.type = type;
453
- }
454
-
455
- try {
456
- returnValue = this._invokeListeners(event, args, firstListener);
457
- } finally {
458
- // reset event type after delegation
459
- if (type !== originalType) {
460
- event.type = originalType;
461
- }
462
- } // set the return value to false if the event default
463
- // got prevented and no other return value exists
464
-
465
-
466
- if (returnValue === undefined && event.defaultPrevented) {
467
- returnValue = false;
468
- }
469
-
470
- return returnValue;
471
- };
472
-
473
- EventBus.prototype.handleError = function (error) {
474
- return this.fire('error', {
475
- error: error
476
- }) === false;
477
- };
478
-
479
- EventBus.prototype._destroy = function () {
480
- this._listeners = {};
481
- };
482
-
483
- EventBus.prototype._invokeListeners = function (event, args, listener) {
484
- var returnValue;
485
-
486
- while (listener) {
487
- // handle stopped propagation
488
- if (event.cancelBubble) {
489
- break;
490
- }
491
-
492
- returnValue = this._invokeListener(event, args, listener);
493
- listener = listener.next;
494
- }
495
-
496
- return returnValue;
497
- };
498
-
499
- EventBus.prototype._invokeListener = function (event, args, listener) {
500
- var returnValue;
501
-
502
- if (listener.callback.__isTomb) {
503
- return returnValue;
504
- }
505
-
506
- try {
507
- // returning false prevents the default action
508
- returnValue = invokeFunction(listener.callback, args); // stop propagation on return value
509
-
510
- if (returnValue !== undefined) {
511
- event.returnValue = returnValue;
512
- event.stopPropagation();
513
- } // prevent default on return false
514
-
515
-
516
- if (returnValue === false) {
517
- event.preventDefault();
518
- }
519
- } catch (error) {
520
- if (!this.handleError(error)) {
521
- console.error('unhandled error in event listener', error);
522
- throw error;
523
- }
524
- }
525
-
526
- return returnValue;
527
- };
528
- /*
529
- * Add new listener with a certain priority to the list
530
- * of listeners (for the given event).
531
- *
532
- * The semantics of listener registration / listener execution are
533
- * first register, first serve: New listeners will always be inserted
534
- * after existing listeners with the same priority.
535
- *
536
- * Example: Inserting two listeners with priority 1000 and 1300
537
- *
538
- * * before: [ 1500, 1500, 1000, 1000 ]
539
- * * after: [ 1500, 1500, (new=1300), 1000, 1000, (new=1000) ]
540
- *
541
- * @param {string} event
542
- * @param {Object} listener { priority, callback }
543
- */
544
-
545
-
546
- EventBus.prototype._addListener = function (event, newListener) {
547
- var listener = this._getListeners(event),
548
- previousListener; // no prior listeners
549
-
550
-
551
- if (!listener) {
552
- this._setListeners(event, newListener);
553
-
554
- return;
555
- } // ensure we order listeners by priority from
556
- // 0 (high) to n > 0 (low)
557
-
558
-
559
- while (listener) {
560
- if (listener.priority < newListener.priority) {
561
- newListener.next = listener;
562
-
563
- if (previousListener) {
564
- previousListener.next = newListener;
565
- } else {
566
- this._setListeners(event, newListener);
567
- }
568
-
569
- return;
570
- }
571
-
572
- previousListener = listener;
573
- listener = listener.next;
574
- } // add new listener to back
575
-
576
-
577
- previousListener.next = newListener;
578
- };
579
-
580
- EventBus.prototype._getListeners = function (name) {
581
- return this._listeners[name];
582
- };
583
-
584
- EventBus.prototype._setListeners = function (name, listener) {
585
- this._listeners[name] = listener;
586
- };
587
-
588
- EventBus.prototype._removeListener = function (event, callback) {
589
- var listener = this._getListeners(event),
590
- nextListener,
591
- previousListener,
592
- listenerCallback;
593
-
594
- if (!callback) {
595
- // clear listeners
596
- this._setListeners(event, null);
597
-
598
- return;
599
- }
600
-
601
- while (listener) {
602
- nextListener = listener.next;
603
- listenerCallback = listener.callback;
604
-
605
- if (listenerCallback === callback || listenerCallback[FN_REF] === callback) {
606
- if (previousListener) {
607
- previousListener.next = nextListener;
608
- } else {
609
- // new first listener
610
- this._setListeners(event, nextListener);
611
- }
612
- }
613
-
614
- previousListener = listener;
615
- listener = nextListener;
616
- }
617
- };
618
- /**
619
- * A event that is emitted via the event bus.
620
- */
621
-
622
-
623
- function InternalEvent() {}
624
-
625
- InternalEvent.prototype.stopPropagation = function () {
626
- this.cancelBubble = true;
627
- };
628
-
629
- InternalEvent.prototype.preventDefault = function () {
630
- this.defaultPrevented = true;
631
- };
632
-
633
- InternalEvent.prototype.init = function (data) {
634
- minDash.assign(this, data || {});
635
- };
636
- /**
637
- * Invoke function. Be fast...
638
- *
639
- * @param {Function} fn
640
- * @param {Array<Object>} args
641
- *
642
- * @return {Any}
643
- */
644
-
645
-
646
- function invokeFunction(fn, args) {
647
- return fn.apply(null, args);
648
- }
649
-
650
177
  /**
651
178
  * @typedef {Function} <propertiesPanel.showEntry> callback
652
179
  *
@@ -661,9 +188,8 @@ function invokeFunction(fn, args) {
661
188
  *
662
189
  * @returns void
663
190
  */
664
- const eventBus = new EventBus();
665
191
  const EventContext = preact.createContext({
666
- eventBus
192
+ eventBus: null
667
193
  });
668
194
 
669
195
  const LayoutContext = preact.createContext({
@@ -684,7 +210,7 @@ const LayoutContext = preact.createContext({
684
210
  * ```
685
211
  *
686
212
  * @param {string} id
687
- * @param {djs.model.Base} element
213
+ * @param {object} element
688
214
  *
689
215
  * @returns {string}
690
216
  */
@@ -712,9 +238,13 @@ function useEvent(event, callback, priority = DEFAULT_PRIORITY) {
712
238
  eventBus
713
239
  } = hooks.useContext(EventContext);
714
240
  hooks.useEffect(() => {
241
+ if (!eventBus) {
242
+ return;
243
+ }
244
+
715
245
  eventBus.on(event, priority, callback);
716
246
  return () => eventBus.off(event, callback);
717
- }, [event, eventBus, callback, priority]);
247
+ }, [callback, event, eventBus, priority]);
718
248
  }
719
249
 
720
250
  const HIGH_PRIORITY = 10000;
@@ -920,7 +450,10 @@ function useShowErrorEvent(show) {
920
450
  setTemporaryError(null);
921
451
 
922
452
  if (show(event)) {
923
- eventBus.fire('propertiesPanel.showEntry', event);
453
+ if (eventBus) {
454
+ eventBus.fire('propertiesPanel.showEntry', event);
455
+ }
456
+
924
457
  setTemporaryError(event.message);
925
458
  }
926
459
  }, [show]);
@@ -928,6 +461,57 @@ function useShowErrorEvent(show) {
928
461
  return temporaryError;
929
462
  }
930
463
 
464
+ /**
465
+ * @callback setSticky
466
+ * @param {boolean} value
467
+ */
468
+
469
+ /**
470
+ * Use IntersectionObserver to identify when DOM element is in sticky mode.
471
+ * If sticky is observered setSticky(true) will be called.
472
+ * If sticky mode is left, setSticky(false) will be called.
473
+ *
474
+ *
475
+ * @param {Object} ref
476
+ * @param {string} scrollContainerSelector
477
+ * @param {setSticky} setSticky
478
+ */
479
+
480
+ function useStickyIntersectionObserver(ref, scrollContainerSelector, setSticky) {
481
+ hooks.useEffect(() => {
482
+ // return early if IntersectionObserver is not available
483
+ if (!IntersectionObserver) {
484
+ return;
485
+ }
486
+
487
+ let observer;
488
+
489
+ if (ref.current) {
490
+ const scrollContainer = minDom.query(scrollContainerSelector);
491
+ observer = new IntersectionObserver(entries => {
492
+ if (entries[0].intersectionRatio < 1) {
493
+ setSticky(true);
494
+ } else if (entries[0].intersectionRatio === 1) {
495
+ setSticky(false);
496
+ }
497
+ }, {
498
+ root: scrollContainer,
499
+ rootMargin: '0px 0px 999999% 0px',
500
+ // Use bottom margin to avoid stickyness when scrolling out to bottom
501
+ threshold: [1]
502
+ });
503
+ observer.observe(ref.current);
504
+ } // Unobserve if unmounted
505
+
506
+
507
+ return () => {
508
+ if (ref.current && observer) {
509
+ observer.unobserve(ref.current);
510
+ }
511
+ };
512
+ }, [ref]);
513
+ }
514
+
931
515
  function Group(props) {
932
516
  const {
933
517
  element,
@@ -936,12 +520,14 @@ function Group(props) {
936
520
  label,
937
521
  shouldOpen = false
938
522
  } = props;
523
+ const groupRef = hooks.useRef(null);
939
524
  const [open, setOpen] = useLayoutState(['groups', id, 'open'], shouldOpen);
940
525
  const onShow = hooks.useCallback(() => setOpen(true), [setOpen]);
941
526
 
942
527
  const toggleOpen = () => setOpen(!open);
943
528
 
944
- const [edited, setEdited] = hooks.useState(false); // set edited state depending on all entries
529
+ const [edited, setEdited] = hooks.useState(false);
530
+ const [sticky, setSticky] = hooks.useState(false); // set edited state depending on all entries
945
531
 
946
532
  hooks.useEffect(() => {
947
533
  const hasOneEditedEntry = entries.find(entry => {
@@ -959,15 +545,18 @@ function Group(props) {
959
545
  return isEdited(inputNode);
960
546
  });
961
547
  setEdited(hasOneEditedEntry);
962
- }, [entries]);
548
+ }, [entries]); // set css class when group is sticky to top
549
+
550
+ useStickyIntersectionObserver(groupRef, 'div.bio-properties-panel-scroll-container', setSticky);
963
551
  const propertiesPanelContext = { ...hooks.useContext(LayoutContext),
964
552
  onShow
965
553
  };
966
554
  return jsxRuntime.jsxs("div", {
967
555
  class: "bio-properties-panel-group",
968
556
  "data-group-id": 'group-' + id,
557
+ ref: groupRef,
969
558
  children: [jsxRuntime.jsxs("div", {
970
- class: classnames__default["default"]('bio-properties-panel-group-header', edited ? '' : 'empty', open ? 'open' : ''),
559
+ class: classnames__default["default"]('bio-properties-panel-group-header', edited ? '' : 'empty', open ? 'open' : '', sticky && open ? 'sticky' : ''),
971
560
  onClick: toggleOpen,
972
561
  children: [jsxRuntime.jsx("div", {
973
562
  title: label,
@@ -1009,6 +598,33 @@ function DataMarker() {
1009
598
  });
1010
599
  }
1011
600
 
601
+ /**
602
+ * @typedef { {
603
+ * text: (element: object) => string,
604
+ * icon?: (element: Object) => import('preact').Component
605
+ * } } PlaceholderDefinition
606
+ *
607
+ * @param { PlaceholderDefinition } props
608
+ */
609
+ function Placeholder(props) {
610
+ const {
611
+ text,
612
+ icon: Icon
613
+ } = props;
614
+ return jsxRuntime.jsx("div", {
615
+ class: "bio-properties-panel open",
616
+ children: jsxRuntime.jsxs("section", {
617
+ class: "bio-properties-panel-placeholder",
618
+ children: [Icon && jsxRuntime.jsx(Icon, {
619
+ class: "bio-properties-panel-placeholder-icon"
620
+ }), jsxRuntime.jsx("p", {
621
+ class: "bio-properties-panel-placeholder-text",
622
+ children: text
623
+ })]
624
+ })
625
+ });
626
+ }
627
+
1012
628
  const DEFAULT_LAYOUT = {
1013
629
  open: true
1014
630
  };
@@ -1055,10 +671,15 @@ const bufferedEvents = ['propertiesPanel.showEntry', 'propertiesPanel.showError'
1055
671
  *
1056
672
  * @callback { {
1057
673
  * @param {string} id
1058
- * @param {djs.model.base} element
674
+ * @param {Object} element
1059
675
  * @returns {string}
1060
676
  * } } GetDescriptionFunction
1061
677
  *
678
+ * @typedef { {
679
+ * getEmpty: (element: object) => import('./components/Placeholder').PlaceholderDefinition,
680
+ * getMultiple: (element: Object) => import('./components/Placeholder').PlaceholderDefinition
681
+ * } } PlaceholderProvider
682
+ *
1062
683
  */
1063
684
 
1064
685
  /**
@@ -1066,19 +687,22 @@ const bufferedEvents = ['propertiesPanel.showEntry', 'propertiesPanel.showError'
1066
687
  * data from implementor to describe *what* will be rendered.
1067
688
  *
1068
689
  * @param {Object} props
1069
- * @param {Object} props.element
690
+ * @param {Object|Array} props.element
1070
691
  * @param {import('./components/Header').HeaderProvider} props.headerProvider
692
+ * @param {PlaceholderProvider} [props.placeholderProvider]
1071
693
  * @param {Array<GroupDefinition|ListGroupDefinition>} props.groups
1072
694
  * @param {Object} [props.layoutConfig]
1073
695
  * @param {Function} [props.layoutChanged]
1074
696
  * @param {DescriptionConfig} [props.descriptionConfig]
1075
697
  * @param {Function} [props.descriptionLoaded]
698
+ * @param {Object} [props.eventBus]
1076
699
  */
1077
700
 
1078
701
  function PropertiesPanel(props) {
1079
702
  const {
1080
703
  element,
1081
704
  headerProvider,
705
+ placeholderProvider,
1082
706
  groups,
1083
707
  layoutConfig = {},
1084
708
  layoutChanged,
@@ -1131,12 +755,16 @@ function PropertiesPanel(props) {
1131
755
  };
1132
756
  const propertiesPanelContext = {
1133
757
  element
1134
- };
758
+ }; // empty state
1135
759
 
1136
- if (!element) {
1137
- return jsxRuntime.jsx("div", {
1138
- class: "bio-properties-panel-placeholder",
1139
- children: "Select an element to edit its properties."
760
+ if (placeholderProvider && !element) {
761
+ return jsxRuntime.jsx(Placeholder, { ...placeholderProvider.getEmpty()
762
+ });
763
+ } // multiple state
764
+
765
+
766
+ if (placeholderProvider && minDash.isArray(element)) {
767
+ return jsxRuntime.jsx(Placeholder, { ...placeholderProvider.getMultiple()
1140
768
  });
1141
769
  }
1142
770
 
@@ -1408,7 +1036,9 @@ function ListGroup(props) {
1408
1036
  shouldOpen = true,
1409
1037
  shouldSort = true
1410
1038
  } = props;
1039
+ const groupRef = hooks.useRef(null);
1411
1040
  const [open, setOpen] = useLayoutState(['groups', id, 'open'], false);
1041
+ const [sticky, setSticky] = hooks.useState(false);
1412
1042
  const onShow = hooks.useCallback(() => setOpen(true), [setOpen]);
1413
1043
  const [ordering, setOrdering] = hooks.useState([]);
1414
1044
  const [newItemAdded, setNewItemAdded] = hooks.useState(false);
@@ -1479,7 +1109,9 @@ function ListGroup(props) {
1479
1109
  });
1480
1110
  setOrdering(keep);
1481
1111
  }
1482
- }, [items, shouldHandleEffects]);
1112
+ }, [items, shouldHandleEffects]); // set css class when group is sticky to top
1113
+
1114
+ useStickyIntersectionObserver(groupRef, 'div.bio-properties-panel-scroll-container', setSticky);
1483
1115
 
1484
1116
  const toggleOpen = () => setOpen(!open);
1485
1117
 
@@ -1490,8 +1122,9 @@ function ListGroup(props) {
1490
1122
  return jsxRuntime.jsxs("div", {
1491
1123
  class: "bio-properties-panel-group",
1492
1124
  "data-group-id": 'group-' + id,
1125
+ ref: groupRef,
1493
1126
  children: [jsxRuntime.jsxs("div", {
1494
- class: classnames__default["default"]('bio-properties-panel-group-header', hasItems ? '' : 'empty', hasItems && open ? 'open' : ''),
1127
+ class: classnames__default["default"]('bio-properties-panel-group-header', hasItems ? '' : 'empty', hasItems && open ? 'open' : '', sticky && open ? 'sticky' : ''),
1495
1128
  onClick: hasItems ? toggleOpen : noop$3,
1496
1129
  children: [jsxRuntime.jsx("div", {
1497
1130
  title: label,
@@ -2494,6 +2127,7 @@ exports.ListEntry = List;
2494
2127
  exports.ListGroup = ListGroup;
2495
2128
  exports.ListItem = ListItem;
2496
2129
  exports.NumberFieldEntry = NumberFieldEntry;
2130
+ exports.Placeholder = Placeholder;
2497
2131
  exports.PropertiesPanel = PropertiesPanel;
2498
2132
  exports.PropertiesPanelContext = LayoutContext;
2499
2133
  exports.SelectEntry = SelectEntry;
@@ -2516,4 +2150,5 @@ exports.useLayoutState = useLayoutState;
2516
2150
  exports.usePrevious = usePrevious;
2517
2151
  exports.useShowEntryEvent = useShowEntryEvent;
2518
2152
  exports.useShowErrorEvent = useShowErrorEvent;
2153
+ exports.useStickyIntersectionObserver = useStickyIntersectionObserver;
2519
2154
  //# sourceMappingURL=index.js.map