@bpmn-io/properties-panel 0.11.0 → 0.13.1

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,154 @@ 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
+ title: "Open documentation",
165
+ target: "_blank",
166
+ children: jsxRuntime.jsx(ExternalLinkIcon, {})
167
+ }) : null
59
168
  })]
60
169
  });
61
170
  }
62
171
 
172
+ const DescriptionContext = preact.createContext({
173
+ description: {},
174
+ getDescriptionForId: () => {}
175
+ });
176
+
63
177
  /**
64
- * @pinussilvestrus: we need to introduce our own hook to persist the previous
65
- * state on updates.
178
+ * @typedef {Function} <propertiesPanel.showEntry> callback
66
179
  *
67
- * cf. https://reactjs.org/docs/hooks-faq.html#how-to-get-the-previous-props-or-state
180
+ * @example
181
+ *
182
+ * useEvent('propertiesPanel.showEntry', ({ focus = false, ...rest }) => {
183
+ * // ...
184
+ * });
185
+ *
186
+ * @param {Object} context
187
+ * @param {boolean} [context.focus]
188
+ *
189
+ * @returns void
68
190
  */
191
+ const EventContext = preact.createContext({
192
+ eventBus: null
193
+ });
69
194
 
70
- function usePrevious(value) {
71
- const ref = hooks.useRef();
195
+ const LayoutContext = preact.createContext({
196
+ layout: {},
197
+ setLayout: () => {},
198
+ getLayoutForKey: () => {},
199
+ setLayoutForKey: () => {}
200
+ });
201
+
202
+ /**
203
+ * Accesses the global DescriptionContext and returns a description for a given id and element.
204
+ *
205
+ * @example
206
+ * ```jsx
207
+ * function TextField(props) {
208
+ * const description = useDescriptionContext('input1', element);
209
+ * }
210
+ * ```
211
+ *
212
+ * @param {string} id
213
+ * @param {djs.model.Base} element
214
+ *
215
+ * @returns {string}
216
+ */
217
+
218
+ function useDescriptionContext(id, element) {
219
+ const {
220
+ getDescriptionForId
221
+ } = hooks.useContext(DescriptionContext);
222
+ return getDescriptionForId(id, element);
223
+ }
224
+
225
+ const DEFAULT_PRIORITY = 1000;
226
+ /**
227
+ * Subscribe to an event.
228
+ *
229
+ * @param {string} event
230
+ * @param {Function} callback
231
+ * @param {number} [priority]
232
+ *
233
+ * @returns {import('preact').Ref}
234
+ */
235
+
236
+ function useEvent(event, callback, priority = DEFAULT_PRIORITY) {
237
+ const {
238
+ eventBus
239
+ } = hooks.useContext(EventContext);
72
240
  hooks.useEffect(() => {
73
- ref.current = value;
241
+ if (!eventBus) {
242
+ return;
243
+ }
244
+
245
+ eventBus.on(event, priority, callback);
246
+ return () => eventBus.off(event, callback);
247
+ }, [callback, event, eventBus, priority]);
248
+ }
249
+
250
+ const HIGH_PRIORITY = 10000;
251
+ /**
252
+ * Buffer events and re-fire during passive effect phase.
253
+ *
254
+ * @param {string[]} bufferedEvents
255
+ * @param {Object} [eventBus]
256
+ */
257
+
258
+ function useEventBuffer(bufferedEvents, eventBus) {
259
+ const buffer = hooks.useRef([]),
260
+ buffering = hooks.useRef(true);
261
+
262
+ const createCallback = event => data => {
263
+ if (buffering.current === true) {
264
+ buffer.current.unshift([event, data]);
265
+ }
266
+ }; // (1) buffer events
267
+
268
+
269
+ hooks.useEffect(() => {
270
+ if (!eventBus) {
271
+ return;
272
+ }
273
+
274
+ const listeners = bufferedEvents.map(event => {
275
+ return [event, createCallback(event)];
276
+ });
277
+ listeners.forEach(([event, callback]) => {
278
+ eventBus.on(event, HIGH_PRIORITY, callback);
279
+ });
280
+ return () => {
281
+ listeners.forEach(([event, callback]) => {
282
+ eventBus.off(event, callback);
283
+ });
284
+ };
285
+ }, [bufferedEvents, eventBus]); // (2) re-fire events
286
+
287
+ hooks.useEffect(() => {
288
+ if (!eventBus) {
289
+ return;
290
+ }
291
+
292
+ buffering.current = false;
293
+
294
+ while (buffer.current.length) {
295
+ const [event, data] = buffer.current.pop();
296
+ eventBus.fire(event, data);
297
+ }
298
+
299
+ buffering.current = true;
74
300
  });
75
- return ref.current;
76
301
  }
77
302
 
78
303
  const KEY_LENGTH = 6;
@@ -113,18 +338,6 @@ function useKeyFactory(dependencies = []) {
113
338
  return getKey;
114
339
  }
115
340
 
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
341
  /**
129
342
  * Creates a state that persists in the global LayoutContext.
130
343
  *
@@ -160,81 +373,104 @@ function useLayoutState(path, defaultValue) {
160
373
  }
161
374
 
162
375
  /**
163
- * Accesses the global DescriptionContext and returns a description for a given id and element.
376
+ * @pinussilvestrus: we need to introduce our own hook to persist the previous
377
+ * state on updates.
164
378
  *
165
- * @example
166
- * ```jsx
167
- * function TextField(props) {
168
- * const description = useDescriptionContext('input1', element);
169
- * }
170
- * ```
379
+ * cf. https://reactjs.org/docs/hooks-faq.html#how-to-get-the-previous-props-or-state
380
+ */
381
+
382
+ function usePrevious(value) {
383
+ const ref = hooks.useRef();
384
+ hooks.useEffect(() => {
385
+ ref.current = value;
386
+ });
387
+ return ref.current;
388
+ }
389
+
390
+ /**
391
+ * Subscribe to `propertiesPanel.showEntry`.
171
392
  *
172
- * @param {string} id
173
- * @param {djs.model.Base} element
393
+ * @param {Function} show
174
394
  *
175
- * @returns {string}
395
+ * @returns {import('preact').Ref}
176
396
  */
177
397
 
178
- function useDescriptionContext(id, element) {
398
+ function useShowEntryEvent(show) {
179
399
  const {
180
- getDescriptionForId
181
- } = hooks.useContext(DescriptionContext);
182
- return getDescriptionForId(id, element);
183
- }
400
+ onShow
401
+ } = hooks.useContext(LayoutContext);
402
+ const ref = hooks.useRef();
403
+ const [focus, setFocus] = hooks.useState(false);
404
+ const onShowEntry = hooks.useCallback(event => {
405
+ if (show(event)) {
406
+ if (minDash.isFunction(onShow)) {
407
+ onShow();
408
+ }
184
409
 
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
- };
410
+ if (event.focus && !focus) {
411
+ setFocus(true);
412
+ }
413
+ }
414
+ }, [show]);
415
+ hooks.useEffect(() => {
416
+ if (focus && ref.current) {
417
+ if (minDash.isFunction(ref.current.focus)) {
418
+ ref.current.focus();
419
+ }
193
420
 
194
- ArrowIcon.defaultProps = {
195
- xmlns: "http://www.w3.org/2000/svg",
196
- width: "16",
197
- height: "16"
198
- };
421
+ if (minDash.isFunction(ref.current.select)) {
422
+ ref.current.select();
423
+ }
199
424
 
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
- })
206
- });
207
- };
425
+ setFocus(false);
426
+ }
427
+ }, [focus]);
428
+ useEvent('propertiesPanel.showEntry', onShowEntry);
429
+ return ref;
430
+ }
208
431
 
