@bpmn-io/properties-panel 0.13.2 → 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/CHANGELOG.md +151 -145
- package/LICENSE +20 -20
- package/README.md +34 -34
- package/assets/properties-panel.css +929 -900
- package/dist/index.esm.js +357 -258
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +357 -256
- package/dist/index.js.map +1 -1
- package/package.json +89 -89
package/dist/index.esm.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useContext, useEffect, useRef, useMemo, useState, useCallback } from '../preact/hooks';
|
|
2
|
-
import { isFunction, get, assign, set, sortBy, find, isNumber, debounce } from 'min-dash';
|
|
2
|
+
import { isFunction, isArray, get, assign, set, sortBy, find, isNumber, debounce } from 'min-dash';
|
|
3
3
|
import classnames from 'classnames';
|
|
4
4
|
import '../preact/compat';
|
|
5
5
|
import { jsx, jsxs } from '../preact/jsx-runtime';
|
|
@@ -166,19 +166,19 @@ const DescriptionContext = createContext({
|
|
|
166
166
|
getDescriptionForId: () => {}
|
|
167
167
|
});
|
|
168
168
|
|
|
169
|
-
/**
|
|
170
|
-
* @typedef {Function} <propertiesPanel.showEntry> callback
|
|
171
|
-
*
|
|
172
|
-
* @example
|
|
173
|
-
*
|
|
174
|
-
* useEvent('propertiesPanel.showEntry', ({ focus = false, ...rest }) => {
|
|
175
|
-
* // ...
|
|
176
|
-
* });
|
|
177
|
-
*
|
|
178
|
-
* @param {Object} context
|
|
179
|
-
* @param {boolean} [context.focus]
|
|
180
|
-
*
|
|
181
|
-
* @returns void
|
|
169
|
+
/**
|
|
170
|
+
* @typedef {Function} <propertiesPanel.showEntry> callback
|
|
171
|
+
*
|
|
172
|
+
* @example
|
|
173
|
+
*
|
|
174
|
+
* useEvent('propertiesPanel.showEntry', ({ focus = false, ...rest }) => {
|
|
175
|
+
* // ...
|
|
176
|
+
* });
|
|
177
|
+
*
|
|
178
|
+
* @param {Object} context
|
|
179
|
+
* @param {boolean} [context.focus]
|
|
180
|
+
*
|
|
181
|
+
* @returns void
|
|
182
182
|
*/
|
|
183
183
|
const EventContext = createContext({
|
|
184
184
|
eventBus: null
|
|
@@ -191,20 +191,20 @@ const LayoutContext = createContext({
|
|
|
191
191
|
setLayoutForKey: () => {}
|
|
192
192
|
});
|
|
193
193
|
|
|
194
|
-
/**
|
|
195
|
-
* Accesses the global DescriptionContext and returns a description for a given id and element.
|
|
196
|
-
*
|
|
197
|
-
* @example
|
|
198
|
-
* ```jsx
|
|
199
|
-
* function TextField(props) {
|
|
200
|
-
* const description = useDescriptionContext('input1', element);
|
|
201
|
-
* }
|
|
202
|
-
* ```
|
|
203
|
-
*
|
|
204
|
-
* @param {string} id
|
|
205
|
-
* @param {
|
|
206
|
-
*
|
|
207
|
-
* @returns {string}
|
|
194
|
+
/**
|
|
195
|
+
* Accesses the global DescriptionContext and returns a description for a given id and element.
|
|
196
|
+
*
|
|
197
|
+
* @example
|
|
198
|
+
* ```jsx
|
|
199
|
+
* function TextField(props) {
|
|
200
|
+
* const description = useDescriptionContext('input1', element);
|
|
201
|
+
* }
|
|
202
|
+
* ```
|
|
203
|
+
*
|
|
204
|
+
* @param {string} id
|
|
205
|
+
* @param {object} element
|
|
206
|
+
*
|
|
207
|
+
* @returns {string}
|
|
208
208
|
*/
|
|
209
209
|
|
|
210
210
|
function useDescriptionContext(id, element) {
|
|
@@ -215,14 +215,14 @@ function useDescriptionContext(id, element) {
|
|
|
215
215
|
}
|
|
216
216
|
|
|
217
217
|
const DEFAULT_PRIORITY = 1000;
|
|
218
|
-
/**
|
|
219
|
-
* Subscribe to an event.
|
|
220
|
-
*
|
|
221
|
-
* @param {string} event
|
|
222
|
-
* @param {Function} callback
|
|
223
|
-
* @param {number} [priority]
|
|
224
|
-
*
|
|
225
|
-
* @returns {import('preact').Ref}
|
|
218
|
+
/**
|
|
219
|
+
* Subscribe to an event.
|
|
220
|
+
*
|
|
221
|
+
* @param {string} event
|
|
222
|
+
* @param {Function} callback
|
|
223
|
+
* @param {number} [priority]
|
|
224
|
+
*
|
|
225
|
+
* @returns {import('preact').Ref}
|
|
226
226
|
*/
|
|
227
227
|
|
|
228
228
|
function useEvent(event, callback, priority = DEFAULT_PRIORITY) {
|
|
@@ -240,11 +240,11 @@ function useEvent(event, callback, priority = DEFAULT_PRIORITY) {
|
|
|
240
240
|
}
|
|
241
241
|
|
|
242
242
|
const HIGH_PRIORITY = 10000;
|
|
243
|
-
/**
|
|
244
|
-
* Buffer events and re-fire during passive effect phase.
|
|
245
|
-
*
|
|
246
|
-
* @param {string[]} bufferedEvents
|
|
247
|
-
* @param {Object} [eventBus]
|
|
243
|
+
/**
|
|
244
|
+
* Buffer events and re-fire during passive effect phase.
|
|
245
|
+
*
|
|
246
|
+
* @param {string[]} bufferedEvents
|
|
247
|
+
* @param {Object} [eventBus]
|
|
248
248
|
*/
|
|
249
249
|
|
|
250
250
|
function useEventBuffer(bufferedEvents, eventBus) {
|
|
@@ -293,24 +293,24 @@ function useEventBuffer(bufferedEvents, eventBus) {
|
|
|
293
293
|
}
|
|
294
294
|
|
|
295
295
|
const KEY_LENGTH = 6;
|
|
296
|
-
/**
|
|
297
|
-
* Create a persistent key factory for plain objects without id.
|
|
298
|
-
*
|
|
299
|
-
* @example
|
|
300
|
-
* ```jsx
|
|
301
|
-
* function List({ objects }) {
|
|
302
|
-
* const getKey = useKeyFactory();
|
|
303
|
-
* return (<ol>{
|
|
304
|
-
* objects.map(obj => {
|
|
305
|
-
* const key = getKey(obj);
|
|
306
|
-
* return <li key={key}>obj.name</li>
|
|
307
|
-
* })
|
|
308
|
-
* }</ol>);
|
|
309
|
-
* }
|
|
310
|
-
* ```
|
|
311
|
-
*
|
|
312
|
-
* @param {any[]} dependencies
|
|
313
|
-
* @returns {(element: object) => string}
|
|
296
|
+
/**
|
|
297
|
+
* Create a persistent key factory for plain objects without id.
|
|
298
|
+
*
|
|
299
|
+
* @example
|
|
300
|
+
* ```jsx
|
|
301
|
+
* function List({ objects }) {
|
|
302
|
+
* const getKey = useKeyFactory();
|
|
303
|
+
* return (<ol>{
|
|
304
|
+
* objects.map(obj => {
|
|
305
|
+
* const key = getKey(obj);
|
|
306
|
+
* return <li key={key}>obj.name</li>
|
|
307
|
+
* })
|
|
308
|
+
* }</ol>);
|
|
309
|
+
* }
|
|
310
|
+
* ```
|
|
311
|
+
*
|
|
312
|
+
* @param {any[]} dependencies
|
|
313
|
+
* @returns {(element: object) => string}
|
|
314
314
|
*/
|
|
315
315
|
|
|
316
316
|
function useKeyFactory(dependencies = []) {
|
|
@@ -330,20 +330,20 @@ function useKeyFactory(dependencies = []) {
|
|
|
330
330
|
return getKey;
|
|
331
331
|
}
|
|
332
332
|
|
|
333
|
-
/**
|
|
334
|
-
* Creates a state that persists in the global LayoutContext.
|
|
335
|
-
*
|
|
336
|
-
* @example
|
|
337
|
-
* ```jsx
|
|
338
|
-
* function Group(props) {
|
|
339
|
-
* const [ open, setOpen ] = useLayoutState([ 'groups', 'foo', 'open' ], false);
|
|
340
|
-
* }
|
|
341
|
-
* ```
|
|
342
|
-
*
|
|
343
|
-
* @param {(string|number)[]} path
|
|
344
|
-
* @param {any} [defaultValue]
|
|
345
|
-
*
|
|
346
|
-
* @returns {[ any, Function ]}
|
|
333
|
+
/**
|
|
334
|
+
* Creates a state that persists in the global LayoutContext.
|
|
335
|
+
*
|
|
336
|
+
* @example
|
|
337
|
+
* ```jsx
|
|
338
|
+
* function Group(props) {
|
|
339
|
+
* const [ open, setOpen ] = useLayoutState([ 'groups', 'foo', 'open' ], false);
|
|
340
|
+
* }
|
|
341
|
+
* ```
|
|
342
|
+
*
|
|
343
|
+
* @param {(string|number)[]} path
|
|
344
|
+
* @param {any} [defaultValue]
|
|
345
|
+
*
|
|
346
|
+
* @returns {[ any, Function ]}
|
|
347
347
|
*/
|
|
348
348
|
|
|
349
349
|
function useLayoutState(path, defaultValue) {
|
|
@@ -364,11 +364,11 @@ function useLayoutState(path, defaultValue) {
|
|
|
364
364
|
return [value, setState];
|
|
365
365
|
}
|
|
366
366
|
|
|
367
|
-
/**
|
|
368
|
-
* @pinussilvestrus: we need to introduce our own hook to persist the previous
|
|
369
|
-
* state on updates.
|
|
370
|
-
*
|
|
371
|
-
* cf. https://reactjs.org/docs/hooks-faq.html#how-to-get-the-previous-props-or-state
|
|
367
|
+
/**
|
|
368
|
+
* @pinussilvestrus: we need to introduce our own hook to persist the previous
|
|
369
|
+
* state on updates.
|
|
370
|
+
*
|
|
371
|
+
* cf. https://reactjs.org/docs/hooks-faq.html#how-to-get-the-previous-props-or-state
|
|
372
372
|
*/
|
|
373
373
|
|
|
374
374
|
function usePrevious(value) {
|
|
@@ -379,12 +379,12 @@ function usePrevious(value) {
|
|
|
379
379
|
return ref.current;
|
|
380
380
|
}
|
|
381
381
|
|
|
382
|
-
/**
|
|
383
|
-
* Subscribe to `propertiesPanel.showEntry`.
|
|
384
|
-
*
|
|
385
|
-
* @param {Function} show
|
|
386
|
-
*
|
|
387
|
-
* @returns {import('preact').Ref}
|
|
382
|
+
/**
|
|
383
|
+
* Subscribe to `propertiesPanel.showEntry`.
|
|
384
|
+
*
|
|
385
|
+
* @param {Function} show
|
|
386
|
+
*
|
|
387
|
+
* @returns {import('preact').Ref}
|
|
388
388
|
*/
|
|
389
389
|
|
|
390
390
|
function useShowEntryEvent(show) {
|
|
@@ -421,14 +421,14 @@ function useShowEntryEvent(show) {
|
|
|
421
421
|
return ref;
|
|
422
422
|
}
|
|
423
423
|
|
|
424
|
-
/**
|
|
425
|
-
* Subscribe to `propertiesPanel.showError`. On `propertiesPanel.showError` set
|
|
426
|
-
* temporary error. Fire `propertiesPanel.showEntry` for temporary error to be
|
|
427
|
-
* visible. Unset error on `propertiesPanel.updated`.
|
|
428
|
-
*
|
|
429
|
-
* @param {Function} show
|
|
430
|
-
*
|
|
431
|
-
* @returns {import('preact').Ref}
|
|
424
|
+
/**
|
|
425
|
+
* Subscribe to `propertiesPanel.showError`. On `propertiesPanel.showError` set
|
|
426
|
+
* temporary error. Fire `propertiesPanel.showEntry` for temporary error to be
|
|
427
|
+
* visible. Unset error on `propertiesPanel.updated`.
|
|
428
|
+
*
|
|
429
|
+
* @param {Function} show
|
|
430
|
+
*
|
|
431
|
+
* @returns {import('preact').Ref}
|
|
432
432
|
*/
|
|
433
433
|
|
|
434
434
|
function useShowErrorEvent(show) {
|
|
@@ -453,6 +453,57 @@ function useShowErrorEvent(show) {
|
|
|
453
453
|
return temporaryError;
|
|
454
454
|
}
|
|
455
455
|
|
|
456
|
+
/**
|
|
457
|
+
* @callback setSticky
|
|
458
|
+
* @param {boolean} value
|
|
459
|
+
*/
|
|
460
|
+
|
|
461
|
+
/**
|
|
462
|
+
* Use IntersectionObserver to identify when DOM element is in sticky mode.
|
|
463
|
+
* If sticky is observered setSticky(true) will be called.
|
|
464
|
+
* If sticky mode is left, setSticky(false) will be called.
|
|
465
|
+
*
|
|
466
|
+
*
|
|
467
|
+
* @param {Object} ref
|
|
468
|
+
* @param {string} scrollContainerSelector
|
|
469
|
+
* @param {setSticky} setSticky
|
|
470
|
+
*/
|
|
471
|
+
|
|
472
|
+
function useStickyIntersectionObserver(ref, scrollContainerSelector, setSticky) {
|
|
473
|
+
useEffect(() => {
|
|
474
|
+
// return early if IntersectionObserver is not available
|
|
475
|
+
if (!IntersectionObserver) {
|
|
476
|
+
return;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
let observer;
|
|
480
|
+
|
|
481
|
+
if (ref.current) {
|
|
482
|
+
const scrollContainer = query(scrollContainerSelector);
|
|
483
|
+
observer = new IntersectionObserver(entries => {
|
|
484
|
+
if (entries[0].intersectionRatio < 1) {
|
|
485
|
+
setSticky(true);
|
|
486
|
+
} else if (entries[0].intersectionRatio === 1) {
|
|
487
|
+
setSticky(false);
|
|
488
|
+
}
|
|
489
|
+
}, {
|
|
490
|
+
root: scrollContainer,
|
|
491
|
+
rootMargin: '0px 0px 999999% 0px',
|
|
492
|
+
// Use bottom margin to avoid stickyness when scrolling out to bottom
|
|
493
|
+
threshold: [1]
|
|
494
|
+
});
|
|
495
|
+
observer.observe(ref.current);
|
|
496
|
+
} // Unobserve if unmounted
|
|
497
|
+
|
|
498
|
+
|
|
499
|
+
return () => {
|
|
500
|
+
if (ref.current && observer) {
|
|
501
|
+
observer.unobserve(ref.current);
|
|
502
|
+
}
|
|
503
|
+
};
|
|
504
|
+
}, [ref]);
|
|
505
|
+
}
|
|
506
|
+
|
|
456
507
|
function Group(props) {
|
|
457
508
|
const {
|
|
458
509
|
element,
|
|
@@ -461,12 +512,14 @@ function Group(props) {
|
|
|
461
512
|
label,
|
|
462
513
|
shouldOpen = false
|
|
463
514
|
} = props;
|
|
515
|
+
const groupRef = useRef(null);
|
|
464
516
|
const [open, setOpen] = useLayoutState(['groups', id, 'open'], shouldOpen);
|
|
465
517
|
const onShow = useCallback(() => setOpen(true), [setOpen]);
|
|
466
518
|
|
|
467
519
|
const toggleOpen = () => setOpen(!open);
|
|
468
520
|
|
|
469
|
-
const [edited, setEdited] = useState(false);
|
|
521
|
+
const [edited, setEdited] = useState(false);
|
|
522
|
+
const [sticky, setSticky] = useState(false); // set edited state depending on all entries
|
|
470
523
|
|
|
471
524
|
useEffect(() => {
|
|
472
525
|
const hasOneEditedEntry = entries.find(entry => {
|
|
@@ -484,15 +537,18 @@ function Group(props) {
|
|
|
484
537
|
return isEdited(inputNode);
|
|
485
538
|
});
|
|
486
539
|
setEdited(hasOneEditedEntry);
|
|
487
|
-
}, [entries]);
|
|
540
|
+
}, [entries]); // set css class when group is sticky to top
|
|
541
|
+
|
|
542
|
+
useStickyIntersectionObserver(groupRef, 'div.bio-properties-panel-scroll-container', setSticky);
|
|
488
543
|
const propertiesPanelContext = { ...useContext(LayoutContext),
|
|
489
544
|
onShow
|
|
490
545
|
};
|
|
491
546
|
return jsxs("div", {
|
|
492
547
|
class: "bio-properties-panel-group",
|
|
493
548
|
"data-group-id": 'group-' + id,
|
|
549
|
+
ref: groupRef,
|
|
494
550
|
children: [jsxs("div", {
|
|
495
|
-
class: classnames('bio-properties-panel-group-header', edited ? '' : 'empty', open ? 'open' : ''),
|
|
551
|
+
class: classnames('bio-properties-panel-group-header', edited ? '' : 'empty', open ? 'open' : '', sticky && open ? 'sticky' : ''),
|
|
496
552
|
onClick: toggleOpen,
|
|
497
553
|
children: [jsx("div", {
|
|
498
554
|
title: label,
|
|
@@ -534,77 +590,111 @@ function DataMarker() {
|
|
|
534
590
|
});
|
|
535
591
|
}
|
|
536
592
|
|
|
593
|
+
/**
|
|
594
|
+
* @typedef { {
|
|
595
|
+
* text: (element: object) => string,
|
|
596
|
+
* icon?: (element: Object) => import('preact').Component
|
|
597
|
+
* } } PlaceholderDefinition
|
|
598
|
+
*
|
|
599
|
+
* @param { PlaceholderDefinition } props
|
|
600
|
+
*/
|
|
601
|
+
function Placeholder(props) {
|
|
602
|
+
const {
|
|
603
|
+
text,
|
|
604
|
+
icon: Icon
|
|
605
|
+
} = props;
|
|
606
|
+
return jsx("div", {
|
|
607
|
+
class: "bio-properties-panel open",
|
|
608
|
+
children: jsxs("section", {
|
|
609
|
+
class: "bio-properties-panel-placeholder",
|
|
610
|
+
children: [Icon && jsx(Icon, {
|
|
611
|
+
class: "bio-properties-panel-placeholder-icon"
|
|
612
|
+
}), jsx("p", {
|
|
613
|
+
class: "bio-properties-panel-placeholder-text",
|
|
614
|
+
children: text
|
|
615
|
+
})]
|
|
616
|
+
})
|
|
617
|
+
});
|
|
618
|
+
}
|
|
619
|
+
|
|
537
620
|
const DEFAULT_LAYOUT = {
|
|
538
621
|
open: true
|
|
539
622
|
};
|
|
540
623
|
const DEFAULT_DESCRIPTION = {};
|
|
541
624
|
const bufferedEvents = ['propertiesPanel.showEntry', 'propertiesPanel.showError'];
|
|
542
|
-
/**
|
|
543
|
-
* @typedef { {
|
|
544
|
-
* component: import('preact').Component,
|
|
545
|
-
* id: String,
|
|
546
|
-
* isEdited?: Function
|
|
547
|
-
* } } EntryDefinition
|
|
548
|
-
*
|
|
549
|
-
* @typedef { {
|
|
550
|
-
* autoFocusEntry: String,
|
|
551
|
-
* autoOpen?: Boolean,
|
|
552
|
-
* entries: Array<EntryDefinition>,
|
|
553
|
-
* id: String,
|
|
554
|
-
* label: String,
|
|
555
|
-
* remove: (event: MouseEvent) => void
|
|
556
|
-
* } } ListItemDefinition
|
|
557
|
-
*
|
|
558
|
-
* @typedef { {
|
|
559
|
-
* add: (event: MouseEvent) => void,
|
|
560
|
-
* component: import('preact').Component,
|
|
561
|
-
* element: Object,
|
|
562
|
-
* id: String,
|
|
563
|
-
* items: Array<ListItemDefinition>,
|
|
564
|
-
* label: String,
|
|
565
|
-
* shouldSort?: Boolean,
|
|
566
|
-
* shouldOpen?: Boolean
|
|
567
|
-
* } } ListGroupDefinition
|
|
568
|
-
*
|
|
569
|
-
* @typedef { {
|
|
570
|
-
* component?: import('preact').Component,
|
|
571
|
-
* entries: Array<EntryDefinition>,
|
|
572
|
-
* id: String,
|
|
573
|
-
* label: String,
|
|
574
|
-
* shouldOpen?: Boolean
|
|
575
|
-
* } } GroupDefinition
|
|
576
|
-
*
|
|
577
|
-
* @typedef { {
|
|
578
|
-
* [id: String]: GetDescriptionFunction
|
|
579
|
-
* } } DescriptionConfig
|
|
580
|
-
*
|
|
581
|
-
* @callback { {
|
|
582
|
-
* @param {string} id
|
|
583
|
-
* @param {
|
|
584
|
-
* @returns {string}
|
|
585
|
-
* } } GetDescriptionFunction
|
|
586
|
-
*
|
|
625
|
+
/**
|
|
626
|
+
* @typedef { {
|
|
627
|
+
* component: import('preact').Component,
|
|
628
|
+
* id: String,
|
|
629
|
+
* isEdited?: Function
|
|
630
|
+
* } } EntryDefinition
|
|
631
|
+
*
|
|
632
|
+
* @typedef { {
|
|
633
|
+
* autoFocusEntry: String,
|
|
634
|
+
* autoOpen?: Boolean,
|
|
635
|
+
* entries: Array<EntryDefinition>,
|
|
636
|
+
* id: String,
|
|
637
|
+
* label: String,
|
|
638
|
+
* remove: (event: MouseEvent) => void
|
|
639
|
+
* } } ListItemDefinition
|
|
640
|
+
*
|
|
641
|
+
* @typedef { {
|
|
642
|
+
* add: (event: MouseEvent) => void,
|
|
643
|
+
* component: import('preact').Component,
|
|
644
|
+
* element: Object,
|
|
645
|
+
* id: String,
|
|
646
|
+
* items: Array<ListItemDefinition>,
|
|
647
|
+
* label: String,
|
|
648
|
+
* shouldSort?: Boolean,
|
|
649
|
+
* shouldOpen?: Boolean
|
|
650
|
+
* } } ListGroupDefinition
|
|
651
|
+
*
|
|
652
|
+
* @typedef { {
|
|
653
|
+
* component?: import('preact').Component,
|
|
654
|
+
* entries: Array<EntryDefinition>,
|
|
655
|
+
* id: String,
|
|
656
|
+
* label: String,
|
|
657
|
+
* shouldOpen?: Boolean
|
|
658
|
+
* } } GroupDefinition
|
|
659
|
+
*
|
|
660
|
+
* @typedef { {
|
|
661
|
+
* [id: String]: GetDescriptionFunction
|
|
662
|
+
* } } DescriptionConfig
|
|
663
|
+
*
|
|
664
|
+
* @callback { {
|
|
665
|
+
* @param {string} id
|
|
666
|
+
* @param {Object} element
|
|
667
|
+
* @returns {string}
|
|
668
|
+
* } } GetDescriptionFunction
|
|
669
|
+
*
|
|
670
|
+
* @typedef { {
|
|
671
|
+
* getEmpty: (element: object) => import('./components/Placeholder').PlaceholderDefinition,
|
|
672
|
+
* getMultiple: (element: Object) => import('./components/Placeholder').PlaceholderDefinition
|
|
673
|
+
* } } PlaceholderProvider
|
|
674
|
+
*
|
|
587
675
|
*/
|
|
588
676
|
|
|
589
|
-
/**
|
|
590
|
-
* A basic properties panel component. Describes *how* content will be rendered, accepts
|
|
591
|
-
* data from implementor to describe *what* will be rendered.
|
|
592
|
-
*
|
|
593
|
-
* @param {Object} props
|
|
594
|
-
* @param {Object} props.element
|
|
595
|
-
* @param {import('./components/Header').HeaderProvider} props.headerProvider
|
|
596
|
-
* @param {
|
|
597
|
-
* @param {
|
|
598
|
-
* @param {
|
|
599
|
-
* @param {
|
|
600
|
-
* @param {
|
|
601
|
-
* @param {
|
|
677
|
+
/**
|
|
678
|
+
* A basic properties panel component. Describes *how* content will be rendered, accepts
|
|
679
|
+
* data from implementor to describe *what* will be rendered.
|
|
680
|
+
*
|
|
681
|
+
* @param {Object} props
|
|
682
|
+
* @param {Object|Array} props.element
|
|
683
|
+
* @param {import('./components/Header').HeaderProvider} props.headerProvider
|
|
684
|
+
* @param {PlaceholderProvider} [props.placeholderProvider]
|
|
685
|
+
* @param {Array<GroupDefinition|ListGroupDefinition>} props.groups
|
|
686
|
+
* @param {Object} [props.layoutConfig]
|
|
687
|
+
* @param {Function} [props.layoutChanged]
|
|
688
|
+
* @param {DescriptionConfig} [props.descriptionConfig]
|
|
689
|
+
* @param {Function} [props.descriptionLoaded]
|
|
690
|
+
* @param {Object} [props.eventBus]
|
|
602
691
|
*/
|
|
603
692
|
|
|
604
693
|
function PropertiesPanel(props) {
|
|
605
694
|
const {
|
|
606
695
|
element,
|
|
607
696
|
headerProvider,
|
|
697
|
+
placeholderProvider,
|
|
608
698
|
groups,
|
|
609
699
|
layoutConfig = {},
|
|
610
700
|
layoutChanged,
|
|
@@ -657,12 +747,16 @@ function PropertiesPanel(props) {
|
|
|
657
747
|
};
|
|
658
748
|
const propertiesPanelContext = {
|
|
659
749
|
element
|
|
660
|
-
};
|
|
750
|
+
}; // empty state
|
|
661
751
|
|
|
662
|
-
if (!element) {
|
|
663
|
-
return jsx(
|
|
664
|
-
|
|
665
|
-
|
|
752
|
+
if (placeholderProvider && !element) {
|
|
753
|
+
return jsx(Placeholder, { ...placeholderProvider.getEmpty()
|
|
754
|
+
});
|
|
755
|
+
} // multiple state
|
|
756
|
+
|
|
757
|
+
|
|
758
|
+
if (placeholderProvider && isArray(element)) {
|
|
759
|
+
return jsx(Placeholder, { ...placeholderProvider.getMultiple()
|
|
666
760
|
});
|
|
667
761
|
}
|
|
668
762
|
|
|
@@ -779,17 +873,17 @@ function MenuItem({
|
|
|
779
873
|
children: item.entry
|
|
780
874
|
});
|
|
781
875
|
}
|
|
782
|
-
/**
|
|
783
|
-
*
|
|
784
|
-
* @param {Array<null | Element>} ignoredElements
|
|
785
|
-
* @param {Function} callback
|
|
876
|
+
/**
|
|
877
|
+
*
|
|
878
|
+
* @param {Array<null | Element>} ignoredElements
|
|
879
|
+
* @param {Function} callback
|
|
786
880
|
*/
|
|
787
881
|
|
|
788
882
|
|
|
789
883
|
function useGlobalClick(ignoredElements, callback) {
|
|
790
884
|
useEffect(() => {
|
|
791
|
-
/**
|
|
792
|
-
* @param {MouseEvent} event
|
|
885
|
+
/**
|
|
886
|
+
* @param {MouseEvent} event
|
|
793
887
|
*/
|
|
794
888
|
function listener(event) {
|
|
795
889
|
if (ignoredElements.some(element => element && element.contains(event.target))) {
|
|
@@ -919,8 +1013,8 @@ function ListItem(props) {
|
|
|
919
1013
|
}
|
|
920
1014
|
|
|
921
1015
|
const noop$3 = () => {};
|
|
922
|
-
/**
|
|
923
|
-
* @param {import('../PropertiesPanel').ListGroupDefinition} props
|
|
1016
|
+
/**
|
|
1017
|
+
* @param {import('../PropertiesPanel').ListGroupDefinition} props
|
|
924
1018
|
*/
|
|
925
1019
|
|
|
926
1020
|
|
|
@@ -934,7 +1028,9 @@ function ListGroup(props) {
|
|
|
934
1028
|
shouldOpen = true,
|
|
935
1029
|
shouldSort = true
|
|
936
1030
|
} = props;
|
|
1031
|
+
const groupRef = useRef(null);
|
|
937
1032
|
const [open, setOpen] = useLayoutState(['groups', id, 'open'], false);
|
|
1033
|
+
const [sticky, setSticky] = useState(false);
|
|
938
1034
|
const onShow = useCallback(() => setOpen(true), [setOpen]);
|
|
939
1035
|
const [ordering, setOrdering] = useState([]);
|
|
940
1036
|
const [newItemAdded, setNewItemAdded] = useState(false);
|
|
@@ -1005,7 +1101,9 @@ function ListGroup(props) {
|
|
|
1005
1101
|
});
|
|
1006
1102
|
setOrdering(keep);
|
|
1007
1103
|
}
|
|
1008
|
-
}, [items, shouldHandleEffects]);
|
|
1104
|
+
}, [items, shouldHandleEffects]); // set css class when group is sticky to top
|
|
1105
|
+
|
|
1106
|
+
useStickyIntersectionObserver(groupRef, 'div.bio-properties-panel-scroll-container', setSticky);
|
|
1009
1107
|
|
|
1010
1108
|
const toggleOpen = () => setOpen(!open);
|
|
1011
1109
|
|
|
@@ -1016,8 +1114,9 @@ function ListGroup(props) {
|
|
|
1016
1114
|
return jsxs("div", {
|
|
1017
1115
|
class: "bio-properties-panel-group",
|
|
1018
1116
|
"data-group-id": 'group-' + id,
|
|
1117
|
+
ref: groupRef,
|
|
1019
1118
|
children: [jsxs("div", {
|
|
1020
|
-
class: classnames('bio-properties-panel-group-header', hasItems ? '' : 'empty', hasItems && open ? 'open' : ''),
|
|
1119
|
+
class: classnames('bio-properties-panel-group-header', hasItems ? '' : 'empty', hasItems && open ? 'open' : '', sticky && open ? 'sticky' : ''),
|
|
1021
1120
|
onClick: hasItems ? toggleOpen : noop$3,
|
|
1022
1121
|
children: [jsx("div", {
|
|
1023
1122
|
title: label,
|
|
@@ -1073,8 +1172,8 @@ function ListGroup(props) {
|
|
|
1073
1172
|
});
|
|
1074
1173
|
} // helpers ////////////////////
|
|
1075
1174
|
|
|
1076
|
-
/**
|
|
1077
|
-
* Sorts given items alphanumeric by label
|
|
1175
|
+
/**
|
|
1176
|
+
* Sorts given items alphanumeric by label
|
|
1078
1177
|
*/
|
|
1079
1178
|
|
|
1080
1179
|
function sortItems(items) {
|
|
@@ -1143,15 +1242,15 @@ function Checkbox(props) {
|
|
|
1143
1242
|
})]
|
|
1144
1243
|
});
|
|
1145
1244
|
}
|
|
1146
|
-
/**
|
|
1147
|
-
* @param {Object} props
|
|
1148
|
-
* @param {Object} props.element
|
|
1149
|
-
* @param {String} props.id
|
|
1150
|
-
* @param {String} props.description
|
|
1151
|
-
* @param {String} props.label
|
|
1152
|
-
* @param {Function} props.getValue
|
|
1153
|
-
* @param {Function} props.setValue
|
|
1154
|
-
* @param {boolean} [props.disabled]
|
|
1245
|
+
/**
|
|
1246
|
+
* @param {Object} props
|
|
1247
|
+
* @param {Object} props.element
|
|
1248
|
+
* @param {String} props.id
|
|
1249
|
+
* @param {String} props.description
|
|
1250
|
+
* @param {String} props.label
|
|
1251
|
+
* @param {Function} props.getValue
|
|
1252
|
+
* @param {Function} props.setValue
|
|
1253
|
+
* @param {boolean} [props.disabled]
|
|
1155
1254
|
*/
|
|
1156
1255
|
|
|
1157
1256
|
|
|
@@ -1224,8 +1323,8 @@ function List(props) {
|
|
|
1224
1323
|
setOpen(false);
|
|
1225
1324
|
}
|
|
1226
1325
|
}, [open, hasItems]);
|
|
1227
|
-
/**
|
|
1228
|
-
* @param {MouseEvent} event
|
|
1326
|
+
/**
|
|
1327
|
+
* @param {MouseEvent} event
|
|
1229
1328
|
*/
|
|
1230
1329
|
|
|
1231
1330
|
function addItem(event) {
|
|
@@ -1335,14 +1434,14 @@ function ItemsList(props) {
|
|
|
1335
1434
|
})
|
|
1336
1435
|
});
|
|
1337
1436
|
}
|
|
1338
|
-
/**
|
|
1339
|
-
* Place new items in the beginning of the list and sort the rest with provided function.
|
|
1340
|
-
*
|
|
1341
|
-
* @template Item
|
|
1342
|
-
* @param {Item[]} currentItems
|
|
1343
|
-
* @param {(a: Item, b: Item) => 0 | 1 | -1} [compareFn] function used to sort items
|
|
1344
|
-
* @param {boolean} [shouldReset=false] set to `true` to reset state of the hook
|
|
1345
|
-
* @returns {Item[]}
|
|
1437
|
+
/**
|
|
1438
|
+
* Place new items in the beginning of the list and sort the rest with provided function.
|
|
1439
|
+
*
|
|
1440
|
+
* @template Item
|
|
1441
|
+
* @param {Item[]} currentItems
|
|
1442
|
+
* @param {(a: Item, b: Item) => 0 | 1 | -1} [compareFn] function used to sort items
|
|
1443
|
+
* @param {boolean} [shouldReset=false] set to `true` to reset state of the hook
|
|
1444
|
+
* @returns {Item[]}
|
|
1346
1445
|
*/
|
|
1347
1446
|
|
|
1348
1447
|
|
|
@@ -1428,19 +1527,19 @@ function NumberField(props) {
|
|
|
1428
1527
|
})]
|
|
1429
1528
|
});
|
|
1430
1529
|
}
|
|
1431
|
-
/**
|
|
1432
|
-
* @param {Object} props
|
|
1433
|
-
* @param {Boolean} props.debounce
|
|
1434
|
-
* @param {String} props.description
|
|
1435
|
-
* @param {Boolean} props.disabled
|
|
1436
|
-
* @param {Object} props.element
|
|
1437
|
-
* @param {Function} props.getValue
|
|
1438
|
-
* @param {String} props.id
|
|
1439
|
-
* @param {String} props.label
|
|
1440
|
-
* @param {String} props.max
|
|
1441
|
-
* @param {String} props.min
|
|
1442
|
-
* @param {Function} props.setValue
|
|
1443
|
-
* @param {String} props.step
|
|
1530
|
+
/**
|
|
1531
|
+
* @param {Object} props
|
|
1532
|
+
* @param {Boolean} props.debounce
|
|
1533
|
+
* @param {String} props.description
|
|
1534
|
+
* @param {Boolean} props.disabled
|
|
1535
|
+
* @param {Object} props.element
|
|
1536
|
+
* @param {Function} props.getValue
|
|
1537
|
+
* @param {String} props.id
|
|
1538
|
+
* @param {String} props.label
|
|
1539
|
+
* @param {String} props.max
|
|
1540
|
+
* @param {String} props.min
|
|
1541
|
+
* @param {Function} props.setValue
|
|
1542
|
+
* @param {String} props.step
|
|
1444
1543
|
*/
|
|
1445
1544
|
|
|
1446
1545
|
|
|
@@ -1488,21 +1587,21 @@ function prefixId$5(id) {
|
|
|
1488
1587
|
}
|
|
1489
1588
|
|
|
1490
1589
|
const noop$1 = () => {};
|
|
1491
|
-
/**
|
|
1492
|
-
* @typedef { { value: string, label: string, disabled: boolean } } Option
|
|
1590
|
+
/**
|
|
1591
|
+
* @typedef { { value: string, label: string, disabled: boolean } } Option
|
|
1493
1592
|
*/
|
|
1494
1593
|
|
|
1495
|
-
/**
|
|
1496
|
-
* Provides basic select input.
|
|
1497
|
-
*
|
|
1498
|
-
* @param {object} props
|
|
1499
|
-
* @param {string} props.id
|
|
1500
|
-
* @param {string[]} props.path
|
|
1501
|
-
* @param {string} props.label
|
|
1502
|
-
* @param {Function} props.onChange
|
|
1503
|
-
* @param {Array<Option>} [props.options]
|
|
1504
|
-
* @param {string} props.value
|
|
1505
|
-
* @param {boolean} [props.disabled]
|
|
1594
|
+
/**
|
|
1595
|
+
* Provides basic select input.
|
|
1596
|
+
*
|
|
1597
|
+
* @param {object} props
|
|
1598
|
+
* @param {string} props.id
|
|
1599
|
+
* @param {string[]} props.path
|
|
1600
|
+
* @param {string} props.label
|
|
1601
|
+
* @param {Function} props.onChange
|
|
1602
|
+
* @param {Array<Option>} [props.options]
|
|
1603
|
+
* @param {string} props.value
|
|
1604
|
+
* @param {boolean} [props.disabled]
|
|
1506
1605
|
*/
|
|
1507
1606
|
|
|
1508
1607
|
|
|
@@ -1548,16 +1647,16 @@ function Select(props) {
|
|
|
1548
1647
|
})]
|
|
1549
1648
|
});
|
|
1550
1649
|
}
|
|
1551
|
-
/**
|
|
1552
|
-
* @param {object} props
|
|
1553
|
-
* @param {object} props.element
|
|
1554
|
-
* @param {string} props.id
|
|
1555
|
-
* @param {string} [props.description]
|
|
1556
|
-
* @param {string} props.label
|
|
1557
|
-
* @param {Function} props.getValue
|
|
1558
|
-
* @param {Function} props.setValue
|
|
1559
|
-
* @param {Function} props.getOptions
|
|
1560
|
-
* @param {boolean} [props.disabled]
|
|
1650
|
+
/**
|
|
1651
|
+
* @param {object} props
|
|
1652
|
+
* @param {object} props.element
|
|
1653
|
+
* @param {string} props.id
|
|
1654
|
+
* @param {string} [props.description]
|
|
1655
|
+
* @param {string} props.label
|
|
1656
|
+
* @param {Function} props.getValue
|
|
1657
|
+
* @param {Function} props.setValue
|
|
1658
|
+
* @param {Function} props.getOptions
|
|
1659
|
+
* @param {boolean} [props.disabled]
|
|
1561
1660
|
*/
|
|
1562
1661
|
|
|
1563
1662
|
|
|
@@ -1702,18 +1801,18 @@ function TextArea(props) {
|
|
|
1702
1801
|
})]
|
|
1703
1802
|
});
|
|
1704
1803
|
}
|
|
1705
|
-
/**
|
|
1706
|
-
* @param {object} props
|
|
1707
|
-
* @param {object} props.element
|
|
1708
|
-
* @param {string} props.id
|
|
1709
|
-
* @param {string} props.description
|
|
1710
|
-
* @param {boolean} props.debounce
|
|
1711
|
-
* @param {string} props.label
|
|
1712
|
-
* @param {Function} props.getValue
|
|
1713
|
-
* @param {Function} props.setValue
|
|
1714
|
-
* @param {number} props.rows
|
|
1715
|
-
* @param {boolean} props.monospace
|
|
1716
|
-
* @param {boolean} [props.disabled]
|
|
1804
|
+
/**
|
|
1805
|
+
* @param {object} props
|
|
1806
|
+
* @param {object} props.element
|
|
1807
|
+
* @param {string} props.id
|
|
1808
|
+
* @param {string} props.description
|
|
1809
|
+
* @param {boolean} props.debounce
|
|
1810
|
+
* @param {string} props.label
|
|
1811
|
+
* @param {Function} props.getValue
|
|
1812
|
+
* @param {Function} props.setValue
|
|
1813
|
+
* @param {number} props.rows
|
|
1814
|
+
* @param {boolean} props.monospace
|
|
1815
|
+
* @param {boolean} [props.disabled]
|
|
1717
1816
|
*/
|
|
1718
1817
|
|
|
1719
1818
|
|
|
@@ -1804,17 +1903,17 @@ function Textfield(props) {
|
|
|
1804
1903
|
})]
|
|
1805
1904
|
});
|
|
1806
1905
|
}
|
|
1807
|
-
/**
|
|
1808
|
-
* @param {Object} props
|
|
1809
|
-
* @param {Object} props.element
|
|
1810
|
-
* @param {String} props.id
|
|
1811
|
-
* @param {String} props.description
|
|
1812
|
-
* @param {Boolean} props.debounce
|
|
1813
|
-
* @param {Boolean} props.disabled
|
|
1814
|
-
* @param {String} props.label
|
|
1815
|
-
* @param {Function} props.getValue
|
|
1816
|
-
* @param {Function} props.setValue
|
|
1817
|
-
* @param {Function} props.validate
|
|
1906
|
+
/**
|
|
1907
|
+
* @param {Object} props
|
|
1908
|
+
* @param {Object} props.element
|
|
1909
|
+
* @param {String} props.id
|
|
1910
|
+
* @param {String} props.description
|
|
1911
|
+
* @param {Boolean} props.debounce
|
|
1912
|
+
* @param {Boolean} props.disabled
|
|
1913
|
+
* @param {String} props.label
|
|
1914
|
+
* @param {Function} props.getValue
|
|
1915
|
+
* @param {Function} props.setValue
|
|
1916
|
+
* @param {Function} props.validate
|
|
1818
1917
|
*/
|
|
1819
1918
|
|
|
1820
1919
|
|
|
@@ -1935,15 +2034,15 @@ function ToggleSwitch(props) {
|
|
|
1935
2034
|
})]
|
|
1936
2035
|
});
|
|
1937
2036
|
}
|
|
1938
|
-
/**
|
|
1939
|
-
* @param {Object} props
|
|
1940
|
-
* @param {Object} props.element
|
|
1941
|
-
* @param {String} props.id
|
|
1942
|
-
* @param {String} props.description
|
|
1943
|
-
* @param {String} props.label
|
|
1944
|
-
* @param {String} props.switcherLabel
|
|
1945
|
-
* @param {Function} props.getValue
|
|
1946
|
-
* @param {Function} props.setValue
|
|
2037
|
+
/**
|
|
2038
|
+
* @param {Object} props
|
|
2039
|
+
* @param {Object} props.element
|
|
2040
|
+
* @param {String} props.id
|
|
2041
|
+
* @param {String} props.description
|
|
2042
|
+
* @param {String} props.label
|
|
2043
|
+
* @param {String} props.switcherLabel
|
|
2044
|
+
* @param {Function} props.getValue
|
|
2045
|
+
* @param {Function} props.setValue
|
|
1947
2046
|
*/
|
|
1948
2047
|
|
|
1949
2048
|
|
|
@@ -1999,5 +2098,5 @@ var index = {
|
|
|
1999
2098
|
debounceInput: ['factory', debounceInput]
|
|
2000
2099
|
};
|
|
2001
2100
|
|
|
2002
|
-
export { ArrowIcon, CheckboxEntry, CollapsibleEntry, CreateIcon, index as DebounceInputModule, DeleteIcon, DescriptionContext, Description as DescriptionEntry, DropdownButton, EventContext, ExternalLinkIcon, FeelOptionalIcon, FeelRequiredIcon, Group, Header, HeaderButton, LayoutContext, List as ListEntry, ListGroup, ListItem, NumberFieldEntry, PropertiesPanel, LayoutContext as PropertiesPanelContext, SelectEntry, Simple as SimpleEntry, TextAreaEntry, TextfieldEntry as TextFieldEntry, ToggleSwitchEntry, isEdited$6 as isCheckboxEntryEdited, isEdited$5 as isNumberFieldEntryEdited, isEdited$4 as isSelectEntryEdited, isEdited$3 as isSimpleEntryEdited, isEdited$2 as isTextAreaEntryEdited, isEdited$1 as isTextFieldEntryEdited, isEdited as isToggleSwitchEntryEdited, useDescriptionContext, useEvent, useEventBuffer, useKeyFactory, useLayoutState, usePrevious, useShowEntryEvent, useShowErrorEvent };
|
|
2101
|
+
export { ArrowIcon, CheckboxEntry, CollapsibleEntry, CreateIcon, index as DebounceInputModule, DeleteIcon, DescriptionContext, Description as DescriptionEntry, DropdownButton, EventContext, ExternalLinkIcon, FeelOptionalIcon, FeelRequiredIcon, Group, Header, HeaderButton, LayoutContext, List as ListEntry, ListGroup, ListItem, NumberFieldEntry, Placeholder, PropertiesPanel, LayoutContext as PropertiesPanelContext, SelectEntry, Simple as SimpleEntry, TextAreaEntry, TextfieldEntry as TextFieldEntry, ToggleSwitchEntry, isEdited$6 as isCheckboxEntryEdited, isEdited$5 as isNumberFieldEntryEdited, isEdited$4 as isSelectEntryEdited, isEdited$3 as isSimpleEntryEdited, isEdited$2 as isTextAreaEntryEdited, isEdited$1 as isTextFieldEntryEdited, isEdited as isToggleSwitchEntryEdited, useDescriptionContext, useEvent, useEventBuffer, useKeyFactory, useLayoutState, usePrevious, useShowEntryEvent, useShowErrorEvent, useStickyIntersectionObserver };
|
|
2003
2102
|
//# sourceMappingURL=index.esm.js.map
|