@bpmn-io/properties-panel 0.8.0 → 0.10.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.
Files changed (177) hide show
  1. package/CHANGELOG.md +112 -85
  2. package/LICENSE +20 -20
  3. package/README.md +34 -34
  4. package/assets/properties-panel.css +891 -848
  5. package/dist/index.esm.js +1609 -0
  6. package/dist/index.esm.js.map +1 -0
  7. package/dist/index.js +1650 -0
  8. package/dist/index.js.map +1 -0
  9. package/package.json +87 -78
  10. package/preact/LICENSE +21 -0
  11. package/preact/README.md +185 -0
  12. package/preact/compat/dist/compat.js +2 -0
  13. package/preact/compat/dist/compat.js.map +1 -0
  14. package/preact/compat/dist/compat.mjs +2 -0
  15. package/preact/compat/dist/compat.module.js +2 -0
  16. package/preact/compat/dist/compat.module.js.map +1 -0
  17. package/preact/compat/dist/compat.umd.js +2 -0
  18. package/preact/compat/dist/compat.umd.js.map +1 -0
  19. package/preact/compat/jsx-dev-runtime.js +1 -0
  20. package/preact/compat/jsx-dev-runtime.mjs +1 -0
  21. package/preact/compat/jsx-runtime.js +1 -0
  22. package/preact/compat/jsx-runtime.mjs +1 -0
  23. package/preact/compat/package.json +19 -0
  24. package/preact/compat/server.js +15 -0
  25. package/preact/compat/server.mjs +4 -0
  26. package/preact/compat/src/Children.js +21 -0
  27. package/preact/compat/src/PureComponent.js +15 -0
  28. package/preact/compat/src/forwardRef.js +51 -0
  29. package/preact/compat/src/index.d.ts +140 -0
  30. package/preact/compat/src/index.js +175 -0
  31. package/preact/compat/src/internal.d.ts +47 -0
  32. package/preact/compat/src/memo.js +34 -0
  33. package/preact/compat/src/portals.js +80 -0
  34. package/preact/compat/src/render.js +219 -0
  35. package/preact/compat/src/scheduler.js +24 -0
  36. package/preact/compat/src/suspense-list.d.ts +14 -0
  37. package/preact/compat/src/suspense-list.js +126 -0
  38. package/preact/compat/src/suspense.d.ts +15 -0
  39. package/preact/compat/src/suspense.js +270 -0
  40. package/preact/compat/src/util.js +28 -0
  41. package/preact/compat/test-utils.js +1 -0
  42. package/preact/debug/dist/debug.js +2 -0
  43. package/preact/debug/dist/debug.js.map +1 -0
  44. package/preact/debug/dist/debug.mjs +2 -0
  45. package/preact/debug/dist/debug.module.js +2 -0
  46. package/preact/debug/dist/debug.module.js.map +1 -0
  47. package/preact/debug/dist/debug.umd.js +2 -0
  48. package/preact/debug/dist/debug.umd.js.map +1 -0
  49. package/preact/debug/package.json +18 -0
  50. package/preact/debug/src/check-props.js +54 -0
  51. package/preact/debug/src/component-stack.js +146 -0
  52. package/preact/debug/src/constants.js +3 -0
  53. package/preact/debug/src/debug.js +442 -0
  54. package/preact/debug/src/index.js +6 -0
  55. package/preact/debug/src/internal.d.ts +82 -0
  56. package/preact/debug/src/util.js +11 -0
  57. package/preact/devtools/dist/devtools.js +2 -0
  58. package/preact/devtools/dist/devtools.js.map +1 -0
  59. package/preact/devtools/dist/devtools.mjs +2 -0
  60. package/preact/devtools/dist/devtools.module.js +2 -0
  61. package/preact/devtools/dist/devtools.module.js.map +1 -0
  62. package/preact/devtools/dist/devtools.umd.js +2 -0
  63. package/preact/devtools/dist/devtools.umd.js.map +1 -0
  64. package/preact/devtools/package.json +16 -0
  65. package/preact/devtools/src/devtools.js +10 -0
  66. package/preact/devtools/src/index.d.ts +8 -0
  67. package/preact/devtools/src/index.js +15 -0
  68. package/preact/dist/preact.js +2 -0
  69. package/preact/dist/preact.js.map +1 -0
  70. package/preact/dist/preact.min.js +2 -0
  71. package/preact/dist/preact.min.js.map +1 -0
  72. package/preact/dist/preact.mjs +2 -0
  73. package/preact/dist/preact.module.js +2 -0
  74. package/preact/dist/preact.module.js.map +1 -0
  75. package/preact/dist/preact.umd.js +2 -0
  76. package/preact/dist/preact.umd.js.map +1 -0
  77. package/preact/hooks/dist/hooks.js +2 -0
  78. package/preact/hooks/dist/hooks.js.map +1 -0
  79. package/preact/hooks/dist/hooks.mjs +2 -0
  80. package/preact/hooks/dist/hooks.module.js +2 -0
  81. package/preact/hooks/dist/hooks.module.js.map +1 -0
  82. package/preact/hooks/dist/hooks.umd.js +2 -0
  83. package/preact/hooks/dist/hooks.umd.js.map +1 -0
  84. package/preact/hooks/package.json +26 -0
  85. package/preact/hooks/src/index.d.ts +130 -0
  86. package/preact/hooks/src/index.js +386 -0
  87. package/preact/hooks/src/internal.d.ts +75 -0
  88. package/preact/jsx-runtime/dist/jsxRuntime.js +2 -0
  89. package/preact/jsx-runtime/dist/jsxRuntime.js.map +1 -0
  90. package/preact/jsx-runtime/dist/jsxRuntime.mjs +2 -0
  91. package/preact/jsx-runtime/dist/jsxRuntime.module.js +2 -0
  92. package/preact/jsx-runtime/dist/jsxRuntime.module.js.map +1 -0
  93. package/preact/jsx-runtime/dist/jsxRuntime.umd.js +2 -0
  94. package/preact/jsx-runtime/dist/jsxRuntime.umd.js.map +1 -0
  95. package/preact/jsx-runtime/package.json +19 -0
  96. package/preact/jsx-runtime/src/index.d.ts +50 -0
  97. package/preact/jsx-runtime/src/index.js +72 -0
  98. package/preact/package.json +268 -0
  99. package/preact/src/cjs.js +3 -0
  100. package/preact/src/clone-element.js +39 -0
  101. package/preact/src/component.js +225 -0
  102. package/preact/src/constants.js +3 -0
  103. package/preact/src/create-context.js +68 -0
  104. package/preact/src/create-element.js +100 -0
  105. package/preact/src/diff/catch-error.js +38 -0
  106. package/preact/src/diff/children.js +347 -0
  107. package/preact/src/diff/index.js +516 -0
  108. package/preact/src/diff/props.js +158 -0
  109. package/preact/src/index.d.ts +310 -0
  110. package/preact/src/index.js +13 -0
  111. package/preact/src/internal.d.ts +147 -0
  112. package/preact/src/jsx.d.ts +955 -0
  113. package/preact/src/options.js +17 -0
  114. package/preact/src/render.js +74 -0
  115. package/preact/src/util.js +23 -0
  116. package/preact/test-utils/dist/testUtils.js +2 -0
  117. package/preact/test-utils/dist/testUtils.js.map +1 -0
  118. package/preact/test-utils/dist/testUtils.mjs +2 -0
  119. package/preact/test-utils/dist/testUtils.module.js +2 -0
  120. package/preact/test-utils/dist/testUtils.module.js.map +1 -0
  121. package/preact/test-utils/dist/testUtils.umd.js +2 -0
  122. package/preact/test-utils/dist/testUtils.umd.js.map +1 -0
  123. package/preact/test-utils/package.json +19 -0
  124. package/preact/test-utils/src/index.d.ts +3 -0
  125. package/preact/test-utils/src/index.js +117 -0
  126. package/lib/PropertiesPanel.js +0 -126
  127. package/lib/PropertiesPanel.js.map +0 -1
  128. package/lib/components/DropdownButton.js +0 -109
  129. package/lib/components/DropdownButton.js.map +0 -1
  130. package/lib/components/Group.js +0 -75
  131. package/lib/components/Group.js.map +0 -1
  132. package/lib/components/Header.js +0 -49
  133. package/lib/components/Header.js.map +0 -1
  134. package/lib/components/HeaderButton.js +0 -16
  135. package/lib/components/HeaderButton.js.map +0 -1
  136. package/lib/components/ListGroup.js +0 -167
  137. package/lib/components/ListGroup.js.map +0 -1
  138. package/lib/components/ListItem.js +0 -37
  139. package/lib/components/ListItem.js.map +0 -1
  140. package/lib/components/entries/Checkbox.js +0 -81
  141. package/lib/components/entries/Checkbox.js.map +0 -1
  142. package/lib/components/entries/Collapsible.js +0 -48
  143. package/lib/components/entries/Collapsible.js.map +0 -1
  144. package/lib/components/entries/List.js +0 -204
  145. package/lib/components/entries/List.js.map +0 -1
  146. package/lib/components/entries/NumberField.js +0 -108
  147. package/lib/components/entries/NumberField.js.map +0 -1
  148. package/lib/components/entries/Select.js +0 -107
  149. package/lib/components/entries/Select.js.map +0 -1
  150. package/lib/components/entries/Simple.js +0 -56
  151. package/lib/components/entries/Simple.js.map +0 -1
  152. package/lib/components/entries/TextArea.js +0 -96
  153. package/lib/components/entries/TextArea.js.map +0 -1
  154. package/lib/components/entries/TextField.js +0 -121
  155. package/lib/components/entries/TextField.js.map +0 -1
  156. package/lib/components/entries/ToggleSwitch.js +0 -87
  157. package/lib/components/entries/ToggleSwitch.js.map +0 -1
  158. package/lib/components/icons/index.js +0 -51
  159. package/lib/components/icons/index.js.map +0 -1
  160. package/lib/context/LayoutContext.js +0 -9
  161. package/lib/context/LayoutContext.js.map +0 -1
  162. package/lib/context/index.js +0 -2
  163. package/lib/context/index.js.map +0 -1
  164. package/lib/features/debounce-input/debounceInput.js +0 -14
  165. package/lib/features/debounce-input/debounceInput.js.map +0 -1
  166. package/lib/features/debounce-input/index.js +0 -5
  167. package/lib/features/debounce-input/index.js.map +0 -1
  168. package/lib/hooks/index.js +0 -4
  169. package/lib/hooks/index.js.map +0 -1
  170. package/lib/hooks/useKeyFactory.js +0 -39
  171. package/lib/hooks/useKeyFactory.js.map +0 -1
  172. package/lib/hooks/useLayoutState.js +0 -36
  173. package/lib/hooks/useLayoutState.js.map +0 -1
  174. package/lib/hooks/usePrevious.js +0 -16
  175. package/lib/hooks/usePrevious.js.map +0 -1
  176. package/lib/index.js +0 -2
  177. package/lib/index.js.map +0 -1
