@3t-transform/threeteeui 0.2.97 → 0.2.99
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/tttx-form.cjs.entry.js +114 -29
- package/dist/cjs/tttx-icon.cjs.entry.js +6 -1
- package/dist/cjs/tttx-standalone-input.cjs.entry.js +1 -1
- package/dist/collection/components/atoms/tttx-icon/tttx-icon.js +6 -1
- package/dist/collection/components/atoms/tttx-icon/tttx-icon.stories.js +1 -1
- package/dist/collection/components/atoms/tttx-loading-spinner/tttx-loading-spinner.stories.js +8 -1
- package/dist/collection/components/molecules/tttx-form/lib/setErrorState.js +2 -0
- package/dist/collection/components/molecules/tttx-form/lib/validityCheck.js +10 -5
- package/dist/collection/components/molecules/tttx-form/tttx-form.css +7 -0
- package/dist/collection/components/molecules/tttx-form/tttx-form.js +101 -23
- package/dist/collection/components/molecules/tttx-form/tttx-form.stories.js +126 -3
- package/dist/collection/components/molecules/tttx-standalone-input/tttx-standalone-input.css +7 -0
- package/dist/components/tttx-form.js +114 -29
- package/dist/components/tttx-icon2.js +6 -1
- package/dist/components/tttx-standalone-input2.js +1 -1
- package/dist/esm/tttx-form.entry.js +114 -29
- package/dist/esm/tttx-icon.entry.js +6 -1
- package/dist/esm/tttx-standalone-input.entry.js +1 -1
- package/dist/tttx/{p-93e63568.entry.js → p-6e0fac85.entry.js} +1 -1
- package/dist/tttx/p-b2b0e16d.entry.js +1 -0
- package/dist/tttx/p-bcf3844e.entry.js +1 -0
- package/dist/tttx/tttx.esm.js +1 -1
- package/dist/types/components/atoms/tttx-loading-spinner/tttx-loading-spinner.stories.d.ts +10 -1
- package/dist/types/components/molecules/tttx-form/tttx-form.d.ts +12 -0
- package/dist/types/components/molecules/tttx-form/tttx-form.stories.d.ts +110 -0
- package/package.json +2 -2
- package/dist/tttx/p-a94f7efc.entry.js +0 -1
- package/dist/tttx/p-feea36cb.entry.js +0 -1
|
@@ -38,6 +38,16 @@ function validityCheck(event) {
|
|
|
38
38
|
// target.setCustomValidity('custom error!');
|
|
39
39
|
// and cleared with
|
|
40
40
|
// target.setCustomValidity('');
|
|
41
|
+
//handle whitespace-only input
|
|
42
|
+
if (target.value.length && !target.value.replace(/\s/g, '').length) {
|
|
43
|
+
errorMessage = 'This field cannot be left blank';
|
|
44
|
+
target.setCustomValidity(errorMessage);
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
errorMessage = '';
|
|
48
|
+
if (target.setCustomValidity) // tests are dumb as a brick
|
|
49
|
+
target.setCustomValidity('');
|
|
50
|
+
}
|
|
41
51
|
// Check the validity of the input field and set an error message if needed
|
|
42
52
|
switch (true) {
|
|
43
53
|
// The field is required, but has no value
|
|
@@ -65,11 +75,6 @@ function validityCheck(event) {
|
|
|
65
75
|
default:
|
|
66
76
|
hasError = false;
|
|
67
77
|
}
|
|
68
|
-
//handle whitespace-only input
|
|
69
|
-
if (!target.value.replace(/\s/g, '').length && target.value.length !== 0) {
|
|
70
|
-
errorMessage = 'Whitespace-only not allowed';
|
|
71
|
-
hasError = true;
|
|
72
|
-
}
|
|
73
78
|
// Return the error state
|
|
74
79
|
return { target, hasError, errorMessage };
|
|
75
80
|
}
|
|
@@ -99,6 +104,8 @@ function setErrorState(target, hasError, errorMessage, parent = undefined) {
|
|
|
99
104
|
errorBubble = target.parentElement.parentElement.querySelector('.errorBubble');
|
|
100
105
|
}
|
|
101
106
|
}
|
|
107
|
+
if (!errorBubble)
|
|
108
|
+
return;
|
|
102
109
|
// If an error was detected, set the input field's class to "invalid" and display the error message in the error bubble
|
|
103
110
|
if (hasError) {
|
|
104
111
|
target.classList.add('invalid');
|
|
@@ -122,7 +129,7 @@ function setErrorState(target, hasError, errorMessage, parent = undefined) {
|
|
|
122
129
|
}
|
|
123
130
|
}
|
|
124
131
|
|
|
125
|
-
const tttxFormCss = ".material-symbols-rounded{font-variation-settings:\"FILL\" 1, \"wght\" 400, \"GRAD\" 0, \"opsz\" 24}.material-symbols-rounded{font-variation-settings:\"FILL\" 1, \"wght\" 400, \"GRAD\" 0, \"opsz\" 24}label{font-weight:500;font-size:16px;line-height:19px;color:#212121}label .optional{color:#757575;font-weight:normal}label .outer-container{position:relative}label .outer-container .left-icons,label .outer-container .right-icons{display:flex;position:absolute;height:24px;gap:8px}label .outer-container .left-icons tttx-icon,label .outer-container .right-icons tttx-icon{height:24px;width:24px}label .outer-container .left-icons{left:8px}label .outer-container .right-icons{right:8px}label .outer-container input{color:#212121;box-sizing:border-box;border:1px solid #d5d5d5;border-radius:4px;padding:0;padding-left:16px;padding-right:16px;margin-top:4px;}label .outer-container input.has-input-icon{padding-left:40px}label .outer-container input.has-input-icon.has-left-icon{padding-left:72px}label .outer-container input.has-left-icon{padding-left:40px}label .outer-container input.has-right-icon{padding-right:40px}label .outer-container input.invalid{border:1px solid #dc0000}label .outer-container input:not([type=submit]){font-family:\"Roboto\", serif;width:100%;height:36px;font-size:16px;line-height:19px}label .outer-container input[type=date]{background:white;display:block;min-width:calc(100% - 18px);line-height:37px}label .outer-container input[readonly]{cursor:default;pointer-events:none;user-select:none;color:gray}label .outer-container input:focus{border-color:#1479c6}label .outer-container input:focus-visible{outline:none}label .outer-container.inputBlock{display:flex;align-items:center;line-height:21px}label .outer-container.inputBlock .left-icons,label .outer-container.inputBlock .right-icons{margin-top:4px}label .outer-container.inputBlock.readonly{pointer-events:none;user-select:none;color:gray}label .outer-container.inputInline{display:flex;white-space:nowrap;align-items:center;margin:0}label .outer-container.inputInline input{margin-top:0}label .secondarylabel{color:#757575;font-size:14px;line-height:16px;font-weight:normal;display:flex;margin-top:4px}label .errorBubble{position:relative;font-size:14px;line-height:16px;font-weight:normal;width:100%;font-family:\"Roboto\", sans-serif;color:#dc0000;display:flex;align-content:center;align-items:center;justify-items:center;margin-top:4px}label .errorBubble:not(.visible){display:none}label .errorBubble span{color:#dc0000;font-size:16px;margin-right:4px}.material-symbols-rounded{font-family:\"Material Symbols Rounded\", sans-serif;font-weight:400;font-style:normal;font-size:24px;line-height:1;letter-spacing:normal;text-transform:none;display:inline-block;white-space:nowrap;word-wrap:normal;direction:ltr;text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased;color:#9e9e9e}button{cursor:pointer}.button{font-family:Roboto, serif;box-sizing:border-box;height:36px;min-width:36px;padding:0;margin:0;background:transparent;color:#212121;border:1px solid #c8c8c8;border-radius:4px;text-transform:uppercase;display:flex;justify-content:left;align-items:center;font-size:14px;font-weight:500}.button-content{display:block;padding:0 16px}.icon-left,.icon-right{margin-top:4px}.iconleft{padding-left:8px}.iconleft .button-content{padding-left:4px}.iconright{padding-right:8px}.iconright .button-content{padding-right:4px}.notext{padding:0 6px}.button:active{background:rgba(17, 17, 17, 0.2);border:1px solid #d5d5d5}.primary{background:#1479c6;border:1px solid #1479c6;color:white}.primary:active{background:#1464a2;border:1px solid #1464a2}.borderless{background:transparent;border:none;color:#212121}.borderless:active{background:rgba(17, 17, 17, 0.2);border:none}.borderless-circle{background:transparent;border:none;color:#212121;border-radius:50%}.borderless-circle:active{border:none}.borderless-circle:focus{border-color:transparent}.danger{background:#dc0000;border:1px solid #dc0000;color:white}.danger:active{background:#b00000;border:1px solid #b00000}.disabled{background:#aeaeae;border:none;color:#4c4c4c;cursor:not-allowed}.disabled:active{background:#aeaeae;border:none;color:#4c4c4c;cursor:not-allowed}@media (hover: hover){.button:hover{background:rgba(17, 17, 17, 0.1);border:1px solid #d5d5d5}.primary:hover{background:#146eb3;border:1px solid #146eb3}.borderless:hover{background:rgba(17, 17, 17, 0.1);border:none}.borderless-circle:hover{background:rgba(17, 17, 17, 0.1);border:none}.danger:hover{background:#c60000;border:1px solid #c60000}.disabled:hover{background:#aeaeae;border:none;color:#4c4c4c;cursor:not-allowed}}:host{display:block}fieldset{margin:0;padding:0;border:none}label{display:block;position:relative;margin-bottom:16px}.inlineLabel{font-weight:400;display:inline-block;vertical-align:top;padding-top:4px}input[type=checkbox]{width:18px;height:18px}input~label{font-weight:400}select{font-family:\"Roboto\", serif;box-sizing:border-box;width:100%;height:36px;padding:0 16px;font-size:16px;border:1px solid #d5d5d5;border-radius:4px;margin-top:4px}.placeholder{color:#9e9e9e}.placeholder option{color:initial}select.invalid:invalid{border:1px solid #dc0000}select~.errorBubble{position:relative;font-size:14px;font-weight:normal;width:100%;font-family:\"Roboto\", sans-serif;color:#dc0000;display:flex;align-content:center;align-items:center;justify-items:center}select~.errorBubble:not(.visible){visibility:hidden}select~.errorBubble span{color:#dc0000;font-size:16px;margin-right:4px;height:16px}select.invalid:invalid~.errorBubble{position:relative;font-size:14px;font-weight:normal;width:100%;font-family:\"Roboto\", sans-serif;color:#dc0000;visibility:visible}select:focus{border-color:#1479c6}select:focus-visible{outline:none}.button{padding:0 16px}.footer{display:flex;gap:16px;flex-direction:row-reverse}";
|
|
132
|
+
const tttxFormCss = ".material-symbols-rounded{font-variation-settings:\"FILL\" 1, \"wght\" 400, \"GRAD\" 0, \"opsz\" 24}.material-symbols-rounded{font-variation-settings:\"FILL\" 1, \"wght\" 400, \"GRAD\" 0, \"opsz\" 24}label{font-weight:500;font-size:16px;line-height:19px;color:#212121}label .optional{color:#757575;font-weight:normal}label .outer-container{position:relative}label .outer-container .left-icons,label .outer-container .right-icons{display:flex;position:absolute;height:24px;gap:8px}label .outer-container .left-icons tttx-icon,label .outer-container .right-icons tttx-icon{height:24px;width:24px}label .outer-container .left-icons{left:8px}label .outer-container .right-icons{right:8px}label .outer-container input{color:#212121;box-sizing:border-box;border:1px solid #d5d5d5;border-radius:4px;padding:0;padding-left:16px;padding-right:16px;margin-top:4px;}label .outer-container input.has-input-icon{padding-left:40px}label .outer-container input.has-input-icon.has-left-icon{padding-left:72px}label .outer-container input.has-left-icon{padding-left:40px}label .outer-container input.has-right-icon{padding-right:40px}label .outer-container input.invalid{border:1px solid #dc0000}label .outer-container input:not([type=submit]){font-family:\"Roboto\", serif;width:100%;height:36px;font-size:16px;line-height:19px}label .outer-container input[type=radio]{width:20px;height:20px}label .outer-container input[type=date]{background:white;display:block;min-width:calc(100% - 18px);line-height:37px}label .outer-container input[readonly]{cursor:default;pointer-events:none;user-select:none;color:gray}label .outer-container input:focus{border-color:#1479c6}label .outer-container input:focus-visible{outline:none}label .outer-container.inputBlock{display:flex;align-items:center;line-height:21px}label .outer-container.inputBlock .left-icons,label .outer-container.inputBlock .right-icons{margin-top:4px}label .outer-container.inputBlock.readonly{pointer-events:none;user-select:none;color:gray}label .outer-container.inputBlock.radioBlock{display:block}label .outer-container.inputInline{display:flex;white-space:nowrap;align-items:center;margin:0}label .outer-container.inputInline input{margin-top:0}label .secondarylabel{color:#757575;font-size:14px;line-height:16px;font-weight:normal;display:flex;margin-top:4px}label .errorBubble{position:relative;font-size:14px;line-height:16px;font-weight:normal;width:100%;font-family:\"Roboto\", sans-serif;color:#dc0000;display:flex;align-content:center;align-items:center;justify-items:center;margin-top:4px}label .errorBubble:not(.visible){display:none}label .errorBubble span{color:#dc0000;font-size:16px;margin-right:4px}.material-symbols-rounded{font-family:\"Material Symbols Rounded\", sans-serif;font-weight:400;font-style:normal;font-size:24px;line-height:1;letter-spacing:normal;text-transform:none;display:inline-block;white-space:nowrap;word-wrap:normal;direction:ltr;text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased;color:#9e9e9e}button{cursor:pointer}.button{font-family:Roboto, serif;box-sizing:border-box;height:36px;min-width:36px;padding:0;margin:0;background:transparent;color:#212121;border:1px solid #c8c8c8;border-radius:4px;text-transform:uppercase;display:flex;justify-content:left;align-items:center;font-size:14px;font-weight:500}.button-content{display:block;padding:0 16px}.icon-left,.icon-right{margin-top:4px}.iconleft{padding-left:8px}.iconleft .button-content{padding-left:4px}.iconright{padding-right:8px}.iconright .button-content{padding-right:4px}.notext{padding:0 6px}.button:active{background:rgba(17, 17, 17, 0.2);border:1px solid #d5d5d5}.primary{background:#1479c6;border:1px solid #1479c6;color:white}.primary:active{background:#1464a2;border:1px solid #1464a2}.borderless{background:transparent;border:none;color:#212121}.borderless:active{background:rgba(17, 17, 17, 0.2);border:none}.borderless-circle{background:transparent;border:none;color:#212121;border-radius:50%}.borderless-circle:active{border:none}.borderless-circle:focus{border-color:transparent}.danger{background:#dc0000;border:1px solid #dc0000;color:white}.danger:active{background:#b00000;border:1px solid #b00000}.disabled{background:#aeaeae;border:none;color:#4c4c4c;cursor:not-allowed}.disabled:active{background:#aeaeae;border:none;color:#4c4c4c;cursor:not-allowed}@media (hover: hover){.button:hover{background:rgba(17, 17, 17, 0.1);border:1px solid #d5d5d5}.primary:hover{background:#146eb3;border:1px solid #146eb3}.borderless:hover{background:rgba(17, 17, 17, 0.1);border:none}.borderless-circle:hover{background:rgba(17, 17, 17, 0.1);border:none}.danger:hover{background:#c60000;border:1px solid #c60000}.disabled:hover{background:#aeaeae;border:none;color:#4c4c4c;cursor:not-allowed}}:host{display:block}fieldset{margin:0;padding:0;border:none}label{display:block;position:relative;margin-bottom:16px}.inlineLabel{font-weight:400;display:inline-block;vertical-align:top;padding-top:4px}input[type=checkbox]{width:18px;height:18px}input~label{font-weight:400}select{font-family:\"Roboto\", serif;box-sizing:border-box;width:100%;height:36px;padding:0 16px;font-size:16px;border:1px solid #d5d5d5;border-radius:4px;margin-top:4px}.placeholder{color:#9e9e9e}.placeholder option{color:initial}select.invalid:invalid{border:1px solid #dc0000}select~.errorBubble{position:relative;font-size:14px;font-weight:normal;width:100%;font-family:\"Roboto\", sans-serif;color:#dc0000;display:flex;align-content:center;align-items:center;justify-items:center}select~.errorBubble:not(.visible){visibility:hidden}select~.errorBubble span{color:#dc0000;font-size:16px;margin-right:4px;height:16px}select.invalid:invalid~.errorBubble{position:relative;font-size:14px;font-weight:normal;width:100%;font-family:\"Roboto\", sans-serif;color:#dc0000;visibility:visible}select:focus{border-color:#1479c6}select:focus-visible{outline:none}.button{padding:0 16px}.footer{display:flex;gap:16px;flex-direction:row-reverse}";
|
|
126
133
|
|
|
127
134
|
const TttxForm = class {
|
|
128
135
|
constructor(hostRef) {
|
|
@@ -195,6 +202,23 @@ const TttxForm = class {
|
|
|
195
202
|
event.preventDefault();
|
|
196
203
|
// create a new FormData object with the form data
|
|
197
204
|
const formData = new FormData(event.target);
|
|
205
|
+
// get a list of checkboxes, if any, so we can manually set unchecked box data
|
|
206
|
+
const checkboxSchemaItems = [];
|
|
207
|
+
const formProperties = this._formSchema.properties;
|
|
208
|
+
for (const formKey of Object.keys(formProperties)) {
|
|
209
|
+
if (formProperties[formKey].form.type === 'checkbox') {
|
|
210
|
+
checkboxSchemaItems.push(formKey);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
const allFormKeys = [];
|
|
214
|
+
for (const key of formData.keys()) {
|
|
215
|
+
allFormKeys.push(key);
|
|
216
|
+
}
|
|
217
|
+
for (const checkItem of checkboxSchemaItems) {
|
|
218
|
+
if (allFormKeys.indexOf(checkItem) === -1) {
|
|
219
|
+
formData.append(checkItem, 'off');
|
|
220
|
+
}
|
|
221
|
+
}
|
|
198
222
|
// emit the form data through the `dataSubmitted` event
|
|
199
223
|
this.dataSubmitted.emit(formData);
|
|
200
224
|
}
|
|
@@ -379,17 +403,21 @@ const TttxForm = class {
|
|
|
379
403
|
*/
|
|
380
404
|
createLabel(formProperties, input, errorBubble) {
|
|
381
405
|
const outerContainer = document.createElement('div');
|
|
382
|
-
|
|
406
|
+
let outerContainerClassName = 'outer-container inputBlock';
|
|
383
407
|
// Create a new <label> element with the "inputBlock" class and the specified text
|
|
384
408
|
const label = document.createElement('label');
|
|
385
409
|
label.innerText = formProperties.label;
|
|
386
410
|
// If the form property has no validation object, add an "optional" span element to the label
|
|
387
|
-
if (!formProperties.validation) {
|
|
411
|
+
if (!formProperties.validation && formProperties.label) {
|
|
388
412
|
const optionalSpan = document.createElement('span');
|
|
389
413
|
optionalSpan.className = 'optional';
|
|
390
414
|
optionalSpan.innerHTML = ' (optional)';
|
|
391
415
|
label.appendChild(optionalSpan);
|
|
392
416
|
}
|
|
417
|
+
if (formProperties.type === 'radio') {
|
|
418
|
+
outerContainerClassName += ' radioBlock';
|
|
419
|
+
}
|
|
420
|
+
outerContainer.className = outerContainerClassName;
|
|
393
421
|
if (formProperties.readonly) {
|
|
394
422
|
label.classList.add('readonly');
|
|
395
423
|
}
|
|
@@ -407,6 +435,38 @@ const TttxForm = class {
|
|
|
407
435
|
// Return the label element
|
|
408
436
|
return label;
|
|
409
437
|
}
|
|
438
|
+
/**
|
|
439
|
+
* Creates a new radio input with a set of options.
|
|
440
|
+
*
|
|
441
|
+
* @param {string} formKey - The name of the dropdown field, as specified in the form schema.
|
|
442
|
+
* @param {Object} formProperties - An object containing additional properties, such as the field type and options properties.
|
|
443
|
+
* @param {'radio'} formProperties.type - The type of form field. In this case, it will always be "radio".
|
|
444
|
+
* @param {Object} formProperties.validation - A set of validation rules for the field.
|
|
445
|
+
* @param {Object[]} formProperties.options - A list of properties to pass to the select options.
|
|
446
|
+
* @param {string} formProperties.options.label - The visible value of the option.
|
|
447
|
+
* @param {string} formProperties.options.value - The actual value of the option.
|
|
448
|
+
*/
|
|
449
|
+
createRadio(formKey, formProperties) {
|
|
450
|
+
var _a, _b;
|
|
451
|
+
const fragment = new DocumentFragment();
|
|
452
|
+
for (const optionProperties of formProperties.options) {
|
|
453
|
+
// Create a new <input> element with the specified name and type
|
|
454
|
+
const input = document.createElement('input');
|
|
455
|
+
input.type = 'radio';
|
|
456
|
+
input.name = formKey;
|
|
457
|
+
input.value = optionProperties.value;
|
|
458
|
+
if ((_a = formProperties === null || formProperties === void 0 ? void 0 : formProperties.validation) === null || _a === void 0 ? void 0 : _a.required) {
|
|
459
|
+
input.setAttribute('required', 'required');
|
|
460
|
+
input.setAttribute('data-required', (_b = formProperties.validation.required.message) !== null && _b !== void 0 ? _b : '');
|
|
461
|
+
}
|
|
462
|
+
const span = document.createElement('span');
|
|
463
|
+
span.innerText = optionProperties.label;
|
|
464
|
+
fragment.appendChild(input);
|
|
465
|
+
fragment.appendChild(span);
|
|
466
|
+
fragment.appendChild(document.createElement('br'));
|
|
467
|
+
}
|
|
468
|
+
return fragment;
|
|
469
|
+
}
|
|
410
470
|
/**
|
|
411
471
|
* Populates the form template with input fields and labels based on the properties of the
|
|
412
472
|
* current form schema. For each property in the schema, it creates an input element, applies
|
|
@@ -426,9 +486,19 @@ const TttxForm = class {
|
|
|
426
486
|
propertyKeys.forEach(formKey => {
|
|
427
487
|
const formItem = properties[formKey];
|
|
428
488
|
const formProperties = formItem.form;
|
|
429
|
-
|
|
489
|
+
let input;
|
|
490
|
+
switch (formProperties.type) {
|
|
491
|
+
case 'select':
|
|
492
|
+
input = this.createSelect(formKey, formProperties);
|
|
493
|
+
break;
|
|
494
|
+
case 'radio':
|
|
495
|
+
input = this.createRadio(formKey, formProperties);
|
|
496
|
+
break;
|
|
497
|
+
default:
|
|
498
|
+
input = this.createInput(formKey, formProperties);
|
|
499
|
+
}
|
|
430
500
|
// If the form property has validation, apply it to the input
|
|
431
|
-
if (formProperties.validation) {
|
|
501
|
+
if (formProperties.validation && formProperties.type !== 'radio') {
|
|
432
502
|
this.applyValidation(input, formProperties.validation);
|
|
433
503
|
}
|
|
434
504
|
// Create an error bubble and label element for the input
|
|
@@ -459,25 +529,40 @@ const TttxForm = class {
|
|
|
459
529
|
const propertyKeys = Object.keys(properties);
|
|
460
530
|
propertyKeys.forEach(formKey => {
|
|
461
531
|
var _a, _b;
|
|
462
|
-
const
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
532
|
+
const formInputs = formItems.querySelectorAll(`[name=${formKey}]`);
|
|
533
|
+
for (const formInput of formInputs) {
|
|
534
|
+
// Bind events to form input elements
|
|
535
|
+
formInput.oninvalid = this.validityCheckWrapper.bind(this);
|
|
536
|
+
formInput.onblur = this.validityCheckWrapper.bind(this);
|
|
537
|
+
formInput.onkeyup = this.fieldChanged.bind(this);
|
|
538
|
+
formInput.onchange = this.fieldChanged.bind(this);
|
|
539
|
+
if ((_a = this._data) === null || _a === void 0 ? void 0 : _a[formKey]) {
|
|
540
|
+
switch (formInput.type) {
|
|
541
|
+
case 'checkbox':
|
|
542
|
+
if (this._data[formKey] === 'on') {
|
|
543
|
+
formInput.checked = true;
|
|
544
|
+
}
|
|
545
|
+
break;
|
|
546
|
+
case 'radio':
|
|
547
|
+
if (formInput.value === this._data[formKey]) {
|
|
548
|
+
formInput.checked = true;
|
|
549
|
+
}
|
|
550
|
+
break;
|
|
551
|
+
default:
|
|
552
|
+
formInput.value = this._data[formKey];
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
// If explicitly setting input as invalid, set invalid state and error message on render
|
|
556
|
+
if ((_b = properties[formKey].form.validation) === null || _b === void 0 ? void 0 : _b.invalid) {
|
|
557
|
+
const errorMessage = properties[formKey].form.validation.invalid.message;
|
|
558
|
+
formInput.setCustomValidity(errorMessage); // Prevents the invalid styling from resetting on blur
|
|
559
|
+
setErrorState(formInput, true, errorMessage);
|
|
560
|
+
}
|
|
561
|
+
if (properties[formKey].form.type === 'select' && formInput.classList.contains('placeholder')) {
|
|
562
|
+
formInput.addEventListener('change', () => {
|
|
563
|
+
formInput.classList.remove('placeholder');
|
|
564
|
+
});
|
|
565
|
+
}
|
|
481
566
|
}
|
|
482
567
|
});
|
|
483
568
|
// Append the cloned form elements to the fieldset
|
|
@@ -13,7 +13,12 @@ const TttxIcon = class {
|
|
|
13
13
|
this.color = 'grey';
|
|
14
14
|
}
|
|
15
15
|
render() {
|
|
16
|
-
|
|
16
|
+
if (this.color.startsWith('#')) {
|
|
17
|
+
return (index.h(index.Host, null, index.h("span", { class: 'material-symbols-rounded', style: { color: this.color } }, this.icon)));
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
return (index.h(index.Host, null, index.h("span", { class: `material-symbols-rounded ${this.color}` }, this.icon)));
|
|
21
|
+
}
|
|
17
22
|
}
|
|
18
23
|
};
|
|
19
24
|
TttxIcon.style = tttxIconCss;
|
|
@@ -4,7 +4,7 @@ Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
4
4
|
|
|
5
5
|
const index = require('./index-992a9fb3.js');
|
|
6
6
|
|
|
7
|
-
const tttxStandaloneInputCss = ".material-symbols-rounded.sc-tttx-standalone-input{font-variation-settings:\"FILL\" 1, \"wght\" 400, \"GRAD\" 0, \"opsz\" 24}.material-symbols-rounded.sc-tttx-standalone-input{font-variation-settings:\"FILL\" 1, \"wght\" 400, \"GRAD\" 0, \"opsz\" 24}label.sc-tttx-standalone-input{font-weight:500;font-size:16px;line-height:19px;color:#212121}label.sc-tttx-standalone-input .optional.sc-tttx-standalone-input{color:#757575;font-weight:normal}label.sc-tttx-standalone-input .outer-container.sc-tttx-standalone-input{position:relative}label.sc-tttx-standalone-input .outer-container.sc-tttx-standalone-input .left-icons.sc-tttx-standalone-input,label.sc-tttx-standalone-input .outer-container.sc-tttx-standalone-input .right-icons.sc-tttx-standalone-input{display:flex;position:absolute;height:24px;gap:8px}label.sc-tttx-standalone-input .outer-container.sc-tttx-standalone-input .left-icons.sc-tttx-standalone-input tttx-icon.sc-tttx-standalone-input,label.sc-tttx-standalone-input .outer-container.sc-tttx-standalone-input .right-icons.sc-tttx-standalone-input tttx-icon.sc-tttx-standalone-input{height:24px;width:24px}label.sc-tttx-standalone-input .outer-container.sc-tttx-standalone-input .left-icons.sc-tttx-standalone-input{left:8px}label.sc-tttx-standalone-input .outer-container.sc-tttx-standalone-input .right-icons.sc-tttx-standalone-input{right:8px}label.sc-tttx-standalone-input .outer-container.sc-tttx-standalone-input input.sc-tttx-standalone-input{color:#212121;box-sizing:border-box;border:1px solid #d5d5d5;border-radius:4px;padding:0;padding-left:16px;padding-right:16px;margin-top:4px}label.sc-tttx-standalone-input .outer-container.sc-tttx-standalone-input input.has-input-icon.sc-tttx-standalone-input{padding-left:40px}label.sc-tttx-standalone-input .outer-container.sc-tttx-standalone-input input.has-input-icon.has-left-icon.sc-tttx-standalone-input{padding-left:72px}label.sc-tttx-standalone-input .outer-container.sc-tttx-standalone-input input.has-left-icon.sc-tttx-standalone-input{padding-left:40px}label.sc-tttx-standalone-input .outer-container.sc-tttx-standalone-input input.has-right-icon.sc-tttx-standalone-input{padding-right:40px}label.sc-tttx-standalone-input .outer-container.sc-tttx-standalone-input input.invalid.sc-tttx-standalone-input{border:1px solid #dc0000}label.sc-tttx-standalone-input .outer-container.sc-tttx-standalone-input input.sc-tttx-standalone-input:not([type=submit]){font-family:\"Roboto\", serif;width:100%;height:36px;font-size:16px;line-height:19px}label.sc-tttx-standalone-input .outer-container.sc-tttx-standalone-input input[type=date].sc-tttx-standalone-input{background:white;display:block;min-width:calc(100% - 18px);line-height:37px}label.sc-tttx-standalone-input .outer-container.sc-tttx-standalone-input input[readonly].sc-tttx-standalone-input{cursor:default;pointer-events:none;user-select:none;color:gray}label.sc-tttx-standalone-input .outer-container.sc-tttx-standalone-input input.sc-tttx-standalone-input:focus{border-color:#1479c6}label.sc-tttx-standalone-input .outer-container.sc-tttx-standalone-input input.sc-tttx-standalone-input:focus-visible{outline:none}label.sc-tttx-standalone-input .outer-container.inputBlock.sc-tttx-standalone-input{display:flex;align-items:center;line-height:21px}label.sc-tttx-standalone-input .outer-container.inputBlock.sc-tttx-standalone-input .left-icons.sc-tttx-standalone-input,label.sc-tttx-standalone-input .outer-container.inputBlock.sc-tttx-standalone-input .right-icons.sc-tttx-standalone-input{margin-top:4px}label.sc-tttx-standalone-input .outer-container.inputBlock.readonly.sc-tttx-standalone-input{pointer-events:none;user-select:none;color:gray}label.sc-tttx-standalone-input .outer-container.inputInline.sc-tttx-standalone-input{display:flex;white-space:nowrap;align-items:center;margin:0}label.sc-tttx-standalone-input .outer-container.inputInline.sc-tttx-standalone-input input.sc-tttx-standalone-input{margin-top:0}label.sc-tttx-standalone-input .secondarylabel.sc-tttx-standalone-input{color:#757575;font-size:14px;line-height:16px;font-weight:normal;display:flex;margin-top:4px}label.sc-tttx-standalone-input .errorBubble.sc-tttx-standalone-input{position:relative;font-size:14px;line-height:16px;font-weight:normal;width:100%;font-family:\"Roboto\", sans-serif;color:#dc0000;display:flex;align-content:center;align-items:center;justify-items:center;margin-top:4px}label.sc-tttx-standalone-input .errorBubble.sc-tttx-standalone-input:not(.visible){display:none}label.sc-tttx-standalone-input .errorBubble.sc-tttx-standalone-input span.sc-tttx-standalone-input{color:#dc0000;font-size:16px;margin-right:4px}.material-symbols-rounded.sc-tttx-standalone-input{font-family:\"Material Symbols Rounded\", sans-serif;font-weight:400;font-style:normal;font-size:24px;line-height:1;letter-spacing:normal;text-transform:none;display:inline-block;white-space:nowrap;word-wrap:normal;direction:ltr;text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased;color:#9e9e9e}.sc-tttx-standalone-input-h{display:block}";
|
|
7
|
+
const tttxStandaloneInputCss = ".material-symbols-rounded.sc-tttx-standalone-input{font-variation-settings:\"FILL\" 1, \"wght\" 400, \"GRAD\" 0, \"opsz\" 24}.material-symbols-rounded.sc-tttx-standalone-input{font-variation-settings:\"FILL\" 1, \"wght\" 400, \"GRAD\" 0, \"opsz\" 24}label.sc-tttx-standalone-input{font-weight:500;font-size:16px;line-height:19px;color:#212121}label.sc-tttx-standalone-input .optional.sc-tttx-standalone-input{color:#757575;font-weight:normal}label.sc-tttx-standalone-input .outer-container.sc-tttx-standalone-input{position:relative}label.sc-tttx-standalone-input .outer-container.sc-tttx-standalone-input .left-icons.sc-tttx-standalone-input,label.sc-tttx-standalone-input .outer-container.sc-tttx-standalone-input .right-icons.sc-tttx-standalone-input{display:flex;position:absolute;height:24px;gap:8px}label.sc-tttx-standalone-input .outer-container.sc-tttx-standalone-input .left-icons.sc-tttx-standalone-input tttx-icon.sc-tttx-standalone-input,label.sc-tttx-standalone-input .outer-container.sc-tttx-standalone-input .right-icons.sc-tttx-standalone-input tttx-icon.sc-tttx-standalone-input{height:24px;width:24px}label.sc-tttx-standalone-input .outer-container.sc-tttx-standalone-input .left-icons.sc-tttx-standalone-input{left:8px}label.sc-tttx-standalone-input .outer-container.sc-tttx-standalone-input .right-icons.sc-tttx-standalone-input{right:8px}label.sc-tttx-standalone-input .outer-container.sc-tttx-standalone-input input.sc-tttx-standalone-input{color:#212121;box-sizing:border-box;border:1px solid #d5d5d5;border-radius:4px;padding:0;padding-left:16px;padding-right:16px;margin-top:4px}label.sc-tttx-standalone-input .outer-container.sc-tttx-standalone-input input.has-input-icon.sc-tttx-standalone-input{padding-left:40px}label.sc-tttx-standalone-input .outer-container.sc-tttx-standalone-input input.has-input-icon.has-left-icon.sc-tttx-standalone-input{padding-left:72px}label.sc-tttx-standalone-input .outer-container.sc-tttx-standalone-input input.has-left-icon.sc-tttx-standalone-input{padding-left:40px}label.sc-tttx-standalone-input .outer-container.sc-tttx-standalone-input input.has-right-icon.sc-tttx-standalone-input{padding-right:40px}label.sc-tttx-standalone-input .outer-container.sc-tttx-standalone-input input.invalid.sc-tttx-standalone-input{border:1px solid #dc0000}label.sc-tttx-standalone-input .outer-container.sc-tttx-standalone-input input.sc-tttx-standalone-input:not([type=submit]){font-family:\"Roboto\", serif;width:100%;height:36px;font-size:16px;line-height:19px}label.sc-tttx-standalone-input .outer-container.sc-tttx-standalone-input input[type=radio].sc-tttx-standalone-input{width:20px;height:20px}label.sc-tttx-standalone-input .outer-container.sc-tttx-standalone-input input[type=date].sc-tttx-standalone-input{background:white;display:block;min-width:calc(100% - 18px);line-height:37px}label.sc-tttx-standalone-input .outer-container.sc-tttx-standalone-input input[readonly].sc-tttx-standalone-input{cursor:default;pointer-events:none;user-select:none;color:gray}label.sc-tttx-standalone-input .outer-container.sc-tttx-standalone-input input.sc-tttx-standalone-input:focus{border-color:#1479c6}label.sc-tttx-standalone-input .outer-container.sc-tttx-standalone-input input.sc-tttx-standalone-input:focus-visible{outline:none}label.sc-tttx-standalone-input .outer-container.inputBlock.sc-tttx-standalone-input{display:flex;align-items:center;line-height:21px}label.sc-tttx-standalone-input .outer-container.inputBlock.sc-tttx-standalone-input .left-icons.sc-tttx-standalone-input,label.sc-tttx-standalone-input .outer-container.inputBlock.sc-tttx-standalone-input .right-icons.sc-tttx-standalone-input{margin-top:4px}label.sc-tttx-standalone-input .outer-container.inputBlock.readonly.sc-tttx-standalone-input{pointer-events:none;user-select:none;color:gray}label.sc-tttx-standalone-input .outer-container.inputBlock.radioBlock.sc-tttx-standalone-input{display:block}label.sc-tttx-standalone-input .outer-container.inputInline.sc-tttx-standalone-input{display:flex;white-space:nowrap;align-items:center;margin:0}label.sc-tttx-standalone-input .outer-container.inputInline.sc-tttx-standalone-input input.sc-tttx-standalone-input{margin-top:0}label.sc-tttx-standalone-input .secondarylabel.sc-tttx-standalone-input{color:#757575;font-size:14px;line-height:16px;font-weight:normal;display:flex;margin-top:4px}label.sc-tttx-standalone-input .errorBubble.sc-tttx-standalone-input{position:relative;font-size:14px;line-height:16px;font-weight:normal;width:100%;font-family:\"Roboto\", sans-serif;color:#dc0000;display:flex;align-content:center;align-items:center;justify-items:center;margin-top:4px}label.sc-tttx-standalone-input .errorBubble.sc-tttx-standalone-input:not(.visible){display:none}label.sc-tttx-standalone-input .errorBubble.sc-tttx-standalone-input span.sc-tttx-standalone-input{color:#dc0000;font-size:16px;margin-right:4px}.material-symbols-rounded.sc-tttx-standalone-input{font-family:\"Material Symbols Rounded\", sans-serif;font-weight:400;font-style:normal;font-size:24px;line-height:1;letter-spacing:normal;text-transform:none;display:inline-block;white-space:nowrap;word-wrap:normal;direction:ltr;text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased;color:#9e9e9e}.sc-tttx-standalone-input-h{display:block}";
|
|
8
8
|
|
|
9
9
|
const TttxInput = class {
|
|
10
10
|
constructor(hostRef) {
|
|
@@ -5,7 +5,12 @@ export class TttxIcon {
|
|
|
5
5
|
this.color = 'grey';
|
|
6
6
|
}
|
|
7
7
|
render() {
|
|
8
|
-
|
|
8
|
+
if (this.color.startsWith('#')) {
|
|
9
|
+
return (h(Host, null, h("span", { class: 'material-symbols-rounded', style: { color: this.color } }, this.icon)));
|
|
10
|
+
}
|
|
11
|
+
else {
|
|
12
|
+
return (h(Host, null, h("span", { class: `material-symbols-rounded ${this.color}` }, this.icon)));
|
|
13
|
+
}
|
|
9
14
|
}
|
|
10
15
|
static get is() { return "tttx-icon"; }
|
|
11
16
|
static get encapsulation() { return "shadow"; }
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import icons from './../../../icons';
|
|
2
|
-
const colors = ['red', 'blue', 'black', 'white', 'gray', 'green', 'orange', 'darkred'];
|
|
2
|
+
const colors = ['red', 'blue', 'black', 'white', 'gray', 'green', 'orange', 'darkred', '#397A4C', '#FF00BB'];
|
|
3
3
|
export default {
|
|
4
4
|
title: 'Atoms/Icons',
|
|
5
5
|
component: 'tttx-icon',
|
package/dist/collection/components/atoms/tttx-loading-spinner/tttx-loading-spinner.stories.js
CHANGED
|
@@ -13,5 +13,12 @@ export default {
|
|
|
13
13
|
};
|
|
14
14
|
export const Example = args => {
|
|
15
15
|
const size = args.size || 'large';
|
|
16
|
-
return `<tttx-loading-spinner ${args.loadingMessage ? 'loading-message' : ''} size='${size}' />`;
|
|
16
|
+
return `<tttx-loading-spinner data-chromatic="ignore" ${args.loadingMessage ? 'loading-message' : ''} size='${size}' />`;
|
|
17
|
+
};
|
|
18
|
+
Example.parameters = {
|
|
19
|
+
chromatic: {
|
|
20
|
+
pauseAnimationAtEnd: true,
|
|
21
|
+
delay: 5000,
|
|
22
|
+
disableSnapshot: true
|
|
23
|
+
},
|
|
17
24
|
};
|
|
@@ -23,6 +23,8 @@ function setErrorState(target, hasError, errorMessage, parent = undefined) {
|
|
|
23
23
|
errorBubble = target.parentElement.parentElement.querySelector('.errorBubble');
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
|
+
if (!errorBubble)
|
|
27
|
+
return;
|
|
26
28
|
// If an error was detected, set the input field's class to "invalid" and display the error message in the error bubble
|
|
27
29
|
if (hasError) {
|
|
28
30
|
target.classList.add('invalid');
|
|
@@ -30,6 +30,16 @@ function validityCheck(event) {
|
|
|
30
30
|
// target.setCustomValidity('custom error!');
|
|
31
31
|
// and cleared with
|
|
32
32
|
// target.setCustomValidity('');
|
|
33
|
+
//handle whitespace-only input
|
|
34
|
+
if (target.value.length && !target.value.replace(/\s/g, '').length) {
|
|
35
|
+
errorMessage = 'This field cannot be left blank';
|
|
36
|
+
target.setCustomValidity(errorMessage);
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
errorMessage = '';
|
|
40
|
+
if (target.setCustomValidity) // tests are dumb as a brick
|
|
41
|
+
target.setCustomValidity('');
|
|
42
|
+
}
|
|
33
43
|
// Check the validity of the input field and set an error message if needed
|
|
34
44
|
switch (true) {
|
|
35
45
|
// The field is required, but has no value
|
|
@@ -57,11 +67,6 @@ function validityCheck(event) {
|
|
|
57
67
|
default:
|
|
58
68
|
hasError = false;
|
|
59
69
|
}
|
|
60
|
-
//handle whitespace-only input
|
|
61
|
-
if (!target.value.replace(/\s/g, '').length && target.value.length !== 0) {
|
|
62
|
-
errorMessage = 'Whitespace-only not allowed';
|
|
63
|
-
hasError = true;
|
|
64
|
-
}
|
|
65
70
|
// Return the error state
|
|
66
71
|
return { target, hasError, errorMessage };
|
|
67
72
|
}
|
|
@@ -70,6 +70,10 @@ label .outer-container input:not([type=submit]) {
|
|
|
70
70
|
font-size: 16px;
|
|
71
71
|
line-height: 19px;
|
|
72
72
|
}
|
|
73
|
+
label .outer-container input[type=radio] {
|
|
74
|
+
width: 20px;
|
|
75
|
+
height: 20px;
|
|
76
|
+
}
|
|
73
77
|
label .outer-container input[type=date] {
|
|
74
78
|
background: white;
|
|
75
79
|
display: block;
|
|
@@ -102,6 +106,9 @@ label .outer-container.inputBlock.readonly {
|
|
|
102
106
|
user-select: none;
|
|
103
107
|
color: gray;
|
|
104
108
|
}
|
|
109
|
+
label .outer-container.inputBlock.radioBlock {
|
|
110
|
+
display: block;
|
|
111
|
+
}
|
|
105
112
|
label .outer-container.inputInline {
|
|
106
113
|
display: flex;
|
|
107
114
|
white-space: nowrap;
|
|
@@ -74,6 +74,23 @@ export class TttxForm {
|
|
|
74
74
|
event.preventDefault();
|
|
75
75
|
// create a new FormData object with the form data
|
|
76
76
|
const formData = new FormData(event.target);
|
|
77
|
+
// get a list of checkboxes, if any, so we can manually set unchecked box data
|
|
78
|
+
const checkboxSchemaItems = [];
|
|
79
|
+
const formProperties = this._formSchema.properties;
|
|
80
|
+
for (const formKey of Object.keys(formProperties)) {
|
|
81
|
+
if (formProperties[formKey].form.type === 'checkbox') {
|
|
82
|
+
checkboxSchemaItems.push(formKey);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
const allFormKeys = [];
|
|
86
|
+
for (const key of formData.keys()) {
|
|
87
|
+
allFormKeys.push(key);
|
|
88
|
+
}
|
|
89
|
+
for (const checkItem of checkboxSchemaItems) {
|
|
90
|
+
if (allFormKeys.indexOf(checkItem) === -1) {
|
|
91
|
+
formData.append(checkItem, 'off');
|
|
92
|
+
}
|
|
93
|
+
}
|
|
77
94
|
// emit the form data through the `dataSubmitted` event
|
|
78
95
|
this.dataSubmitted.emit(formData);
|
|
79
96
|
}
|
|
@@ -258,17 +275,21 @@ export class TttxForm {
|
|
|
258
275
|
*/
|
|
259
276
|
createLabel(formProperties, input, errorBubble) {
|
|
260
277
|
const outerContainer = document.createElement('div');
|
|
261
|
-
|
|
278
|
+
let outerContainerClassName = 'outer-container inputBlock';
|
|
262
279
|
// Create a new <label> element with the "inputBlock" class and the specified text
|
|
263
280
|
const label = document.createElement('label');
|
|
264
281
|
label.innerText = formProperties.label;
|
|
265
282
|
// If the form property has no validation object, add an "optional" span element to the label
|
|
266
|
-
if (!formProperties.validation) {
|
|
283
|
+
if (!formProperties.validation && formProperties.label) {
|
|
267
284
|
const optionalSpan = document.createElement('span');
|
|
268
285
|
optionalSpan.className = 'optional';
|
|
269
286
|
optionalSpan.innerHTML = ' (optional)';
|
|
270
287
|
label.appendChild(optionalSpan);
|
|
271
288
|
}
|
|
289
|
+
if (formProperties.type === 'radio') {
|
|
290
|
+
outerContainerClassName += ' radioBlock';
|
|
291
|
+
}
|
|
292
|
+
outerContainer.className = outerContainerClassName;
|
|
272
293
|
if (formProperties.readonly) {
|
|
273
294
|
label.classList.add('readonly');
|
|
274
295
|
}
|
|
@@ -286,6 +307,38 @@ export class TttxForm {
|
|
|
286
307
|
// Return the label element
|
|
287
308
|
return label;
|
|
288
309
|
}
|
|
310
|
+
/**
|
|
311
|
+
* Creates a new radio input with a set of options.
|
|
312
|
+
*
|
|
313
|
+
* @param {string} formKey - The name of the dropdown field, as specified in the form schema.
|
|
314
|
+
* @param {Object} formProperties - An object containing additional properties, such as the field type and options properties.
|
|
315
|
+
* @param {'radio'} formProperties.type - The type of form field. In this case, it will always be "radio".
|
|
316
|
+
* @param {Object} formProperties.validation - A set of validation rules for the field.
|
|
317
|
+
* @param {Object[]} formProperties.options - A list of properties to pass to the select options.
|
|
318
|
+
* @param {string} formProperties.options.label - The visible value of the option.
|
|
319
|
+
* @param {string} formProperties.options.value - The actual value of the option.
|
|
320
|
+
*/
|
|
321
|
+
createRadio(formKey, formProperties) {
|
|
322
|
+
var _a, _b;
|
|
323
|
+
const fragment = new DocumentFragment();
|
|
324
|
+
for (const optionProperties of formProperties.options) {
|
|
325
|
+
// Create a new <input> element with the specified name and type
|
|
326
|
+
const input = document.createElement('input');
|
|
327
|
+
input.type = 'radio';
|
|
328
|
+
input.name = formKey;
|
|
329
|
+
input.value = optionProperties.value;
|
|
330
|
+
if ((_a = formProperties === null || formProperties === void 0 ? void 0 : formProperties.validation) === null || _a === void 0 ? void 0 : _a.required) {
|
|
331
|
+
input.setAttribute('required', 'required');
|
|
332
|
+
input.setAttribute('data-required', (_b = formProperties.validation.required.message) !== null && _b !== void 0 ? _b : '');
|
|
333
|
+
}
|
|
334
|
+
const span = document.createElement('span');
|
|
335
|
+
span.innerText = optionProperties.label;
|
|
336
|
+
fragment.appendChild(input);
|
|
337
|
+
fragment.appendChild(span);
|
|
338
|
+
fragment.appendChild(document.createElement('br'));
|
|
339
|
+
}
|
|
340
|
+
return fragment;
|
|
341
|
+
}
|
|
289
342
|
/**
|
|
290
343
|
* Populates the form template with input fields and labels based on the properties of the
|
|
291
344
|
* current form schema. For each property in the schema, it creates an input element, applies
|
|
@@ -305,9 +358,19 @@ export class TttxForm {
|
|
|
305
358
|
propertyKeys.forEach(formKey => {
|
|
306
359
|
const formItem = properties[formKey];
|
|
307
360
|
const formProperties = formItem.form;
|
|
308
|
-
|
|
361
|
+
let input;
|
|
362
|
+
switch (formProperties.type) {
|
|
363
|
+
case 'select':
|
|
364
|
+
input = this.createSelect(formKey, formProperties);
|
|
365
|
+
break;
|
|
366
|
+
case 'radio':
|
|
367
|
+
input = this.createRadio(formKey, formProperties);
|
|
368
|
+
break;
|
|
369
|
+
default:
|
|
370
|
+
input = this.createInput(formKey, formProperties);
|
|
371
|
+
}
|
|
309
372
|
// If the form property has validation, apply it to the input
|
|
310
|
-
if (formProperties.validation) {
|
|
373
|
+
if (formProperties.validation && formProperties.type !== 'radio') {
|
|
311
374
|
this.applyValidation(input, formProperties.validation);
|
|
312
375
|
}
|
|
313
376
|
// Create an error bubble and label element for the input
|
|
@@ -338,25 +401,40 @@ export class TttxForm {
|
|
|
338
401
|
const propertyKeys = Object.keys(properties);
|
|
339
402
|
propertyKeys.forEach(formKey => {
|
|
340
403
|
var _a, _b;
|
|
341
|
-
const
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
404
|
+
const formInputs = formItems.querySelectorAll(`[name=${formKey}]`);
|
|
405
|
+
for (const formInput of formInputs) {
|
|
406
|
+
// Bind events to form input elements
|
|
407
|
+
formInput.oninvalid = this.validityCheckWrapper.bind(this);
|
|
408
|
+
formInput.onblur = this.validityCheckWrapper.bind(this);
|
|
409
|
+
formInput.onkeyup = this.fieldChanged.bind(this);
|
|
410
|
+
formInput.onchange = this.fieldChanged.bind(this);
|
|
411
|
+
if ((_a = this._data) === null || _a === void 0 ? void 0 : _a[formKey]) {
|
|
412
|
+
switch (formInput.type) {
|
|
413
|
+
case 'checkbox':
|
|
414
|
+
if (this._data[formKey] === 'on') {
|
|
415
|
+
formInput.checked = true;
|
|
416
|
+
}
|
|
417
|
+
break;
|
|
418
|
+
case 'radio':
|
|
419
|
+
if (formInput.value === this._data[formKey]) {
|
|
420
|
+
formInput.checked = true;
|
|
421
|
+
}
|
|
422
|
+
break;
|
|
423
|
+
default:
|
|
424
|
+
formInput.value = this._data[formKey];
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
// If explicitly setting input as invalid, set invalid state and error message on render
|
|
428
|
+
if ((_b = properties[formKey].form.validation) === null || _b === void 0 ? void 0 : _b.invalid) {
|
|
429
|
+
const errorMessage = properties[formKey].form.validation.invalid.message;
|
|
430
|
+
formInput.setCustomValidity(errorMessage); // Prevents the invalid styling from resetting on blur
|
|
431
|
+
setErrorState(formInput, true, errorMessage);
|
|
432
|
+
}
|
|
433
|
+
if (properties[formKey].form.type === 'select' && formInput.classList.contains('placeholder')) {
|
|
434
|
+
formInput.addEventListener('change', () => {
|
|
435
|
+
formInput.classList.remove('placeholder');
|
|
436
|
+
});
|
|
437
|
+
}
|
|
360
438
|
}
|
|
361
439
|
});
|
|
362
440
|
// Append the cloned form elements to the fieldset
|