@bpmn-io/properties-panel 0.12.0 → 0.13.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
@@ -5,36 +5,135 @@ Object.defineProperty(exports, '__esModule', { value: true });
5
5
  var hooks = require('../preact/hooks');
6
6
  var minDash = require('min-dash');
7
7
  var classnames = require('classnames');
8
+ require('../preact/compat');
8
9
  var jsxRuntime = require('../preact/jsx-runtime');
9
10
  var minDom = require('min-dom');
10
11
  var preact = require('../preact');
11
- require('../preact/compat');
12
12
 
13
13
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
14
14
 
15
15
  var classnames__default = /*#__PURE__*/_interopDefaultLegacy(classnames);
16
16
 
17
- /**
18
- * @typedef { { getElementLabel: Function, getTypeLabel: Function, getElementIcon: Function } } HeaderProvider
19
- */
17
+ var ArrowIcon = function ArrowIcon(props) {
18
+ return jsxRuntime.jsx("svg", { ...props,
19
+ children: jsxRuntime.jsx("path", {
20
+ fillRule: "evenodd",
21
+ d: "m11.657 8-4.95 4.95a1 1 0 0 1-1.414-1.414L8.828 8 5.293 4.464A1 1 0 1 1 6.707 3.05L11.657 8z"
22
+ })
23
+ });
24
+ };
25
+
26
+ ArrowIcon.defaultProps = {
27
+ xmlns: "http://www.w3.org/2000/svg",
28
+ width: "16",
29
+ height: "16"
30
+ };
31
+
32
+ var CreateIcon = function CreateIcon(props) {
33
+ return jsxRuntime.jsx("svg", { ...props,
34
+ children: jsxRuntime.jsx("path", {
35
+ fillRule: "evenodd",
36
+ d: "M9 13V9h4a1 1 0 0 0 0-2H9V3a1 1 0 1 0-2 0v4H3a1 1 0 1 0 0 2h4v4a1 1 0 0 0 2 0z"
37
+ })
38
+ });
39
+ };
40
+
41
+ CreateIcon.defaultProps = {
42
+ xmlns: "http://www.w3.org/2000/svg",
43
+ width: "16",
44
+ height: "16"
45
+ };
46
+
47
+ var DeleteIcon = function DeleteIcon(props) {
48
+ return jsxRuntime.jsx("svg", { ...props,
49
+ children: jsxRuntime.jsx("path", {
50
+ fillRule: "evenodd",
51
+ d: "M12 6v7c0 1.1-.4 1.55-1.5 1.55h-5C4.4 14.55 4 14.1 4 13V6h8zm-1.5 1.5h-5v4.3c0 .66.5 1.2 1.111 1.2H9.39c.611 0 1.111-.54 1.111-1.2V7.5zM13 3h-2l-1-1H6L5 3H3v1.5h10V3z"
52
+ })
53
+ });
54
+ };
55
+
56
+ DeleteIcon.defaultProps = {
57
+ xmlns: "http://www.w3.org/2000/svg",
58
+ width: "16",
59
+ height: "16"
60
+ };
61
+
62
+ var ExternalLinkIcon = function ExternalLinkIcon(props) {
63
+ return jsxRuntime.jsx("svg", { ...props,
64
+ children: jsxRuntime.jsx("path", {
65
+ fillRule: "evenodd",
66
+ clipRule: "evenodd",
67
+ d: "M12.637 12.637v-4.72h1.362v4.721c0 .36-.137.676-.411.95-.275.275-.591.412-.95.412H3.362c-.38 0-.703-.132-.967-.396A1.315 1.315 0 0 1 2 12.638V3.362c0-.38.132-.703.396-.967S2.982 2 3.363 2h4.553v1.363H3.363v9.274h9.274zM14 2H9.28l-.001 1.362h2.408L5.065 9.984l.95.95 6.622-6.622v2.409H14V2z",
68
+ fill: "#818798"
69
+ })
70
+ });
71
+ };
72
+
73
+ ExternalLinkIcon.defaultProps = {
74
+ width: "16",
75
+ height: "16",
76
+ fill: "none",
77
+ xmlns: "http://www.w3.org/2000/svg"
78
+ };
79
+
80
+ var FeelRequiredIcon = function FeelRequiredIcon(props) {
81
+ return jsxRuntime.jsxs("svg", { ...props,
82
+ children: [jsxRuntime.jsx("path", {
83
+ d: "M5.8 7.06V5.95h4.307v1.11H5.8zm0 3.071v-1.11h4.307v1.11H5.8z",
84
+ fill: "#505562"
85
+ }), jsxRuntime.jsx("path", {
86
+ fillRule: "evenodd",
87
+ clipRule: "evenodd",
88
+ d: "M8 3.268A4.732 4.732 0 1 0 12.732 8H14a6 6 0 1 1-6-6v1.268z",
89
+ fill: "#505562"
90
+ }), jsxRuntime.jsx("path", {
91
+ d: "m11.28 6.072-.832-.56 1.016-1.224L10 3.848l.312-.912 1.392.584L11.632 2h1.032l-.072 1.52 1.392-.584.312.912-1.464.44 1.008 1.224-.832.552-.864-1.296-.864 1.304z",
92
+ fill: "#505562"
93
+ })]
94
+ });
95
+ };
96
+
97
+ FeelRequiredIcon.defaultProps = {
98
+ viewBox: "0 0 16 16",
99
+ fill: "none",
100
+ xmlns: "http://www.w3.org/2000/svg"
101
+ };
102
+
103
+ var FeelOptionalIcon = function FeelOptionalIcon(props) {
104
+ return jsxRuntime.jsxs("svg", { ...props,
105
+ children: [jsxRuntime.jsx("path", {
106
+ d: "M5.845 7.04V5.93h4.307v1.11H5.845zm0 3.07V9h4.307v1.11H5.845z",
107
+ fill: "#505562"
108
+ }), jsxRuntime.jsx("path", {
109
+ fillRule: "evenodd",
110
+ clipRule: "evenodd",
111
+ d: "M3.286 8a4.714 4.714 0 1 0 9.428 0 4.714 4.714 0 0 0-9.428 0zM8 2a6 6 0 1 0 0 12A6 6 0 0 0 8 2z",
112
+ fill: "#505562"
113
+ })]
114
+ });
115
+ };
116
+
117
+ FeelOptionalIcon.defaultProps = {
118
+ viewBox: "0 0 16 16",
119
+ fill: "none",
120
+ xmlns: "http://www.w3.org/2000/svg"
121
+ };
20
122
 
