@bpmn-io/form-js-viewer 0.9.9 → 0.10.0-alpha.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/README.md +6 -0
- package/dist/assets/form-js.css +31 -8
- package/dist/index.cjs +330 -431
- package/dist/index.cjs.map +1 -1
- package/dist/index.es.js +329 -431
- package/dist/index.es.js.map +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/render/components/Util.d.ts +4 -1
- package/dist/types/render/components/form-fields/Textarea.d.ts +13 -0
- package/dist/types/render/components/index.d.ts +2 -1
- package/package.json +2 -2
package/dist/index.es.js
CHANGED
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
import Ids from 'ids';
|
|
2
2
|
import { isArray, isFunction, isNumber, bind, assign, isNil, get, isUndefined, isObject, set, isString } from 'min-dash';
|
|
3
3
|
import snarkdown from '@bpmn-io/snarkdown';
|
|
4
|
+
import classNames from 'classnames';
|
|
4
5
|
import { jsx, jsxs } from 'preact/jsx-runtime';
|
|
5
6
|
import { useContext, useState, useEffect, useRef, useMemo, useCallback } from 'preact/hooks';
|
|
6
7
|
import { createContext, createElement, Fragment, render } from 'preact';
|
|
7
8
|
import React, { createPortal } from 'preact/compat';
|
|
8
|
-
import classNames from 'classnames';
|
|
9
9
|
import Markup from 'preact-markup';
|
|
10
10
|
import { Injector } from 'didi';
|
|
11
11
|
|
|
12
12
|
var FN_REF = '__fn';
|
|
13
13
|
var DEFAULT_PRIORITY = 1000;
|
|
14
14
|
var slice = Array.prototype.slice;
|
|
15
|
+
|
|
15
16
|
/**
|
|
16
17
|
* A general purpose event bus.
|
|
17
18
|
*
|
|
@@ -95,13 +96,14 @@ var slice = Array.prototype.slice;
|
|
|
95
96
|
* console.log(sum); // 3
|
|
96
97
|
* ```
|
|
97
98
|
*/
|
|
98
|
-
|
|
99
99
|
function EventBus() {
|
|
100
|
-
this._listeners = {};
|
|
101
|
-
// message passing until the bitter end
|
|
100
|
+
this._listeners = {};
|
|
102
101
|
|
|
102
|
+
// cleanup on destroy on lowest priority to allow
|
|
103
|
+
// message passing until the bitter end
|
|
103
104
|
this.on('diagram.destroy', 1, this._destroy, this);
|
|
104
105
|
}
|
|
106
|
+
|
|
105
107
|
/**
|
|
106
108
|
* Register an event listener for events with the given name.
|
|
107
109
|
*
|
|
@@ -119,30 +121,25 @@ function EventBus() {
|
|
|
119
121
|
* @param {Function} callback
|
|
120
122
|
* @param {Object} [that] Pass context (`this`) to the callback
|
|
121
123
|
*/
|
|
122
|
-
|
|
123
124
|
EventBus.prototype.on = function (events, priority, callback, that) {
|
|
124
125
|
events = isArray(events) ? events : [events];
|
|
125
|
-
|
|
126
126
|
if (isFunction(priority)) {
|
|
127
127
|
that = callback;
|
|
128
128
|
callback = priority;
|
|
129
129
|
priority = DEFAULT_PRIORITY;
|
|
130
130
|
}
|
|
131
|
-
|
|
132
131
|
if (!isNumber(priority)) {
|
|
133
132
|
throw new Error('priority must be a number');
|
|
134
133
|
}
|
|
135
|
-
|
|
136
134
|
var actualCallback = callback;
|
|
137
|
-
|
|
138
135
|
if (that) {
|
|
139
|
-
actualCallback = bind(callback, that);
|
|
136
|
+
actualCallback = bind(callback, that);
|
|
137
|
+
|
|
138
|
+
// make sure we remember and are able to remove
|
|
140
139
|
// bound callbacks via {@link #off} using the original
|
|
141
140
|
// callback
|
|
142
|
-
|
|
143
141
|
actualCallback[FN_REF] = callback[FN_REF] || callback;
|
|
144
142
|
}
|
|
145
|
-
|
|
146
143
|
var self = this;
|
|
147
144
|
events.forEach(function (e) {
|
|
148
145
|
self._addListener(e, {
|
|
@@ -152,6 +149,7 @@ EventBus.prototype.on = function (events, priority, callback, that) {
|
|
|
152
149
|
});
|
|
153
150
|
});
|
|
154
151
|
};
|
|
152
|
+
|
|
155
153
|
/**
|
|
156
154
|
* Register an event listener that is executed only once.
|
|
157
155
|
*
|
|
@@ -160,34 +158,30 @@ EventBus.prototype.on = function (events, priority, callback, that) {
|
|
|
160
158
|
* @param {Function} callback the callback to execute
|
|
161
159
|
* @param {Object} [that] Pass context (`this`) to the callback
|
|
162
160
|
*/
|
|
163
|
-
|
|
164
|
-
|
|
165
161
|
EventBus.prototype.once = function (event, priority, callback, that) {
|
|
166
162
|
var self = this;
|
|
167
|
-
|
|
168
163
|
if (isFunction(priority)) {
|
|
169
164
|
that = callback;
|
|
170
165
|
callback = priority;
|
|
171
166
|
priority = DEFAULT_PRIORITY;
|
|
172
167
|
}
|
|
173
|
-
|
|
174
168
|
if (!isNumber(priority)) {
|
|
175
169
|
throw new Error('priority must be a number');
|
|
176
170
|
}
|
|
177
|
-
|
|
178
171
|
function wrappedCallback() {
|
|
179
172
|
wrappedCallback.__isTomb = true;
|
|
180
173
|
var result = callback.apply(that, arguments);
|
|
181
174
|
self.off(event, wrappedCallback);
|
|
182
175
|
return result;
|
|
183
|
-
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// make sure we remember and are able to remove
|
|
184
179
|
// bound callbacks via {@link #off} using the original
|
|
185
180
|
// callback
|
|
186
|
-
|
|
187
|
-
|
|
188
181
|
wrappedCallback[FN_REF] = callback;
|
|
189
182
|
this.on(event, priority, wrappedCallback);
|
|
190
183
|
};
|
|
184
|
+
|
|
191
185
|
/**
|
|
192
186
|
* Removes event listeners by event and callback.
|
|
193
187
|
*
|
|
@@ -196,8 +190,6 @@ EventBus.prototype.once = function (event, priority, callback, that) {
|
|
|
196
190
|
* @param {string|Array<string>} events
|
|
197
191
|
* @param {Function} [callback]
|
|
198
192
|
*/
|
|
199
|
-
|
|
200
|
-
|
|
201
193
|
EventBus.prototype.off = function (events, callback) {
|
|
202
194
|
events = isArray(events) ? events : [events];
|
|
203
195
|
var self = this;
|
|
@@ -205,6 +197,7 @@ EventBus.prototype.off = function (events, callback) {
|
|
|
205
197
|
self._removeListener(event, callback);
|
|
206
198
|
});
|
|
207
199
|
};
|
|
200
|
+
|
|
208
201
|
/**
|
|
209
202
|
* Create an EventBus event.
|
|
210
203
|
*
|
|
@@ -212,13 +205,12 @@ EventBus.prototype.off = function (events, callback) {
|
|
|
212
205
|
*
|
|
213
206
|
* @return {Object} event, recognized by the eventBus
|
|
214
207
|
*/
|
|
215
|
-
|
|
216
|
-
|
|
217
208
|
EventBus.prototype.createEvent = function (data) {
|
|
218
209
|
var event = new InternalEvent();
|
|
219
210
|
event.init(data);
|
|
220
211
|
return event;
|
|
221
212
|
};
|
|
213
|
+
|
|
222
214
|
/**
|
|
223
215
|
* Fires a named event.
|
|
224
216
|
*
|
|
@@ -249,45 +241,40 @@ EventBus.prototype.createEvent = function (data) {
|
|
|
249
241
|
* @return {boolean} the events return value, if specified or false if the
|
|
250
242
|
* default action was prevented by listeners
|
|
251
243
|
*/
|
|
252
|
-
|
|
253
|
-
|
|
254
244
|
EventBus.prototype.fire = function (type, data) {
|
|
255
245
|
var event, firstListener, returnValue, args;
|
|
256
246
|
args = slice.call(arguments);
|
|
257
|
-
|
|
258
247
|
if (typeof type === 'object') {
|
|
259
248
|
data = type;
|
|
260
249
|
type = data.type;
|
|
261
250
|
}
|
|
262
|
-
|
|
263
251
|
if (!type) {
|
|
264
252
|
throw new Error('no event type specified');
|
|
265
253
|
}
|
|
266
|
-
|
|
267
254
|
firstListener = this._listeners[type];
|
|
268
|
-
|
|
269
255
|
if (!firstListener) {
|
|
270
256
|
return;
|
|
271
|
-
}
|
|
272
|
-
// events here. We wrap them only once, though
|
|
273
|
-
|
|
257
|
+
}
|
|
274
258
|
|
|
259
|
+
// we make sure we fire instances of our home made
|
|
260
|
+
// events here. We wrap them only once, though
|
|
275
261
|
if (data instanceof InternalEvent) {
|
|
276
262
|
// we are fine, we alread have an event
|
|
277
263
|
event = data;
|
|
278
264
|
} else {
|
|
279
265
|
event = this.createEvent(data);
|
|
280
|
-
}
|
|
281
|
-
|
|
266
|
+
}
|
|
282
267
|
|
|
283
|
-
|
|
268
|
+
// ensure we pass the event as the first parameter
|
|
269
|
+
args[0] = event;
|
|
284
270
|
|
|
285
|
-
|
|
271
|
+
// original event type (in case we delegate)
|
|
272
|
+
var originalType = event.type;
|
|
286
273
|
|
|
274
|
+
// update event type before delegation
|
|
287
275
|
if (type !== originalType) {
|
|
288
276
|
event.type = type;
|
|
289
277
|
}
|
|
290
|
-
|
|
291
278
|
try {
|
|
292
279
|
returnValue = this._invokeListeners(event, args, firstListener);
|
|
293
280
|
} finally {
|
|
@@ -295,60 +282,51 @@ EventBus.prototype.fire = function (type, data) {
|
|
|
295
282
|
if (type !== originalType) {
|
|
296
283
|
event.type = originalType;
|
|
297
284
|
}
|
|
298
|
-
}
|
|
299
|
-
// got prevented and no other return value exists
|
|
300
|
-
|
|
285
|
+
}
|
|
301
286
|
|
|
287
|
+
// set the return value to false if the event default
|
|
288
|
+
// got prevented and no other return value exists
|
|
302
289
|
if (returnValue === undefined && event.defaultPrevented) {
|
|
303
290
|
returnValue = false;
|
|
304
291
|
}
|
|
305
|
-
|
|
306
292
|
return returnValue;
|
|
307
293
|
};
|
|
308
|
-
|
|
309
294
|
EventBus.prototype.handleError = function (error) {
|
|
310
295
|
return this.fire('error', {
|
|
311
296
|
error: error
|
|
312
297
|
}) === false;
|
|
313
298
|
};
|
|
314
|
-
|
|
315
299
|
EventBus.prototype._destroy = function () {
|
|
316
300
|
this._listeners = {};
|
|
317
301
|
};
|
|
318
|
-
|
|
319
302
|
EventBus.prototype._invokeListeners = function (event, args, listener) {
|
|
320
303
|
var returnValue;
|
|
321
|
-
|
|
322
304
|
while (listener) {
|
|
323
305
|
// handle stopped propagation
|
|
324
306
|
if (event.cancelBubble) {
|
|
325
307
|
break;
|
|
326
308
|
}
|
|
327
|
-
|
|
328
309
|
returnValue = this._invokeListener(event, args, listener);
|
|
329
310
|
listener = listener.next;
|
|
330
311
|
}
|
|
331
|
-
|
|
332
312
|
return returnValue;
|
|
333
313
|
};
|
|
334
|
-
|
|
335
314
|
EventBus.prototype._invokeListener = function (event, args, listener) {
|
|
336
315
|
var returnValue;
|
|
337
|
-
|
|
338
316
|
if (listener.callback.__isTomb) {
|
|
339
317
|
return returnValue;
|
|
340
318
|
}
|
|
341
|
-
|
|
342
319
|
try {
|
|
343
320
|
// returning false prevents the default action
|
|
344
|
-
returnValue = invokeFunction(listener.callback, args);
|
|
321
|
+
returnValue = invokeFunction(listener.callback, args);
|
|
345
322
|
|
|
323
|
+
// stop propagation on return value
|
|
346
324
|
if (returnValue !== undefined) {
|
|
347
325
|
event.returnValue = returnValue;
|
|
348
326
|
event.stopPropagation();
|
|
349
|
-
}
|
|
350
|
-
|
|
327
|
+
}
|
|
351
328
|
|
|
329
|
+
// prevent default on return false
|
|
352
330
|
if (returnValue === false) {
|
|
353
331
|
event.preventDefault();
|
|
354
332
|
}
|
|
@@ -358,9 +336,9 @@ EventBus.prototype._invokeListener = function (event, args, listener) {
|
|
|
358
336
|
throw error;
|
|
359
337
|
}
|
|
360
338
|
}
|
|
361
|
-
|
|
362
339
|
return returnValue;
|
|
363
340
|
};
|
|
341
|
+
|
|
364
342
|
/*
|
|
365
343
|
* Add new listener with a certain priority to the list
|
|
366
344
|
* of listeners (for the given event).
|
|
@@ -377,67 +355,54 @@ EventBus.prototype._invokeListener = function (event, args, listener) {
|
|
|
377
355
|
* @param {string} event
|
|
378
356
|
* @param {Object} listener { priority, callback }
|
|
379
357
|
*/
|
|
380
|
-
|
|
381
|
-
|
|
382
358
|
EventBus.prototype._addListener = function (event, newListener) {
|
|
383
359
|
var listener = this._getListeners(event),
|
|
384
|
-
|
|
385
|
-
|
|
360
|
+
previousListener;
|
|
386
361
|
|
|
362
|
+
// no prior listeners
|
|
387
363
|
if (!listener) {
|
|
388
364
|
this._setListeners(event, newListener);
|
|
389
|
-
|
|
390
365
|
return;
|
|
391
|
-
}
|
|
392
|
-
// 0 (high) to n > 0 (low)
|
|
393
|
-
|
|
366
|
+
}
|
|
394
367
|
|
|
368
|
+
// ensure we order listeners by priority from
|
|
369
|
+
// 0 (high) to n > 0 (low)
|
|
395
370
|
while (listener) {
|
|
396
371
|
if (listener.priority < newListener.priority) {
|
|
397
372
|
newListener.next = listener;
|
|
398
|
-
|
|
399
373
|
if (previousListener) {
|
|
400
374
|
previousListener.next = newListener;
|
|
401
375
|
} else {
|
|
402
376
|
this._setListeners(event, newListener);
|
|
403
377
|
}
|
|
404
|
-
|
|
405
378
|
return;
|
|
406
379
|
}
|
|
407
|
-
|
|
408
380
|
previousListener = listener;
|
|
409
381
|
listener = listener.next;
|
|
410
|
-
}
|
|
411
|
-
|
|
382
|
+
}
|
|
412
383
|
|
|
384
|
+
// add new listener to back
|
|
413
385
|
previousListener.next = newListener;
|
|
414
386
|
};
|
|
415
|
-
|
|
416
387
|
EventBus.prototype._getListeners = function (name) {
|
|
417
388
|
return this._listeners[name];
|
|
418
389
|
};
|
|
419
|
-
|
|
420
390
|
EventBus.prototype._setListeners = function (name, listener) {
|
|
421
391
|
this._listeners[name] = listener;
|
|
422
392
|
};
|
|
423
|
-
|
|
424
393
|
EventBus.prototype._removeListener = function (event, callback) {
|
|
425
394
|
var listener = this._getListeners(event),
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
395
|
+
nextListener,
|
|
396
|
+
previousListener,
|
|
397
|
+
listenerCallback;
|
|
430
398
|
if (!callback) {
|
|
431
399
|
// clear listeners
|
|
432
400
|
this._setListeners(event, null);
|
|
433
|
-
|
|
434
401
|
return;
|
|
435
402
|
}
|
|
436
|
-
|
|
437
403
|
while (listener) {
|
|
438
404
|
nextListener = listener.next;
|
|
439
405
|
listenerCallback = listener.callback;
|
|
440
|
-
|
|
441
406
|
if (listenerCallback === callback || listenerCallback[FN_REF] === callback) {
|
|
442
407
|
if (previousListener) {
|
|
443
408
|
previousListener.next = nextListener;
|
|
@@ -446,29 +411,25 @@ EventBus.prototype._removeListener = function (event, callback) {
|
|
|
446
411
|
this._setListeners(event, nextListener);
|
|
447
412
|
}
|
|
448
413
|
}
|
|
449
|
-
|
|
450
414
|
previousListener = listener;
|
|
451
415
|
listener = nextListener;
|
|
452
416
|
}
|
|
453
417
|
};
|
|
418
|
+
|
|
454
419
|
/**
|
|
455
420
|
* A event that is emitted via the event bus.
|
|
456
421
|
*/
|
|
457
|
-
|
|
458
|
-
|
|
459
422
|
function InternalEvent() {}
|
|
460
|
-
|
|
461
423
|
InternalEvent.prototype.stopPropagation = function () {
|
|
462
424
|
this.cancelBubble = true;
|
|
463
425
|
};
|
|
464
|
-
|
|
465
426
|
InternalEvent.prototype.preventDefault = function () {
|
|
466
427
|
this.defaultPrevented = true;
|
|
467
428
|
};
|
|
468
|
-
|
|
469
429
|
InternalEvent.prototype.init = function (data) {
|
|
470
430
|
assign(this, data || {});
|
|
471
431
|
};
|
|
432
|
+
|
|
472
433
|
/**
|
|
473
434
|
* Invoke function. Be fast...
|
|
474
435
|
*
|
|
@@ -477,50 +438,47 @@ InternalEvent.prototype.init = function (data) {
|
|
|
477
438
|
*
|
|
478
439
|
* @return {Any}
|
|
479
440
|
*/
|
|
480
|
-
|
|
481
|
-
|
|
482
441
|
function invokeFunction(fn, args) {
|
|
483
442
|
return fn.apply(null, args);
|
|
484
443
|
}
|
|
485
444
|
|
|
445
|
+
const EMAIL_PATTERN = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;
|
|
446
|
+
const PHONE_PATTERN = /(\+|00)(297|93|244|1264|358|355|376|971|54|374|1684|1268|61|43|994|257|32|229|226|880|359|973|1242|387|590|375|501|1441|591|55|1246|673|975|267|236|1|61|41|56|86|225|237|243|242|682|57|269|238|506|53|5999|61|1345|357|420|49|253|1767|45|1809|1829|1849|213|593|20|291|212|34|372|251|358|679|500|33|298|691|241|44|995|44|233|350|224|590|220|245|240|30|1473|299|502|594|1671|592|852|504|385|509|36|62|44|91|246|353|98|964|354|972|39|1876|44|962|81|76|77|254|996|855|686|1869|82|383|965|856|961|231|218|1758|423|94|266|370|352|371|853|590|212|377|373|261|960|52|692|389|223|356|95|382|976|1670|258|222|1664|596|230|265|60|262|264|687|227|672|234|505|683|31|47|977|674|64|968|92|507|64|51|63|680|675|48|1787|1939|850|351|595|970|689|974|262|40|7|250|966|249|221|65|500|4779|677|232|503|378|252|508|381|211|239|597|421|386|46|268|1721|248|963|1649|235|228|66|992|690|993|670|676|1868|216|90|688|886|255|256|380|598|1|998|3906698|379|1784|58|1284|1340|84|678|681|685|967|27|260|263)(9[976]\d|8[987530]\d|6[987]\d|5[90]\d|42\d|3[875]\d|2[98654321]\d|9[8543210]|8[6421]|6[6543210]|5[87654321]|4[987654310]|3[9643210]|2[70]|7|1)\d{4,20}$/;
|
|
486
447
|
class Validator {
|
|
487
448
|
validateField(field, value) {
|
|
488
449
|
const {
|
|
489
450
|
validate
|
|
490
451
|
} = field;
|
|
491
452
|
let errors = [];
|
|
492
|
-
|
|
493
453
|
if (!validate) {
|
|
494
454
|
return errors;
|
|
495
455
|
}
|
|
496
|
-
|
|
497
456
|
if (validate.pattern && value && !new RegExp(validate.pattern).test(value)) {
|
|
498
457
|
errors = [...errors, `Field must match pattern ${validate.pattern}.`];
|
|
499
458
|
}
|
|
500
|
-
|
|
501
459
|
if (validate.required && (isNil(value) || value === '')) {
|
|
502
460
|
errors = [...errors, 'Field is required.'];
|
|
503
461
|
}
|
|
504
|
-
|
|
505
462
|
if ('min' in validate && value && value < validate.min) {
|
|
506
463
|
errors = [...errors, `Field must have minimum value of ${validate.min}.`];
|
|
507
464
|
}
|
|
508
|
-
|
|
509
465
|
if ('max' in validate && value && value > validate.max) {
|
|
510
466
|
errors = [...errors, `Field must have maximum value of ${validate.max}.`];
|
|
511
467
|
}
|
|
512
|
-
|
|
513
468
|
if ('minLength' in validate && value && value.trim().length < validate.minLength) {
|
|
514
469
|
errors = [...errors, `Field must have minimum length of ${validate.minLength}.`];
|
|
515
470
|
}
|
|
516
|
-
|
|
517
471
|
if ('maxLength' in validate && value && value.trim().length > validate.maxLength) {
|
|
518
472
|
errors = [...errors, `Field must have maximum length of ${validate.maxLength}.`];
|
|
519
473
|
}
|
|
520
|
-
|
|
474
|
+
if ('validationType' in validate && value && validate.validationType === 'phone' && !PHONE_PATTERN.test(value)) {
|
|
475
|
+
errors = [...errors, 'Field must be a valid international phone number. (e.g. +4930664040900)'];
|
|
476
|
+
}
|
|
477
|
+
if ('validationType' in validate && value && validate.validationType === 'email' && !EMAIL_PATTERN.test(value)) {
|
|
478
|
+
errors = [...errors, 'Field must be a valid email.'];
|
|
479
|
+
}
|
|
521
480
|
return errors;
|
|
522
481
|
}
|
|
523
|
-
|
|
524
482
|
}
|
|
525
483
|
Validator.$inject = [];
|
|
526
484
|
|
|
@@ -532,59 +490,44 @@ class FormFieldRegistry {
|
|
|
532
490
|
this._ids = new Ids([32, 36, 1]);
|
|
533
491
|
this._keys = new Ids([32, 36, 1]);
|
|
534
492
|
}
|
|
535
|
-
|
|
536
493
|
add(formField) {
|
|
537
494
|
const {
|
|
538
495
|
id
|
|
539
496
|
} = formField;
|
|
540
|
-
|
|
541
497
|
if (this._formFields[id]) {
|
|
542
498
|
throw new Error(`form field with ID ${id} already exists`);
|
|
543
499
|
}
|
|
544
|
-
|
|
545
500
|
this._eventBus.fire('formField.add', {
|
|
546
501
|
formField
|
|
547
502
|
});
|
|
548
|
-
|
|
549
503
|
this._formFields[id] = formField;
|
|
550
504
|
}
|
|
551
|
-
|
|
552
505
|
remove(formField) {
|
|
553
506
|
const {
|
|
554
507
|
id
|
|
555
508
|
} = formField;
|
|
556
|
-
|
|
557
509
|
if (!this._formFields[id]) {
|
|
558
510
|
return;
|
|
559
511
|
}
|
|
560
|
-
|
|
561
512
|
this._eventBus.fire('formField.remove', {
|
|
562
513
|
formField
|
|
563
514
|
});
|
|
564
|
-
|
|
565
515
|
delete this._formFields[id];
|
|
566
516
|
}
|
|
567
|
-
|
|
568
517
|
get(id) {
|
|
569
518
|
return this._formFields[id];
|
|
570
519
|
}
|
|
571
|
-
|
|
572
520
|
getAll() {
|
|
573
521
|
return Object.values(this._formFields);
|
|
574
522
|
}
|
|
575
|
-
|
|
576
523
|
forEach(callback) {
|
|
577
524
|
this.getAll().forEach(formField => callback(formField));
|
|
578
525
|
}
|
|
579
|
-
|
|
580
526
|
clear() {
|
|
581
527
|
this._formFields = {};
|
|
582
|
-
|
|
583
528
|
this._ids.clear();
|
|
584
|
-
|
|
585
529
|
this._keys.clear();
|
|
586
530
|
}
|
|
587
|
-
|
|
588
531
|
}
|
|
589
532
|
FormFieldRegistry.$inject = ['eventBus'];
|
|
590
533
|
|
|
@@ -615,7 +558,6 @@ function pathParse(path) {
|
|
|
615
558
|
if (!path) {
|
|
616
559
|
return [];
|
|
617
560
|
}
|
|
618
|
-
|
|
619
561
|
return path.split('.').map(key => {
|
|
620
562
|
return isNaN(parseInt(key)) ? key : parseInt(key);
|
|
621
563
|
});
|
|
@@ -627,7 +569,6 @@ function pathStringify(path) {
|
|
|
627
569
|
if (!path) {
|
|
628
570
|
return '';
|
|
629
571
|
}
|
|
630
|
-
|
|
631
572
|
return path.join('.');
|
|
632
573
|
}
|
|
633
574
|
const indices = {};
|
|
@@ -637,22 +578,22 @@ function generateIndexForType(type) {
|
|
|
637
578
|
} else {
|
|
638
579
|
indices[type] = 1;
|
|
639
580
|
}
|
|
640
|
-
|
|
641
581
|
return indices[type];
|
|
642
582
|
}
|
|
643
583
|
function generateIdForType(type) {
|
|
644
584
|
return `${type}${generateIndexForType(type)}`;
|
|
645
585
|
}
|
|
586
|
+
|
|
646
587
|
/**
|
|
647
588
|
* @template T
|
|
648
589
|
* @param {T} data
|
|
649
590
|
* @param {(this: any, key: string, value: any) => any} [replacer]
|
|
650
591
|
* @return {T}
|
|
651
592
|
*/
|
|
652
|
-
|
|
653
593
|
function clone(data, replacer) {
|
|
654
594
|
return JSON.parse(JSON.stringify(data, replacer));
|
|
655
595
|
}
|
|
596
|
+
|
|
656
597
|
/**
|
|
657
598
|
* Parse the schema for input variables a form might make use of
|
|
658
599
|
*
|
|
@@ -665,26 +606,21 @@ function getSchemaVariables(schema) {
|
|
|
665
606
|
if (!schema.components) {
|
|
666
607
|
return [];
|
|
667
608
|
}
|
|
668
|
-
|
|
669
609
|
return schema.components.reduce((variables, component) => {
|
|
670
610
|
const {
|
|
671
611
|
key,
|
|
672
612
|
valuesKey,
|
|
673
613
|
type
|
|
674
614
|
} = component;
|
|
675
|
-
|
|
676
615
|
if (['text', 'button'].includes(type)) {
|
|
677
616
|
return variables;
|
|
678
617
|
}
|
|
679
|
-
|
|
680
618
|
if (key) {
|
|
681
619
|
variables = [...variables, key];
|
|
682
620
|
}
|
|
683
|
-
|
|
684
621
|
if (valuesKey && !variables.includes(valuesKey)) {
|
|
685
622
|
variables = [...variables, valuesKey];
|
|
686
623
|
}
|
|
687
|
-
|
|
688
624
|
return variables;
|
|
689
625
|
}, []);
|
|
690
626
|
}
|
|
@@ -699,6 +635,7 @@ class Importer {
|
|
|
699
635
|
this._formFieldRegistry = formFieldRegistry;
|
|
700
636
|
this._formFields = formFields;
|
|
701
637
|
}
|
|
638
|
+
|
|
702
639
|
/**
|
|
703
640
|
* Import schema adding `id`, `_parent` and `_path`
|
|
704
641
|
* information to each field and adding it to the
|
|
@@ -709,15 +646,12 @@ class Importer {
|
|
|
709
646
|
*
|
|
710
647
|
* @return { { warnings: Array<any>, schema: any, data: any } }
|
|
711
648
|
*/
|
|
712
|
-
|
|
713
|
-
|
|
714
649
|
importSchema(schema, data = {}) {
|
|
715
650
|
// TODO: Add warnings - https://github.com/bpmn-io/form-js/issues/289
|
|
716
651
|
const warnings = [];
|
|
717
|
-
|
|
718
652
|
try {
|
|
719
653
|
const importedSchema = this.importFormField(clone(schema)),
|
|
720
|
-
|
|
654
|
+
importedData = this.importData(clone(data));
|
|
721
655
|
return {
|
|
722
656
|
warnings,
|
|
723
657
|
schema: importedSchema,
|
|
@@ -728,14 +662,13 @@ class Importer {
|
|
|
728
662
|
throw err;
|
|
729
663
|
}
|
|
730
664
|
}
|
|
665
|
+
|
|
731
666
|
/**
|
|
732
667
|
* @param {any} formField
|
|
733
668
|
* @param {string} [parentId]
|
|
734
669
|
*
|
|
735
670
|
* @return {any} importedField
|
|
736
671
|
*/
|
|
737
|
-
|
|
738
|
-
|
|
739
672
|
importFormField(formField, parentId) {
|
|
740
673
|
const {
|
|
741
674
|
components,
|
|
@@ -743,64 +676,53 @@ class Importer {
|
|
|
743
676
|
type,
|
|
744
677
|
id = generateIdForType(type)
|
|
745
678
|
} = formField;
|
|
746
|
-
|
|
747
679
|
if (parentId) {
|
|
748
680
|
// set form field parent
|
|
749
681
|
formField._parent = parentId;
|
|
750
682
|
}
|
|
751
|
-
|
|
752
683
|
if (!this._formFields.get(type)) {
|
|
753
684
|
throw new Error(`form field of type <${type}> not supported`);
|
|
754
685
|
}
|
|
755
|
-
|
|
756
686
|
if (key) {
|
|
757
687
|
// validate <key> uniqueness
|
|
758
688
|
if (this._formFieldRegistry._keys.assigned(key)) {
|
|
759
689
|
throw new Error(`form field with key <${key}> already exists`);
|
|
760
690
|
}
|
|
691
|
+
this._formFieldRegistry._keys.claim(key, formField);
|
|
761
692
|
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
693
|
+
// TODO: buttons should not have key
|
|
765
694
|
if (type !== 'button') {
|
|
766
695
|
// set form field path
|
|
767
696
|
formField._path = [key];
|
|
768
697
|
}
|
|
769
698
|
}
|
|
770
|
-
|
|
771
699
|
if (id) {
|
|
772
700
|
// validate <id> uniqueness
|
|
773
701
|
if (this._formFieldRegistry._ids.assigned(id)) {
|
|
774
702
|
throw new Error(`form field with id <${id}> already exists`);
|
|
775
703
|
}
|
|
776
|
-
|
|
777
704
|
this._formFieldRegistry._ids.claim(id, formField);
|
|
778
|
-
}
|
|
779
|
-
|
|
705
|
+
}
|
|
780
706
|
|
|
707
|
+
// set form field ID
|
|
781
708
|
formField.id = id;
|
|
782
|
-
|
|
783
709
|
this._formFieldRegistry.add(formField);
|
|
784
|
-
|
|
785
710
|
if (components) {
|
|
786
711
|
this.importFormFields(components, id);
|
|
787
712
|
}
|
|
788
|
-
|
|
789
713
|
return formField;
|
|
790
714
|
}
|
|
791
|
-
|
|
792
715
|
importFormFields(components, parentId) {
|
|
793
716
|
components.forEach(component => {
|
|
794
717
|
this.importFormField(component, parentId);
|
|
795
718
|
});
|
|
796
719
|
}
|
|
720
|
+
|
|
797
721
|
/**
|
|
798
722
|
* @param {Object} data
|
|
799
723
|
*
|
|
800
724
|
* @return {Object} importedData
|
|
801
725
|
*/
|
|
802
|
-
|
|
803
|
-
|
|
804
726
|
importData(data) {
|
|
805
727
|
return this._formFieldRegistry.getAll().reduce((importedData, formField) => {
|
|
806
728
|
const {
|
|
@@ -808,22 +730,24 @@ class Importer {
|
|
|
808
730
|
_path,
|
|
809
731
|
type,
|
|
810
732
|
valuesKey
|
|
811
|
-
} = formField;
|
|
733
|
+
} = formField;
|
|
734
|
+
|
|
735
|
+
// get values defined via valuesKey
|
|
812
736
|
|
|
813
737
|
if (valuesKey) {
|
|
814
|
-
importedData = {
|
|
738
|
+
importedData = {
|
|
739
|
+
...importedData,
|
|
815
740
|
[valuesKey]: get(data, [valuesKey])
|
|
816
741
|
};
|
|
817
|
-
}
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
// try to get value from data
|
|
818
745
|
// if unavailable - try to get default value from form field
|
|
819
746
|
// if unavailable - get empty value from form field
|
|
820
747
|
|
|
821
|
-
|
|
822
748
|
if (_path) {
|
|
823
749
|
const fieldImplementation = this._formFields.get(type);
|
|
824
|
-
|
|
825
750
|
let valueData = get(data, _path);
|
|
826
|
-
|
|
827
751
|
if (!isUndefined(valueData) && fieldImplementation.sanitizeValue) {
|
|
828
752
|
valueData = fieldImplementation.sanitizeValue({
|
|
829
753
|
formField,
|
|
@@ -831,17 +755,15 @@ class Importer {
|
|
|
831
755
|
value: valueData
|
|
832
756
|
});
|
|
833
757
|
}
|
|
834
|
-
|
|
835
758
|
const initialFieldValue = !isUndefined(valueData) ? valueData : !isUndefined(defaultValue) ? defaultValue : fieldImplementation.emptyValue;
|
|
836
|
-
importedData = {
|
|
759
|
+
importedData = {
|
|
760
|
+
...importedData,
|
|
837
761
|
[_path[0]]: initialFieldValue
|
|
838
762
|
};
|
|
839
763
|
}
|
|
840
|
-
|
|
841
764
|
return importedData;
|
|
842
765
|
}, {});
|
|
843
766
|
}
|
|
844
|
-
|
|
845
767
|
}
|
|
846
768
|
Importer.$inject = ['formFieldRegistry', 'formFields'];
|
|
847
769
|
|
|
@@ -850,30 +772,26 @@ var importModule = {
|
|
|
850
772
|
};
|
|
851
773
|
|
|
852
774
|
const NODE_TYPE_TEXT = 3,
|
|
853
|
-
|
|
775
|
+
NODE_TYPE_ELEMENT = 1;
|
|
854
776
|
const ALLOWED_NODES = ['h1', 'h2', 'h3', 'h4', 'h5', 'span', 'em', 'a', 'p', 'div', 'ul', 'ol', 'li', 'hr', 'blockquote', 'img', 'pre', 'code', 'br', 'strong'];
|
|
855
777
|
const ALLOWED_ATTRIBUTES = ['align', 'alt', 'class', 'href', 'id', 'name', 'rel', 'target', 'src'];
|
|
856
778
|
const ALLOWED_URI_PATTERN = /^(?:(?:(?:f|ht)tps?|mailto|tel|callto|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i; // eslint-disable-line no-useless-escape
|
|
857
|
-
|
|
858
779
|
const ATTR_WHITESPACE_PATTERN = /[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g; // eslint-disable-line no-control-regex
|
|
859
780
|
|
|
860
781
|
const FORM_ELEMENT = document.createElement('form');
|
|
782
|
+
|
|
861
783
|
/**
|
|
862
784
|
* Sanitize a HTML string and return the cleaned, safe version.
|
|
863
785
|
*
|
|
864
786
|
* @param {string} html
|
|
865
787
|
* @return {string}
|
|
866
788
|
*/
|
|
867
|
-
|
|
868
789
|
function sanitizeHTML(html) {
|
|
869
790
|
const doc = new DOMParser().parseFromString(`<!DOCTYPE html>\n<html><body><div>${html}`, 'text/html');
|
|
870
791
|
doc.normalize();
|
|
871
792
|
const element = doc.body.firstChild;
|
|
872
|
-
|
|
873
793
|
if (element) {
|
|
874
|
-
sanitizeNode(
|
|
875
|
-
/** @type Element */
|
|
876
|
-
element);
|
|
794
|
+
sanitizeNode( /** @type Element */element);
|
|
877
795
|
return new XMLSerializer().serializeToString(element);
|
|
878
796
|
} else {
|
|
879
797
|
// handle the case that document parsing
|
|
@@ -881,6 +799,7 @@ function sanitizeHTML(html) {
|
|
|
881
799
|
return '';
|
|
882
800
|
}
|
|
883
801
|
}
|
|
802
|
+
|
|
884
803
|
/**
|
|
885
804
|
* Recursively sanitize a HTML node, potentially
|
|
886
805
|
* removing it, its children or attributes.
|
|
@@ -891,51 +810,48 @@ function sanitizeHTML(html) {
|
|
|
891
810
|
*
|
|
892
811
|
* @param {Element} node
|
|
893
812
|
*/
|
|
894
|
-
|
|
895
813
|
function sanitizeNode(node) {
|
|
896
814
|
// allow text nodes
|
|
897
815
|
if (node.nodeType === NODE_TYPE_TEXT) {
|
|
898
816
|
return;
|
|
899
|
-
}
|
|
900
|
-
|
|
817
|
+
}
|
|
901
818
|
|
|
819
|
+
// disallow all other nodes but Element
|
|
902
820
|
if (node.nodeType !== NODE_TYPE_ELEMENT) {
|
|
903
821
|
return node.remove();
|
|
904
822
|
}
|
|
823
|
+
const lcTag = node.tagName.toLowerCase();
|
|
905
824
|
|
|
906
|
-
|
|
907
|
-
|
|
825
|
+
// disallow non-whitelisted tags
|
|
908
826
|
if (!ALLOWED_NODES.includes(lcTag)) {
|
|
909
827
|
return node.remove();
|
|
910
828
|
}
|
|
829
|
+
const attributes = node.attributes;
|
|
911
830
|
|
|
912
|
-
|
|
913
|
-
|
|
831
|
+
// clean attributes
|
|
914
832
|
for (let i = attributes.length; i--;) {
|
|
915
833
|
const attribute = attributes[i];
|
|
916
834
|
const name = attribute.name;
|
|
917
|
-
const lcName = name.toLowerCase();
|
|
835
|
+
const lcName = name.toLowerCase();
|
|
918
836
|
|
|
837
|
+
// normalize node value
|
|
919
838
|
const value = attribute.value.trim();
|
|
920
839
|
node.removeAttribute(name);
|
|
921
840
|
const valid = isValidAttribute(lcTag, lcName, value);
|
|
922
|
-
|
|
923
841
|
if (valid) {
|
|
924
842
|
node.setAttribute(name, value);
|
|
925
843
|
}
|
|
926
|
-
}
|
|
927
|
-
|
|
844
|
+
}
|
|
928
845
|
|
|
846
|
+
// force noopener on target="_blank" links
|
|
929
847
|
if (lcTag === 'a' && node.getAttribute('target') === '_blank' && node.getAttribute('rel') !== 'noopener') {
|
|
930
848
|
node.setAttribute('rel', 'noopener');
|
|
931
849
|
}
|
|
932
|
-
|
|
933
850
|
for (let i = node.childNodes.length; i--;) {
|
|
934
|
-
sanitizeNode(
|
|
935
|
-
/** @type Element */
|
|
936
|
-
node.childNodes[i]);
|
|
851
|
+
sanitizeNode( /** @type Element */node.childNodes[i]);
|
|
937
852
|
}
|
|
938
853
|
}
|
|
854
|
+
|
|
939
855
|
/**
|
|
940
856
|
* Validates attributes for validity.
|
|
941
857
|
*
|
|
@@ -944,56 +860,51 @@ function sanitizeNode(node) {
|
|
|
944
860
|
* @param {string} value
|
|
945
861
|
* @return {boolean}
|
|
946
862
|
*/
|
|
947
|
-
|
|
948
|
-
|
|
949
863
|
function isValidAttribute(lcTag, lcName, value) {
|
|
950
864
|
// disallow most attributes based on whitelist
|
|
951
865
|
if (!ALLOWED_ATTRIBUTES.includes(lcName)) {
|
|
952
866
|
return false;
|
|
953
|
-
}
|
|
954
|
-
|
|
867
|
+
}
|
|
955
868
|
|
|
869
|
+
// disallow "DOM clobbering" / polution of document and wrapping form elements
|
|
956
870
|
if ((lcName === 'id' || lcName === 'name') && (value in document || value in FORM_ELEMENT)) {
|
|
957
871
|
return false;
|
|
958
872
|
}
|
|
959
|
-
|
|
960
873
|
if (lcName === 'target' && value !== '_blank') {
|
|
961
874
|
return false;
|
|
962
|
-
}
|
|
963
|
-
|
|
875
|
+
}
|
|
964
876
|
|
|
877
|
+
// allow valid url links only
|
|
965
878
|
if (lcName === 'href' && !ALLOWED_URI_PATTERN.test(value.replace(ATTR_WHITESPACE_PATTERN, ''))) {
|
|
966
879
|
return false;
|
|
967
880
|
}
|
|
968
|
-
|
|
969
881
|
return true;
|
|
970
882
|
}
|
|
971
883
|
|
|
972
|
-
function formFieldClasses(type,
|
|
884
|
+
function formFieldClasses(type, {
|
|
885
|
+
errors = [],
|
|
886
|
+
disabled = false
|
|
887
|
+
} = {}) {
|
|
973
888
|
if (!type) {
|
|
974
889
|
throw new Error('type required');
|
|
975
890
|
}
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
classes.push('fjs-has-errors');
|
|
981
|
-
}
|
|
982
|
-
|
|
983
|
-
return classes.join(' ');
|
|
891
|
+
return classNames('fjs-form-field', `fjs-form-field-${type}`, {
|
|
892
|
+
'fjs-has-errors': errors.length > 0,
|
|
893
|
+
'fjs-disabled': disabled
|
|
894
|
+
});
|
|
984
895
|
}
|
|
985
896
|
function prefixId(id, formId) {
|
|
986
897
|
if (formId) {
|
|
987
898
|
return `fjs-form-${formId}-${id}`;
|
|
988
899
|
}
|
|
989
|
-
|
|
990
900
|
return `fjs-form-${id}`;
|
|
991
901
|
}
|
|
992
902
|
function markdownToHTML(markdown) {
|
|
993
903
|
const htmls = markdown.split(/(?:\r?\n){2,}/).map(line => /^((\d+.)|[><\s#-*])/.test(line) ? snarkdown(line) : `<p>${snarkdown(line)}</p>`);
|
|
994
904
|
return htmls.join('\n\n');
|
|
995
|
-
}
|
|
905
|
+
}
|
|
996
906
|
|
|
907
|
+
// see https://github.com/developit/snarkdown/issues/70
|
|
997
908
|
function safeMarkdown(markdown) {
|
|
998
909
|
const html = markdownToHTML(markdown);
|
|
999
910
|
return sanitizeHTML(html);
|
|
@@ -1008,7 +919,6 @@ function sanitizeSingleSelectValue(options) {
|
|
|
1008
919
|
valuesKey,
|
|
1009
920
|
values
|
|
1010
921
|
} = formField;
|
|
1011
|
-
|
|
1012
922
|
try {
|
|
1013
923
|
const validValues = (valuesKey ? get(data, [valuesKey]) : values).map(v => v.value) || [];
|
|
1014
924
|
return validValues.includes(value) ? value : null;
|
|
@@ -1028,7 +938,6 @@ function sanitizeMultiSelectValue(options) {
|
|
|
1028
938
|
valuesKey,
|
|
1029
939
|
values
|
|
1030
940
|
} = formField;
|
|
1031
|
-
|
|
1032
941
|
try {
|
|
1033
942
|
const validValues = (valuesKey ? get(data, [valuesKey]) : values).map(v => v.value) || [];
|
|
1034
943
|
return value.filter(v => validValues.includes(v));
|
|
@@ -1039,7 +948,7 @@ function sanitizeMultiSelectValue(options) {
|
|
|
1039
948
|
}
|
|
1040
949
|
}
|
|
1041
950
|
|
|
1042
|
-
const type$
|
|
951
|
+
const type$9 = 'button';
|
|
1043
952
|
function Button(props) {
|
|
1044
953
|
const {
|
|
1045
954
|
disabled,
|
|
@@ -1049,7 +958,7 @@ function Button(props) {
|
|
|
1049
958
|
action = 'submit'
|
|
1050
959
|
} = field;
|
|
1051
960
|
return jsx("div", {
|
|
1052
|
-
class: formFieldClasses(type$
|
|
961
|
+
class: formFieldClasses(type$9),
|
|
1053
962
|
children: jsx("button", {
|
|
1054
963
|
class: "fjs-button",
|
|
1055
964
|
type: action,
|
|
@@ -1058,15 +967,13 @@ function Button(props) {
|
|
|
1058
967
|
})
|
|
1059
968
|
});
|
|
1060
969
|
}
|
|
1061
|
-
|
|
1062
970
|
Button.create = function (options = {}) {
|
|
1063
971
|
return {
|
|
1064
972
|
action: 'submit',
|
|
1065
973
|
...options
|
|
1066
974
|
};
|
|
1067
975
|
};
|
|
1068
|
-
|
|
1069
|
-
Button.type = type$8;
|
|
976
|
+
Button.type = type$9;
|
|
1070
977
|
Button.label = 'Button';
|
|
1071
978
|
Button.keyed = true;
|
|
1072
979
|
|
|
@@ -1088,9 +995,7 @@ const FormRenderContext = createContext({
|
|
|
1088
995
|
*
|
|
1089
996
|
* @returns {any}
|
|
1090
997
|
*/
|
|
1091
|
-
|
|
1092
998
|
function getService(type, strict) {}
|
|
1093
|
-
|
|
1094
999
|
const FormContext = createContext({
|
|
1095
1000
|
getService,
|
|
1096
1001
|
formId: null
|
|
@@ -1100,11 +1005,9 @@ function Description(props) {
|
|
|
1100
1005
|
const {
|
|
1101
1006
|
description
|
|
1102
1007
|
} = props;
|
|
1103
|
-
|
|
1104
1008
|
if (!description) {
|
|
1105
1009
|
return null;
|
|
1106
1010
|
}
|
|
1107
|
-
|
|
1108
1011
|
return jsx("div", {
|
|
1109
1012
|
class: "fjs-form-field-description",
|
|
1110
1013
|
children: description
|
|
@@ -1115,11 +1018,9 @@ function Errors(props) {
|
|
|
1115
1018
|
const {
|
|
1116
1019
|
errors
|
|
1117
1020
|
} = props;
|
|
1118
|
-
|
|
1119
1021
|
if (!errors.length) {
|
|
1120
1022
|
return null;
|
|
1121
1023
|
}
|
|
1122
|
-
|
|
1123
1024
|
return jsx("div", {
|
|
1124
1025
|
class: "fjs-form-field-error",
|
|
1125
1026
|
children: jsx("ul", {
|
|
@@ -1140,7 +1041,7 @@ function Label(props) {
|
|
|
1140
1041
|
} = props;
|
|
1141
1042
|
return jsxs("label", {
|
|
1142
1043
|
for: id,
|
|
1143
|
-
class:
|
|
1044
|
+
class: classNames('fjs-form-field-label', props['class']),
|
|
1144
1045
|
children: [props.children, label || '', required && jsx("span", {
|
|
1145
1046
|
class: "fjs-asterix",
|
|
1146
1047
|
children: "*"
|
|
@@ -1148,7 +1049,7 @@ function Label(props) {
|
|
|
1148
1049
|
});
|
|
1149
1050
|
}
|
|
1150
1051
|
|
|
1151
|
-
const type$
|
|
1052
|
+
const type$8 = 'checkbox';
|
|
1152
1053
|
function Checkbox(props) {
|
|
1153
1054
|
const {
|
|
1154
1055
|
disabled,
|
|
@@ -1161,7 +1062,6 @@ function Checkbox(props) {
|
|
|
1161
1062
|
id,
|
|
1162
1063
|
label
|
|
1163
1064
|
} = field;
|
|
1164
|
-
|
|
1165
1065
|
const onChange = ({
|
|
1166
1066
|
target
|
|
1167
1067
|
}) => {
|
|
@@ -1170,12 +1070,16 @@ function Checkbox(props) {
|
|
|
1170
1070
|
value: target.checked
|
|
1171
1071
|
});
|
|
1172
1072
|
};
|
|
1173
|
-
|
|
1174
1073
|
const {
|
|
1175
1074
|
formId
|
|
1176
1075
|
} = useContext(FormContext);
|
|
1177
1076
|
return jsxs("div", {
|
|
1178
|
-
class: formFieldClasses(type$
|
|
1077
|
+
class: classNames(formFieldClasses(type$8, {
|
|
1078
|
+
errors,
|
|
1079
|
+
disabled
|
|
1080
|
+
}), {
|
|
1081
|
+
'fjs-checked': value
|
|
1082
|
+
}),
|
|
1179
1083
|
children: [jsx(Label, {
|
|
1180
1084
|
id: prefixId(id, formId),
|
|
1181
1085
|
label: label,
|
|
@@ -1195,17 +1099,15 @@ function Checkbox(props) {
|
|
|
1195
1099
|
})]
|
|
1196
1100
|
});
|
|
1197
1101
|
}
|
|
1198
|
-
|
|
1199
1102
|
Checkbox.create = function (options = {}) {
|
|
1200
|
-
return {
|
|
1103
|
+
return {
|
|
1104
|
+
...options
|
|
1201
1105
|
};
|
|
1202
1106
|
};
|
|
1203
|
-
|
|
1204
|
-
Checkbox.type = type$7;
|
|
1107
|
+
Checkbox.type = type$8;
|
|
1205
1108
|
Checkbox.label = 'Checkbox';
|
|
1206
1109
|
Checkbox.keyed = true;
|
|
1207
1110
|
Checkbox.emptyValue = false;
|
|
1208
|
-
|
|
1209
1111
|
Checkbox.sanitizeValue = ({
|
|
1210
1112
|
value
|
|
1211
1113
|
}) => value === true;
|
|
@@ -1220,12 +1122,12 @@ function useService (type, strict) {
|
|
|
1220
1122
|
/**
|
|
1221
1123
|
* @enum { String }
|
|
1222
1124
|
*/
|
|
1223
|
-
|
|
1224
1125
|
const LOAD_STATES = {
|
|
1225
1126
|
LOADING: 'loading',
|
|
1226
1127
|
LOADED: 'loaded',
|
|
1227
1128
|
ERROR: 'error'
|
|
1228
1129
|
};
|
|
1130
|
+
|
|
1229
1131
|
/**
|
|
1230
1132
|
* @typedef {Object} ValuesGetter
|
|
1231
1133
|
* @property {Object[]} values - The values data
|
|
@@ -1238,7 +1140,6 @@ const LOAD_STATES = {
|
|
|
1238
1140
|
* @param {Object} field - The form field to handle values for
|
|
1239
1141
|
* @return {ValuesGetter} valuesGetter - A values getter object providing loading state and values
|
|
1240
1142
|
*/
|
|
1241
|
-
|
|
1242
1143
|
function useValuesAsync (field) {
|
|
1243
1144
|
const {
|
|
1244
1145
|
valuesKey,
|
|
@@ -1249,15 +1150,11 @@ function useValuesAsync (field) {
|
|
|
1249
1150
|
error: undefined,
|
|
1250
1151
|
state: LOAD_STATES.LOADING
|
|
1251
1152
|
});
|
|
1252
|
-
|
|
1253
1153
|
const initialData = useService('form')._getState().initialData;
|
|
1254
|
-
|
|
1255
1154
|
useEffect(() => {
|
|
1256
1155
|
let values = [];
|
|
1257
|
-
|
|
1258
1156
|
if (valuesKey !== undefined) {
|
|
1259
1157
|
const keyedValues = (initialData || {})[valuesKey];
|
|
1260
|
-
|
|
1261
1158
|
if (keyedValues && Array.isArray(keyedValues)) {
|
|
1262
1159
|
values = keyedValues;
|
|
1263
1160
|
}
|
|
@@ -1267,25 +1164,22 @@ function useValuesAsync (field) {
|
|
|
1267
1164
|
setValuesGetter(getErrorState('No values source defined in the form definition'));
|
|
1268
1165
|
return;
|
|
1269
1166
|
}
|
|
1270
|
-
|
|
1271
1167
|
setValuesGetter(buildLoadedState(values));
|
|
1272
1168
|
}, [valuesKey, staticValues, initialData]);
|
|
1273
1169
|
return valuesGetter;
|
|
1274
1170
|
}
|
|
1275
|
-
|
|
1276
1171
|
const getErrorState = error => ({
|
|
1277
1172
|
values: [],
|
|
1278
1173
|
error,
|
|
1279
1174
|
state: LOAD_STATES.ERROR
|
|
1280
1175
|
});
|
|
1281
|
-
|
|
1282
1176
|
const buildLoadedState = values => ({
|
|
1283
1177
|
values,
|
|
1284
1178
|
error: undefined,
|
|
1285
1179
|
state: LOAD_STATES.LOADED
|
|
1286
1180
|
});
|
|
1287
1181
|
|
|
1288
|
-
const type$
|
|
1182
|
+
const type$7 = 'checklist';
|
|
1289
1183
|
function Checklist(props) {
|
|
1290
1184
|
const {
|
|
1291
1185
|
disabled,
|
|
@@ -1298,22 +1192,18 @@ function Checklist(props) {
|
|
|
1298
1192
|
id,
|
|
1299
1193
|
label
|
|
1300
1194
|
} = field;
|
|
1301
|
-
|
|
1302
1195
|
const toggleCheckbox = v => {
|
|
1303
1196
|
let newValue = [...value];
|
|
1304
|
-
|
|
1305
1197
|
if (!newValue.includes(v)) {
|
|
1306
1198
|
newValue.push(v);
|
|
1307
1199
|
} else {
|
|
1308
1200
|
newValue = newValue.filter(x => x != v);
|
|
1309
1201
|
}
|
|
1310
|
-
|
|
1311
1202
|
props.onChange({
|
|
1312
1203
|
field,
|
|
1313
1204
|
value: newValue
|
|
1314
1205
|
});
|
|
1315
1206
|
};
|
|
1316
|
-
|
|
1317
1207
|
const {
|
|
1318
1208
|
state: loadState,
|
|
1319
1209
|
values: options
|
|
@@ -1322,13 +1212,19 @@ function Checklist(props) {
|
|
|
1322
1212
|
formId
|
|
1323
1213
|
} = useContext(FormContext);
|
|
1324
1214
|
return jsxs("div", {
|
|
1325
|
-
class: formFieldClasses(type$
|
|
1215
|
+
class: classNames(formFieldClasses(type$7, {
|
|
1216
|
+
errors,
|
|
1217
|
+
disabled
|
|
1218
|
+
})),
|
|
1326
1219
|
children: [jsx(Label, {
|
|
1327
1220
|
label: label
|
|
1328
1221
|
}), loadState == LOAD_STATES.LOADED && options.map((v, index) => {
|
|
1329
1222
|
return jsx(Label, {
|
|
1330
1223
|
id: prefixId(`${id}-${index}`, formId),
|
|
1331
1224
|
label: v.label,
|
|
1225
|
+
class: classNames({
|
|
1226
|
+
'fjs-checked': value.includes(v.value)
|
|
1227
|
+
}),
|
|
1332
1228
|
required: false,
|
|
1333
1229
|
children: jsx("input", {
|
|
1334
1230
|
checked: value.includes(v.value),
|
|
@@ -1346,7 +1242,6 @@ function Checklist(props) {
|
|
|
1346
1242
|
})]
|
|
1347
1243
|
});
|
|
1348
1244
|
}
|
|
1349
|
-
|
|
1350
1245
|
Checklist.create = function (options = {}) {
|
|
1351
1246
|
if (options.valuesKey) return options;
|
|
1352
1247
|
return {
|
|
@@ -1357,15 +1252,13 @@ Checklist.create = function (options = {}) {
|
|
|
1357
1252
|
...options
|
|
1358
1253
|
};
|
|
1359
1254
|
};
|
|
1360
|
-
|
|
1361
|
-
Checklist.type = type$6;
|
|
1255
|
+
Checklist.type = type$7;
|
|
1362
1256
|
Checklist.label = 'Checklist';
|
|
1363
1257
|
Checklist.keyed = true;
|
|
1364
1258
|
Checklist.emptyValue = [];
|
|
1365
1259
|
Checklist.sanitizeValue = sanitizeMultiSelectValue;
|
|
1366
1260
|
|
|
1367
1261
|
const noop$1 = () => false;
|
|
1368
|
-
|
|
1369
1262
|
function FormField(props) {
|
|
1370
1263
|
const {
|
|
1371
1264
|
field,
|
|
@@ -1375,29 +1268,26 @@ function FormField(props) {
|
|
|
1375
1268
|
_path
|
|
1376
1269
|
} = field;
|
|
1377
1270
|
const formFields = useService('formFields'),
|
|
1378
|
-
|
|
1379
|
-
|
|
1271
|
+
form = useService('form');
|
|
1380
1272
|
const {
|
|
1381
1273
|
data,
|
|
1382
1274
|
errors,
|
|
1383
1275
|
properties
|
|
1384
1276
|
} = form._getState();
|
|
1385
|
-
|
|
1386
1277
|
const {
|
|
1387
1278
|
Element
|
|
1388
1279
|
} = useContext(FormRenderContext);
|
|
1389
1280
|
const FormFieldComponent = formFields.get(field.type);
|
|
1390
|
-
|
|
1391
1281
|
if (!FormFieldComponent) {
|
|
1392
1282
|
throw new Error(`cannot render field <${field.type}>`);
|
|
1393
1283
|
}
|
|
1394
|
-
|
|
1395
1284
|
const value = get(data, _path);
|
|
1396
1285
|
const fieldErrors = findErrors(errors, _path);
|
|
1397
1286
|
const disabled = properties.readOnly || field.disabled || false;
|
|
1398
1287
|
return jsx(Element, {
|
|
1399
1288
|
field: field,
|
|
1400
|
-
children: jsx(FormFieldComponent, {
|
|
1289
|
+
children: jsx(FormFieldComponent, {
|
|
1290
|
+
...props,
|
|
1401
1291
|
disabled: disabled,
|
|
1402
1292
|
errors: fieldErrors,
|
|
1403
1293
|
onChange: disabled ? noop$1 : onChange,
|
|
@@ -1421,21 +1311,20 @@ function Default(props) {
|
|
|
1421
1311
|
class: "fjs-vertical-layout",
|
|
1422
1312
|
field: field,
|
|
1423
1313
|
children: [components.map(childField => {
|
|
1424
|
-
return createElement(FormField, {
|
|
1314
|
+
return createElement(FormField, {
|
|
1315
|
+
...props,
|
|
1425
1316
|
key: childField.id,
|
|
1426
1317
|
field: childField
|
|
1427
1318
|
});
|
|
1428
1319
|
}), components.length ? null : jsx(Empty, {})]
|
|
1429
1320
|
});
|
|
1430
1321
|
}
|
|
1431
|
-
|
|
1432
1322
|
Default.create = function (options = {}) {
|
|
1433
1323
|
return {
|
|
1434
1324
|
components: [],
|
|
1435
1325
|
...options
|
|
1436
1326
|
};
|
|
1437
1327
|
};
|
|
1438
|
-
|
|
1439
1328
|
Default.type = 'default';
|
|
1440
1329
|
Default.keyed = false;
|
|
1441
1330
|
|
|
@@ -1444,7 +1333,6 @@ Default.keyed = false;
|
|
|
1444
1333
|
*
|
|
1445
1334
|
* @see http://bpmn.io/license for more information.
|
|
1446
1335
|
*/
|
|
1447
|
-
|
|
1448
1336
|
function Logo() {
|
|
1449
1337
|
return jsxs("svg", {
|
|
1450
1338
|
xmlns: "http://www.w3.org/2000/svg",
|
|
@@ -1461,16 +1349,13 @@ function Logo() {
|
|
|
1461
1349
|
})]
|
|
1462
1350
|
});
|
|
1463
1351
|
}
|
|
1464
|
-
|
|
1465
1352
|
function Lightbox(props) {
|
|
1466
1353
|
const {
|
|
1467
1354
|
open
|
|
1468
1355
|
} = props;
|
|
1469
|
-
|
|
1470
1356
|
if (!open) {
|
|
1471
1357
|
return null;
|
|
1472
1358
|
}
|
|
1473
|
-
|
|
1474
1359
|
return jsxs("div", {
|
|
1475
1360
|
class: "fjs-powered-by-lightbox",
|
|
1476
1361
|
style: "z-index: 100; position: fixed; top: 0; left: 0;right: 0; bottom: 0",
|
|
@@ -1498,7 +1383,6 @@ function Lightbox(props) {
|
|
|
1498
1383
|
})]
|
|
1499
1384
|
});
|
|
1500
1385
|
}
|
|
1501
|
-
|
|
1502
1386
|
function Link(props) {
|
|
1503
1387
|
return jsx("div", {
|
|
1504
1388
|
class: "fjs-powered-by fjs-form-field",
|
|
@@ -1515,17 +1399,14 @@ function Link(props) {
|
|
|
1515
1399
|
})
|
|
1516
1400
|
});
|
|
1517
1401
|
}
|
|
1518
|
-
|
|
1519
1402
|
function PoweredBy(props) {
|
|
1520
1403
|
const [open, setOpen] = useState(false);
|
|
1521
|
-
|
|
1522
1404
|
function toggleOpen(open) {
|
|
1523
1405
|
return event => {
|
|
1524
1406
|
event.preventDefault();
|
|
1525
1407
|
setOpen(open);
|
|
1526
1408
|
};
|
|
1527
1409
|
}
|
|
1528
|
-
|
|
1529
1410
|
return jsxs(Fragment, {
|
|
1530
1411
|
children: [createPortal(jsx(Lightbox, {
|
|
1531
1412
|
open: open,
|
|
@@ -1537,30 +1418,24 @@ function PoweredBy(props) {
|
|
|
1537
1418
|
}
|
|
1538
1419
|
|
|
1539
1420
|
const noop = () => {};
|
|
1540
|
-
|
|
1541
1421
|
function FormComponent(props) {
|
|
1542
1422
|
const form = useService('form');
|
|
1543
|
-
|
|
1544
1423
|
const {
|
|
1545
1424
|
schema
|
|
1546
1425
|
} = form._getState();
|
|
1547
|
-
|
|
1548
1426
|
const {
|
|
1549
1427
|
onSubmit = noop,
|
|
1550
1428
|
onReset = noop,
|
|
1551
1429
|
onChange = noop
|
|
1552
1430
|
} = props;
|
|
1553
|
-
|
|
1554
1431
|
const handleSubmit = event => {
|
|
1555
1432
|
event.preventDefault();
|
|
1556
1433
|
onSubmit();
|
|
1557
1434
|
};
|
|
1558
|
-
|
|
1559
1435
|
const handleReset = event => {
|
|
1560
1436
|
event.preventDefault();
|
|
1561
1437
|
onReset();
|
|
1562
1438
|
};
|
|
1563
|
-
|
|
1564
1439
|
return jsxs("form", {
|
|
1565
1440
|
class: "fjs-form",
|
|
1566
1441
|
onSubmit: handleSubmit,
|
|
@@ -1572,7 +1447,7 @@ function FormComponent(props) {
|
|
|
1572
1447
|
});
|
|
1573
1448
|
}
|
|
1574
1449
|
|
|
1575
|
-
const type$
|
|
1450
|
+
const type$6 = 'number';
|
|
1576
1451
|
function Number(props) {
|
|
1577
1452
|
const {
|
|
1578
1453
|
disabled,
|
|
@@ -1589,7 +1464,6 @@ function Number(props) {
|
|
|
1589
1464
|
const {
|
|
1590
1465
|
required
|
|
1591
1466
|
} = validate;
|
|
1592
|
-
|
|
1593
1467
|
const onChange = ({
|
|
1594
1468
|
target
|
|
1595
1469
|
}) => {
|
|
@@ -1600,12 +1474,14 @@ function Number(props) {
|
|
|
1600
1474
|
})
|
|
1601
1475
|
});
|
|
1602
1476
|
};
|
|
1603
|
-
|
|
1604
1477
|
const {
|
|
1605
1478
|
formId
|
|
1606
1479
|
} = useContext(FormContext);
|
|
1607
1480
|
return jsxs("div", {
|
|
1608
|
-
class: formFieldClasses(type$
|
|
1481
|
+
class: formFieldClasses(type$6, {
|
|
1482
|
+
errors,
|
|
1483
|
+
disabled
|
|
1484
|
+
}),
|
|
1609
1485
|
children: [jsx(Label, {
|
|
1610
1486
|
id: prefixId(id, formId),
|
|
1611
1487
|
label: label,
|
|
@@ -1624,25 +1500,23 @@ function Number(props) {
|
|
|
1624
1500
|
})]
|
|
1625
1501
|
});
|
|
1626
1502
|
}
|
|
1627
|
-
|
|
1628
1503
|
Number.create = function (options = {}) {
|
|
1629
|
-
return {
|
|
1504
|
+
return {
|
|
1505
|
+
...options
|
|
1630
1506
|
};
|
|
1631
1507
|
};
|
|
1632
|
-
|
|
1633
1508
|
Number.sanitizeValue = ({
|
|
1634
1509
|
value
|
|
1635
1510
|
}) => {
|
|
1636
1511
|
const parsedValue = parseInt(value, 10);
|
|
1637
1512
|
return isNaN(parsedValue) ? null : parsedValue;
|
|
1638
1513
|
};
|
|
1639
|
-
|
|
1640
|
-
Number.type = type$5;
|
|
1514
|
+
Number.type = type$6;
|
|
1641
1515
|
Number.keyed = true;
|
|
1642
1516
|
Number.label = 'Number';
|
|
1643
1517
|
Number.emptyValue = null;
|
|
1644
1518
|
|
|
1645
|
-
const type$
|
|
1519
|
+
const type$5 = 'radio';
|
|
1646
1520
|
function Radio(props) {
|
|
1647
1521
|
const {
|
|
1648
1522
|
disabled,
|
|
@@ -1659,14 +1533,12 @@ function Radio(props) {
|
|
|
1659
1533
|
const {
|
|
1660
1534
|
required
|
|
1661
1535
|
} = validate;
|
|
1662
|
-
|
|
1663
1536
|
const onChange = v => {
|
|
1664
1537
|
props.onChange({
|
|
1665
1538
|
field,
|
|
1666
1539
|
value: v
|
|
1667
1540
|
});
|
|
1668
1541
|
};
|
|
1669
|
-
|
|
1670
1542
|
const {
|
|
1671
1543
|
state: loadState,
|
|
1672
1544
|
values: options
|
|
@@ -1675,7 +1547,10 @@ function Radio(props) {
|
|
|
1675
1547
|
formId
|
|
1676
1548
|
} = useContext(FormContext);
|
|
1677
1549
|
return jsxs("div", {
|
|
1678
|
-
class: formFieldClasses(type$
|
|
1550
|
+
class: formFieldClasses(type$5, {
|
|
1551
|
+
errors,
|
|
1552
|
+
disabled
|
|
1553
|
+
}),
|
|
1679
1554
|
children: [jsx(Label, {
|
|
1680
1555
|
label: label,
|
|
1681
1556
|
required: required
|
|
@@ -1683,6 +1558,9 @@ function Radio(props) {
|
|
|
1683
1558
|
return jsx(Label, {
|
|
1684
1559
|
id: prefixId(`${id}-${index}`, formId),
|
|
1685
1560
|
label: option.label,
|
|
1561
|
+
class: classNames({
|
|
1562
|
+
'fjs-checked': option.value === value
|
|
1563
|
+
}),
|
|
1686
1564
|
required: false,
|
|
1687
1565
|
children: jsx("input", {
|
|
1688
1566
|
checked: option.value === value,
|
|
@@ -1700,7 +1578,6 @@ function Radio(props) {
|
|
|
1700
1578
|
})]
|
|
1701
1579
|
});
|
|
1702
1580
|
}
|
|
1703
|
-
|
|
1704
1581
|
Radio.create = function (options = {}) {
|
|
1705
1582
|
if (options.valuesKey) return options;
|
|
1706
1583
|
return {
|
|
@@ -1711,14 +1588,13 @@ Radio.create = function (options = {}) {
|
|
|
1711
1588
|
...options
|
|
1712
1589
|
};
|
|
1713
1590
|
};
|
|
1714
|
-
|
|
1715
|
-
Radio.type = type$4;
|
|
1591
|
+
Radio.type = type$5;
|
|
1716
1592
|
Radio.label = 'Radio';
|
|
1717
1593
|
Radio.keyed = true;
|
|
1718
1594
|
Radio.emptyValue = null;
|
|
1719
1595
|
Radio.sanitizeValue = sanitizeSingleSelectValue;
|
|
1720
1596
|
|
|
1721
|
-
const type$
|
|
1597
|
+
const type$4 = 'select';
|
|
1722
1598
|
function Select(props) {
|
|
1723
1599
|
const {
|
|
1724
1600
|
disabled,
|
|
@@ -1735,7 +1611,6 @@ function Select(props) {
|
|
|
1735
1611
|
const {
|
|
1736
1612
|
required
|
|
1737
1613
|
} = validate;
|
|
1738
|
-
|
|
1739
1614
|
const onChange = ({
|
|
1740
1615
|
target
|
|
1741
1616
|
}) => {
|
|
@@ -1744,7 +1619,6 @@ function Select(props) {
|
|
|
1744
1619
|
value: target.value === '' ? null : target.value
|
|
1745
1620
|
});
|
|
1746
1621
|
};
|
|
1747
|
-
|
|
1748
1622
|
const {
|
|
1749
1623
|
state: loadState,
|
|
1750
1624
|
values: options
|
|
@@ -1753,7 +1627,10 @@ function Select(props) {
|
|
|
1753
1627
|
formId
|
|
1754
1628
|
} = useContext(FormContext);
|
|
1755
1629
|
return jsxs("div", {
|
|
1756
|
-
class: formFieldClasses(type$
|
|
1630
|
+
class: formFieldClasses(type$4, {
|
|
1631
|
+
errors,
|
|
1632
|
+
disabled
|
|
1633
|
+
}),
|
|
1757
1634
|
children: [jsx(Label, {
|
|
1758
1635
|
id: prefixId(id, formId),
|
|
1759
1636
|
label: label,
|
|
@@ -1779,7 +1656,6 @@ function Select(props) {
|
|
|
1779
1656
|
})]
|
|
1780
1657
|
});
|
|
1781
1658
|
}
|
|
1782
|
-
|
|
1783
1659
|
Select.create = function (options = {}) {
|
|
1784
1660
|
if (options.valuesKey) return options;
|
|
1785
1661
|
return {
|
|
@@ -1790,8 +1666,7 @@ Select.create = function (options = {}) {
|
|
|
1790
1666
|
...options
|
|
1791
1667
|
};
|
|
1792
1668
|
};
|
|
1793
|
-
|
|
1794
|
-
Select.type = type$3;
|
|
1669
|
+
Select.type = type$4;
|
|
1795
1670
|
Select.label = 'Select';
|
|
1796
1671
|
Select.keyed = true;
|
|
1797
1672
|
Select.emptyValue = null;
|
|
@@ -1810,7 +1685,7 @@ var CloseIcon = (({
|
|
|
1810
1685
|
fillRule: "evenodd",
|
|
1811
1686
|
clipRule: "evenodd",
|
|
1812
1687
|
d: "M12 4.7l-.7-.7L8 7.3 4.7 4l-.7.7L7.3 8 4 11.3l.7.7L8 8.7l3.3 3.3.7-.7L8.7 8 12 4.7z",
|
|
1813
|
-
fill: "
|
|
1688
|
+
fill: "currentColor"
|
|
1814
1689
|
})));
|
|
1815
1690
|
|
|
1816
1691
|
function useKeyDownAction(targetKey, action, listenerElement = window) {
|
|
@@ -1821,7 +1696,6 @@ function useKeyDownAction(targetKey, action, listenerElement = window) {
|
|
|
1821
1696
|
action();
|
|
1822
1697
|
}
|
|
1823
1698
|
}
|
|
1824
|
-
|
|
1825
1699
|
useEffect(() => {
|
|
1826
1700
|
listenerElement.addEventListener('keydown', downHandler);
|
|
1827
1701
|
return () => {
|
|
@@ -1831,9 +1705,7 @@ function useKeyDownAction(targetKey, action, listenerElement = window) {
|
|
|
1831
1705
|
}
|
|
1832
1706
|
|
|
1833
1707
|
const DEFAULT_LABEL_GETTER = value => value;
|
|
1834
|
-
|
|
1835
1708
|
const NOOP = () => {};
|
|
1836
|
-
|
|
1837
1709
|
function DropdownList(props) {
|
|
1838
1710
|
const {
|
|
1839
1711
|
keyEventsListener = window,
|
|
@@ -1853,7 +1725,6 @@ function DropdownList(props) {
|
|
|
1853
1725
|
}, [values.length]);
|
|
1854
1726
|
useEffect(() => {
|
|
1855
1727
|
if (focusedValueIndex === 0) return;
|
|
1856
|
-
|
|
1857
1728
|
if (!focusedValueIndex || !values.length) {
|
|
1858
1729
|
setFocusedValueIndex(0);
|
|
1859
1730
|
} else if (focusedValueIndex >= values.length) {
|
|
@@ -1879,7 +1750,6 @@ function DropdownList(props) {
|
|
|
1879
1750
|
}, keyEventsListener);
|
|
1880
1751
|
useEffect(() => {
|
|
1881
1752
|
const individualEntries = dropdownContainer.current.children;
|
|
1882
|
-
|
|
1883
1753
|
if (individualEntries.length && !mouseControl) {
|
|
1884
1754
|
individualEntries[focusedValueIndex].scrollIntoView({
|
|
1885
1755
|
block: 'nearest',
|
|
@@ -1887,23 +1757,19 @@ function DropdownList(props) {
|
|
|
1887
1757
|
});
|
|
1888
1758
|
}
|
|
1889
1759
|
}, [focusedValueIndex, mouseControl]);
|
|
1890
|
-
|
|
1891
1760
|
const mouseMove = (e, i) => {
|
|
1892
1761
|
const userMoved = !mouseScreenPos.current || mouseScreenPos.current.x !== e.screenX && mouseScreenPos.current.y !== e.screenY;
|
|
1893
|
-
|
|
1894
1762
|
if (userMoved) {
|
|
1895
1763
|
mouseScreenPos.current = {
|
|
1896
1764
|
x: e.screenX,
|
|
1897
1765
|
y: e.screenY
|
|
1898
1766
|
};
|
|
1899
|
-
|
|
1900
1767
|
if (!mouseControl) {
|
|
1901
1768
|
setMouseControl(true);
|
|
1902
1769
|
setFocusedValueIndex(i);
|
|
1903
1770
|
}
|
|
1904
1771
|
}
|
|
1905
1772
|
};
|
|
1906
|
-
|
|
1907
1773
|
return jsxs("div", {
|
|
1908
1774
|
ref: dropdownContainer,
|
|
1909
1775
|
tabIndex: -1,
|
|
@@ -1929,7 +1795,7 @@ function DropdownList(props) {
|
|
|
1929
1795
|
});
|
|
1930
1796
|
}
|
|
1931
1797
|
|
|
1932
|
-
const type$
|
|
1798
|
+
const type$3 = 'taglist';
|
|
1933
1799
|
function Taglist(props) {
|
|
1934
1800
|
const {
|
|
1935
1801
|
disabled,
|
|
@@ -1954,12 +1820,14 @@ function Taglist(props) {
|
|
|
1954
1820
|
const {
|
|
1955
1821
|
state: loadState,
|
|
1956
1822
|
values: options
|
|
1957
|
-
} = useValuesAsync(field);
|
|
1823
|
+
} = useValuesAsync(field);
|
|
1958
1824
|
|
|
1825
|
+
// We cache a map of option values to their index so that we don't need to search the whole options array every time to correlate the label
|
|
1959
1826
|
const valueToOptionMap = useMemo(() => Object.assign({}, ...options.map((o, x) => ({
|
|
1960
1827
|
[o.value]: options[x]
|
|
1961
|
-
}))), [options]);
|
|
1828
|
+
}))), [options]);
|
|
1962
1829
|
|
|
1830
|
+
// Usage of stringify is necessary here because we want this effect to only trigger when there is a value change to the array
|
|
1963
1831
|
useEffect(() => {
|
|
1964
1832
|
if (loadState === LOAD_STATES.LOADED) {
|
|
1965
1833
|
setFilteredOptions(options.filter(o => o.label && o.value && o.label.toLowerCase().includes(filter.toLowerCase()) && !values.includes(o.value)));
|
|
@@ -1970,37 +1838,32 @@ function Taglist(props) {
|
|
|
1970
1838
|
useEffect(() => {
|
|
1971
1839
|
setHasOptionsLeft(options.length > values.length);
|
|
1972
1840
|
}, [options.length, values.length]);
|
|
1973
|
-
|
|
1974
1841
|
const onFilterChange = ({
|
|
1975
1842
|
target
|
|
1976
1843
|
}) => {
|
|
1977
1844
|
setIsEscapeClose(false);
|
|
1978
1845
|
setFilter(target.value);
|
|
1979
1846
|
};
|
|
1980
|
-
|
|
1981
1847
|
const selectValue = value => {
|
|
1982
1848
|
if (filter) {
|
|
1983
1849
|
setFilter('');
|
|
1984
|
-
}
|
|
1985
|
-
|
|
1850
|
+
}
|
|
1986
1851
|
|
|
1852
|
+
// Ensure values cannot be double selected due to latency
|
|
1987
1853
|
if (values.at(-1) === value) {
|
|
1988
1854
|
return;
|
|
1989
1855
|
}
|
|
1990
|
-
|
|
1991
1856
|
props.onChange({
|
|
1992
1857
|
value: [...values, value],
|
|
1993
1858
|
field
|
|
1994
1859
|
});
|
|
1995
1860
|
};
|
|
1996
|
-
|
|
1997
1861
|
const deselectValue = value => {
|
|
1998
1862
|
props.onChange({
|
|
1999
1863
|
value: values.filter(v => v != value),
|
|
2000
1864
|
field
|
|
2001
1865
|
});
|
|
2002
1866
|
};
|
|
2003
|
-
|
|
2004
1867
|
const onInputKeyDown = e => {
|
|
2005
1868
|
switch (e.key) {
|
|
2006
1869
|
case 'ArrowUp':
|
|
@@ -2008,49 +1871,63 @@ function Taglist(props) {
|
|
|
2008
1871
|
// We do not want the cursor to seek in the search field when we press up and down
|
|
2009
1872
|
e.preventDefault();
|
|
2010
1873
|
break;
|
|
2011
|
-
|
|
2012
1874
|
case 'Backspace':
|
|
2013
1875
|
if (!filter && values.length) {
|
|
2014
1876
|
deselectValue(values[values.length - 1]);
|
|
2015
1877
|
}
|
|
2016
|
-
|
|
2017
1878
|
break;
|
|
2018
|
-
|
|
2019
1879
|
case 'Escape':
|
|
2020
1880
|
setIsEscapeClose(true);
|
|
2021
1881
|
break;
|
|
2022
|
-
|
|
2023
1882
|
case 'Enter':
|
|
2024
1883
|
if (isEscapeClosed) {
|
|
2025
1884
|
setIsEscapeClose(false);
|
|
2026
1885
|
}
|
|
2027
|
-
|
|
2028
1886
|
break;
|
|
2029
1887
|
}
|
|
2030
1888
|
};
|
|
2031
|
-
|
|
1889
|
+
const onTagRemoveClick = (event, value) => {
|
|
1890
|
+
const {
|
|
1891
|
+
target
|
|
1892
|
+
} = event;
|
|
1893
|
+
deselectValue(value);
|
|
1894
|
+
|
|
1895
|
+
// restore focus if there is no next sibling to focus
|
|
1896
|
+
const nextTag = target.closest('.fjs-taglist-tag').nextSibling;
|
|
1897
|
+
if (!nextTag) {
|
|
1898
|
+
searchbarRef.current.focus();
|
|
1899
|
+
}
|
|
1900
|
+
};
|
|
2032
1901
|
return jsxs("div", {
|
|
2033
|
-
class: formFieldClasses(type$
|
|
1902
|
+
class: formFieldClasses(type$3, {
|
|
1903
|
+
errors,
|
|
1904
|
+
disabled
|
|
1905
|
+
}),
|
|
2034
1906
|
children: [jsx(Label, {
|
|
2035
1907
|
label: label,
|
|
2036
|
-
id: prefixId(id
|
|
1908
|
+
id: prefixId(`${id}-search`, formId)
|
|
2037
1909
|
}), jsxs("div", {
|
|
2038
1910
|
class: classNames('fjs-taglist', {
|
|
2039
1911
|
'disabled': disabled
|
|
2040
1912
|
}),
|
|
2041
|
-
children: [!disabled && loadState === LOAD_STATES.LOADED &&
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
children:
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
1913
|
+
children: [!disabled && loadState === LOAD_STATES.LOADED && jsx("div", {
|
|
1914
|
+
class: "fjs-taglist-tags",
|
|
1915
|
+
children: values.map(v => {
|
|
1916
|
+
return jsxs("div", {
|
|
1917
|
+
class: "fjs-taglist-tag",
|
|
1918
|
+
onMouseDown: e => e.preventDefault(),
|
|
1919
|
+
children: [jsx("span", {
|
|
1920
|
+
class: "fjs-taglist-tag-label",
|
|
1921
|
+
children: valueToOptionMap[v] ? valueToOptionMap[v].label : `unexpected value{${v}}`
|
|
1922
|
+
}), jsx("button", {
|
|
1923
|
+
type: "button",
|
|
1924
|
+
title: "Remove tag",
|
|
1925
|
+
class: "fjs-taglist-tag-remove",
|
|
1926
|
+
onClick: event => onTagRemoveClick(event, v),
|
|
1927
|
+
children: jsx(CloseIcon, {})
|
|
1928
|
+
})]
|
|
1929
|
+
});
|
|
1930
|
+
})
|
|
2054
1931
|
}), jsx("input", {
|
|
2055
1932
|
disabled: disabled,
|
|
2056
1933
|
class: "fjs-taglist-input",
|
|
@@ -2085,7 +1962,6 @@ function Taglist(props) {
|
|
|
2085
1962
|
})]
|
|
2086
1963
|
});
|
|
2087
1964
|
}
|
|
2088
|
-
|
|
2089
1965
|
Taglist.create = function (options = {}) {
|
|
2090
1966
|
if (options.valuesKey) return options;
|
|
2091
1967
|
return {
|
|
@@ -2096,14 +1972,13 @@ Taglist.create = function (options = {}) {
|
|
|
2096
1972
|
...options
|
|
2097
1973
|
};
|
|
2098
1974
|
};
|
|
2099
|
-
|
|
2100
|
-
Taglist.type = type$2;
|
|
1975
|
+
Taglist.type = type$3;
|
|
2101
1976
|
Taglist.label = 'Taglist';
|
|
2102
1977
|
Taglist.keyed = true;
|
|
2103
1978
|
Taglist.emptyValue = [];
|
|
2104
1979
|
Taglist.sanitizeValue = sanitizeMultiSelectValue;
|
|
2105
1980
|
|
|
2106
|
-
const type$
|
|
1981
|
+
const type$2 = 'text';
|
|
2107
1982
|
function Text(props) {
|
|
2108
1983
|
const {
|
|
2109
1984
|
field
|
|
@@ -2112,25 +1987,23 @@ function Text(props) {
|
|
|
2112
1987
|
text = ''
|
|
2113
1988
|
} = field;
|
|
2114
1989
|
return jsx("div", {
|
|
2115
|
-
class: formFieldClasses(type$
|
|
1990
|
+
class: formFieldClasses(type$2),
|
|
2116
1991
|
children: jsx(Markup, {
|
|
2117
1992
|
markup: safeMarkdown(text),
|
|
2118
1993
|
trim: false
|
|
2119
1994
|
})
|
|
2120
1995
|
});
|
|
2121
1996
|
}
|
|
2122
|
-
|
|
2123
1997
|
Text.create = function (options = {}) {
|
|
2124
1998
|
return {
|
|
2125
1999
|
text: '# Text',
|
|
2126
2000
|
...options
|
|
2127
2001
|
};
|
|
2128
2002
|
};
|
|
2129
|
-
|
|
2130
|
-
Text.type = type$1;
|
|
2003
|
+
Text.type = type$2;
|
|
2131
2004
|
Text.keyed = false;
|
|
2132
2005
|
|
|
2133
|
-
const type = 'textfield';
|
|
2006
|
+
const type$1 = 'textfield';
|
|
2134
2007
|
function Textfield(props) {
|
|
2135
2008
|
const {
|
|
2136
2009
|
disabled,
|
|
@@ -2147,7 +2020,6 @@ function Textfield(props) {
|
|
|
2147
2020
|
const {
|
|
2148
2021
|
required
|
|
2149
2022
|
} = validate;
|
|
2150
|
-
|
|
2151
2023
|
const onChange = ({
|
|
2152
2024
|
target
|
|
2153
2025
|
}) => {
|
|
@@ -2156,12 +2028,14 @@ function Textfield(props) {
|
|
|
2156
2028
|
value: target.value
|
|
2157
2029
|
});
|
|
2158
2030
|
};
|
|
2159
|
-
|
|
2160
2031
|
const {
|
|
2161
2032
|
formId
|
|
2162
2033
|
} = useContext(FormContext);
|
|
2163
2034
|
return jsxs("div", {
|
|
2164
|
-
class: formFieldClasses(type,
|
|
2035
|
+
class: formFieldClasses(type$1, {
|
|
2036
|
+
errors,
|
|
2037
|
+
disabled
|
|
2038
|
+
}),
|
|
2165
2039
|
children: [jsx(Label, {
|
|
2166
2040
|
id: prefixId(id, formId),
|
|
2167
2041
|
label: label,
|
|
@@ -2180,22 +2054,101 @@ function Textfield(props) {
|
|
|
2180
2054
|
})]
|
|
2181
2055
|
});
|
|
2182
2056
|
}
|
|
2183
|
-
|
|
2184
2057
|
Textfield.create = function (options = {}) {
|
|
2185
|
-
return {
|
|
2058
|
+
return {
|
|
2059
|
+
...options
|
|
2186
2060
|
};
|
|
2187
2061
|
};
|
|
2188
|
-
|
|
2189
|
-
Textfield.
|
|
2190
|
-
Textfield.label = 'Text Field';
|
|
2062
|
+
Textfield.type = type$1;
|
|
2063
|
+
Textfield.label = 'Text field';
|
|
2191
2064
|
Textfield.keyed = true;
|
|
2192
2065
|
Textfield.emptyValue = '';
|
|
2193
|
-
|
|
2194
2066
|
Textfield.sanitizeValue = ({
|
|
2195
2067
|
value
|
|
2196
|
-
}) => isArray(value) || isObject(value) ?
|
|
2068
|
+
}) => isArray(value) || isObject(value) ? '' : String(value);
|
|
2069
|
+
|
|
2070
|
+
const type = 'textarea';
|
|
2071
|
+
function Textarea(props) {
|
|
2072
|
+
const {
|
|
2073
|
+
disabled,
|
|
2074
|
+
errors = [],
|
|
2075
|
+
field,
|
|
2076
|
+
value = ''
|
|
2077
|
+
} = props;
|
|
2078
|
+
const {
|
|
2079
|
+
description,
|
|
2080
|
+
id,
|
|
2081
|
+
label,
|
|
2082
|
+
validate = {}
|
|
2083
|
+
} = field;
|
|
2084
|
+
const {
|
|
2085
|
+
required
|
|
2086
|
+
} = validate;
|
|
2087
|
+
const textareaRef = useRef();
|
|
2088
|
+
const onInput = ({
|
|
2089
|
+
target
|
|
2090
|
+
}) => {
|
|
2091
|
+
props.onChange({
|
|
2092
|
+
field,
|
|
2093
|
+
value: target.value
|
|
2094
|
+
});
|
|
2095
|
+
};
|
|
2096
|
+
const autoSizeTextarea = useCallback(textarea => {
|
|
2097
|
+
// Ensures the textarea shrinks back, and improves resizing behavior consistency
|
|
2098
|
+
textarea.style.height = '0px';
|
|
2099
|
+
const computed = window.getComputedStyle(textarea);
|
|
2100
|
+
const calculatedHeight = parseInt(computed.getPropertyValue('border-top-width')) + parseInt(computed.getPropertyValue('padding-top')) + textarea.scrollHeight + parseInt(computed.getPropertyValue('padding-bottom')) + parseInt(computed.getPropertyValue('border-bottom-width'));
|
|
2101
|
+
const minHeight = 75;
|
|
2102
|
+
const maxHeight = 350;
|
|
2103
|
+
const displayHeight = Math.max(Math.min(calculatedHeight, maxHeight), minHeight);
|
|
2104
|
+
textarea.style.height = `${displayHeight}px`;
|
|
2105
|
+
|
|
2106
|
+
// Overflow is hidden by default to hide scrollbar flickering
|
|
2107
|
+
textarea.style.overflow = calculatedHeight > maxHeight ? 'visible' : 'hidden';
|
|
2108
|
+
}, []);
|
|
2109
|
+
useEffect(() => {
|
|
2110
|
+
autoSizeTextarea(textareaRef.current);
|
|
2111
|
+
}, [autoSizeTextarea, value]);
|
|
2112
|
+
const {
|
|
2113
|
+
formId
|
|
2114
|
+
} = useContext(FormContext);
|
|
2115
|
+
return jsxs("div", {
|
|
2116
|
+
class: formFieldClasses(type, {
|
|
2117
|
+
errors,
|
|
2118
|
+
disabled
|
|
2119
|
+
}),
|
|
2120
|
+
children: [jsx(Label, {
|
|
2121
|
+
id: prefixId(id, formId),
|
|
2122
|
+
label: label,
|
|
2123
|
+
required: required
|
|
2124
|
+
}), jsx("textarea", {
|
|
2125
|
+
class: "fjs-textarea",
|
|
2126
|
+
disabled: disabled,
|
|
2127
|
+
id: prefixId(id, formId),
|
|
2128
|
+
onInput: onInput,
|
|
2129
|
+
value: value,
|
|
2130
|
+
ref: textareaRef
|
|
2131
|
+
}), jsx(Description, {
|
|
2132
|
+
description: description
|
|
2133
|
+
}), jsx(Errors, {
|
|
2134
|
+
errors: errors
|
|
2135
|
+
})]
|
|
2136
|
+
});
|
|
2137
|
+
}
|
|
2138
|
+
Textarea.create = function (options = {}) {
|
|
2139
|
+
return {
|
|
2140
|
+
...options
|
|
2141
|
+
};
|
|
2142
|
+
};
|
|
2143
|
+
Textarea.type = type;
|
|
2144
|
+
Textarea.label = 'Text area';
|
|
2145
|
+
Textarea.keyed = true;
|
|
2146
|
+
Textarea.emptyValue = '';
|
|
2147
|
+
Textarea.sanitizeValue = ({
|
|
2148
|
+
value
|
|
2149
|
+
}) => isArray(value) || isObject(value) ? '' : String(value);
|
|
2197
2150
|
|
|
2198
|
-
const formFields = [Button, Checkbox, Checklist, Default, Number, Radio, Select, Taglist, Text, Textfield];
|
|
2151
|
+
const formFields = [Button, Checkbox, Checklist, Default, Number, Radio, Select, Taglist, Text, Textfield, Textarea];
|
|
2199
2152
|
|
|
2200
2153
|
class FormFields {
|
|
2201
2154
|
constructor() {
|
|
@@ -2207,15 +2160,12 @@ class FormFields {
|
|
|
2207
2160
|
this.register(type, formField);
|
|
2208
2161
|
});
|
|
2209
2162
|
}
|
|
2210
|
-
|
|
2211
2163
|
register(type, formField) {
|
|
2212
2164
|
this._formFields[type] = formField;
|
|
2213
2165
|
}
|
|
2214
|
-
|
|
2215
2166
|
get(type) {
|
|
2216
2167
|
return this._formFields[type];
|
|
2217
2168
|
}
|
|
2218
|
-
|
|
2219
2169
|
}
|
|
2220
2170
|
|
|
2221
2171
|
function Renderer(config, eventBus, form, injector) {
|
|
@@ -2225,7 +2175,6 @@ function Renderer(config, eventBus, form, injector) {
|
|
|
2225
2175
|
getService(type, strict = true) {
|
|
2226
2176
|
return injector.get(type, strict);
|
|
2227
2177
|
},
|
|
2228
|
-
|
|
2229
2178
|
formId: form._id
|
|
2230
2179
|
};
|
|
2231
2180
|
eventBus.on('changed', newState => {
|
|
@@ -2247,11 +2196,9 @@ function Renderer(config, eventBus, form, injector) {
|
|
|
2247
2196
|
const {
|
|
2248
2197
|
schema
|
|
2249
2198
|
} = state;
|
|
2250
|
-
|
|
2251
2199
|
if (!schema) {
|
|
2252
2200
|
return null;
|
|
2253
2201
|
}
|
|
2254
|
-
|
|
2255
2202
|
return jsx(FormContext.Provider, {
|
|
2256
2203
|
value: formContext,
|
|
2257
2204
|
children: jsx(FormComponent, {
|
|
@@ -2261,7 +2208,6 @@ function Renderer(config, eventBus, form, injector) {
|
|
|
2261
2208
|
})
|
|
2262
2209
|
});
|
|
2263
2210
|
};
|
|
2264
|
-
|
|
2265
2211
|
const {
|
|
2266
2212
|
container
|
|
2267
2213
|
} = config;
|
|
@@ -2311,10 +2257,10 @@ var core = {
|
|
|
2311
2257
|
*/
|
|
2312
2258
|
|
|
2313
2259
|
const ids = new Ids([32, 36, 1]);
|
|
2260
|
+
|
|
2314
2261
|
/**
|
|
2315
2262
|
* The form.
|
|
2316
2263
|
*/
|
|
2317
|
-
|
|
2318
2264
|
class Form {
|
|
2319
2265
|
/**
|
|
2320
2266
|
* @constructor
|
|
@@ -2326,28 +2272,28 @@ class Form {
|
|
|
2326
2272
|
* @type {OnEventType}
|
|
2327
2273
|
*/
|
|
2328
2274
|
this.on = this._onEvent;
|
|
2275
|
+
|
|
2329
2276
|
/**
|
|
2330
2277
|
* @public
|
|
2331
2278
|
* @type {String}
|
|
2332
2279
|
*/
|
|
2333
|
-
|
|
2334
2280
|
this._id = ids.next();
|
|
2281
|
+
|
|
2335
2282
|
/**
|
|
2336
2283
|
* @private
|
|
2337
2284
|
* @type {Element}
|
|
2338
2285
|
*/
|
|
2339
|
-
|
|
2340
2286
|
this._container = createFormContainer();
|
|
2341
2287
|
const {
|
|
2342
2288
|
container,
|
|
2343
2289
|
injector = this._createInjector(options, this._container),
|
|
2344
2290
|
properties = {}
|
|
2345
2291
|
} = options;
|
|
2292
|
+
|
|
2346
2293
|
/**
|
|
2347
2294
|
* @private
|
|
2348
2295
|
* @type {State}
|
|
2349
2296
|
*/
|
|
2350
|
-
|
|
2351
2297
|
this._state = {
|
|
2352
2298
|
initialData: null,
|
|
2353
2299
|
data: null,
|
|
@@ -2358,33 +2304,31 @@ class Form {
|
|
|
2358
2304
|
this.get = injector.get;
|
|
2359
2305
|
this.invoke = injector.invoke;
|
|
2360
2306
|
this.get('eventBus').fire('form.init');
|
|
2361
|
-
|
|
2362
2307
|
if (container) {
|
|
2363
2308
|
this.attachTo(container);
|
|
2364
2309
|
}
|
|
2365
2310
|
}
|
|
2366
|
-
|
|
2367
2311
|
clear() {
|
|
2368
2312
|
// clear form services
|
|
2369
|
-
this._emit('diagram.clear');
|
|
2370
|
-
|
|
2313
|
+
this._emit('diagram.clear');
|
|
2371
2314
|
|
|
2315
|
+
// clear diagram services (e.g. EventBus)
|
|
2372
2316
|
this._emit('form.clear');
|
|
2373
2317
|
}
|
|
2318
|
+
|
|
2374
2319
|
/**
|
|
2375
2320
|
* Destroy the form, removing it from DOM,
|
|
2376
2321
|
* if attached.
|
|
2377
2322
|
*/
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
2323
|
destroy() {
|
|
2381
2324
|
// destroy form services
|
|
2382
|
-
this.get('eventBus').fire('form.destroy');
|
|
2325
|
+
this.get('eventBus').fire('form.destroy');
|
|
2383
2326
|
|
|
2327
|
+
// destroy diagram services (e.g. EventBus)
|
|
2384
2328
|
this.get('eventBus').fire('diagram.destroy');
|
|
2385
|
-
|
|
2386
2329
|
this._detach(false);
|
|
2387
2330
|
}
|
|
2331
|
+
|
|
2388
2332
|
/**
|
|
2389
2333
|
* Open a form schema with the given initial data.
|
|
2390
2334
|
*
|
|
@@ -2393,8 +2337,6 @@ class Form {
|
|
|
2393
2337
|
*
|
|
2394
2338
|
* @return Promise<{ warnings: Array<any> }>
|
|
2395
2339
|
*/
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
2340
|
importSchema(schema, data = {}) {
|
|
2399
2341
|
return new Promise((resolve, reject) => {
|
|
2400
2342
|
try {
|
|
@@ -2404,18 +2346,15 @@ class Form {
|
|
|
2404
2346
|
data: importedData,
|
|
2405
2347
|
warnings
|
|
2406
2348
|
} = this.get('importer').importSchema(schema, data);
|
|
2407
|
-
|
|
2408
2349
|
this._setState({
|
|
2409
2350
|
data: importedData,
|
|
2410
2351
|
errors: {},
|
|
2411
2352
|
schema: importedSchema,
|
|
2412
2353
|
initialData: clone(importedData)
|
|
2413
2354
|
});
|
|
2414
|
-
|
|
2415
2355
|
this._emit('import.done', {
|
|
2416
2356
|
warnings
|
|
2417
2357
|
});
|
|
2418
|
-
|
|
2419
2358
|
return resolve({
|
|
2420
2359
|
warnings
|
|
2421
2360
|
});
|
|
@@ -2424,154 +2363,124 @@ class Form {
|
|
|
2424
2363
|
error,
|
|
2425
2364
|
warnings: error.warnings || []
|
|
2426
2365
|
});
|
|
2427
|
-
|
|
2428
2366
|
return reject(error);
|
|
2429
2367
|
}
|
|
2430
2368
|
});
|
|
2431
2369
|
}
|
|
2370
|
+
|
|
2432
2371
|
/**
|
|
2433
2372
|
* Submit the form, triggering all field validations.
|
|
2434
2373
|
*
|
|
2435
2374
|
* @returns { { data: Data, errors: Errors } }
|
|
2436
2375
|
*/
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
2376
|
submit() {
|
|
2440
2377
|
const {
|
|
2441
2378
|
properties
|
|
2442
2379
|
} = this._getState();
|
|
2443
|
-
|
|
2444
2380
|
if (properties.readOnly) {
|
|
2445
2381
|
throw new Error('form is read-only');
|
|
2446
2382
|
}
|
|
2447
|
-
|
|
2448
2383
|
const data = this._getSubmitData();
|
|
2449
|
-
|
|
2450
2384
|
const errors = this.validate();
|
|
2451
|
-
|
|
2452
2385
|
this._emit('submit', {
|
|
2453
2386
|
data,
|
|
2454
2387
|
errors
|
|
2455
2388
|
});
|
|
2456
|
-
|
|
2457
2389
|
return {
|
|
2458
2390
|
data,
|
|
2459
2391
|
errors
|
|
2460
2392
|
};
|
|
2461
2393
|
}
|
|
2462
|
-
|
|
2463
2394
|
reset() {
|
|
2464
2395
|
this._emit('reset');
|
|
2465
|
-
|
|
2466
2396
|
this._setState({
|
|
2467
2397
|
data: clone(this._state.initialData),
|
|
2468
2398
|
errors: {}
|
|
2469
2399
|
});
|
|
2470
2400
|
}
|
|
2401
|
+
|
|
2471
2402
|
/**
|
|
2472
2403
|
* @returns {Errors}
|
|
2473
2404
|
*/
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
2405
|
validate() {
|
|
2477
2406
|
const formFieldRegistry = this.get('formFieldRegistry'),
|
|
2478
|
-
|
|
2479
|
-
|
|
2407
|
+
validator = this.get('validator');
|
|
2480
2408
|
const {
|
|
2481
2409
|
data
|
|
2482
2410
|
} = this._getState();
|
|
2483
|
-
|
|
2484
2411
|
const errors = formFieldRegistry.getAll().reduce((errors, field) => {
|
|
2485
2412
|
const {
|
|
2486
2413
|
disabled,
|
|
2487
2414
|
_path
|
|
2488
2415
|
} = field;
|
|
2489
|
-
|
|
2490
2416
|
if (disabled) {
|
|
2491
2417
|
return errors;
|
|
2492
2418
|
}
|
|
2493
|
-
|
|
2494
2419
|
const value = get(data, _path);
|
|
2495
2420
|
const fieldErrors = validator.validateField(field, value);
|
|
2496
2421
|
return set(errors, [pathStringify(_path)], fieldErrors.length ? fieldErrors : undefined);
|
|
2497
|
-
},
|
|
2498
|
-
/** @type {Errors} */
|
|
2499
|
-
{});
|
|
2500
|
-
|
|
2422
|
+
}, /** @type {Errors} */{});
|
|
2501
2423
|
this._setState({
|
|
2502
2424
|
errors
|
|
2503
2425
|
});
|
|
2504
|
-
|
|
2505
2426
|
return errors;
|
|
2506
2427
|
}
|
|
2428
|
+
|
|
2507
2429
|
/**
|
|
2508
2430
|
* @param {Element|string} parentNode
|
|
2509
2431
|
*/
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
2432
|
attachTo(parentNode) {
|
|
2513
2433
|
if (!parentNode) {
|
|
2514
2434
|
throw new Error('parentNode required');
|
|
2515
2435
|
}
|
|
2516
|
-
|
|
2517
2436
|
this.detach();
|
|
2518
|
-
|
|
2519
2437
|
if (isString(parentNode)) {
|
|
2520
2438
|
parentNode = document.querySelector(parentNode);
|
|
2521
2439
|
}
|
|
2522
|
-
|
|
2523
2440
|
const container = this._container;
|
|
2524
2441
|
parentNode.appendChild(container);
|
|
2525
|
-
|
|
2526
2442
|
this._emit('attach');
|
|
2527
2443
|
}
|
|
2528
|
-
|
|
2529
2444
|
detach() {
|
|
2530
2445
|
this._detach();
|
|
2531
2446
|
}
|
|
2447
|
+
|
|
2532
2448
|
/**
|
|
2533
2449
|
* @private
|
|
2534
2450
|
*
|
|
2535
2451
|
* @param {boolean} [emit]
|
|
2536
2452
|
*/
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
2453
|
_detach(emit = true) {
|
|
2540
2454
|
const container = this._container,
|
|
2541
|
-
|
|
2542
|
-
|
|
2455
|
+
parentNode = container.parentNode;
|
|
2543
2456
|
if (!parentNode) {
|
|
2544
2457
|
return;
|
|
2545
2458
|
}
|
|
2546
|
-
|
|
2547
2459
|
if (emit) {
|
|
2548
2460
|
this._emit('detach');
|
|
2549
2461
|
}
|
|
2550
|
-
|
|
2551
2462
|
parentNode.removeChild(container);
|
|
2552
2463
|
}
|
|
2464
|
+
|
|
2553
2465
|
/**
|
|
2554
2466
|
* @param {FormProperty} property
|
|
2555
2467
|
* @param {any} value
|
|
2556
2468
|
*/
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
2469
|
setProperty(property, value) {
|
|
2560
2470
|
const properties = set(this._getState().properties, [property], value);
|
|
2561
|
-
|
|
2562
2471
|
this._setState({
|
|
2563
2472
|
properties
|
|
2564
2473
|
});
|
|
2565
2474
|
}
|
|
2475
|
+
|
|
2566
2476
|
/**
|
|
2567
2477
|
* @param {FormEvent} type
|
|
2568
2478
|
* @param {Function} handler
|
|
2569
2479
|
*/
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
2480
|
off(type, handler) {
|
|
2573
2481
|
this.get('eventBus').off(type, handler);
|
|
2574
2482
|
}
|
|
2483
|
+
|
|
2575
2484
|
/**
|
|
2576
2485
|
* @private
|
|
2577
2486
|
*
|
|
@@ -2580,8 +2489,6 @@ class Form {
|
|
|
2580
2489
|
*
|
|
2581
2490
|
* @returns {Injector}
|
|
2582
2491
|
*/
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
2492
|
_createInjector(options, container) {
|
|
2586
2493
|
const {
|
|
2587
2494
|
additionalModules = [],
|
|
@@ -2598,21 +2505,19 @@ class Form {
|
|
|
2598
2505
|
form: ['value', this]
|
|
2599
2506
|
}, core, ...modules, ...additionalModules]);
|
|
2600
2507
|
}
|
|
2508
|
+
|
|
2601
2509
|
/**
|
|
2602
2510
|
* @private
|
|
2603
2511
|
*/
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
2512
|
_emit(type, data) {
|
|
2607
2513
|
this.get('eventBus').fire(type, data);
|
|
2608
2514
|
}
|
|
2515
|
+
|
|
2609
2516
|
/**
|
|
2610
2517
|
* @internal
|
|
2611
2518
|
*
|
|
2612
2519
|
* @param { { add?: boolean, field: any, remove?: number, value?: any } } update
|
|
2613
2520
|
*/
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
2521
|
_update(update) {
|
|
2617
2522
|
const {
|
|
2618
2523
|
field,
|
|
@@ -2621,77 +2526,71 @@ class Form {
|
|
|
2621
2526
|
const {
|
|
2622
2527
|
_path
|
|
2623
2528
|
} = field;
|
|
2624
|
-
|
|
2625
2529
|
let {
|
|
2626
2530
|
data,
|
|
2627
2531
|
errors
|
|
2628
2532
|
} = this._getState();
|
|
2629
|
-
|
|
2630
2533
|
const validator = this.get('validator');
|
|
2631
2534
|
const fieldErrors = validator.validateField(field, value);
|
|
2632
2535
|
set(data, _path, value);
|
|
2633
2536
|
set(errors, [pathStringify(_path)], fieldErrors.length ? fieldErrors : undefined);
|
|
2634
|
-
|
|
2635
2537
|
this._setState({
|
|
2636
2538
|
data: clone(data),
|
|
2637
2539
|
errors: clone(errors)
|
|
2638
2540
|
});
|
|
2639
2541
|
}
|
|
2542
|
+
|
|
2640
2543
|
/**
|
|
2641
2544
|
* @internal
|
|
2642
2545
|
*/
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
2546
|
_getState() {
|
|
2646
2547
|
return this._state;
|
|
2647
2548
|
}
|
|
2549
|
+
|
|
2648
2550
|
/**
|
|
2649
2551
|
* @internal
|
|
2650
2552
|
*/
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
2553
|
_setState(state) {
|
|
2654
|
-
this._state = {
|
|
2554
|
+
this._state = {
|
|
2555
|
+
...this._state,
|
|
2655
2556
|
...state
|
|
2656
2557
|
};
|
|
2657
|
-
|
|
2658
2558
|
this._emit('changed', this._getState());
|
|
2659
2559
|
}
|
|
2560
|
+
|
|
2660
2561
|
/**
|
|
2661
2562
|
* @internal
|
|
2662
2563
|
*/
|
|
2663
|
-
|
|
2664
|
-
|
|
2665
2564
|
_onEvent(type, priority, handler) {
|
|
2666
2565
|
this.get('eventBus').on(type, priority, handler);
|
|
2667
2566
|
}
|
|
2567
|
+
|
|
2668
2568
|
/**
|
|
2669
2569
|
* @internal
|
|
2670
2570
|
*/
|
|
2671
|
-
|
|
2672
|
-
|
|
2673
2571
|
_getSubmitData() {
|
|
2674
2572
|
const formFieldRegistry = this.get('formFieldRegistry');
|
|
2675
2573
|
return formFieldRegistry.getAll().reduce((data, field) => {
|
|
2676
2574
|
const {
|
|
2677
2575
|
disabled,
|
|
2678
2576
|
_path
|
|
2679
|
-
} = field;
|
|
2577
|
+
} = field;
|
|
2680
2578
|
|
|
2579
|
+
// do not submit disabled form fields
|
|
2681
2580
|
if (disabled || !_path) {
|
|
2682
2581
|
return data;
|
|
2683
2582
|
}
|
|
2684
|
-
|
|
2685
2583
|
const value = get(this._getState().data, _path);
|
|
2686
|
-
return {
|
|
2584
|
+
return {
|
|
2585
|
+
...data,
|
|
2687
2586
|
[_path[0]]: value
|
|
2688
2587
|
};
|
|
2689
2588
|
}, {});
|
|
2690
2589
|
}
|
|
2691
|
-
|
|
2692
2590
|
}
|
|
2693
2591
|
|
|
2694
|
-
const schemaVersion =
|
|
2592
|
+
const schemaVersion = 6;
|
|
2593
|
+
|
|
2695
2594
|
/**
|
|
2696
2595
|
* @typedef { import('./types').CreateFormOptions } CreateFormOptions
|
|
2697
2596
|
*/
|
|
@@ -2703,7 +2602,6 @@ const schemaVersion = 5;
|
|
|
2703
2602
|
*
|
|
2704
2603
|
* @return {Promise<Form>}
|
|
2705
2604
|
*/
|
|
2706
|
-
|
|
2707
2605
|
function createForm(options) {
|
|
2708
2606
|
const {
|
|
2709
2607
|
data,
|
|
@@ -2716,5 +2614,5 @@ function createForm(options) {
|
|
|
2716
2614
|
});
|
|
2717
2615
|
}
|
|
2718
2616
|
|
|
2719
|
-
export { Button, Checkbox, Checklist, Default, Form, FormComponent, FormContext, FormFieldRegistry, FormFields, FormRenderContext, Number, Radio, Select, Taglist, Text, Textfield, clone, createForm, createFormContainer, createInjector, findErrors, formFields, generateIdForType, generateIndexForType, getSchemaVariables, isRequired, pathParse, pathStringify, pathsEqual, schemaVersion };
|
|
2617
|
+
export { Button, Checkbox, Checklist, Default, Form, FormComponent, FormContext, FormFieldRegistry, FormFields, FormRenderContext, Number, Radio, Select, Taglist, Text, Textarea, Textfield, clone, createForm, createFormContainer, createInjector, findErrors, formFields, generateIdForType, generateIndexForType, getSchemaVariables, isRequired, pathParse, pathStringify, pathsEqual, schemaVersion };
|
|
2720
2618
|
//# sourceMappingURL=index.es.js.map
|