@@ -0,0 +1,1609 @@
1
+ import { useRef, useEffect, useMemo, useContext, useState } from '../preact/hooks';
2
+ import { isFunction, get, assign, set, sortBy, find, isNumber, debounce } from 'min-dash';
3
+ import classnames from 'classnames';
4
+ import { jsxs, jsx } from '../preact/jsx-runtime';
5
+ import { query } from 'min-dom';
6
+ import { createContext } from '../preact';
7
+ import '../preact/compat';
8
+
9
+ /**
10
+ * @typedef { { getElementLabel: Function, getTypeLabel: Function, getElementIcon: Function } } HeaderProvider
11
+ */
12
+
13
+ /**
14
+ * @param {Object} props
15
+ * @param {Object} props.element,
16
+ * @param {HeaderProvider} props.headerProvider
17
+ */
18
+ function Header(props) {
19
+ const {
20
+ element,
21
+ headerProvider
22
+ } = props;
23
+ const {
24
+ getElementLabel,
25
+ getTypeLabel,
26
+ getElementIcon
27
+ } = headerProvider;
28
+ const label = getElementLabel(element);
29
+ const type = getTypeLabel(element);
30
+ const ElementIcon = getElementIcon(element);
31
+ return jsxs("div", {
32
+ class: "bio-properties-panel-header",
33
+ children: [jsx("div", {
34
+ class: "bio-properties-panel-header-icon",
35
+ children: ElementIcon && jsx(ElementIcon, {
36
+ width: "32",
37
+ height: "32",
38
+ viewBox: "0 0 32 32"
39
+ })
40
+ }), jsxs("div", {
41
+ class: "bio-properties-panel-header-labels",
42
+ children: [jsx("div", {
43
+ title: type,
44
+ class: "bio-properties-panel-header-type",
45
+ children: type
46
+ }), getElementLabel(element) ? jsx("div", {
47
+ title: label,
48
+ class: "bio-properties-panel-header-label",
49
+ children: label
50
+ }) : null]
51
+ })]
52
+ });
53
+ }
54
+
55
+ /**
56
+ * @pinussilvestrus: we need to introduce our own hook to persist the previous
57
+ * state on updates.
58
+ *
59
+ * cf. https://reactjs.org/docs/hooks-faq.html#how-to-get-the-previous-props-or-state
60
+ */
61
+
62
+ function usePrevious(value) {
63
+ const ref = useRef();
64
+ useEffect(() => {
65
+ ref.current = value;
66
+ });
67
+ return ref.current;
68
+ }
69
+
70
+ const KEY_LENGTH = 6;
71
+ /**
72
+ * Create a persistent key factory for plain objects without id.
73
+ *
74
+ * @example
75
+ * ```jsx
76
+ * function List({ objects }) {
77
+ * const getKey = useKeyFactory();
78
+ * return (<ol>{
79
+ * objects.map(obj => {
80
+ * const key = getKey(obj);
81
+ * return <li key={key}>obj.name</li>
82
+ * })
83
+ * }</ol>);
84
+ * }
85
+ * ```
86
+ *
87
+ * @param {any[]} dependencies
88
+ * @returns {(element: object) => string}
89
+ */
90
+
91
+ function useKeyFactory(dependencies = []) {
92
+ const map = useMemo(() => new Map(), dependencies);
93
+
94
+ const getKey = el => {
95
+ let key = map.get(el);
96
+
97
+ if (!key) {
98
+ key = Math.random().toString().slice(-KEY_LENGTH);
99
+ map.set(el, key);
100
+ }
101
+
102
+ return key;
103
+ };
104
+
105
+ return getKey;
106
+ }
107
+
108
+ const DescriptionContext = createContext({
109
+ description: {},
110
+ getDescriptionForId: () => {}
111
+ });
112
+
113
+ const LayoutContext = createContext({
114
+ layout: {},
115
+ setLayout: () => {},
116
+ getLayoutForKey: () => {},
117
+ setLayoutForKey: () => {}
118
+ });
119
+
120
+ /**
121
+ * Creates a state that persists in the global LayoutContext.
122
+ *
123
+ * @example
124
+ * ```jsx
125
+ * function Group(props) {
126
+ * const [ open, setOpen ] = useLayoutState([ 'groups', 'foo', 'open' ], false);
127
+ * }
128
+ * ```
129
+ *
130
+ * @param {(string|number)[]} path
131
+ * @param {any} [defaultValue]
132
+ *
133
+ * @returns {[ any, Function ]}
134
+ */
135
+
136
+ function useLayoutState(path, defaultValue) {
137
+ const {
138
+ getLayoutForKey,
139
+ setLayoutForKey
140
+ } = useContext(LayoutContext);
141
+ const layoutForKey = getLayoutForKey(path, defaultValue);
142
+ const [value, set] = useState(layoutForKey);
143
+
144
+ const setState = newValue => {
145
+ // (1) set component state
146
+ set(newValue); // (2) set context
147
+
148
+ setLayoutForKey(path, newValue);
149
+ };
150
+
151
+ return [value, setState];
152
+ }
153
+
154
+ /**
155
+ * Accesses the global DescriptionContext and returns a description for a given id and element.
156
+ *
157
+ * @example
158
+ * ```jsx
159
+ * function TextField(props) {
160
+ * const description = useDescriptionContext('input1', element);
161
+ * }
162
+ * ```
163
+ *
164
+ * @param {string} id
165
+ * @param {djs.model.Base} element
166
+ *
167
+ * @returns {string}
168
+ */
169
+
170
+ function useDescriptionContext(id, element) {
171
+ const {
172
+ getDescriptionForId
173
+ } = useContext(DescriptionContext);
174
+ return getDescriptionForId(id, element);
175
+ }
176
+
177
+ var ArrowIcon = function ArrowIcon(props) {
178
+ return jsx("svg", { ...props,
179
+ children: jsx("path", {
180
+ fillRule: "evenodd",
181
+ 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"
182
+ })
183
+ });
184
+ };
185
+
186
+ ArrowIcon.defaultProps = {
187
+ xmlns: "http://www.w3.org/2000/svg",
188
+ width: "16",
189
+ height: "16"
190
+ };
191
+
192
+ var CreateIcon = function CreateIcon(props) {
193
+ return jsx("svg", { ...props,
194
+ children: jsx("path", {
195
+ fillRule: "evenodd",
196
+ 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"
197
+ })
198
+ });
199
+ };
200
+
201
+ CreateIcon.defaultProps = {
202
+ xmlns: "http://www.w3.org/2000/svg",
203
+ width: "16",
204
+ height: "16"
205
+ };
206
+
207
+ var DeleteIcon = function DeleteIcon(props) {
208
+ return jsx("svg", { ...props,
209
+ children: jsx("path", {
210
+ fillRule: "evenodd",
211
+ 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"
212
+ })
213
+ });
214
+ };
215
+
216
+ DeleteIcon.defaultProps = {
217
+ xmlns: "http://www.w3.org/2000/svg",
218
+ width: "16",
219
+ height: "16"
220
+ };
221
+
222
+ function Group(props) {
223
+ const {
224
+ id,
225
+ entries = [],
226
+ label
227
+ } = props;
228
+ const [open, setOpen] = useLayoutState(['groups', id, 'open'], false);
229
+
230
+ const toggleOpen = () => setOpen(!open);
231
+
232
+ const [edited, setEdited] = useState(false); // set edited state depending on all entries
233
+
234
+ useEffect(() => {
235
+ const hasOneEditedEntry = entries.find(entry => {
236
+ const {
237
+ id,
238
+ isEdited
239
+ } = entry;
240
+ const entryNode = query(`[data-entry-id="${id}"]`);
241
+
242
+ if (!isFunction(isEdited) || !entryNode) {
243
+ return false;
244
+ }
245
+
246
+ const inputNode = query('.bio-properties-panel-input', entryNode);
247
+ return isEdited(inputNode);
248
+ });
249
+ setEdited(hasOneEditedEntry);
250
+ }, [entries]);
251
+ return jsxs("div", {
252
+ class: "bio-properties-panel-group",
253
+ "data-group-id": 'group-' + id,
254
+ children: [jsxs("div", {
255
+ class: classnames('bio-properties-panel-group-header', edited ? '' : 'empty', open ? 'open' : ''),
256
+ onClick: toggleOpen,
257
+ children: [jsx("div", {
258
+ title: label,
259
+ class: "bio-properties-panel-group-header-title",
260
+ children: label
261
+ }), jsxs("div", {
262
+ class: "bio-properties-panel-group-header-buttons",
263
+ children: [edited && jsx(DataMarker, {}), jsx("button", {
264
+ title: "Toggle section",
265
+ class: "bio-properties-panel-group-header-button bio-properties-panel-arrow",
266
+ children: jsx(ArrowIcon, {
267
+ class: open ? 'bio-properties-panel-arrow-down' : 'bio-properties-panel-arrow-right'
268
+ })
269
+ })]
270
+ })]
271
+ }), jsx("div", {
272
+ class: classnames('bio-properties-panel-group-entries', open ? 'open' : ''),
273
+ children: entries.map(e => e.component)
274
+ })]
275
+ });
276
+ }
277
+
278
+ function DataMarker() {
279
+ return jsx("div", {
280
+ title: "Section contains data",
281
+ class: "bio-properties-panel-dot"
282
+ });
283
+ }
284
+
285
+ const DEFAULT_LAYOUT = {
286
+ open: true
287
+ };
288
+ const DEFAULT_DESCRIPTION = {};
289
+ /**
290
+ * @typedef { {
291
+ * component: import('preact').ComponentChild,
292
+ * id: String,
293
+ * isEdited?: Function
294
+ * } } EntryDefinition
295
+ *
296
+ * @typedef { {
297
+ * autoFocusEntry: String,
298
+ * autoOpen?: Boolean,
299
+ * entries: Array<EntryDefinition>,
300
+ * id: String,
301
+ * label: String,
302
+ * remove: (event: MouseEvent) => void
303
+ * } } ListItemDefinition
304
+ *
305
+ * @typedef { {
306
+ * add: (event: MouseEvent) => void,
307
+ * component: import('preact').Component,
308
+ * element: Object,
309
+ * id: String,
310
+ * items: Array<ListItemDefinition>,
311
+ * label: String,
312
+ * shouldSort?: Boolean,
313
+ * shouldOpen?: Boolean
314
+ * } } ListGroupDefinition
315
+ *
316
+ * @typedef { {
317
+ * component?: import('preact').Component,
318
+ * entries: Array<EntryDefinition>,
319
+ * id: String,
320
+ * label: String
321
+ * } } GroupDefinition
322
+ *
323
+ * @typedef { {
324
+ * [id: String]: GetDescriptionFunction
325
+ * } } DescriptionConfig
326
+ *
327
+ * @callback { {
328
+ * @param {string} id
329
+ * @param {djs.model.base} element
330
+ * @returns {string}
331
+ * } } GetDescriptionFunction
332
+ *
333
+ */
334
+
335
+ /**
336
+ * A basic properties panel component. Describes *how* content will be rendered, accepts
337
+ * data from implementor to describe *what* will be rendered.
338
+ *
339
+ * @param {Object} props
340
+ * @param {Object} props.element
341
+ * @param {import('./components/Header').HeaderProvider} props.headerProvider
342
+ * @param {Array<GroupDefinition|ListGroupDefinition>} props.groups
343
+ * @param {Object} [props.layoutConfig]
344
+ * @param {Function} [props.layoutChanged]
345
+ * @param {DescriptionConfig} [props.descriptionConfig]
346
+ * @param {Function} [props.descriptionLoaded]
347
+ */
348
+
349
+ function PropertiesPanel(props) {
350
+ const {
351
+ element,
352
+ headerProvider,
353
+ groups,
354
+ layoutConfig = {},
355
+ layoutChanged,
356
+ descriptionConfig = {},
357
+ descriptionLoaded
358
+ } = props; // set-up layout context
359
+
360
+ const [layout, setLayout] = useState(createLayout(layoutConfig));
361
+ useEffect(() => {
362
+ if (typeof layoutChanged === 'function') {
363
+ layoutChanged(layout);
364
+ }
365
+ }, [layout, layoutChanged]);
366
+
367
+ const getLayoutForKey = (key, defaultValue) => {
368
+ return get(layout, key, defaultValue);
369
+ };
370
+
371
+ const setLayoutForKey = (key, config) => {
372
+ const newLayout = assign({}, layout);
373
+ set(newLayout, key, config);
374
+ setLayout(newLayout);
375
+ };
376
+
377
+ const layoutContext = {
378
+ layout,
379
+ setLayout,
380
+ getLayoutForKey,
381
+ setLayoutForKey
382
+ }; // set-up description context
383
+
384
+ const description = createDescriptionContext(descriptionConfig);
385
+
386
+ if (typeof descriptionLoaded === 'function') {
387
+ descriptionLoaded(description);
388
+ }
389
+
390
+ const getDescriptionForId = (id, element) => {
391
+ return description[id] && description[id](element);
392
+ };
393
+
394
+ const descriptionContext = {
395
+ description,
396
+ getDescriptionForId
397
+ };
398
+
399
+ if (!element) {
400
+ return jsx("div", {
401
+ class: "bio-properties-panel-placeholder",
402
+ children: "Select an element to edit its properties."
403
+ });
404
+ }
405
+
406
+ return jsx(DescriptionContext.Provider, {
407
+ value: descriptionContext,
408
+ children: jsx(LayoutContext.Provider, {
409
+ value: layoutContext,
410
+ children: jsxs("div", {
411
+ class: classnames('bio-properties-panel', layout.open ? 'open' : ''),
412
+ children: [jsx(Header, {
413
+ element: element,
414
+ headerProvider: headerProvider
415
+ }), jsx("div", {
416
+ class: "bio-properties-panel-scroll-container",
417
+ children: groups.map(group => {
418
+ const {
419
+ component: GroupComponent = Group,
420
+ id
421
+ } = group;
422
+ return jsx(GroupComponent, {
423
+ element: element,
424
+ ...group
425
+ }, id);
426
+ })
427
+ })]
428
+ })
429
+ })
430
+ });
431
+ } // helpers //////////////////
432
+
433
+ function createLayout(overrides) {
434
+ return { ...DEFAULT_LAYOUT,
435
+ ...overrides
436
+ };
437
+ }
438
+
439
+ function createDescriptionContext(overrides) {
440
+ return { ...DEFAULT_DESCRIPTION,
441
+ ...overrides
442
+ };
443
+ }
444
+
445
+ function DropdownButton(props) {
446
+ const {
447
+ class: className,
448
+ children,
449
+ menuItems = []
450
+ } = props;
451
+ const dropdownRef = useRef(null);
452
+ const menuRef = useRef(null);
453
+ const [open, setOpen] = useState(false);
454
+
455
+ const close = () => setOpen(false);
456
+
457
+ function onDropdownToggle(event) {
458
+ if (menuRef.current && menuRef.current.contains(event.target)) {
459
+ return;
460
+ }
461
+
462
+ event.stopPropagation();
463
+ setOpen(open => !open);
464
+ }
465
+
466
+ function onActionClick(event, action) {
467
+ event.stopPropagation();
468
+ close();
469
+ action();
470
+ }
471
+
472
+ useGlobalClick([dropdownRef.current], () => close());
473
+ return jsxs("div", {
474
+ class: classnames('bio-properties-panel-dropdown-button', {
475
+ open
476
+ }, className),
477
+ onClick: onDropdownToggle,
478
+ ref: dropdownRef,
479
+ children: [children, jsx("div", {
480
+ class: "bio-properties-panel-dropdown-button__menu",
481
+ ref: menuRef,
482
+ children: menuItems.map((item, index) => jsx(MenuItem, {
483
+ onClick: onActionClick,
484
+ item: item
485
+ }, index))
486
+ })]
487
+ });
488
+ }
489
+
490
+ function MenuItem({
491
+ item,
492
+ onClick
493
+ }) {
494
+ if (item.separator) {
495
+ return jsx("div", {
496
+ class: "bio-properties-panel-dropdown-button__menu-item bio-properties-panel-dropdown-button__menu-item--separator"
497
+ });
498
+ }
499
+
500
+ if (item.action) {
501
+ return jsx("button", {
502
+ class: "bio-properties-panel-dropdown-button__menu-item bio-properties-panel-dropdown-button__menu-item--actionable",
503
+ onClick: event => onClick(event, item.action),
504
+ children: item.entry
505
+ });
506
+ }
507
+
508
+ return jsx("div", {
509
+ class: "bio-properties-panel-dropdown-button__menu-item",
510
+ children: item.entry
511
+ });
512
+ }
513
+ /**
514
+ *
515
+ * @param {Array<null | Element>} ignoredElements
516
+ * @param {Function} callback
517
+ */
518
+
519
+
520
+ function useGlobalClick(ignoredElements, callback) {
521
+ useEffect(() => {
522
+ /**
523
+ * @param {MouseEvent} event
524
+ */
525
+ function listener(event) {
526
+ if (ignoredElements.some(element => element && element.contains(event.target))) {
527
+ return;
528
+ }
529
+
530
+ callback();
531
+ }
532
+
533
+ document.addEventListener('click', listener, {
534
+ capture: true
535
+ });
536
+ return () => document.removeEventListener('click', listener, {
537
+ capture: true
538
+ });
539
+ }, [...ignoredElements, callback]);
540
+ }
541
+
542
+ function HeaderButton(props) {
543
+ const {
544
+ children = null,
545
+ class: classname,
546
+ onClick = () => {},
547
+ ...otherProps
548
+ } = props;
549
+ return jsx("button", { ...otherProps,
550
+ onClick: onClick,
551
+ class: classnames('bio-properties-panel-group-header-button', classname),
552
+ children: children
553
+ });
554
+ }
555
+
556
+ function CollapsibleEntry(props) {
557
+ const {
558
+ id,
559
+ entries = [],
560
+ label,
561
+ remove,
562
+ open: shouldOpen
563
+ } = props;
564
+ const [open, setOpen] = useState(shouldOpen);
565
+
566
+ const toggleOpen = () => setOpen(!open); // todo(pinussilvestrus): translate once we have a translate mechanism for the core
567
+
568
+
569
+ const placeholderLabel = '<empty>';
570
+ return jsxs("div", {
571
+ "data-entry-id": id,
572
+ class: classnames('bio-properties-panel-collapsible-entry', open ? 'open' : ''),
573
+ children: [jsxs("div", {
574
+ class: "bio-properties-panel-collapsible-entry-header",
575
+ onClick: toggleOpen,
576
+ children: [jsx("div", {
577
+ title: label || placeholderLabel,
578
+ class: classnames('bio-properties-panel-collapsible-entry-header-title', !label && 'empty'),
579
+ children: label || placeholderLabel
580
+ }), jsx("button", {
581
+ title: "Toggle list item",
582
+ class: "bio-properties-panel-arrow bio-properties-panel-collapsible-entry-arrow",
583
+ children: jsx(ArrowIcon, {
584
+ class: open ? 'bio-properties-panel-arrow-down' : 'bio-properties-panel-arrow-right'
585
+ })
586
+ }), remove ? jsx("button", {
587
+ title: "Delete item",
588
+ class: "bio-properties-panel-remove-entry",
589
+ onClick: remove,
590
+ children: jsx(DeleteIcon, {})
591
+ }) : null]
592
+ }), jsx("div", {
593
+ class: classnames('bio-properties-panel-collapsible-entry-entries', open ? 'open' : ''),
594
+ children: entries.map(e => e.component)
595
+ })]
596
+ });
597
+ }
598
+
599
+ function ListItem(props) {
600
+ const {
601
+ autoOpen,
602
+ autoFocusEntry
603
+ } = props; // focus specified entry on auto open
604
+
605
+ useEffect(() => {
606
+ if (autoOpen && autoFocusEntry) {
607
+ const entry = query(`[data-entry-id="${autoFocusEntry}"]`);
608
+ const focusableInput = query('.bio-properties-panel-input', entry);
609
+
610
+ if (focusableInput) {
611
+ if (isFunction(focusableInput.select)) {
612
+ focusableInput.select();
613
+ } else if (isFunction(focusableInput.focus)) {
614
+ focusableInput.focus();
615
+ }
616
+ }
617
+ }
618
+ }, [autoOpen, autoFocusEntry]);
619
+ return jsx("div", {
620
+ class: "bio-properties-panel-list-item",
621
+ children: jsx(CollapsibleEntry, { ...props,
622
+ open: autoOpen
623
+ })
624
+ });
625
+ }
626
+
627
+ const noop = () => {};
628
+ /**
629
+ * @param {import('../PropertiesPanel').ListGroupDefinition} props
630
+ */
631
+
632
+
633
+ function ListGroup(props) {
634
+ const {
635
+ element,
636
+ id,
637
+ items,
638
+ label,
639
+ add,
640
+ shouldSort = true,
641
+ shouldOpen = true
642
+ } = props;
643
+ const [open, setOpen] = useLayoutState(['groups', id, 'open'], false);
644
+ const [ordering, setOrdering] = useState([]);
645
+ const [newItemAdded, setNewItemAdded] = useState(false);
646
+ const prevItems = usePrevious(items);
647
+ const prevElement = usePrevious(element);
648
+ const elementChanged = element !== prevElement;
649
+ const shouldHandleEffects = !elementChanged && (shouldSort || shouldOpen); // reset initial ordering when element changes (before first render)
650
+
651
+ if (elementChanged) {
652
+ setOrdering(createOrdering(shouldSort ? sortItems(items) : items));
653
+ } // keep ordering in sync to items - and open changes
654
+ // (0) set initial ordering from given items
655
+
656
+
657
+ useEffect(() => {
658
+ if (!prevItems || !shouldSort) {
659
+ setOrdering(createOrdering(items));
660
+ }
661
+ }, [items, element]); // (1) items were added
662
+
663
+ useEffect(() => {
664
+ if (shouldHandleEffects && prevItems && items.length > prevItems.length) {
665
+ let add = [];
666
+ items.forEach(item => {
667
+ if (!ordering.includes(item.id)) {
668
+ add.push(item.id);
669
+ }
670
+ });
671
+ let newOrdering = ordering; // open if not open and configured
672
+
673
+ if (!open && shouldOpen) {
674
+ toggleOpen(); // if I opened and I should sort, then sort items
675
+
676
+ if (shouldSort) {
677
+ newOrdering = createOrdering(sortItems(items));
678
+ }
679
+ } // add new items on top or bottom depending on sorting behavior
680
+
681
+
682
+ newOrdering = newOrdering.filter(item => !add.includes(item));
683
+
684
+ if (shouldSort) {
685
+ newOrdering.unshift(...add);
686
+ } else {
687
+ newOrdering.push(...add);
688
+ }
689
+
690
+ setOrdering(newOrdering);
691
+ setNewItemAdded(true);
692
+ } else {
693
+ setNewItemAdded(false);
694
+ }
695
+ }, [items, open, shouldHandleEffects]); // (2) sort items on open if shouldSort is set
696
+
697
+ useEffect(() => {
698
+ if (shouldSort && open && !newItemAdded) {
699
+ setOrdering(createOrdering(sortItems(items)));
700
+ }
701
+ }, [open, shouldSort]); // (3) items were deleted
702
+
703
+ useEffect(() => {
704
+ if (shouldHandleEffects && prevItems && items.length < prevItems.length) {
705
+ let keep = [];
706
+ ordering.forEach(o => {
707
+ if (getItem(items, o)) {
708
+ keep.push(o);
709
+ }
710
+ });
711
+ setOrdering(keep);
712
+ }
713
+ }, [items, shouldHandleEffects]);
714
+
715
+ const toggleOpen = () => setOpen(!open);
716
+
717
+ const hasItems = !!items.length;
718
+ return jsxs("div", {
719
+ class: "bio-properties-panel-group",
720
+ "data-group-id": 'group-' + id,
721
+ children: [jsxs("div", {
722
+ class: classnames('bio-properties-panel-group-header', hasItems ? '' : 'empty', hasItems && open ? 'open' : ''),
723
+ onClick: hasItems ? toggleOpen : noop,
724
+ children: [jsx("div", {
725
+ title: label,
726
+ class: "bio-properties-panel-group-header-title",
727
+ children: label
728
+ }), jsxs("div", {
729
+ class: "bio-properties-panel-group-header-buttons",
730
+ children: [add ? jsxs("button", {
731
+ title: "Create new list item",
732
+ class: "bio-properties-panel-group-header-button bio-properties-panel-add-entry",
733
+ onClick: add,
734
+ children: [jsx(CreateIcon, {}), !hasItems ? jsx("span", {
735
+ class: "bio-properties-panel-add-entry-label",
736
+ children: "Create"
737
+ }) : null]
738
+ }) : null, hasItems ? jsx("div", {
739
+ title: `List contains ${items.length} item${items.length != 1 ? 's' : ''}`,
740
+ class: "bio-properties-panel-list-badge",
741
+ children: items.length
742
+ }) : null, hasItems ? jsx("button", {
743
+ title: "Toggle section",
744
+ class: "bio-properties-panel-group-header-button bio-properties-panel-arrow",
745
+ children: jsx(ArrowIcon, {
746
+ class: open ? 'bio-properties-panel-arrow-down' : 'bio-properties-panel-arrow-right'
747
+ })
748
+ }) : null]
749
+ })]
750
+ }), jsx("div", {
751
+ class: classnames('bio-properties-panel-list', open && hasItems ? 'open' : ''),
752
+ children: ordering.map((o, index) => {
753
+ const item = getItem(items, o);
754
+
755
+ if (!item) {
756
+ return;
757
+ }
758
+
759
+ return jsx(ListItem, {
760
+ // if item was added, open first or last item based on ordering
761
+ autoOpen: newItemAdded && (shouldSort ? index === 0 : index === ordering.length - 1),
762
+ ...item
763
+ }, item.id);
764
+ })
765
+ })]
766
+ });
767
+ } // helpers ////////////////////
768
+
769
+ /**
770
+ * Sorts given items alphanumeric by label
771
+ */
772
+
773
+ function sortItems(items) {
774
+ return sortBy(items, i => i.label.toLowerCase());
775
+ }
776
+
777
+ function getItem(items, id) {
778
+ return find(items, i => i.id === id);
779
+ }
780
+
781
+ function createOrdering(items) {
782
+ return items.map(i => i.id);
783
+ }
784
+
785
+ function Description(props) {
786
+ const {
787
+ element,
788
+ forId,
789
+ value
790
+ } = props;
791
+ const contextDescription = useDescriptionContext(forId, element);
792
+ const description = value || contextDescription;
793
+
794
+ if (description) {
795
+ return jsx("div", {
796
+ class: "bio-properties-panel-description",
797
+ children: description
798
+ });
799
+ }
800
+ }
801
+
802
+ function Checkbox(props) {
803
+ const {
804
+ id,
805
+ label,
806
+ onChange,
807
+ disabled,
808
+ value = false
809
+ } = props;
810
+
811
+ const handleChange = ({
812
+ target
813
+ }) => {
814
+ onChange(target.checked);
815
+ };
816
+
817
+ return jsxs("div", {
818
+ class: "bio-properties-panel-checkbox",
819
+ children: [jsx("input", {
820
+ id: prefixId$6(id),
821
+ name: id,
822
+ type: "checkbox",
823
+ class: "bio-properties-panel-input",
824
+ onChange: handleChange,
825
+ checked: value,
826
+ disabled: disabled
827
+ }), jsx("label", {
828
+ for: prefixId$6(id),
829
+ class: "bio-properties-panel-label",
830
+ children: label
831
+ })]
832
+ });
833
+ }
834
+ /**
835
+ * @param {Object} props
836
+ * @param {Object} props.element
837
+ * @param {String} props.id
838
+ * @param {String} props.description
839
+ * @param {String} props.label
840
+ * @param {Function} props.getValue
841
+ * @param {Function} props.setValue
842
+ * @param {boolean} [props.disabled]
843
+ */
844
+
845
+
846
+ function CheckboxEntry(props) {
847
+ const {
848
+ element,
849
+ id,
850
+ description,
851
+ label,
852
+ getValue,
853
+ setValue,
854
+ disabled
855
+ } = props;
856
+ const value = getValue(element);
857
+ return jsxs("div", {
858
+ class: "bio-properties-panel-entry bio-properties-panel-checkbox-entry",
859
+ "data-entry-id": id,
860
+ children: [jsx(Checkbox, {
861
+ id: id,
862
+ label: label,
863
+ onChange: setValue,
864
+ value: value,
865
+ disabled: disabled
866
+ }), jsx(Description, {
867
+ forId: id,
868
+ element: element,
869
+ value: description
870
+ })]
871
+ });
872
+ }
873
+ function isEdited$6(node) {
874
+ return node && !!node.checked;
875
+ } // helpers /////////////////
876
+
877
+ function prefixId$6(id) {
878
+ return `bio-properties-panel-${id}`;
879
+ }
880
+
881
+ function List(props) {
882
+ const {
883
+ id,
884
+ element,
885
+ items = [],
886
+ renderItem,
887
+ label = '<empty>',
888
+ open: shouldOpen,
889
+ onAdd,
890
+ onRemove,
891
+ autoFocusEntry,
892
+ compareFn
893
+ } = props;
894
+ const [open, setOpen] = useState(!!shouldOpen);
895
+ const hasItems = !!items.length;
896
+
897
+ const toggleOpen = () => hasItems && setOpen(!open);
898
+
899
+ const opening = !usePrevious(open) && open;
900
+ const elementChanged = usePrevious(element) !== element;
901
+ const shouldReset = opening || elementChanged;
902
+ const sortedItems = useSortedItems(items, compareFn, shouldReset);
903
+ const newItems = useNewItems(items, elementChanged);
904
+ useEffect(() => {
905
+ if (open && !hasItems) {
906
+ setOpen(false);
907
+ }
908
+ }, [open, hasItems]);
909
+ /**
910
+ * @param {MouseEvent} event
911
+ */
912
+
913
+ function addItem(event) {
914
+ event.stopPropagation();
915
+ onAdd();
916
+
917
+ if (!open) {
918
+ setOpen(true);
919
+ }
920
+ }
921
+
922
+ return jsxs("div", {
923
+ "data-entry-id": id,
924
+ class: classnames('bio-properties-panel-entry', 'bio-properties-panel-list-entry', hasItems ? '' : 'empty', open ? 'open' : ''),
925
+ children: [jsxs("div", {
926
+ class: "bio-properties-panel-list-entry-header",
927
+ onClick: toggleOpen,
928
+ children: [jsx("div", {
929
+ title: label,
930
+ class: classnames('bio-properties-panel-list-entry-header-title', open && 'open'),
931
+ children: label
932
+ }), jsxs("div", {
933
+ class: "bio-properties-panel-list-entry-header-buttons",
934
+ children: [jsxs("button", {
935
+ title: "Create new list item",
936
+ onClick: addItem,
937
+ class: "bio-properties-panel-add-entry",
938
+ children: [jsx(CreateIcon, {}), !hasItems ? jsx("span", {
939
+ class: "bio-properties-panel-add-entry-label",
940
+ children: "Create"
941
+ }) : null]
942
+ }), hasItems && jsx("div", {
943
+ title: `List contains ${items.length} item${items.length != 1 ? 's' : ''}`,
944
+ class: "bio-properties-panel-list-badge",
945
+ children: items.length
946
+ }), hasItems && jsx("button", {
947
+ title: "Toggle list item",
948
+ class: "bio-properties-panel-arrow",
949
+ children: jsx(ArrowIcon, {
950
+ class: open ? 'bio-properties-panel-arrow-down' : 'bio-properties-panel-arrow-right'
951
+ })
952
+ })]
953
+ })]
954
+ }), hasItems && jsx(ItemsList, {
955
+ autoFocusEntry: autoFocusEntry,
956
+ id: id,
957
+ open: open,
958
+ items: sortedItems,
959
+ newItems: newItems,
960
+ onRemove: onRemove,
961
+ renderItem: renderItem
962
+ })]
963
+ });
964
+ }
965
+
966
+ function ItemsList(props) {
967
+ const {
968
+ autoFocusEntry,
969
+ id,
970
+ items,
971
+ newItems,
972
+ open,
973
+ onRemove,
974
+ renderItem
975
+ } = props;
976
+ const getKey = useKeyFactory();
977
+ const newItem = newItems[0];
978
+ useEffect(() => {
979
+ if (newItem && autoFocusEntry) {
980
+ // (0) select the parent entry (containing all list items)
981
+ const entry = query(`[data-entry-id="${id}"]`); // (1) select the first input or a custom element to be focussed
982
+
983
+ const selector = typeof autoFocusEntry === 'boolean' ? '.bio-properties-panel-input' : autoFocusEntry;
984
+ const focusableInput = query(selector, entry); // (2) set focus
985
+
986
+ if (focusableInput) {
987
+ if (isFunction(focusableInput.select)) {
988
+ focusableInput.select();
989
+ } else if (isFunction(focusableInput.focus)) {
990
+ focusableInput.focus();
991
+ }
992
+ }
993
+ }
994
+ }, [newItem, autoFocusEntry, id]);
995
+ return jsx("ol", {
996
+ class: classnames('bio-properties-panel-list-entry-items', open ? 'open' : ''),
997
+ children: items.map((item, index) => {
998
+ const key = getKey(item);
999
+ return jsxs("li", {
1000
+ class: "bio-properties-panel-list-entry-item",
1001
+ children: [renderItem(item, index, item === newItem), onRemove && jsx("button", {
1002
+ type: "button",
1003
+ title: "Delete item",
1004
+ class: "bio-properties-panel-remove-entry bio-properties-panel-remove-list-entry",
1005
+ onClick: () => onRemove && onRemove(item),
1006
+ children: jsx(DeleteIcon, {})
1007
+ })]
1008
+ }, key);
1009
+ })
1010
+ });
1011
+ }
1012
+ /**
1013
+ * Place new items in the beginning of the list and sort the rest with provided function.
1014
+ *
1015
+ * @template Item
1016
+ * @param {Item[]} currentItems
1017
+ * @param {(a: Item, b: Item) => 0 | 1 | -1} [compareFn] function used to sort items
1018
+ * @param {boolean} [shouldReset=false] set to `true` to reset state of the hook
1019
+ * @returns {Item[]}
1020
+ */
1021
+
1022
+
1023
+ function useSortedItems(currentItems, compareFn, shouldReset = false) {
1024
+ const itemsRef = useRef(currentItems.slice()); // (1) Reset and optionally sort.
1025
+
1026
+ if (shouldReset) {
1027
+ itemsRef.current = currentItems.slice();
1028
+
1029
+ if (compareFn) {
1030
+ itemsRef.current.sort(compareFn);
1031
+ }
1032
+ } else {
1033
+ const items = itemsRef.current; // (2) Add new item to the list.
1034
+
1035
+ for (const item of currentItems) {
1036
+ if (!items.includes(item)) {
1037
+ // Unshift or push depending on whether we have a compareFn
1038
+ compareFn ? items.unshift(item) : items.push(item);
1039
+ }
1040
+ } // (3) Filter out removed items.
1041
+
1042
+
1043
+ itemsRef.current = items.filter(item => currentItems.includes(item));
1044
+ }
1045
+
1046
+ return itemsRef.current;
1047
+ }
1048
+
1049
+ function useNewItems(items = [], shouldReset) {
1050
+ const previousItems = usePrevious(items.slice()) || [];
1051
+
1052
+ if (shouldReset) {
1053
+ return [];
1054
+ }
1055
+
1056
+ return previousItems ? items.filter(item => !previousItems.includes(item)) : [];
1057
+ }
1058
+
1059
+ function NumberField(props) {
1060
+ const {
1061
+ debounce,
1062
+ disabled,
1063
+ id,
1064
+ label,
1065
+ max,
1066
+ min,
1067
+ onInput,
1068
+ step,
1069
+ value = ''
1070
+ } = props;
1071
+ const handleInput = useMemo(() => {
1072
+ return debounce(event => {
1073
+ const {
1074
+ validity,
1075
+ value
1076
+ } = event.target;
1077
+
1078
+ if (validity.valid) {
1079
+ onInput(value ? parseFloat(value) : undefined);
1080
+ }
1081
+ });
1082
+ }, [onInput, debounce]);
1083
+ return jsxs("div", {
1084
+ class: "bio-properties-panel-numberfield",
1085
+ children: [jsx("label", {
1086
+ for: prefixId$5(id),
1087
+ class: "bio-properties-panel-label",
1088
+ children: label
1089
+ }), jsx("input", {
1090
+ id: prefixId$5(id),
1091
+ type: "number",
1092
+ name: id,
1093
+ spellCheck: "false",
1094
+ autoComplete: "off",
1095
+ disabled: disabled,
1096
+ class: "bio-properties-panel-input",
1097
+ max: max,
1098
+ min: min,
1099
+ onInput: handleInput,
1100
+ step: step,
1101
+ value: value
1102
+ })]
1103
+ });
1104
+ }
1105
+ /**
1106
+ * @param {Object} props
1107
+ * @param {Boolean} props.debounce
1108
+ * @param {String} props.description
1109
+ * @param {Boolean} props.disabled
1110
+ * @param {Object} props.element
1111
+ * @param {Function} props.getValue
1112
+ * @param {String} props.id
1113
+ * @param {String} props.label
1114
+ * @param {String} props.max
1115
+ * @param {String} props.min
1116
+ * @param {Function} props.setValue
1117
+ * @param {String} props.step
1118
+ */
1119
+
1120
+
1121
+ function NumberFieldEntry(props) {
1122
+ const {
1123
+ debounce,
1124
+ description,
1125
+ disabled,
1126
+ element,
1127
+ getValue,
1128
+ id,
1129
+ label,
1130
+ max,
1131
+ min,
1132
+ setValue,
1133
+ step
1134
+ } = props;
1135
+ const value = getValue(element);
1136
+ return jsxs("div", {
1137
+ class: "bio-properties-panel-entry",
1138
+ "data-entry-id": id,
1139
+ children: [jsx(NumberField, {
1140
+ debounce: debounce,
1141
+ disabled: disabled,
1142
+ id: id,
1143
+ label: label,
1144
+ onInput: setValue,
1145
+ max: max,
1146
+ min: min,
1147
+ step: step,
1148
+ value: value
1149
+ }), jsx(Description, {
1150
+ forId: id,
1151
+ element: element,
1152
+ value: description
1153
+ })]
1154
+ });
1155
+ }
1156
+ function isEdited$5(node) {
1157
+ return node && !!node.value;
1158
+ } // helpers /////////////////
1159
+
1160
+ function prefixId$5(id) {
1161
+ return `bio-properties-panel-${id}`;
1162
+ }
1163
+
1164
+ function Select(props) {
1165
+ const {
1166
+ id,
1167
+ label,
1168
+ onChange,
1169
+ options = [],
1170
+ value,
1171
+ disabled
1172
+ } = props;
1173
+
1174
+ const handleChange = ({
1175
+ target
1176
+ }) => {
1177
+ onChange(target.value);
1178
+ };
1179
+
1180
+ return jsxs("div", {
1181
+ class: "bio-properties-panel-select",
1182
+ children: [jsx("label", {
1183
+ for: prefixId$4(id),
1184
+ class: "bio-properties-panel-label",
1185
+ children: label
1186
+ }), jsx("select", {
1187
+ id: prefixId$4(id),
1188
+ name: id,
1189
+ class: "bio-properties-panel-input",
1190
+ onInput: handleChange,
1191
+ value: value,
1192
+ disabled: disabled,
1193
+ children: options.map((option, idx) => {
1194
+ return jsx("option", {
1195
+ value: option.value,
1196
+ disabled: option.disabled,
1197
+ children: option.label
1198
+ }, idx);
1199
+ })
1200
+ })]
1201
+ });
1202
+ }
1203
+ /**
1204
+ * @param {object} props
1205
+ * @param {object} props.element
1206
+ * @param {string} props.id
1207
+ * @param {string} [props.description]
1208
+ * @param {string} props.label
1209
+ * @param {Function} props.getValue
1210
+ * @param {Function} props.setValue
1211
+ * @param {Function} props.getOptions
1212
+ * @param {boolean} [props.disabled]
1213
+ */
1214
+
1215
+
1216
+ function SelectEntry(props) {
1217
+ const {
1218
+ element,
1219
+ id,
1220
+ description,
1221
+ label,
1222
+ getValue,
1223
+ setValue,
1224
+ getOptions,
1225
+ disabled
1226
+ } = props;
1227
+ const value = getValue(element);
1228
+ const options = getOptions(element);
1229
+ return jsxs("div", {
1230
+ class: "bio-properties-panel-entry",
1231
+ "data-entry-id": id,
1232
+ children: [jsx(Select, {
1233
+ id: id,
1234
+ label: label,
1235
+ value: value,
1236
+ onChange: setValue,
1237
+ options: options,
1238
+ disabled: disabled
1239
+ }), jsx(Description, {
1240
+ forId: id,
1241
+ element: element,
1242
+ value: description
1243
+ })]
1244
+ });
1245
+ }
1246
+ function isEdited$4(node) {
1247
+ return node && !!node.value;
1248
+ } // helpers /////////////////
1249
+
1250
+ function prefixId$4(id) {
1251
+ return `bio-properties-panel-${id}`;
1252
+ }
1253
+
1254
+ function Simple(props) {
1255
+ const {
1256
+ debounce,
1257
+ disabled,
1258
+ element,
1259
+ getValue,
1260
+ id,
1261
+ onBlur,
1262
+ onFocus,
1263
+ setValue
1264
+ } = props;
1265
+ const handleInput = useMemo(() => {
1266
+ return debounce(({
1267
+ target
1268
+ }) => setValue(target.value.length ? target.value : undefined));
1269
+ }, [setValue, debounce]);
1270
+ const value = getValue(element);
1271
+ return jsx("div", {
1272
+ class: "bio-properties-panel-simple",
1273
+ children: jsx("input", {
1274
+ id: prefixId$3(id),
1275
+ type: "text",
1276
+ name: id,
1277
+ spellCheck: "false",
1278
+ autoComplete: "off",
1279
+ disabled: disabled,
1280
+ class: "bio-properties-panel-input",
1281
+ onInput: handleInput,
1282
+ onFocus: onFocus,
1283
+ onBlur: onBlur,
1284
+ value: value || ''
1285
+ })
1286
+ });
1287
+ }
1288
+ function isEdited$3(node) {
1289
+ return node && !!node.value;
1290
+ } // helpers /////////////////
1291
+
1292
+ function prefixId$3(id) {
1293
+ return `bio-properties-panel-${id}`;
1294
+ }
1295
+
1296
+ function TextArea(props) {
1297
+ const {
1298
+ id,
1299
+ label,
1300
+ rows = 2,
1301
+ debounce,
1302
+ onInput,
1303
+ value = '',
1304
+ disabled,
1305
+ monospace
1306
+ } = props;
1307
+ const handleInput = useMemo(() => {
1308
+ return debounce(({
1309
+ target
1310
+ }) => onInput(target.value.length ? target.value : undefined));
1311
+ }, [onInput, debounce]);
1312
+ return jsxs("div", {
1313
+ class: "bio-properties-panel-textarea",
1314
+ children: [jsx("label", {
1315
+ for: prefixId$2(id),
1316
+ class: "bio-properties-panel-label",
1317
+ children: label
1318
+ }), jsx("textarea", {
1319
+ id: prefixId$2(id),
1320
+ name: id,
1321
+ spellCheck: "false",
1322
+ class: classnames('bio-properties-panel-input', monospace ? 'bio-properties-panel-input-monospace' : ''),
1323
+ onInput: handleInput,
1324
+ onFocus: props.onFocus,
1325
+ onBlur: props.onBlur,
1326
+ rows: rows,
1327
+ value: value,
1328
+ disabled: disabled
1329
+ })]
1330
+ });
1331
+ }
1332
+ /**
1333
+ * @param {object} props
1334
+ * @param {object} props.element
1335
+ * @param {string} props.id
1336
+ * @param {string} props.description
1337
+ * @param {boolean} props.debounce
1338
+ * @param {string} props.label
1339
+ * @param {Function} props.getValue
1340
+ * @param {Function} props.setValue
1341
+ * @param {number} props.rows
1342
+ * @param {boolean} props.monospace
1343
+ * @param {boolean} [props.disabled]
1344
+ */
1345
+
1346
+
1347
+ function TextAreaEntry(props) {
1348
+ const {
1349
+ element,
1350
+ id,
1351
+ description,
1352
+ debounce,
1353
+ label,
1354
+ getValue,
1355
+ setValue,
1356
+ rows,
1357
+ monospace,
1358
+ disabled
1359
+ } = props;
1360
+ const value = getValue(element);
1361
+ return jsxs("div", {
1362
+ class: "bio-properties-panel-entry",
1363
+ "data-entry-id": id,
1364
+ children: [jsx(TextArea, {
1365
+ id: id,
1366
+ label: label,
1367
+ value: value,
1368
+ onInput: setValue,
1369
+ rows: rows,
1370
+ debounce: debounce,
1371
+ monospace: monospace,
1372
+ disabled: disabled
1373
+ }), jsx(Description, {
1374
+ forId: id,
1375
+ element: element,
1376
+ value: description
1377
+ })]
1378
+ });
1379
+ }
1380
+ function isEdited$2(node) {
1381
+ return node && !!node.value;
1382
+ } // helpers /////////////////
1383
+
1384
+ function prefixId$2(id) {
1385
+ return `bio-properties-panel-${id}`;
1386
+ }
1387
+
1388
+ function Textfield(props) {
1389
+ const {
1390
+ debounce,
1391
+ disabled = false,
1392
+ id,
1393
+ label,
1394
+ onInput,
1395
+ value = ''
1396
+ } = props;
1397
+ const handleInput = useMemo(() => {
1398
+ return debounce(({
1399
+ target
1400
+ }) => onInput(target.value.length ? target.value : undefined));
1401
+ }, [onInput, debounce]);
1402
+ return jsxs("div", {
1403
+ class: "bio-properties-panel-textfield",
1404
+ children: [jsx("label", {
1405
+ for: prefixId$1(id),
1406
+ class: "bio-properties-panel-label",
1407
+ children: label
1408
+ }), jsx("input", {
1409
+ id: prefixId$1(id),
1410
+ type: "text",
1411
+ name: id,
1412
+ spellCheck: "false",
1413
+ autoComplete: "off",
1414
+ disabled: disabled,
1415
+ class: "bio-properties-panel-input",
1416
+ onInput: handleInput,
1417
+ onFocus: props.onFocus,
1418
+ onBlur: props.onBlur,
1419
+ value: value || ''
1420
+ })]
1421
+ });
1422
+ }
1423
+ /**
1424
+ * @param {Object} props
1425
+ * @param {Object} props.element
1426
+ * @param {String} props.id
1427
+ * @param {String} props.description
1428
+ * @param {Boolean} props.debounce
1429
+ * @param {Boolean} props.disabled
1430
+ * @param {String} props.label
1431
+ * @param {Function} props.getValue
1432
+ * @param {Function} props.setValue
1433
+ * @param {Function} props.validate
1434
+ */
1435
+
1436
+
1437
+ function TextfieldEntry(props) {
1438
+ const {
1439
+ element,
1440
+ id,
1441
+ description,
1442
+ debounce,
1443
+ disabled,
1444
+ label,
1445
+ getValue,
1446
+ setValue,
1447
+ validate
1448
+ } = props;
1449
+ const [error, setError] = useState(null);
1450
+ const [invalidValueCache, setInvalidValueCache] = useState(null);
1451
+ let value = getValue(element);
1452
+ const prevValue = usePrevious(value); // validate again when value prop changed
1453
+
1454
+ useEffect(() => {
1455
+ const err = validate ? validate(value) : null;
1456
+ setError(err);
1457
+ }, [value]); // validate on change
1458
+
1459
+ const handleChange = newValue => {
1460
+ const err = validate ? validate(newValue) : null;
1461
+
1462
+ if (err) {
1463
+ setInvalidValueCache(newValue);
1464
+ } else {
1465
+ setValue(newValue);
1466
+ }
1467
+
1468
+ setError(err);
1469
+ }; // keep showing invalid value on errors, although it was not set
1470
+
1471
+
1472
+ if (prevValue === value && error) {
1473
+ value = invalidValueCache;
1474
+ }
1475
+
1476
+ return jsxs("div", {
1477
+ class: classnames('bio-properties-panel-entry', error ? 'has-error' : ''),
1478
+ "data-entry-id": id,
1479
+ children: [jsx(Textfield, {
1480
+ id: id,
1481
+ label: label,
1482
+ value: value,
1483
+ onInput: handleChange,
1484
+ debounce: debounce,
1485
+ disabled: disabled
1486
+ }), jsx(Description, {
1487
+ forId: id,
1488
+ element: element,
1489
+ value: description
1490
+ }), error && jsx("div", {
1491
+ class: "bio-properties-panel-error",
1492
+ children: error
1493
+ })]
1494
+ });
1495
+ }
1496
+ function isEdited$1(node) {
1497
+ return node && !!node.value;
1498
+ } // helpers /////////////////
1499
+
1500
+ function prefixId$1(id) {
1501
+ return `bio-properties-panel-${id}`;
1502
+ }
1503
+
1504
+ function ToggleSwitch(props) {
1505
+ const {
1506
+ id,
1507
+ label,
1508
+ onInput,
1509
+ value,
1510
+ switcherLabel
1511
+ } = props;
1512
+
1513
+ const handleInput = async () => {
1514
+ onInput(!value);
1515
+ };
1516
+
1517
+ return jsxs("div", {
1518
+ class: "bio-properties-panel-toggle-switch",
1519
+ children: [jsx("label", {
1520
+ class: "bio-properties-panel-label",
1521
+ for: prefixId(id),
1522
+ children: label
1523
+ }), jsxs("div", {
1524
+ class: "bio-properties-panel-field-wrapper",
1525
+ children: [jsxs("label", {
1526
+ class: "bio-properties-panel-toggle-switch__switcher",
1527
+ children: [jsx("input", {
1528
+ id: prefixId(id),
1529
+ class: "bio-properties-panel-input",
1530
+ type: "checkbox",
1531
+ name: id,
1532
+ onInput: handleInput,
1533
+ checked: value
1534
+ }), jsx("span", {
1535
+ class: "bio-properties-panel-toggle-switch__slider"
1536
+ })]
1537
+ }), jsx("p", {
1538
+ class: "bio-properties-panel-toggle-switch__label",
1539
+ children: switcherLabel
1540
+ })]
1541
+ })]
1542
+ });
1543
+ }
1544
+ /**
1545
+ * @param {Object} props
1546
+ * @param {Object} props.element
1547
+ * @param {String} props.id
1548
+ * @param {String} props.description
1549
+ * @param {String} props.label
1550
+ * @param {String} props.switcherLabel
1551
+ * @param {Function} props.getValue
1552
+ * @param {Function} props.setValue
1553
+ */
1554
+
1555
+
1556
+ function ToggleSwitchEntry(props) {
1557
+ const {
1558
+ element,
1559
+ id,
1560
+ description,
1561
+ label,
1562
+ switcherLabel,
1563
+ getValue,
1564
+ setValue
1565
+ } = props;
1566
+ const value = getValue(element);
1567
+ return jsxs("div", {
1568
+ class: "bio-properties-panel-entry bio-properties-panel-toggle-switch-entry",
1569
+ "data-entry-id": id,
1570
+ children: [jsx(ToggleSwitch, {
1571
+ id: id,
1572
+ label: label,
1573
+ value: value,
1574
+ onInput: setValue,
1575
+ switcherLabel: switcherLabel
1576
+ }), jsx(Description, {
1577
+ forId: id,
1578
+ element: element,
1579
+ value: description
1580
+ })]
1581
+ });
1582
+ }
1583
+ function isEdited(node) {
1584
+ return node && !!node.checked;
1585
+ } // helpers /////////////////
1586
+
1587
+ function prefixId(id) {
1588
+ return `bio-properties-panel-${id}`;
1589
+ }
1590
+
1591
+ const DEFAULT_DEBOUNCE_TIME = 300;
1592
+ function debounceInput(debounceDelay) {
1593
+ return function _debounceInput(fn) {
1594
+ if (debounceDelay !== false) {
1595
+ var debounceTime = isNumber(debounceDelay) ? debounceDelay : DEFAULT_DEBOUNCE_TIME;
1596
+ return debounce(fn, debounceTime);
1597
+ } else {
1598
+ return fn;
1599
+ }
1600
+ };
1601
+ }
1602
+ debounceInput.$inject = ['config.debounceInput'];
1603
+
1604
+ var index = {
1605
+ debounceInput: ['factory', debounceInput]
1606
+ };
1607
+
1608
+ export { ArrowIcon, CheckboxEntry, CollapsibleEntry, CreateIcon, index as DebounceInputModule, DeleteIcon, DescriptionContext, Description as DescriptionEntry, DropdownButton, Group, Header, HeaderButton, LayoutContext, List as ListEntry, ListGroup, ListItem, NumberFieldEntry, PropertiesPanel, 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, useKeyFactory, useLayoutState, usePrevious };
1609
+ //# sourceMappingURL=index.esm.js.map