21
- /**
22
- * @param {Object} props
23
- * @param {Object} props.element,
24
- * @param {HeaderProvider} props.headerProvider
25
- */
26
123
  function Header(props) {
27
124
  const {
28
125
  element,
29
126
  headerProvider
30
127
  } = props;
31
128
  const {
129
+ getElementIcon,
130
+ getDocumentationRef,
32
131
  getElementLabel,
33
- getTypeLabel,
34
- getElementIcon
132
+ getTypeLabel
35
133
  } = headerProvider;
36
134
  const label = getElementLabel(element);
37
135
  const type = getTypeLabel(element);
136
+ const documentationRef = getDocumentationRef && getDocumentationRef(element);
38
137
  const ElementIcon = getElementIcon(element);
39
138
  return jsxRuntime.jsxs("div", {
40
139
  class: "bio-properties-panel-header",
@@ -51,28 +150,624 @@ function Header(props) {
51
150
  title: type,
52
151
  class: "bio-properties-panel-header-type",
53
152
  children: type
54
- }), getElementLabel(element) ? jsxRuntime.jsx("div", {
153
+ }), label ? jsxRuntime.jsx("div", {
55
154
  title: label,
56
155
  class: "bio-properties-panel-header-label",
57
156
  children: label
58
157
  }) : null]
158
+ }), jsxRuntime.jsx("div", {
159
+ class: "bio-properties-panel-header-actions",
160
+ children: documentationRef ? jsxRuntime.jsx("a", {
161
+ rel: "noopener",
162
+ class: "bio-properties-panel-header-link",
163
+ href: documentationRef,
164
+ target: "_blank",
165
+ children: jsxRuntime.jsx(ExternalLinkIcon, {})
166
+ }) : null
59
167
  })]
60
168
  });
61
169
  }
62
170
 
171
+ const DescriptionContext = preact.createContext({
172
+ description: {},
173
+ getDescriptionForId: () => {}
174
+ });
175
+
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
+ /**
651
+ * @typedef {Function} <propertiesPanel.showEntry> callback
652
+ *
653
+ * @example
654
+ *
655
+ * useEvent('propertiesPanel.showEntry', ({ focus = false, ...rest }) => {
656
+ * // ...
657
+ * });
658
+ *
659
+ * @param {Object} context
660
+ * @param {boolean} [context.focus]
661
+ *
662
+ * @returns void
663
+ */
664
+ const eventBus = new EventBus();
665
+ const EventContext = preact.createContext({
666
+ eventBus
667
+ });
668
+
669
+ const LayoutContext = preact.createContext({
670
+ layout: {},
671
+ setLayout: () => {},
672
+ getLayoutForKey: () => {},
673
+ setLayoutForKey: () => {}
674
+ });
675
+
676
+ /**
677
+ * Accesses the global DescriptionContext and returns a description for a given id and element.
678
+ *
679
+ * @example
680
+ * ```jsx
681
+ * function TextField(props) {
682
+ * const description = useDescriptionContext('input1', element);
683
+ * }
684
+ * ```
685
+ *
686
+ * @param {string} id
687
+ * @param {djs.model.Base} element
688
+ *
689
+ * @returns {string}
690
+ */
691
+
692
+ function useDescriptionContext(id, element) {
693
+ const {
694
+ getDescriptionForId
695
+ } = hooks.useContext(DescriptionContext);
696
+ return getDescriptionForId(id, element);
697
+ }
698
+
699
+ const DEFAULT_PRIORITY = 1000;
700
+ /**
701
+ * Subscribe to an event.
702
+ *
703
+ * @param {string} event
704
+ * @param {Function} callback
705
+ * @param {number} [priority]
706
+ *
707
+ * @returns {import('preact').Ref}
708
+ */
709
+
710
+ function useEvent(event, callback, priority = DEFAULT_PRIORITY) {
711
+ const {
712
+ eventBus
713
+ } = hooks.useContext(EventContext);
714
+ hooks.useEffect(() => {
715
+ eventBus.on(event, priority, callback);
716
+ return () => eventBus.off(event, callback);
717
+ }, [event, eventBus, callback, priority]);
718
+ }
719
+
720
+ const HIGH_PRIORITY = 10000;
63
721
  /**
64
- * @pinussilvestrus: we need to introduce our own hook to persist the previous
65
- * state on updates.
722
+ * Buffer events and re-fire during passive effect phase.
66
723
  *
67
- * cf. https://reactjs.org/docs/hooks-faq.html#how-to-get-the-previous-props-or-state
724
+ * @param {string[]} bufferedEvents
725
+ * @param {Object} [eventBus]
68
726
  */