209
- CreateIcon.defaultProps = {
210
- xmlns: "http://www.w3.org/2000/svg",
211
- width: "16",
212
- height: "16"
213
- };
432
+ /**
433
+ * Subscribe to `propertiesPanel.showError`. On `propertiesPanel.showError` set
434
+ * temporary error. Fire `propertiesPanel.showEntry` for temporary error to be
435
+ * visible. Unset error on `propertiesPanel.updated`.
436
+ *
437
+ * @param {Function} show
438
+ *
439
+ * @returns {import('preact').Ref}
440
+ */
214
441
 
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
- };
442
+ function useShowErrorEvent(show) {
443
+ const {
444
+ eventBus
445
+ } = hooks.useContext(EventContext);
446
+ const [temporaryError, setTemporaryError] = hooks.useState(null);
447
+ const onPropertiesPanelUpdated = hooks.useCallback(() => setTemporaryError(null), []);
448
+ useEvent('propertiesPanel.updated', onPropertiesPanelUpdated);
449
+ const onShowError = hooks.useCallback(event => {
450
+ setTemporaryError(null);
451
+
452
+ if (show(event)) {
453
+ if (eventBus) {
454
+ eventBus.fire('propertiesPanel.showEntry', event);
455
+ }
223
456
 
224
- DeleteIcon.defaultProps = {
225
- xmlns: "http://www.w3.org/2000/svg",
226
- width: "16",
227
- height: "16"
228
- };
457
+ setTemporaryError(event.message);
458
+ }
459
+ }, [show]);
460
+ useEvent('propertiesPanel.showError', onShowError);
461
+ return temporaryError;
462
+ }
229
463
 