69
727
 
70
- function usePrevious(value) {
71
- const ref = hooks.useRef();
728
+ function useEventBuffer(bufferedEvents, eventBus) {
729
+ const buffer = hooks.useRef([]),
730
+ buffering = hooks.useRef(true);
731
+
732
+ const createCallback = event => data => {
733
+ if (buffering.current === true) {
734
+ buffer.current.unshift([event, data]);
735
+ }
736
+ }; // (1) buffer events
737
+
738
+
72
739
  hooks.useEffect(() => {
73
- ref.current = value;
740
+ if (!eventBus) {
741
+ return;
742
+ }
743
+
744
+ const listeners = bufferedEvents.map(event => {
745
+ return [event, createCallback(event)];
746
+ });
747
+ listeners.forEach(([event, callback]) => {
748
+ eventBus.on(event, HIGH_PRIORITY, callback);
749
+ });
750
+ return () => {
751
+ listeners.forEach(([event, callback]) => {
752
+ eventBus.off(event, callback);
753
+ });
754
+ };
755
+ }, [bufferedEvents, eventBus]); // (2) re-fire events
756
+
757
+ hooks.useEffect(() => {
758
+ if (!eventBus) {
759
+ return;
760
+ }
761
+
762
+ buffering.current = false;
763
+
764
+ while (buffer.current.length) {
765
+ const [event, data] = buffer.current.pop();
766
+ eventBus.fire(event, data);
767
+ }
768
+
769
+ buffering.current = true;
74
770
  });
75
- return ref.current;
76
771
  }
77
772
 
78
773
  const KEY_LENGTH = 6;
@@ -113,18 +808,6 @@ function useKeyFactory(dependencies = []) {
113
808
  return getKey;
114
809
  }
115
810
 
116
- const DescriptionContext = preact.createContext({
117
- description: {},
118
- getDescriptionForId: () => {}
119
- });
120
-
121
- const LayoutContext = preact.createContext({
122
- layout: {},
123
- setLayout: () => {},
124
- getLayoutForKey: () => {},
125
- setLayoutForKey: () => {}
126
- });
127
-
128
811
  /**
129
812
  * Creates a state that persists in the global LayoutContext.
130
813
  *
@@ -160,124 +843,101 @@ function useLayoutState(path, defaultValue) {
160
843
  }
161
844
 
162
845
  /**
163
- * Accesses the global DescriptionContext and returns a description for a given id and element.
164
- *
165
- * @example
166
- * ```jsx
167
- * function TextField(props) {
168
- * const description = useDescriptionContext('input1', element);
169
- * }
170
- * ```
171
- *
172
- * @param {string} id
173
- * @param {djs.model.Base} element
846
+ * @pinussilvestrus: we need to introduce our own hook to persist the previous
847
+ * state on updates.
174
848
  *
175
- * @returns {string}
849
+ * cf. https://reactjs.org/docs/hooks-faq.html#how-to-get-the-previous-props-or-state
176
850
  */
177
851
 
178
- function useDescriptionContext(id, element) {
179
- const {
180
- getDescriptionForId
181
- } = hooks.useContext(DescriptionContext);
182
- return getDescriptionForId(id, element);
183
- }
184
-
185
- var ArrowIcon = function ArrowIcon(props) {
186
- return jsxRuntime.jsx("svg", { ...props,
187
- children: jsxRuntime.jsx("path", {
188
- fillRule: "evenodd",
189
- d: "m11.657 8-4.95 4.95a1 1 0 0 1-1.414-1.414L8.828 8 5.293 4.464A1 1 0 1 1 6.707 3.05L11.657 8z"
190
- })
191
- });
192
- };
193
-
194
- ArrowIcon.defaultProps = {
195
- xmlns: "http://www.w3.org/2000/svg",
196
- width: "16",
197
- height: "16"
198
- };
199
-
200
- var CreateIcon = function CreateIcon(props) {
201
- return jsxRuntime.jsx("svg", { ...props,
202
- children: jsxRuntime.jsx("path", {
203
- fillRule: "evenodd",
204
- d: "M9 13V9h4a1 1 0 0 0 0-2H9V3a1 1 0 1 0-2 0v4H3a1 1 0 1 0 0 2h4v4a1 1 0 0 0 2 0z"
205
- })
852
+ function usePrevious(value) {
853
+ const ref = hooks.useRef();
854
+ hooks.useEffect(() => {
855
+ ref.current = value;
206
856
  });
207
- };
857
+ return ref.current;
858
+ }
208
859
 
209
- CreateIcon.defaultProps = {
210
- xmlns: "http://www.w3.org/2000/svg",
211
- width: "16",
212
- height: "16"
213
- };
860
+ /**
861
+ * Subscribe to `propertiesPanel.showEntry`.
862
+ *
863
+ * @param {Function} show
864
+ *
865
+ * @returns {import('preact').Ref}
866
+ */
214
867
 
215
- var DeleteIcon = function DeleteIcon(props) {
216
- return jsxRuntime.jsx("svg", { ...props,
217
- children: jsxRuntime.jsx("path", {
218
- fillRule: "evenodd",
219
- d: "M12 6v7c0 1.1-.4 1.55-1.5 1.55h-5C4.4 14.55 4 14.1 4 13V6h8zm-1.5 1.5h-5v4.3c0 .66.5 1.2 1.111 1.2H9.39c.611 0 1.111-.54 1.111-1.2V7.5zM13 3h-2l-1-1H6L5 3H3v1.5h10V3z"
220
- })
221
- });
222
- };
868
+ function useShowEntryEvent(show) {
869
+ const {
870
+ onShow
871
+ } = hooks.useContext(LayoutContext);
872
+ const ref = hooks.useRef();
873
+ const [focus, setFocus] = hooks.useState(false);
874
+ const onShowEntry = hooks.useCallback(event => {
875
+ if (show(event)) {
876
+ if (minDash.isFunction(onShow)) {
877
+ onShow();
878
+ }
223
879
 
224
- DeleteIcon.defaultProps = {
225
- xmlns: "http://www.w3.org/2000/svg",
226
- width: "16",
227
- height: "16"
228
- };
880
+ if (event.focus && !focus) {
881
+ setFocus(true);
882
+ }
883
+ }
884
+ }, [show]);
885
+ hooks.useEffect(() => {
886
+ if (focus && ref.current) {
887
+ if (minDash.isFunction(ref.current.focus)) {
888
+ ref.current.focus();
889
+ }
229
890
 
230
- var FeelRequiredIcon = function FeelRequiredIcon(props) {
231
- return jsxRuntime.jsxs("svg", { ...props,
232
- children: [jsxRuntime.jsx("path", {
233
- d: "M5.8 7.06V5.95h4.307v1.11H5.8zm0 3.071v-1.11h4.307v1.11H5.8z",
234
- fill: "#505562"
235
- }), jsxRuntime.jsx("path", {
236
- fillRule: "evenodd",
237
- clipRule: "evenodd",
238
- d: "M8 3.268A4.732 4.732 0 1 0 12.732 8H14a6 6 0 1 1-6-6v1.268z",
239
- fill: "#505562"
240
- }), jsxRuntime.jsx("path", {
241
- d: "m11.28 6.072-.832-.56 1.016-1.224L10 3.848l.312-.912 1.392.584L11.632 2h1.032l-.072 1.52 1.392-.584.312.912-1.464.44 1.008 1.224-.832.552-.864-1.296-.864 1.304z",
242
- fill: "#505562"
243
- })]
244
- });
245
- };
891
+ if (minDash.isFunction(ref.current.select)) {
892
+ ref.current.select();
893
+ }
246
894
 
247
- FeelRequiredIcon.defaultProps = {
248
- viewBox: "0 0 16 16",
249
- fill: "none",
250
- xmlns: "http://www.w3.org/2000/svg"
251
- };
895
+ setFocus(false);
896
+ }
897
+ }, [focus]);
898
+ useEvent('propertiesPanel.showEntry', onShowEntry);
899
+ return ref;
900
+ }
252
901
 
253
- var FeelOptionalIcon = function FeelOptionalIcon(props) {
254
- return jsxRuntime.jsxs("svg", { ...props,
255
- children: [jsxRuntime.jsx("path", {
256
- d: "M5.845 7.04V5.93h4.307v1.11H5.845zm0 3.07V9h4.307v1.11H5.845z",
257
- fill: "#505562"
258
- }), jsxRuntime.jsx("path", {
259
- fillRule: "evenodd",
260
- clipRule: "evenodd",
261
- d: "M3.286 8a4.714 4.714 0 1 0 9.428 0 4.714 4.714 0 0 0-9.428 0zM8 2a6 6 0 1 0 0 12A6 6 0 0 0 8 2z",
262
- fill: "#505562"
263
- })]
264
- });
265
- };
902
+ /**
903
+ * Subscribe to `propertiesPanel.showError`. On `propertiesPanel.showError` set
904
+ * temporary error. Fire `propertiesPanel.showEntry` for temporary error to be
905
+ * visible. Unset error on `propertiesPanel.updated`.
906
+ *
907
+ * @param {Function} show
908
+ *
909
+ * @returns {import('preact').Ref}
910
+ */
266
911
 
267
- FeelOptionalIcon.defaultProps = {
268
- viewBox: "0 0 16 16",
269
- fill: "none",
270
- xmlns: "http://www.w3.org/2000/svg"
271
- };
912
+ function useShowErrorEvent(show) {
913
+ const {
914
+ eventBus
915
+ } = hooks.useContext(EventContext);
916
+ const [temporaryError, setTemporaryError] = hooks.useState(null);
917
+ const onPropertiesPanelUpdated = hooks.useCallback(() => setTemporaryError(null), []);
918
+ useEvent('propertiesPanel.updated', onPropertiesPanelUpdated);
919
+ const onShowError = hooks.useCallback(event => {
920
+ setTemporaryError(null);
921
+
922
+ if (show(event)) {
923
+ eventBus.fire('propertiesPanel.showEntry', event);
924
+ setTemporaryError(event.message);
925
+ }
926
+ }, [show]);
927
+ useEvent('propertiesPanel.showError', onShowError);
928
+ return temporaryError;
929
+ }
272
930
 
273
931
  function Group(props) {
274
932
  const {
275
933
  element,
276
934
  entries = [],
277
935
  id,
278
- label
936
+ label,
937
+ shouldOpen = false
279
938
  } = props;
280
- const [open, setOpen] = useLayoutState(['groups', id, 'open'], false);
939
+ const [open, setOpen] = useLayoutState(['groups', id, 'open'], shouldOpen);
940
+ const onShow = hooks.useCallback(() => setOpen(true), [setOpen]);
281
941
 
282
942
  const toggleOpen = () => setOpen(!open);
283
943
 
@@ -300,6 +960,9 @@ function Group(props) {
300
960
  });
301
961
  setEdited(hasOneEditedEntry);
302
962
  }, [entries]);
963
+ const propertiesPanelContext = { ...hooks.useContext(LayoutContext),
964
+ onShow
965
+ };
303
966
  return jsxRuntime.jsxs("div", {
304
967
  class: "bio-properties-panel-group",
305
968
  "data-group-id": 'group-' + id,
@@ -322,15 +985,18 @@ function Group(props) {
322
985
  })]
323
986
  }), jsxRuntime.jsx("div", {
324
987
  class: classnames__default["default"]('bio-properties-panel-group-entries', open ? 'open' : ''),
325
- children: entries.map(entry => {
326
- const {
327
- component: Component,
328
- id
329
- } = entry;
330
- return preact.createElement(Component, { ...entry,
331
- key: id,
332
- element: element
333
- });
988
+ children: jsxRuntime.jsx(LayoutContext.Provider, {
989
+ value: propertiesPanelContext,
990
+ children: entries.map(entry => {
991
+ const {
992
+ component: Component,
993
+ id
994
+ } = entry;
995
+ return preact.createElement(Component, { ...entry,
996
+ element: element,
997
+ key: id
998
+ });
999
+ })
334
1000
  })
335
1001
  })]
336
1002
  });
@@ -347,6 +1013,7 @@ const DEFAULT_LAYOUT = {
347
1013
  open: true
348
1014
  };
349
1015
  const DEFAULT_DESCRIPTION = {};
1016
+ const bufferedEvents = ['propertiesPanel.showEntry', 'propertiesPanel.showError'];
350
1017
  /**
351
1018
  * @typedef { {
352
1019
  * component: import('preact').Component,
@@ -378,7 +1045,8 @@ const DEFAULT_DESCRIPTION = {};
378
1045
  * component?: import('preact').Component,
379
1046
  * entries: Array<EntryDefinition>,
380
1047
  * id: String,
381
- * label: String
1048
+ * label: String,
1049
+ * shouldOpen?: Boolean
382
1050
  * } } GroupDefinition
383
1051
  *
384
1052
  * @typedef { {
@@ -415,7 +1083,8 @@ function PropertiesPanel(props) {
415
1083
  layoutConfig = {},
416
1084
  layoutChanged,
417
1085
  descriptionConfig = {},
418
- descriptionLoaded
1086
+ descriptionLoaded,
1087
+ eventBus
419
1088
  } = props; // set-up layout context
420
1089
 
421
1090
  const [layout, setLayout] = hooks.useState(createLayout(layoutConfig));
@@ -456,6 +1125,13 @@ function PropertiesPanel(props) {
456
1125
  description,
457
1126
  getDescriptionForId
458
1127
  };
1128
+ useEventBuffer(bufferedEvents, eventBus);
1129
+ const eventContext = {
1130
+ eventBus
1131
+ };
1132
+ const propertiesPanelContext = {
1133
+ element
1134
+ };
459
1135
 
460
1136
  if (!element) {
461
1137
  return jsxRuntime.jsx("div", {
@@ -464,28 +1140,34 @@ function PropertiesPanel(props) {
464
1140
  });
465
1141
  }
466
1142
 
467
- return jsxRuntime.jsx(DescriptionContext.Provider, {
468
- value: descriptionContext,
469
- children: jsxRuntime.jsx(LayoutContext.Provider, {
470
- value: layoutContext,
471
- children: jsxRuntime.jsxs("div", {
472
- class: classnames__default["default"]('bio-properties-panel', layout.open ? 'open' : ''),
473
- children: [jsxRuntime.jsx(Header, {
474
- element: element,
475
- headerProvider: headerProvider
476
- }), jsxRuntime.jsx("div", {
477
- class: "bio-properties-panel-scroll-container",
478
- children: groups.map(group => {
479
- const {
480
- component: Component = Group,
481
- id
482
- } = group;
483
- return preact.createElement(Component, { ...group,
484
- key: id,
485
- element: element
486
- });
1143
+ return jsxRuntime.jsx(LayoutContext.Provider, {
1144
+ value: propertiesPanelContext,
1145
+ children: jsxRuntime.jsx(DescriptionContext.Provider, {
1146
+ value: descriptionContext,
1147
+ children: jsxRuntime.jsx(LayoutContext.Provider, {
1148
+ value: layoutContext,
1149
+ children: jsxRuntime.jsx(EventContext.Provider, {
1150
+ value: eventContext,
1151
+ children: jsxRuntime.jsxs("div", {
1152
+ class: classnames__default["default"]('bio-properties-panel', layout.open ? 'open' : ''),
1153
+ children: [jsxRuntime.jsx(Header, {
1154
+ element: element,
1155
+ headerProvider: headerProvider
1156
+ }), jsxRuntime.jsx("div", {
1157
+ class: "bio-properties-panel-scroll-container",
1158
+ children: groups.map(group => {
1159
+ const {
1160
+ component: Component = Group,
1161
+ id
1162
+ } = group;
1163
+ return preact.createElement(Component, { ...group,
1164
+ key: id,
1165
+ element: element
1166
+ });
1167
+ })
1168
+ })]
487
1169
  })
488
- })]
1170
+ })
489
1171
  })
490
1172
  })
491
1173
  });
@@ -625,8 +1307,20 @@ function CollapsibleEntry(props) {
625
1307
  } = props;
626
1308
  const [open, setOpen] = hooks.useState(shouldOpen);
627
1309
 
628
- const toggleOpen = () => setOpen(!open); // todo(pinussilvestrus): translate once we have a translate mechanism for the core
1310
+ const toggleOpen = () => setOpen(!open);
1311
+
1312
+ const {
1313
+ onShow
1314
+ } = hooks.useContext(LayoutContext);
1315
+ const propertiesPanelContext = { ...hooks.useContext(LayoutContext),
1316
+ onShow: hooks.useCallback(() => {
1317
+ setOpen(true);
629
1318
 
1319
+ if (minDash.isFunction(onShow)) {
1320
+ onShow();
1321
+ }
1322
+ }, [onShow, setOpen])
1323
+ }; // todo(pinussilvestrus): translate once we have a translate mechanism for the core
630
1324
 
631
1325
  const placeholderLabel = '<empty>';
632
1326
  return jsxRuntime.jsxs("div", {
@@ -653,15 +1347,18 @@ function CollapsibleEntry(props) {
653
1347
  }) : null]
654
1348
  }), jsxRuntime.jsx("div", {
655
1349
  class: classnames__default["default"]('bio-properties-panel-collapsible-entry-entries', open ? 'open' : ''),
656
- children: entries.map(entry => {
657
- const {
658
- component: Component,
659
- id
660
- } = entry;
661
- return preact.createElement(Component, { ...entry,
662
- key: id,
663
- element: element
664
- });
1350
+ children: jsxRuntime.jsx(LayoutContext.Provider, {
1351
+ value: propertiesPanelContext,
1352
+ children: entries.map(entry => {
1353
+ const {
1354
+ component: Component,
1355
+ id
1356
+ } = entry;
1357
+ return preact.createElement(Component, { ...entry,
1358
+ element: element,
1359
+ key: id
1360
+ });
1361
+ })
665
1362
  })
666
1363
  })]
667
1364
  });
@@ -695,7 +1392,7 @@ function ListItem(props) {
695
1392
  });
696
1393
  }
697
1394
 
698
- const noop = () => {};
1395
+ const noop$3 = () => {};
699
1396
  /**
700
1397
  * @param {import('../PropertiesPanel').ListGroupDefinition} props
701
1398
  */