230
464
  function Group(props) {
231
465
  const {
232
466
  element,
233
467
  entries = [],
234
468
  id,
235
- label
469
+ label,
470
+ shouldOpen = false
236
471
  } = props;
237
- const [open, setOpen] = useLayoutState(['groups', id, 'open'], false);
472
+ const [open, setOpen] = useLayoutState(['groups', id, 'open'], shouldOpen);
473
+ const onShow = hooks.useCallback(() => setOpen(true), [setOpen]);
238
474
 
239
475
  const toggleOpen = () => setOpen(!open);
240
476
 
@@ -257,6 +493,9 @@ function Group(props) {
257
493
  });
258
494
  setEdited(hasOneEditedEntry);
259
495
  }, [entries]);
496
+ const propertiesPanelContext = { ...hooks.useContext(LayoutContext),
497
+ onShow
498
+ };
260
499
  return jsxRuntime.jsxs("div", {
261
500
  class: "bio-properties-panel-group",
262
501
  "data-group-id": 'group-' + id,
@@ -279,15 +518,18 @@ function Group(props) {
279
518
  })]
280
519
  }), jsxRuntime.jsx("div", {
281
520
  class: classnames__default["default"]('bio-properties-panel-group-entries', open ? 'open' : ''),
282
- children: entries.map(entry => {
283
- const {
284
- component: Component,
285
- id
286
- } = entry;
287
- return preact.createElement(Component, { ...entry,
288
- key: id,
289
- element: element
290
- });
521
+ children: jsxRuntime.jsx(LayoutContext.Provider, {
522
+ value: propertiesPanelContext,
523
+ children: entries.map(entry => {
524
+ const {
525
+ component: Component,
526
+ id
527
+ } = entry;
528
+ return preact.createElement(Component, { ...entry,
529
+ element: element,
530
+ key: id
531
+ });
532
+ })
291
533
  })
292
534
  })]
293
535
  });
@@ -304,6 +546,7 @@ const DEFAULT_LAYOUT = {
304
546
  open: true
305
547
  };
306
548
  const DEFAULT_DESCRIPTION = {};
549
+ const bufferedEvents = ['propertiesPanel.showEntry', 'propertiesPanel.showError'];
307
550
  /**
308
551
  * @typedef { {
309
552
  * component: import('preact').Component,
@@ -335,7 +578,8 @@ const DEFAULT_DESCRIPTION = {};
335
578
  * component?: import('preact').Component,
336
579
  * entries: Array<EntryDefinition>,
337
580
  * id: String,
338
- * label: String
581
+ * label: String,
582
+ * shouldOpen?: Boolean
339
583
  * } } GroupDefinition
340
584
  *
341
585
  * @typedef { {
@@ -362,6 +606,7 @@ const DEFAULT_DESCRIPTION = {};
362
606
  * @param {Function} [props.layoutChanged]
363
607
  * @param {DescriptionConfig} [props.descriptionConfig]
364
608
  * @param {Function} [props.descriptionLoaded]
609
+ * @param {Object} [props.eventBus]
365
610
  */
366
611
 