@@ -712,6 +1409,7 @@ function ListGroup(props) {
712
1409
  shouldSort = true
713
1410
  } = props;
714
1411
  const [open, setOpen] = useLayoutState(['groups', id, 'open'], false);
1412
+ const onShow = hooks.useCallback(() => setOpen(true), [setOpen]);
715
1413
  const [ordering, setOrdering] = hooks.useState([]);
716
1414
  const [newItemAdded, setNewItemAdded] = hooks.useState(false);
717
1415
  const prevItems = usePrevious(items);
@@ -786,12 +1484,15 @@ function ListGroup(props) {
786
1484
  const toggleOpen = () => setOpen(!open);
787
1485
 
788
1486
  const hasItems = !!items.length;
1487
+ const propertiesPanelContext = { ...hooks.useContext(LayoutContext),
1488
+ onShow
1489
+ };
789
1490
  return jsxRuntime.jsxs("div", {
790
1491
  class: "bio-properties-panel-group",
791
1492
  "data-group-id": 'group-' + id,
792
1493
  children: [jsxRuntime.jsxs("div", {
793
1494
  class: classnames__default["default"]('bio-properties-panel-group-header', hasItems ? '' : 'empty', hasItems && open ? 'open' : ''),
794
- onClick: hasItems ? toggleOpen : noop,
1495
+ onClick: hasItems ? toggleOpen : noop$3,
795
1496
  children: [jsxRuntime.jsx("div", {
796
1497
  title: label,
797
1498
  class: "bio-properties-panel-group-header-title",
@@ -820,23 +1521,27 @@ function ListGroup(props) {
820
1521
  })]
821
1522
  }), jsxRuntime.jsx("div", {
822
1523
  class: classnames__default["default"]('bio-properties-panel-list', open && hasItems ? 'open' : ''),
823
- children: ordering.map((o, index) => {
824
- const item = getItem(items, o);
825
-
826
- if (!item) {
827
- return;
828
- }
829
-
830
- const {
831
- id
832
- } = item;
833
- return preact.createElement(ListItem, { ...item,
834
- element: element,
835
- index: index,
836
- key: id // if item was added, open first or last item based on ordering
837
- ,
838
- autoOpen: newItemAdded && (shouldSort ? index === 0 : index === ordering.length - 1)
839
- });
1524
+ children: jsxRuntime.jsx(LayoutContext.Provider, {
1525
+ value: propertiesPanelContext,
1526
+ children: ordering.map((o, index) => {
1527
+ const item = getItem(items, o);
1528
+
1529
+ if (!item) {
1530
+ return;
1531
+ }
1532
+
1533
+ const {
1534
+ id
1535
+ } = item; // if item was added, open first or last item based on ordering
1536
+
1537
+ const autoOpen = newItemAdded && (shouldSort ? index === 0 : index === ordering.length - 1);
1538
+ return preact.createElement(ListItem, { ...item,
1539
+ autoOpen: autoOpen,
1540
+ element: element,
1541
+ index: index,
1542
+ key: id
1543
+ });
1544
+ })
840
1545
  })
841
1546
  })]
842
1547
  });
@@ -875,13 +1580,16 @@ function Description(props) {
875
1580
  }
876
1581
  }
877
1582
 
1583
+ const noop$2 = () => {};
1584
+
878
1585
  function Checkbox(props) {
879
1586
  const {
880
1587
  id,
881
1588
  label,
882
1589
  onChange,
883
1590
  disabled,
884
- value = false
1591
+ value = false,
1592
+ show = noop$2
885
1593
  } = props;
886
1594
 
887
1595
  const handleChange = ({
@@ -890,9 +1598,11 @@ function Checkbox(props) {
890
1598
  onChange(target.checked);
891
1599
  };
892
1600
 
1601
+ const ref = useShowEntryEvent(show);
893
1602
  return jsxRuntime.jsxs("div", {
894
1603
  class: "bio-properties-panel-checkbox",
895
1604
  children: [jsxRuntime.jsx("input", {
1605
+ ref: ref,
896
1606
  id: prefixId$6(id),
897
1607
  name: id,
898
1608
  type: "checkbox",
@@ -927,18 +1637,24 @@ function CheckboxEntry(props) {
927
1637
  label,
928
1638
  getValue,
929
1639
  setValue,
930
- disabled
1640
+ disabled,
1641
+ show = noop$2
931
1642
  } = props;
932
1643
  const value = getValue(element);
1644
+ const error = useShowErrorEvent(show);
933
1645
  return jsxRuntime.jsxs("div", {
934
1646
  class: "bio-properties-panel-entry bio-properties-panel-checkbox-entry",
935
1647
  "data-entry-id": id,
936
1648
  children: [jsxRuntime.jsx(Checkbox, {
1649
+ disabled: disabled,
937
1650
  id: id,
938
1651
  label: label,
939
1652
  onChange: setValue,
940
- value: value,
941
- disabled: disabled
1653
+ show: show,
1654
+ value: value
1655
+ }), error && jsxRuntime.jsx("div", {
1656
+ class: "bio-properties-panel-error",
1657
+ children: error
942
1658
  }), jsxRuntime.jsx(Description, {
943
1659
  forId: id,
944
1660
  element: element,
@@ -1245,6 +1961,25 @@ function prefixId$5(id) {
1245
1961
  return `bio-properties-panel-${id}`;
1246
1962
  }
1247
1963
 
1964
+ const noop$1 = () => {};
1965
+ /**
1966
+ * @typedef { { value: string, label: string, disabled: boolean } } Option
1967
+ */
1968
+
1969
+ /**
1970
+ * Provides basic select input.
1971
+ *
1972
+ * @param {object} props
1973
+ * @param {string} props.id
1974
+ * @param {string[]} props.path
1975
+ * @param {string} props.label
1976
+ * @param {Function} props.onChange
1977
+ * @param {Array<Option>} [props.options]
1978
+ * @param {string} props.value
1979
+ * @param {boolean} [props.disabled]
1980
+ */
1981
+
1982
+
1248
1983
  function Select(props) {
1249
1984
  const {
1250
1985
  id,
@@ -1252,8 +1987,10 @@ function Select(props) {
1252
1987
  onChange,
1253
1988
  options = [],
1254
1989
  value,
1255
- disabled
1990
+ disabled,
1991
+ show = noop$1
1256
1992
  } = props;
1993
+ const ref = useShowEntryEvent(show);
1257
1994
 
1258
1995
  const handleChange = ({
1259
1996
  target
@@ -1268,6 +2005,7 @@ function Select(props) {
1268
2005
  class: "bio-properties-panel-label",
1269
2006
  children: label
1270
2007
  }), jsxRuntime.jsx("select", {
2008
+ ref: ref,
1271
2009
  id: prefixId$4(id),
1272
2010
  name: id,
1273
2011
  class: "bio-properties-panel-input",
@@ -1306,12 +2044,14 @@ function SelectEntry(props) {
1306
2044
  getValue,
1307
2045
  setValue,
1308
2046
  getOptions,
1309
- disabled
2047
+ disabled,
2048
+ show = noop$1
1310
2049
  } = props;
1311
2050
  const value = getValue(element);
1312
2051
  const options = getOptions(element);
2052
+ const error = useShowErrorEvent(show);
1313
2053
  return jsxRuntime.jsxs("div", {
1314
- class: "bio-properties-panel-entry",
2054
+ class: classnames__default["default"]('bio-properties-panel-entry', error ? 'has-error' : ''),
1315
2055
  "data-entry-id": id,
1316
2056
  children: [jsxRuntime.jsx(Select, {
1317
2057
  id: id,
@@ -1319,7 +2059,11 @@ function SelectEntry(props) {
1319
2059
  value: value,
1320
2060
  onChange: setValue,
1321
2061
  options: options,
1322
- disabled: disabled
2062
+ disabled: disabled,
2063
+ show: show
2064
+ }), error && jsxRuntime.jsx("div", {
2065
+ class: "bio-properties-panel-error",
2066
+ children: error
1323
2067
  }), jsxRuntime.jsx(Description, {
1324
2068
  forId: id,
1325
2069
  element: element,
@@ -1490,6 +2234,8 @@ function prefixId$2(id) {
1490
2234
  return `bio-properties-panel-${id}`;
1491
2235
  }
1492
2236
 
2237
+ const noop = () => {};
2238
+
1493
2239
  function Textfield(props) {
1494
2240
  const {
1495
2241
  debounce,
@@ -1498,8 +2244,10 @@ function Textfield(props) {
1498
2244
  label,
1499
2245
  onInput,
1500
2246
  feel = false,
1501
- value = ''
2247
+ value = '',
2248
+ show = noop
1502
2249
  } = props;
2250
+ const ref = useShowEntryEvent(show);
1503
2251
  const handleInput = hooks.useMemo(() => {
1504
2252
  return debounce(({
1505
2253
  target
@@ -1515,6 +2263,7 @@ function Textfield(props) {
1515
2263
  label: label
1516
2264
  })]
1517
2265
  }), jsxRuntime.jsx("input", {
2266
+ ref: ref,
1518
2267
  id: prefixId$1(id),
1519
2268
  type: "text",
1520
2269
  name: id,
@@ -1554,53 +2303,61 @@ function TextfieldEntry(props) {
1554
2303
  label,
1555
2304
  getValue,
1556
2305
  setValue,
1557
- validate
2306
+ validate,
2307
+ show = noop
1558
2308
  } = props;
1559
- const [error, setError] = hooks.useState(null);
1560
- const [invalidValueCache, setInvalidValueCache] = hooks.useState(null);
2309
+ const [cachedInvalidValue, setCachedInvalidValue] = hooks.useState(null);
2310
+ const [validationError, setValidationError] = hooks.useState(null);
1561
2311
  let value = getValue(element);
1562
- const prevValue = usePrevious(value); // validate again when value prop changed
1563
-
2312
+ const previousValue = usePrevious(value);
1564
2313
  hooks.useEffect(() => {
1565
- const err = validate ? validate(value) : null;
1566
- setError(err);
1567
- }, [value]); // validate on change
2314
+ if (minDash.isFunction(validate)) {
2315
+ const newValidationError = validate(value) || null;
2316
+ setValidationError(newValidationError);
2317
+ }
2318
+ }, [value]);
1568
2319
 
1569
- const handleChange = newValue => {
1570
- const err = validate ? validate(newValue) : null;
2320
+ const onInput = newValue => {
2321
+ let newValidationError = null;
2322
+
2323
+ if (minDash.isFunction(validate)) {
2324
+ newValidationError = validate(newValue) || null;
2325
+ }
1571
2326
 
1572
- if (err) {
1573
- setInvalidValueCache(newValue);
2327
+ if (newValidationError) {
2328
+ setCachedInvalidValue(newValue);
1574
2329
  } else {
1575
2330
  setValue(newValue);
1576
2331
  }
1577
2332
 
1578
- setError(err);
1579
- }; // keep showing invalid value on errors, although it was not set
1580
-
2333
+ setValidationError(newValidationError);
2334
+ };
1581
2335
 
1582
- if (prevValue === value && error) {
1583
- value = invalidValueCache;
2336
+ if (previousValue === value && validationError) {
2337
+ value = cachedInvalidValue;
1584
2338
  }
1585
2339
 
2340
+ const temporaryError = useShowErrorEvent(show);
2341
+ const error = temporaryError || validationError;
1586
2342
  return jsxRuntime.jsxs("div", {
1587
2343
  class: classnames__default["default"]('bio-properties-panel-entry', error ? 'has-error' : ''),
1588
2344
  "data-entry-id": id,
1589
2345
  children: [jsxRuntime.jsx(Textfield, {
1590
- id: id,
1591
- label: label,
1592
- value: value,
1593
- onInput: handleChange,
1594
2346
  debounce: debounce,
1595
2347
  disabled: disabled,
1596
- feel: feel
2348
+ feel: feel,
2349
+ id: id,
2350
+ label: label,
2351
+ onInput: onInput,
2352
+ show: show,
2353
+ value: value
2354
+ }), error && jsxRuntime.jsx("div", {
2355
+ class: "bio-properties-panel-error",
2356
+ children: error
1597
2357
  }), jsxRuntime.jsx(Description, {
1598
2358
  forId: id,
1599
2359
  element: element,
1600
2360
  value: description
1601
- }), error && jsxRuntime.jsx("div", {
1602
- class: "bio-properties-panel-error",
1603
- children: error
1604
2361
  })]
1605
2362
  });
1606
2363
  }
@@ -1725,6 +2482,8 @@ exports.DeleteIcon = DeleteIcon;
1725
2482
  exports.DescriptionContext = DescriptionContext;
1726
2483
  exports.DescriptionEntry = Description;
1727
2484
  exports.DropdownButton = DropdownButton;
2485
+ exports.EventContext = EventContext;
2486
+ exports.ExternalLinkIcon = ExternalLinkIcon;
1728
2487
  exports.FeelOptionalIcon = FeelOptionalIcon;
1729
2488
  exports.FeelRequiredIcon = FeelRequiredIcon;
1730
2489
  exports.Group = Group;
@@ -1736,6 +2495,7 @@ exports.ListGroup = ListGroup;
1736
2495
  exports.ListItem = ListItem;
1737
2496
  exports.NumberFieldEntry = NumberFieldEntry;
1738
2497
  exports.PropertiesPanel = PropertiesPanel;
2498
+ exports.PropertiesPanelContext = LayoutContext;
1739
2499
  exports.SelectEntry = SelectEntry;
1740
2500
  exports.SimpleEntry = Simple;
1741
2501
  exports.TextAreaEntry = TextAreaEntry;
@@ -1749,7 +2509,11 @@ exports.isTextAreaEntryEdited = isEdited$2;
1749
2509
  exports.isTextFieldEntryEdited = isEdited$1;
1750
2510
  exports.isToggleSwitchEntryEdited = isEdited;
1751
2511
  exports.useDescriptionContext = useDescriptionContext;
2512
+ exports.useEvent = useEvent;
2513
+ exports.useEventBuffer = useEventBuffer;
1752
2514
  exports.useKeyFactory = useKeyFactory;
1753
2515
  exports.useLayoutState = useLayoutState;
1754
2516
  exports.usePrevious = usePrevious;
2517
+ exports.useShowEntryEvent = useShowEntryEvent;
2518
+ exports.useShowErrorEvent = useShowErrorEvent;
1755
2519
  //# sourceMappingURL=index.js.map