367
612
  function PropertiesPanel(props) {
@@ -372,7 +617,8 @@ function PropertiesPanel(props) {
372
617
  layoutConfig = {},
373
618
  layoutChanged,
374
619
  descriptionConfig = {},
375
- descriptionLoaded
620
+ descriptionLoaded,
621
+ eventBus
376
622
  } = props; // set-up layout context
377
623
 
378
624
  const [layout, setLayout] = hooks.useState(createLayout(layoutConfig));
@@ -413,6 +659,13 @@ function PropertiesPanel(props) {
413
659
  description,
414
660
  getDescriptionForId
415
661
  };
662
+ useEventBuffer(bufferedEvents, eventBus);
663
+ const eventContext = {
664
+ eventBus
665
+ };
666
+ const propertiesPanelContext = {
667
+ element
668
+ };
416
669
 
417
670
  if (!element) {
418
671
  return jsxRuntime.jsx("div", {
@@ -421,28 +674,34 @@ function PropertiesPanel(props) {
421
674
  });
422
675
  }
423
676
 
424
- return jsxRuntime.jsx(DescriptionContext.Provider, {
425
- value: descriptionContext,
426
- children: jsxRuntime.jsx(LayoutContext.Provider, {
427
- value: layoutContext,
428
- children: jsxRuntime.jsxs("div", {
429
- class: classnames__default["default"]('bio-properties-panel', layout.open ? 'open' : ''),
430
- children: [jsxRuntime.jsx(Header, {
431
- element: element,
432
- headerProvider: headerProvider
433
- }), jsxRuntime.jsx("div", {
434
- class: "bio-properties-panel-scroll-container",
435
- children: groups.map(group => {
436
- const {
437
- component: Component = Group,
438
- id
439
- } = group;
440
- return preact.createElement(Component, { ...group,
441
- key: id,
442
- element: element
443
- });
677
+ return jsxRuntime.jsx(LayoutContext.Provider, {
678
+ value: propertiesPanelContext,
679
+ children: jsxRuntime.jsx(DescriptionContext.Provider, {
680
+ value: descriptionContext,
681
+ children: jsxRuntime.jsx(LayoutContext.Provider, {
682
+ value: layoutContext,
683
+ children: jsxRuntime.jsx(EventContext.Provider, {
684
+ value: eventContext,
685
+ children: jsxRuntime.jsxs("div", {
686
+ class: classnames__default["default"]('bio-properties-panel', layout.open ? 'open' : ''),
687
+ children: [jsxRuntime.jsx(Header, {
688
+ element: element,
689
+ headerProvider: headerProvider
690
+ }), jsxRuntime.jsx("div", {
691
+ class: "bio-properties-panel-scroll-container",
692
+ children: groups.map(group => {
693
+ const {
694
+ component: Component = Group,
695
+ id
696
+ } = group;
697
+ return preact.createElement(Component, { ...group,
698
+ key: id,
699
+ element: element
700
+ });
701
+ })
702
+ })]
444
703
  })
445
- })]
704
+ })
446
705
  })
447
706
  })
448
707
  });
@@ -582,8 +841,20 @@ function CollapsibleEntry(props) {
582
841
  } = props;
583
842
  const [open, setOpen] = hooks.useState(shouldOpen);
584
843
 
585
- const toggleOpen = () => setOpen(!open); // todo(pinussilvestrus): translate once we have a translate mechanism for the core
844
+ const toggleOpen = () => setOpen(!open);
586
845
 
846
+ const {
847
+ onShow
848
+ } = hooks.useContext(LayoutContext);
849
+ const propertiesPanelContext = { ...hooks.useContext(LayoutContext),
850
+ onShow: hooks.useCallback(() => {
851
+ setOpen(true);
852
+
853
+ if (minDash.isFunction(onShow)) {
854
+ onShow();
855
+ }
856
+ }, [onShow, setOpen])
857
+ }; // todo(pinussilvestrus): translate once we have a translate mechanism for the core
587
858
 
588
859
  const placeholderLabel = '<empty>';
589
860
  return jsxRuntime.jsxs("div", {
@@ -610,15 +881,18 @@ function CollapsibleEntry(props) {
610
881
  }) : null]
611
882
  }), jsxRuntime.jsx("div", {
612
883
  class: classnames__default["default"]('bio-properties-panel-collapsible-entry-entries', open ? 'open' : ''),
613
- children: entries.map(entry => {
614
- const {
615
- component: Component,
616
- id
617
- } = entry;
618
- return preact.createElement(Component, { ...entry,
619
- key: id,
620
- element: element
621
- });
884
+ children: jsxRuntime.jsx(LayoutContext.Provider, {
885
+ value: propertiesPanelContext,
886
+ children: entries.map(entry => {
887
+ const {
888
+ component: Component,
889
+ id
890
+ } = entry;
891
+ return preact.createElement(Component, { ...entry,
892
+ element: element,
893
+ key: id
894
+ });
895
+ })
622
896
  })
623
897
  })]
624
898
  });
@@ -652,7 +926,7 @@ function ListItem(props) {
652
926
  });
653
927
  }
654
928
 
655
- const noop = () => {};
929
+ const noop$3 = () => {};
656
930
  /**
657
931
  * @param {import('../PropertiesPanel').ListGroupDefinition} props
658
932
  */
@@ -669,6 +943,7 @@ function ListGroup(props) {
669
943
  shouldSort = true
670
944
  } = props;
671
945
  const [open, setOpen] = useLayoutState(['groups', id, 'open'], false);
946
+ const onShow = hooks.useCallback(() => setOpen(true), [setOpen]);
672
947
  const [ordering, setOrdering] = hooks.useState([]);
673
948
  const [newItemAdded, setNewItemAdded] = hooks.useState(false);
674
949
  const prevItems = usePrevious(items);
@@ -743,12 +1018,15 @@ function ListGroup(props) {
743
1018
  const toggleOpen = () => setOpen(!open);
744
1019
 
745
1020
  const hasItems = !!items.length;
1021
+ const propertiesPanelContext = { ...hooks.useContext(LayoutContext),
1022
+ onShow
1023
+ };
746
1024
  return jsxRuntime.jsxs("div", {
747
1025
  class: "bio-properties-panel-group",
748
1026
  "data-group-id": 'group-' + id,
749
1027
  children: [jsxRuntime.jsxs("div", {
750
1028
  class: classnames__default["default"]('bio-properties-panel-group-header', hasItems ? '' : 'empty', hasItems && open ? 'open' : ''),
751
- onClick: hasItems ? toggleOpen : noop,
1029
+ onClick: hasItems ? toggleOpen : noop$3,
752
1030
  children: [jsxRuntime.jsx("div", {
753
1031
  title: label,
754
1032
  class: "bio-properties-panel-group-header-title",
@@ -777,23 +1055,27 @@ function ListGroup(props) {
777
1055
  })]
778
1056
  }), jsxRuntime.jsx("div", {
779
1057
  class: classnames__default["default"]('bio-properties-panel-list', open && hasItems ? 'open' : ''),
780
- children: ordering.map((o, index) => {
781
- const item = getItem(items, o);
782
-
783
- if (!item) {
784
- return;
785
- }
786
-
787
- const {
788
- id
789
- } = item;
790
- return preact.createElement(ListItem, { ...item,
791
- element: element,
792
- index: index,
793
- key: id // if item was added, open first or last item based on ordering
794
- ,
795
- autoOpen: newItemAdded && (shouldSort ? index === 0 : index === ordering.length - 1)
796
- });
1058
+ children: jsxRuntime.jsx(LayoutContext.Provider, {
1059
+ value: propertiesPanelContext,
1060
+ children: ordering.map((o, index) => {
1061
+ const item = getItem(items, o);
1062
+
1063
+ if (!item) {
1064
+ return;
1065
+ }
1066
+
1067
+ const {
1068
+ id
1069
+ } = item; // if item was added, open first or last item based on ordering
1070
+
1071
+ const autoOpen = newItemAdded && (shouldSort ? index === 0 : index === ordering.length - 1);
1072
+ return preact.createElement(ListItem, { ...item,
1073
+ autoOpen: autoOpen,
1074
+ element: element,
1075
+ index: index,
1076
+ key: id
1077
+ });
1078
+ })
797
1079
  })
798
1080
  })]
799
1081
  });
@@ -832,13 +1114,16 @@ function Description(props) {
832
1114
  }
833
1115
  }
834
1116
 
1117
+ const noop$2 = () => {};
1118
+
835
1119
  function Checkbox(props) {
836
1120
  const {
837
1121
  id,
838
1122
  label,
839
1123
  onChange,
840
1124
  disabled,
841
- value = false
1125
+ value = false,
1126
+ show = noop$2
842
1127
  } = props;
843
1128
 
844
1129
  const handleChange = ({
@@ -847,9 +1132,11 @@ function Checkbox(props) {
847
1132
  onChange(target.checked);
848
1133
  };
849
1134
 
1135
+ const ref = useShowEntryEvent(show);
850
1136
  return jsxRuntime.jsxs("div", {
851
1137
  class: "bio-properties-panel-checkbox",
852
1138
  children: [jsxRuntime.jsx("input", {
1139
+ ref: ref,
853
1140
  id: prefixId$6(id),
854
1141
  name: id,
855
1142
  type: "checkbox",
@@ -884,18 +1171,24 @@ function CheckboxEntry(props) {
884
1171
  label,
885
1172
  getValue,
886
1173
  setValue,
887
- disabled
1174
+ disabled,
1175
+ show = noop$2
888
1176
  } = props;
889
1177
  const value = getValue(element);
1178
+ const error = useShowErrorEvent(show);
890
1179
  return jsxRuntime.jsxs("div", {
891
1180
  class: "bio-properties-panel-entry bio-properties-panel-checkbox-entry",
892
1181
  "data-entry-id": id,
893
1182
  children: [jsxRuntime.jsx(Checkbox, {
1183
+ disabled: disabled,
894
1184
  id: id,
895
1185
  label: label,
896
1186
  onChange: setValue,
897
- value: value,
898
- disabled: disabled
1187
+ show: show,
1188
+ value: value
1189
+ }), error && jsxRuntime.jsx("div", {
1190
+ class: "bio-properties-panel-error",
1191
+ children: error
899
1192
  }), jsxRuntime.jsx(Description, {
900
1193
  forId: id,
901
1194
  element: element,
@@ -1202,6 +1495,25 @@ function prefixId$5(id) {
1202
1495
  return `bio-properties-panel-${id}`;
1203
1496
  }
1204
1497
 
1498
+ const noop$1 = () => {};
1499
+ /**
1500
+ * @typedef { { value: string, label: string, disabled: boolean } } Option
1501
+ */
1502
+
1503
+ /**
1504
+ * Provides basic select input.
1505
+ *
1506
+ * @param {object} props
1507
+ * @param {string} props.id
1508
+ * @param {string[]} props.path
1509
+ * @param {string} props.label
1510
+ * @param {Function} props.onChange
1511
+ * @param {Array<Option>} [props.options]
1512
+ * @param {string} props.value
1513
+ * @param {boolean} [props.disabled]
1514
+ */
1515
+
1516
+
1205
1517
  function Select(props) {
1206
1518
  const {
1207
1519
  id,
@@ -1209,8 +1521,10 @@ function Select(props) {
1209
1521
  onChange,
1210
1522
  options = [],
1211
1523
  value,
1212
- disabled
1524
+ disabled,
1525
+ show = noop$1
1213
1526
  } = props;
1527
+ const ref = useShowEntryEvent(show);
1214
1528
 
1215
1529
  const handleChange = ({
1216
1530
  target
@@ -1225,6 +1539,7 @@ function Select(props) {
1225
1539
  class: "bio-properties-panel-label",
1226
1540
  children: label
1227
1541
  }), jsxRuntime.jsx("select", {
1542
+ ref: ref,
1228
1543
  id: prefixId$4(id),
1229
1544
  name: id,
1230
1545
  class: "bio-properties-panel-input",
@@ -1263,12 +1578,14 @@ function SelectEntry(props) {
1263
1578
  getValue,
1264
1579
  setValue,
1265
1580
  getOptions,
1266
- disabled
1581
+ disabled,
1582
+ show = noop$1
1267
1583
  } = props;
1268
1584
  const value = getValue(element);
1269
1585
  const options = getOptions(element);
1586
+ const error = useShowErrorEvent(show);
1270
1587
  return jsxRuntime.jsxs("div", {
1271
- class: "bio-properties-panel-entry",
1588
+ class: classnames__default["default"]('bio-properties-panel-entry', error ? 'has-error' : ''),
1272
1589
  "data-entry-id": id,
1273
1590
  children: [jsxRuntime.jsx(Select, {
1274
1591
  id: id,
@@ -1276,7 +1593,11 @@ function SelectEntry(props) {
1276
1593
  value: value,
1277
1594
  onChange: setValue,
1278
1595
  options: options,
1279
- disabled: disabled
1596
+ disabled: disabled,
1597
+ show: show
1598
+ }), error && jsxRuntime.jsx("div", {
1599
+ class: "bio-properties-panel-error",
1600
+ children: error
1280
1601
  }), jsxRuntime.jsx(Description, {
1281
1602
  forId: id,
1282
1603
  element: element,
@@ -1335,12 +1656,27 @@ function prefixId$3(id) {
1335
1656
  return `bio-properties-panel-${id}`;
1336
1657
  }
1337
1658
 
1659
+ function FeelIcon(props) {
1660
+ const {
1661
+ label,
1662
+ feel = false
1663
+ } = props;
1664
+ const feelRequiredLabel = ' must be a FEEL expression';
1665
+ const feelOptionalLabel = ' can optionally be a FEEL expression';
1666
+ return jsxRuntime.jsx("i", {
1667
+ class: "bio-properties-panel-feel-icon",
1668
+ title: label + (feel === 'required' ? feelRequiredLabel : feelOptionalLabel),
1669
+ children: feel === 'required' ? jsxRuntime.jsx(FeelRequiredIcon, {}) : jsxRuntime.jsx(FeelOptionalIcon, {})
1670
+ });
1671
+ }
1672
+
1338
1673
  function TextArea(props) {
1339
1674
  const {
1340
1675
  id,
1341
1676
  label,
1342
1677
  rows = 2,
1343
1678
  debounce,
1679
+ feel,
1344
1680
  onInput,
1345
1681
  value = '',
1346
1682
  disabled,
@@ -1353,10 +1689,13 @@ function TextArea(props) {
1353
1689
  }, [onInput, debounce]);
1354
1690
  return jsxRuntime.jsxs("div", {
1355
1691
  class: "bio-properties-panel-textarea",
1356
- children: [jsxRuntime.jsx("label", {
1692
+ children: [jsxRuntime.jsxs("label", {
1357
1693
  for: prefixId$2(id),
1358
1694
  class: "bio-properties-panel-label",
1359
- children: label
1695
+ children: [label, feel && jsxRuntime.jsx(FeelIcon, {
1696
+ feel: feel,
1697
+ label: label
1698
+ })]
1360
1699
  }), jsxRuntime.jsx("textarea", {
1361
1700
  id: prefixId$2(id),
1362
1701
  name: id,
@@ -1392,6 +1731,7 @@ function TextAreaEntry(props) {
1392
1731
  id,
1393
1732
  description,
1394
1733
  debounce,
1734
+ feel,
1395
1735
  label,
1396
1736
  getValue,
1397
1737
  setValue,
@@ -1411,6 +1751,7 @@ function TextAreaEntry(props) {
1411
1751
  rows: rows,
1412
1752
  debounce: debounce,
1413
1753
  monospace: monospace,
1754
+ feel: feel,
1414
1755
  disabled: disabled
1415
1756
  }), jsxRuntime.jsx(Description, {
1416
1757
  forId: id,
@@ -1427,6 +1768,8 @@ function prefixId$2(id) {
1427
1768
  return `bio-properties-panel-${id}`;
1428
1769
  }
1429
1770
 
1771
+ const noop = () => {};
1772
+
1430
1773
  function Textfield(props) {
1431
1774
  const {
1432
1775
  debounce,
@@ -1434,8 +1777,11 @@ function Textfield(props) {
1434
1777
  id,
1435
1778
  label,
1436
1779
  onInput,
1437
- value = ''
1780
+ feel = false,
1781
+ value = '',
1782
+ show = noop
1438
1783
  } = props;
1784
+ const ref = useShowEntryEvent(show);
1439
1785
  const handleInput = hooks.useMemo(() => {
1440
1786
  return debounce(({
1441
1787
  target
@@ -1443,11 +1789,15 @@ function Textfield(props) {
1443
1789
  }, [onInput, debounce]);
1444
1790
  return jsxRuntime.jsxs("div", {
1445
1791
  class: "bio-properties-panel-textfield",
1446
- children: [jsxRuntime.jsx("label", {
1792
+ children: [jsxRuntime.jsxs("label", {
1447
1793
  for: prefixId$1(id),
1448
1794
  class: "bio-properties-panel-label",
1449
- children: label
1795
+ children: [label, feel && jsxRuntime.jsx(FeelIcon, {
1796
+ feel: feel,
1797
+ label: label
1798
+ })]
1450
1799
  }), jsxRuntime.jsx("input", {
1800
+ ref: ref,
1451
1801
  id: prefixId$1(id),
1452
1802
  type: "text",
1453
1803
  name: id,
@@ -1483,55 +1833,65 @@ function TextfieldEntry(props) {
1483
1833
  description,
1484
1834
  debounce,
1485
1835
  disabled,
1836
+ feel,
1486
1837
  label,
1487
1838
  getValue,
1488
1839
  setValue,
1489
- validate
1840
+ validate,
1841
+ show = noop
1490
1842
  } = props;
1491
- const [error, setError] = hooks.useState(null);
1492
- const [invalidValueCache, setInvalidValueCache] = hooks.useState(null);
1843
+ const [cachedInvalidValue, setCachedInvalidValue] = hooks.useState(null);
1844
+ const [validationError, setValidationError] = hooks.useState(null);
1493
1845
  let value = getValue(element);
1494
- const prevValue = usePrevious(value); // validate again when value prop changed
1495
-
1846
+ const previousValue = usePrevious(value);
1496
1847
  hooks.useEffect(() => {
1497
- const err = validate ? validate(value) : null;
1498
- setError(err);
1499
- }, [value]); // validate on change
1848
+ if (minDash.isFunction(validate)) {
1849
+ const newValidationError = validate(value) || null;
1850
+ setValidationError(newValidationError);
1851
+ }
1852
+ }, [value]);
1853
+
1854
+ const onInput = newValue => {
1855
+ let newValidationError = null;
1500
1856
 
1501
- const handleChange = newValue => {
1502
- const err = validate ? validate(newValue) : null;
1857
+ if (minDash.isFunction(validate)) {
1858
+ newValidationError = validate(newValue) || null;
1859
+ }
1503
1860
 
1504
- if (err) {
1505
- setInvalidValueCache(newValue);
1861
+ if (newValidationError) {
1862
+ setCachedInvalidValue(newValue);
1506
1863
  } else {
1507
1864
  setValue(newValue);
1508
1865
  }
1509
1866
 
1510
- setError(err);
1511
- }; // keep showing invalid value on errors, although it was not set
1512
-
1867
+ setValidationError(newValidationError);
1868
+ };
1513
1869
 
1514
- if (prevValue === value && error) {
1515
- value = invalidValueCache;
1870
+ if (previousValue === value && validationError) {
1871
+ value = cachedInvalidValue;
1516
1872
  }
1517
1873
 
1874
+ const temporaryError = useShowErrorEvent(show);
1875
+ const error = temporaryError || validationError;
1518
1876
  return jsxRuntime.jsxs("div", {
1519
1877
  class: classnames__default["default"]('bio-properties-panel-entry', error ? 'has-error' : ''),
1520
1878
  "data-entry-id": id,
1521
1879
  children: [jsxRuntime.jsx(Textfield, {
1880
+ debounce: debounce,
1881
+ disabled: disabled,
1882
+ feel: feel,
1522
1883
  id: id,
1523
1884
  label: label,
1524
- value: value,
1525
- onInput: handleChange,
1526
- debounce: debounce,
1527
- disabled: disabled
1885
+ onInput: onInput,
1886
+ show: show,
1887
+ value: value
1888
+ }), error && jsxRuntime.jsx("div", {
1889
+ class: "bio-properties-panel-error",
1890
+ children: error
1528
1891
  }), jsxRuntime.jsx(Description, {
1529
1892
  forId: id,
1530
1893
  element: element,
1531
1894
  value: description
1532
- }), error && jsxRuntime.jsx("div", {
1533
- class: "bio-properties-panel-error",
1534
- children: error
1535
1895
  })]
1536
1896
  });
1537
1897
  }
@@ -1656,6 +2016,10 @@ exports.DeleteIcon = DeleteIcon;
1656
2016
  exports.DescriptionContext = DescriptionContext;
1657
2017
  exports.DescriptionEntry = Description;
1658
2018
  exports.DropdownButton = DropdownButton;
2019
+ exports.EventContext = EventContext;
2020
+ exports.ExternalLinkIcon = ExternalLinkIcon;
2021
+ exports.FeelOptionalIcon = FeelOptionalIcon;
2022
+ exports.FeelRequiredIcon = FeelRequiredIcon;
1659
2023
  exports.Group = Group;
1660
2024
  exports.Header = Header;
1661
2025
  exports.HeaderButton = HeaderButton;
@@ -1665,6 +2029,7 @@ exports.ListGroup = ListGroup;
1665
2029
  exports.ListItem = ListItem;
1666
2030
  exports.NumberFieldEntry = NumberFieldEntry;
1667
2031
  exports.PropertiesPanel = PropertiesPanel;
2032
+ exports.PropertiesPanelContext = LayoutContext;
1668
2033
  exports.SelectEntry = SelectEntry;
1669
2034
  exports.SimpleEntry = Simple;
1670
2035
  exports.TextAreaEntry = TextAreaEntry;
@@ -1678,7 +2043,11 @@ exports.isTextAreaEntryEdited = isEdited$2;
1678
2043
  exports.isTextFieldEntryEdited = isEdited$1;
1679
2044
  exports.isToggleSwitchEntryEdited = isEdited;
1680
2045
  exports.useDescriptionContext = useDescriptionContext;
2046
+ exports.useEvent = useEvent;
2047
+ exports.useEventBuffer = useEventBuffer;
1681
2048
  exports.useKeyFactory = useKeyFactory;
1682
2049
  exports.useLayoutState = useLayoutState;
1683
2050
  exports.usePrevious = usePrevious;
2051
+ exports.useShowEntryEvent = useShowEntryEvent;
2052
+ exports.useShowErrorEvent = useShowErrorEvent;
1684
2053
  //# sourceMappingURL=index.js.map