@3t-transform/threeteeui 0.1.21 → 0.1.22
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/{index-b8a62ede.js → index-dc6cc829.js} +2 -88
- package/dist/cjs/loader.cjs.js +3 -4
- package/dist/cjs/tttx-button.cjs.entry.js +24 -24
- package/dist/cjs/tttx-filter.cjs.entry.js +152 -152
- package/dist/cjs/tttx-form.cjs.entry.js +363 -363
- package/dist/cjs/tttx-icon.cjs.entry.js +11 -11
- package/dist/cjs/tttx-keyvalue-block.cjs.entry.js +59 -59
- package/dist/cjs/tttx-list.cjs.entry.js +43 -43
- package/dist/cjs/tttx-loading-spinner.cjs.entry.js +16 -16
- package/dist/cjs/tttx-sorter.cjs.entry.js +112 -0
- package/dist/cjs/tttx-standalone-input.cjs.entry.js +60 -60
- package/dist/cjs/tttx-toolbar.cjs.entry.js +10 -10
- package/dist/cjs/tttx.cjs.js +3 -7
- package/dist/collection/collection-manifest.json +3 -2
- package/dist/collection/components/atoms/tttx-button/tttx-button.js +110 -110
- package/dist/collection/components/atoms/tttx-button/tttx-button.stories.js +14 -14
- package/dist/collection/components/atoms/tttx-icon/tttx-icon.js +62 -62
- package/dist/collection/components/atoms/tttx-icon/tttx-icon.stories.js +22 -22
- package/dist/collection/components/atoms/tttx-keyvalue-block/tttx-keyvalue-block.js +109 -109
- package/dist/collection/components/atoms/tttx-keyvalue-block/tttx-keyvalue-block.stories.js +38 -38
- package/dist/collection/components/atoms/tttx-loading-spinner/tttx-loading-spinner.js +67 -67
- package/dist/collection/components/atoms/tttx-loading-spinner/tttx-loading-spinner.stories.js +17 -17
- package/dist/collection/components/molecules/tttx-filter/tttx-filter.js +325 -325
- package/dist/collection/components/molecules/tttx-filter/tttx-filter.stories.js +89 -89
- package/dist/collection/components/molecules/tttx-form/lib/setErrorState.js +35 -35
- package/dist/collection/components/molecules/tttx-form/lib/validityCheck.js +58 -58
- package/dist/collection/components/molecules/tttx-form/tttx-form.js +364 -364
- package/dist/collection/components/molecules/tttx-form/tttx-form.stories.js +127 -127
- package/dist/collection/components/molecules/tttx-list/tttx-list.js +105 -105
- package/dist/collection/components/molecules/tttx-list/tttx-list.stories.js +43 -43
- package/dist/collection/components/molecules/tttx-sorter/tttx-sorter.css +116 -0
- package/dist/collection/components/molecules/tttx-sorter/tttx-sorter.js +224 -0
- package/dist/collection/components/molecules/tttx-sorter/tttx-sorter.stories.js +47 -0
- package/dist/collection/components/molecules/tttx-standalone-input/tttx-standalone-input.js +627 -627
- package/dist/collection/components/molecules/tttx-standalone-input/tttx-standalone-input.stories.js +157 -157
- package/dist/collection/components/molecules/tttx-toolbar/tttx-toolbar.js +44 -44
- package/dist/collection/components/molecules/tttx-toolbar/tttx-toolbar.stories.js +14 -14
- package/dist/collection/components/palette.stories.js +7 -7
- package/dist/collection/docs/gettingstarted-developer.stories.js +5 -5
- package/dist/collection/icons.js +2838 -2838
- package/dist/collection/index.js +1 -1
- package/dist/collection/shared/domsanitiser.options.js +14 -14
- package/dist/components/index.d.ts +1 -9
- package/dist/components/index.js +2 -1
- package/dist/components/tttx-button.js +48 -48
- package/dist/components/tttx-filter.js +184 -184
- package/dist/components/tttx-form.js +380 -380
- package/dist/components/tttx-icon2.js +28 -28
- package/dist/components/tttx-keyvalue-block.js +76 -76
- package/dist/components/tttx-list.js +65 -65
- package/dist/components/tttx-loading-spinner.js +33 -33
- package/dist/components/tttx-sorter.d.ts +11 -0
- package/dist/components/tttx-sorter.js +141 -0
- package/dist/components/tttx-standalone-input.js +107 -107
- package/dist/components/tttx-toolbar.js +26 -26
- package/dist/esm/{index-e888a5f4.js → index-86faeaab.js} +3 -88
- package/dist/esm/loader.js +3 -4
- package/dist/esm/polyfills/core-js.js +0 -0
- package/dist/esm/polyfills/css-shim.js +1 -1
- package/dist/esm/polyfills/dom.js +0 -0
- package/dist/esm/polyfills/es5-html-element.js +0 -0
- package/dist/esm/polyfills/index.js +0 -0
- package/dist/esm/polyfills/system.js +0 -0
- package/dist/esm/tttx-button.entry.js +24 -24
- package/dist/esm/tttx-filter.entry.js +152 -152
- package/dist/esm/tttx-form.entry.js +363 -363
- package/dist/esm/tttx-icon.entry.js +11 -11
- package/dist/esm/tttx-keyvalue-block.entry.js +59 -59
- package/dist/esm/tttx-list.entry.js +43 -43
- package/dist/esm/tttx-loading-spinner.entry.js +16 -16
- package/dist/esm/tttx-sorter.entry.js +108 -0
- package/dist/esm/tttx-standalone-input.entry.js +60 -60
- package/dist/esm/tttx-toolbar.entry.js +10 -10
- package/dist/esm/tttx.js +3 -4
- package/dist/tttx/p-12fc0b16.entry.js +3 -0
- package/dist/tttx/p-52a47b7c.js +2 -0
- package/dist/tttx/p-5d9b6bc0.entry.js +1 -0
- package/dist/tttx/{p-41f5b296.entry.js → p-603f6ebe.entry.js} +1 -1
- package/dist/tttx/{p-e145951b.entry.js → p-72b4c98a.entry.js} +1 -1
- package/dist/tttx/{p-043f9b8a.entry.js → p-8f3badad.entry.js} +1 -1
- package/dist/tttx/{p-4cf3e1e0.entry.js → p-ae48fe5a.entry.js} +1 -1
- package/dist/tttx/{p-01f4628e.entry.js → p-bdb054b2.entry.js} +1 -1
- package/dist/tttx/{p-dc5c356b.entry.js → p-c72d1a03.entry.js} +1 -1
- package/dist/tttx/{p-96bbf1ed.entry.js → p-e25d5fe2.entry.js} +1 -1
- package/dist/tttx/{p-b3a03986.entry.js → p-f1d7eb35.entry.js} +1 -1
- package/dist/tttx/tttx.esm.js +1 -1
- package/dist/types/components/atoms/tttx-button/tttx-button.d.ts +10 -10
- package/dist/types/components/atoms/tttx-button/tttx-button.stories.d.ts +10 -10
- package/dist/types/components/atoms/tttx-icon/tttx-icon.d.ts +5 -5
- package/dist/types/components/atoms/tttx-icon/tttx-icon.stories.d.ts +20 -20
- package/dist/types/components/atoms/tttx-keyvalue-block/tttx-keyvalue-block.d.ts +7 -7
- package/dist/types/components/atoms/tttx-keyvalue-block/tttx-keyvalue-block.stories.d.ts +9 -9
- package/dist/types/components/atoms/tttx-loading-spinner/tttx-loading-spinner.d.ts +6 -6
- package/dist/types/components/atoms/tttx-loading-spinner/tttx-loading-spinner.stories.d.ts +17 -17
- package/dist/types/components/molecules/tttx-filter/tttx-filter.d.ts +37 -37
- package/dist/types/components/molecules/tttx-filter/tttx-filter.stories.d.ts +43 -43
- package/dist/types/components/molecules/tttx-form/lib/setErrorState.d.ts +13 -13
- package/dist/types/components/molecules/tttx-form/lib/validityCheck.d.ts +17 -17
- package/dist/types/components/molecules/tttx-form/tttx-form.d.ts +114 -114
- package/dist/types/components/molecules/tttx-form/tttx-form.stories.d.ts +13 -13
- package/dist/types/components/molecules/tttx-list/tttx-list.d.ts +11 -11
- package/dist/types/components/molecules/tttx-list/tttx-list.stories.d.ts +14 -14
- package/dist/types/components/molecules/tttx-sorter/interfaces.d.ts +9 -0
- package/dist/types/components/molecules/tttx-sorter/tttx-sorter.d.ts +19 -0
- package/dist/types/components/molecules/tttx-sorter/tttx-sorter.stories.d.ts +30 -0
- package/dist/types/components/molecules/tttx-standalone-input/tttx-standalone-input.d.ts +56 -56
- package/dist/types/components/molecules/tttx-standalone-input/tttx-standalone-input.stories.d.ts +123 -123
- package/dist/types/components/molecules/tttx-toolbar/tttx-toolbar.d.ts +4 -4
- package/dist/types/components/molecules/tttx-toolbar/tttx-toolbar.stories.d.ts +13 -13
- package/dist/types/components/palette.stories.d.ts +6 -6
- package/dist/types/components.d.ts +27 -0
- package/dist/types/docs/gettingstarted-developer.stories.d.ts +5 -5
- package/dist/types/icons.d.ts +2 -2
- package/dist/types/index.d.ts +1 -1
- package/dist/types/shared/domsanitiser.options.d.ts +10 -10
- package/dist/types/stencil-public-runtime.d.ts +3 -59
- package/loader/index.d.ts +0 -9
- package/package.json +1 -1
- package/dist/tttx/p-6dff6b5a.entry.js +0 -3
- package/dist/tttx/p-f764ffc4.js +0 -2
|
@@ -1,373 +1,373 @@
|
|
|
1
|
-
import { r as registerInstance, c as createEvent, h, H as Host } from './index-
|
|
1
|
+
import { r as registerInstance, c as createEvent, h, H as Host } from './index-86faeaab.js';
|
|
2
2
|
|
|
3
|
-
/**
|
|
4
|
-
* Validates the input field on focusout event by checking its validity state,
|
|
5
|
-
* sets an error message if there's an issue, and emits a "dataChanged" event to
|
|
6
|
-
* the parent component with the field name and its new value.
|
|
7
|
-
*
|
|
8
|
-
* @param {Event} event - The focusout event triggered by the input field.
|
|
9
|
-
* @return {void}
|
|
10
|
-
*/
|
|
11
|
-
function validityCheck(event) {
|
|
12
|
-
var _a, _b, _c, _d;
|
|
13
|
-
event.preventDefault();
|
|
14
|
-
const target = event.target;
|
|
15
|
-
let hasError = true;
|
|
16
|
-
let errorMessage = '';
|
|
17
|
-
// validity object on HTML5 inputs has the following options
|
|
18
|
-
// badInput
|
|
19
|
-
// customError
|
|
20
|
-
// patternMismatch
|
|
21
|
-
// rangeOverflow
|
|
22
|
-
// rangeUnderflow
|
|
23
|
-
// stepMismatch
|
|
24
|
-
// tooLong
|
|
25
|
-
// tooShort
|
|
26
|
-
// typeMismatch
|
|
27
|
-
// valid
|
|
28
|
-
// valueMissing
|
|
29
|
-
// customErrors can be set with
|
|
30
|
-
// target.setCustomValidity('custom error!');
|
|
31
|
-
// and cleared with
|
|
32
|
-
// target.setCustomValidity('');
|
|
33
|
-
// Check the validity of the input field and set an error message if needed
|
|
34
|
-
switch (true) {
|
|
35
|
-
// The field is required, but has no value
|
|
36
|
-
case target.validity.valueMissing:
|
|
37
|
-
errorMessage = (_a = target.dataset.required) !== null && _a !== void 0 ? _a : 'This field is required';
|
|
38
|
-
break;
|
|
39
|
-
// The field's value does not match the expected pattern
|
|
40
|
-
case target.validity.patternMismatch:
|
|
41
|
-
errorMessage = (_b = target.dataset.pattern) !== null && _b !== void 0 ? _b : 'Incorrect format';
|
|
42
|
-
break;
|
|
43
|
-
// The field's value is not of the correct input type
|
|
44
|
-
case target.validity.badInput:
|
|
45
|
-
// IE string in a number field
|
|
46
|
-
errorMessage = (_c = target.dataset.badinput) !== null && _c !== void 0 ? _c : 'Wrong input type';
|
|
47
|
-
break;
|
|
48
|
-
// The field's value is above or below the range set in the "min" and "max" attributes
|
|
49
|
-
case target.validity.rangeOverflow || target.validity.rangeUnderflow:
|
|
50
|
-
// IE date or number is above or below value set in min or max tags
|
|
51
|
-
errorMessage = (_d = target.dataset.range) !== null && _d !== void 0 ? _d : 'Invalid value';
|
|
52
|
-
break;
|
|
53
|
-
// No error detected
|
|
54
|
-
default:
|
|
55
|
-
hasError = false;
|
|
56
|
-
}
|
|
57
|
-
// Return the error state
|
|
58
|
-
return { target, hasError, errorMessage };
|
|
3
|
+
/**
|
|
4
|
+
* Validates the input field on focusout event by checking its validity state,
|
|
5
|
+
* sets an error message if there's an issue, and emits a "dataChanged" event to
|
|
6
|
+
* the parent component with the field name and its new value.
|
|
7
|
+
*
|
|
8
|
+
* @param {Event} event - The focusout event triggered by the input field.
|
|
9
|
+
* @return {void}
|
|
10
|
+
*/
|
|
11
|
+
function validityCheck(event) {
|
|
12
|
+
var _a, _b, _c, _d;
|
|
13
|
+
event.preventDefault();
|
|
14
|
+
const target = event.target;
|
|
15
|
+
let hasError = true;
|
|
16
|
+
let errorMessage = '';
|
|
17
|
+
// validity object on HTML5 inputs has the following options
|
|
18
|
+
// badInput
|
|
19
|
+
// customError
|
|
20
|
+
// patternMismatch
|
|
21
|
+
// rangeOverflow
|
|
22
|
+
// rangeUnderflow
|
|
23
|
+
// stepMismatch
|
|
24
|
+
// tooLong
|
|
25
|
+
// tooShort
|
|
26
|
+
// typeMismatch
|
|
27
|
+
// valid
|
|
28
|
+
// valueMissing
|
|
29
|
+
// customErrors can be set with
|
|
30
|
+
// target.setCustomValidity('custom error!');
|
|
31
|
+
// and cleared with
|
|
32
|
+
// target.setCustomValidity('');
|
|
33
|
+
// Check the validity of the input field and set an error message if needed
|
|
34
|
+
switch (true) {
|
|
35
|
+
// The field is required, but has no value
|
|
36
|
+
case target.validity.valueMissing:
|
|
37
|
+
errorMessage = (_a = target.dataset.required) !== null && _a !== void 0 ? _a : 'This field is required';
|
|
38
|
+
break;
|
|
39
|
+
// The field's value does not match the expected pattern
|
|
40
|
+
case target.validity.patternMismatch:
|
|
41
|
+
errorMessage = (_b = target.dataset.pattern) !== null && _b !== void 0 ? _b : 'Incorrect format';
|
|
42
|
+
break;
|
|
43
|
+
// The field's value is not of the correct input type
|
|
44
|
+
case target.validity.badInput:
|
|
45
|
+
// IE string in a number field
|
|
46
|
+
errorMessage = (_c = target.dataset.badinput) !== null && _c !== void 0 ? _c : 'Wrong input type';
|
|
47
|
+
break;
|
|
48
|
+
// The field's value is above or below the range set in the "min" and "max" attributes
|
|
49
|
+
case target.validity.rangeOverflow || target.validity.rangeUnderflow:
|
|
50
|
+
// IE date or number is above or below value set in min or max tags
|
|
51
|
+
errorMessage = (_d = target.dataset.range) !== null && _d !== void 0 ? _d : 'Invalid value';
|
|
52
|
+
break;
|
|
53
|
+
// No error detected
|
|
54
|
+
default:
|
|
55
|
+
hasError = false;
|
|
56
|
+
}
|
|
57
|
+
// Return the error state
|
|
58
|
+
return { target, hasError, errorMessage };
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
/**
|
|
62
|
-
* Sets the error state of an input field by updating its class and error message.
|
|
63
|
-
* If an error was detected, it sets the input field's class to "invalid" and
|
|
64
|
-
* displays the error message in an error bubble. If no error was detected,
|
|
65
|
-
* it removes the "invalid" class from the input field and clears the error bubble.
|
|
66
|
-
*
|
|
67
|
-
* @param {HTMLInputElement} target - The input field to update.
|
|
68
|
-
* @param {boolean} hasError - Whether an error was detected in the field.
|
|
69
|
-
* @param {string} errorMessage - The error message to display (if any).
|
|
70
|
-
* @return {void}
|
|
71
|
-
*/
|
|
72
|
-
function setErrorState(target, hasError, errorMessage) {
|
|
73
|
-
// Find the error bubble element for the input field
|
|
74
|
-
const errorBubble = target.parentElement.querySelector('.errorBubble');
|
|
75
|
-
// If an error was detected, set the input field's class to "invalid" and display the error message in the error bubble
|
|
76
|
-
if (hasError) {
|
|
77
|
-
target.className = 'invalid';
|
|
78
|
-
const errorIcon = document.createElement('span');
|
|
79
|
-
// Set the class of the error icon to a pre-defined CSS class that specifies the icon's appearance
|
|
80
|
-
errorIcon.className = 'material-symbols-rounded';
|
|
81
|
-
// Set the text content of the error icon to the word "warning"
|
|
82
|
-
errorIcon.textContent = 'warning';
|
|
83
|
-
// errorBubble.replaceChildren cannot be used here because the tests don't support this new feature :(
|
|
84
|
-
errorBubble.innerHTML = '';
|
|
85
|
-
errorBubble.append(errorIcon);
|
|
86
|
-
errorBubble.append(errorMessage);
|
|
87
|
-
// errorBubble.replaceChildren(errorIcon, errorMessage);
|
|
88
|
-
}
|
|
89
|
-
// If no error was detected, remove the "invalid" class from the input field and clear the error bubble
|
|
90
|
-
else {
|
|
91
|
-
target.className = '';
|
|
92
|
-
errorBubble.innerHTML = '';
|
|
93
|
-
}
|
|
61
|
+
/**
|
|
62
|
+
* Sets the error state of an input field by updating its class and error message.
|
|
63
|
+
* If an error was detected, it sets the input field's class to "invalid" and
|
|
64
|
+
* displays the error message in an error bubble. If no error was detected,
|
|
65
|
+
* it removes the "invalid" class from the input field and clears the error bubble.
|
|
66
|
+
*
|
|
67
|
+
* @param {HTMLInputElement} target - The input field to update.
|
|
68
|
+
* @param {boolean} hasError - Whether an error was detected in the field.
|
|
69
|
+
* @param {string} errorMessage - The error message to display (if any).
|
|
70
|
+
* @return {void}
|
|
71
|
+
*/
|
|
72
|
+
function setErrorState(target, hasError, errorMessage) {
|
|
73
|
+
// Find the error bubble element for the input field
|
|
74
|
+
const errorBubble = target.parentElement.querySelector('.errorBubble');
|
|
75
|
+
// If an error was detected, set the input field's class to "invalid" and display the error message in the error bubble
|
|
76
|
+
if (hasError) {
|
|
77
|
+
target.className = 'invalid';
|
|
78
|
+
const errorIcon = document.createElement('span');
|
|
79
|
+
// Set the class of the error icon to a pre-defined CSS class that specifies the icon's appearance
|
|
80
|
+
errorIcon.className = 'material-symbols-rounded';
|
|
81
|
+
// Set the text content of the error icon to the word "warning"
|
|
82
|
+
errorIcon.textContent = 'warning';
|
|
83
|
+
// errorBubble.replaceChildren cannot be used here because the tests don't support this new feature :(
|
|
84
|
+
errorBubble.innerHTML = '';
|
|
85
|
+
errorBubble.append(errorIcon);
|
|
86
|
+
errorBubble.append(errorMessage);
|
|
87
|
+
// errorBubble.replaceChildren(errorIcon, errorMessage);
|
|
88
|
+
}
|
|
89
|
+
// If no error was detected, remove the "invalid" class from the input field and clear the error bubble
|
|
90
|
+
else {
|
|
91
|
+
target.className = '';
|
|
92
|
+
errorBubble.innerHTML = '';
|
|
93
|
+
}
|
|
94
94
|
}
|
|
95
95
|
|
|
96
96
|
const tttxFormCss = ".material-symbols-rounded{font-variation-settings:\"FILL\" 1, \"wght\" 400, \"GRAD\" 0, \"opsz\" 24}.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}.icon-left,.icon-right{flex-basis:24px}.icon-left span,.icon-right span{font-size:24px;line-height:24px;text-align:center;display:block;width:24px;height:24px;margin-top:4px}.icon-left span{margin-left:4px}.icon-right span{margin-right:4px}.icon-right{margin-top:5px}.icon-left{margin-top:5px;margin-left:4px}.iconleft .input{padding-left:4px}.iconright .input{padding-right:4px}.input-icon{position:absolute;margin-top:9px;margin-left:4px}.errormsg{display:flex;justify-content:center;align-items:center;float:left;margin-bottom:16px;box-sizing:border-box;background-color:transparent;height:26px;font-size:14px;border-radius:none;z-index:2;color:#dc0000}.errormsg .validationicon{width:16px;height:16px;font-size:16px;margin-right:4px;vertical-align:middle;color:#dc0000}.danger{color:#dc0000}.optional{color:#757575;font-weight:normal}label.inputBlock{display:block;position:relative;line-height:21px}label.inputInline{display:flex;white-space:nowrap;align-items:center}label.inputInline .input-container{margin:0 4px;width:100%;display:flex;align-items:center;gap:4px;position:relative}label{font-weight:500;font-size:16px}input:not([type=submit]){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}input[type=date]{background:white;display:block;min-width:calc(100% - 18px);line-height:37px}@media (max-width: 600px){input[type=date]{padding-top:6px}}input.invalid:invalid,input.standalone.invalid{border:1px solid #dc0000}.input-icon~input{padding:0 32px}input~.errorBubble{min-height:27px;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}input~.errorBubble:not(.visible){visibility:hidden}input~.errorBubble span{color:#dc0000;font-size:16px;margin-right:4px;height:16px}input.invalid:invalid~.errorBubble{position:relative;font-size:14px;font-weight:normal;width:100%;font-family:\"Roboto\", sans-serif;color:#dc0000;visibility:visible}input:focus{border-color:#1479c6}input:focus-visible{outline:none}.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:400}.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:hover{background:rgba(17, 17, 17, 0.1);border:1px solid #D5D5D5}.button:active{background:rgba(17, 17, 17, 0.2);border:1px solid #D5D5D5}.primary{background:#1479c6;border:1px solid #1479c6;color:white}.primary:hover{background:#146EB3;border:1px solid #146EB3}.primary:active{background:#1464A2;border:1px solid #1464A2}.borderless{background:transparent;border:none;color:#212121}.borderless:hover{background:rgba(17, 17, 17, 0.1);border:none}.borderless:active{background:rgba(17, 17, 17, 0.2);border:none}.danger{background:#DC0000;border:1px solid #DC0000;color:white}.danger:hover{background:#C60000;border:1px solid #C60000}.danger:active{background:#B00000;border:1px solid #B00000}.disabled{background:#aeaeae;border:none;color:#4c4c4c;cursor:not-allowed}.disabled:hover{background:#aeaeae;border:none;color:#4c4c4c;cursor:not-allowed}.disabled:active{background:#aeaeae;border:none;color:#4c4c4c;cursor:not-allowed}:host{display:block}fieldset{margin:0;padding:0;border:none}input[type=submit]{margin-left:auto}";
|
|
97
97
|
|
|
98
|
-
const TttxForm = class {
|
|
99
|
-
constructor(hostRef) {
|
|
100
|
-
registerInstance(this, hostRef);
|
|
101
|
-
this.dataSubmitted = createEvent(this, "dataSubmitted", 7);
|
|
102
|
-
this.dataChanged = createEvent(this, "dataChanged", 7);
|
|
103
|
-
// Create a new template element using the HTMLTemplateElement interface.
|
|
104
|
-
this.template = document.createElement('template');
|
|
105
|
-
this.formschema = undefined;
|
|
106
|
-
this.submitValue = undefined;
|
|
107
|
-
}
|
|
108
|
-
// This method is called whenever the "formschema" property changes
|
|
109
|
-
onFormSchemaChange(newValue) {
|
|
110
|
-
// Check if the new value is a string, indicating that it needs to be parsed
|
|
111
|
-
if (typeof newValue === 'string') {
|
|
112
|
-
// Parse the string and set the "_formSchema" property
|
|
113
|
-
this._formSchema = JSON.parse(newValue);
|
|
114
|
-
}
|
|
115
|
-
else {
|
|
116
|
-
// If the new value is already an object, set the "_formSchema" property directly
|
|
117
|
-
this._formSchema = newValue;
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
/**
|
|
121
|
-
* Handles the focus event for a form field and emits a "dataChanged" event
|
|
122
|
-
* to the parent component with the field name and its new value.
|
|
123
|
-
*
|
|
124
|
-
* @param {ChangeEvent} event - The focus event triggered by the field.
|
|
125
|
-
* @return {void}
|
|
126
|
-
*/
|
|
127
|
-
fieldChanged(event) {
|
|
128
|
-
// Extract the name and value of the field from the event
|
|
129
|
-
const fieldName = event.target.name;
|
|
130
|
-
const fieldValue = event.target.value;
|
|
131
|
-
// Emit an event to signal that the field's data has changed
|
|
132
|
-
this.dataChanged.emit({ name: fieldName, value: fieldValue });
|
|
133
|
-
}
|
|
134
|
-
/**
|
|
135
|
-
* Submits the form data to the server.
|
|
136
|
-
*
|
|
137
|
-
* @param {SubmitEvent} event - The event object for the form submission.
|
|
138
|
-
* @returns {void}
|
|
139
|
-
*
|
|
140
|
-
* @example
|
|
141
|
-
* const form = document.getElementById('myForm');
|
|
142
|
-
* form.addEventListener('submit', (event) => {
|
|
143
|
-
* doSubmit(event);
|
|
144
|
-
* });
|
|
145
|
-
*/
|
|
146
|
-
doSubmit(event) {
|
|
147
|
-
// prevent the form from submitting normally
|
|
148
|
-
event.preventDefault();
|
|
149
|
-
// create a new FormData object with the form data
|
|
150
|
-
const formData = new FormData(event.target);
|
|
151
|
-
// emit the form data through the `dataSubmitted` event
|
|
152
|
-
this.dataSubmitted.emit(formData);
|
|
153
|
-
}
|
|
154
|
-
// This method is called before the component is loaded into the DOM
|
|
155
|
-
componentWillLoad() {
|
|
156
|
-
// Initialize the form schema by calling the "onFormSchemaChange" method with the current "formschema" property
|
|
157
|
-
this.onFormSchemaChange(this.formschema);
|
|
158
|
-
}
|
|
159
|
-
// This method is called before the component is rendered
|
|
160
|
-
componentWillRender() {
|
|
161
|
-
// Clear the template to account for a potential re-render scenario
|
|
162
|
-
this.template = document.createElement('template');
|
|
163
|
-
// Populate the form from the form schema
|
|
164
|
-
this.populateFormFromSchema();
|
|
165
|
-
}
|
|
166
|
-
/**
|
|
167
|
-
* Creates a new HTMLInputElement with the specified name, type, and placeholder (if any),
|
|
168
|
-
* and sets its autocomplete and autocapitalization properties to off.
|
|
169
|
-
*
|
|
170
|
-
* @param {string} formKey - The name of the input field, as specified in the form schema.
|
|
171
|
-
* @param {Object} formProperties - An object containing additional properties for the input field, such as its type and placeholder value.
|
|
172
|
-
* @param {string} formProperties.type - The type of the input field (e.g., "text", "email", "number", etc.).
|
|
173
|
-
* @param {string} [formProperties.placeholder] - An optional placeholder value to display in the input field.
|
|
174
|
-
* @return {HTMLInputElement} - The new input element.
|
|
175
|
-
*/
|
|
176
|
-
createInput(formKey, formProperties) {
|
|
177
|
-
var _a;
|
|
178
|
-
// Create a new <input> element with the specified name and type
|
|
179
|
-
const input = document.createElement('input');
|
|
180
|
-
input.name = formKey;
|
|
181
|
-
input.type = formProperties.type;
|
|
182
|
-
// Set the placeholder attribute to the specified value (if any)
|
|
183
|
-
input.placeholder = (_a = formProperties.placeholder) !== null && _a !== void 0 ? _a : '';
|
|
184
|
-
// Disable autocomplete and autocapitalization
|
|
185
|
-
input.autocomplete = 'off';
|
|
186
|
-
input.autocapitalize = 'off';
|
|
187
|
-
// Return the input element
|
|
188
|
-
return input;
|
|
189
|
-
}
|
|
190
|
-
/**
|
|
191
|
-
* Applies validation attributes to an input element based on the specified validation object.
|
|
192
|
-
* If a certain property is present in the object, it will set the corresponding attribute on
|
|
193
|
-
* the input element (e.g., "required" will set the "required" and "data-required" attributes,
|
|
194
|
-
* "pattern" will set the "pattern" and "data-pattern" attributes, etc.).
|
|
195
|
-
*
|
|
196
|
-
* @param {HTMLInputElement} input - The input element to apply validation attributes to.
|
|
197
|
-
* @param {Object} validation - An object containing the validation rules for the input field.
|
|
198
|
-
* @param {Object} [validation.required] - An object containing a "message" property to display if the field is required.
|
|
199
|
-
* @param {Object} [validation.pattern] - An object containing a "pattern" property to match against the field value, and a "message" property to display if the pattern doesn't match.
|
|
200
|
-
* @param {Object} [validation.badInput] - An object containing a "message" property to display if the field value is invalid.
|
|
201
|
-
* @param {Object} [validation.minmax] - An object containing "min" and "max" properties to validate the field value against, and a "message" property to display if the value is out of range.
|
|
202
|
-
* @param {string} [validation.maxlength] - The maximum length of the input field.
|
|
203
|
-
* @return {void}
|
|
204
|
-
*/
|
|
205
|
-
applyValidation(input, validation) {
|
|
206
|
-
var _a, _b;
|
|
207
|
-
// If the "required" property is present, add the "required" attribute to the input element and
|
|
208
|
-
// set its "data-required" attribute to the specified message (if any)
|
|
209
|
-
if (validation.required) {
|
|
210
|
-
input.setAttribute('required', '');
|
|
211
|
-
input.setAttribute('data-required', (_a = validation.required.message) !== null && _a !== void 0 ? _a : '');
|
|
212
|
-
}
|
|
213
|
-
// If the "pattern" property is present, add the "pattern" attribute to the input element and set
|
|
214
|
-
// its "data-pattern" attribute to the specified message (if any)
|
|
215
|
-
if (validation.pattern) {
|
|
216
|
-
input.setAttribute('pattern', validation.pattern.pattern);
|
|
217
|
-
input.setAttribute('data-pattern', (_b = validation.pattern.message) !== null && _b !== void 0 ? _b : '');
|
|
218
|
-
}
|
|
219
|
-
// If the "badInput" property is present, set the input element's "data-badinput" attribute to
|
|
220
|
-
// the specified message
|
|
221
|
-
if (validation.badInput) {
|
|
222
|
-
input.setAttribute('data-badinput', validation.badInput.message);
|
|
223
|
-
}
|
|
224
|
-
// If the "minmax" property is present, add the "min" and "max" attributes to the input element
|
|
225
|
-
// and set its "data-range" attribute to the specified message (if any)
|
|
226
|
-
if (validation.minmax) {
|
|
227
|
-
input.setAttribute('min', validation.minmax.min);
|
|
228
|
-
input.setAttribute('max', validation.minmax.max);
|
|
229
|
-
input.setAttribute('data-range', validation.minmax.message);
|
|
230
|
-
}
|
|
231
|
-
// If the "maxlength" property is present, add the "maxlength" attribute to the input element
|
|
232
|
-
if (validation.maxlength) {
|
|
233
|
-
input.setAttribute('maxlength', validation.maxlength);
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
// Create a new error bubble element
|
|
237
|
-
createErrorBubble() {
|
|
238
|
-
// Create a new <div> element with the "errorBubble" class
|
|
239
|
-
const errorBubble = document.createElement('div');
|
|
240
|
-
errorBubble.className = 'errorBubble';
|
|
241
|
-
// Return the error bubble element
|
|
242
|
-
return errorBubble;
|
|
243
|
-
}
|
|
244
|
-
/**
|
|
245
|
-
* Creates a new <label> element with the "inputBlock" class and the specified label text,
|
|
246
|
-
* and appends the input element and error bubble element to it. If the form property has
|
|
247
|
-
* no validation object, it adds an "optional" span element to the label.
|
|
248
|
-
*
|
|
249
|
-
* @param {Object} formProperties - An object containing properties for the form field, including its label text and validation rules.
|
|
250
|
-
* @param {HTMLInputElement} input - The input element to associate with the label.
|
|
251
|
-
* @param {HTMLDivElement} errorBubble - The error bubble element to display error messages in.
|
|
252
|
-
* @return {HTMLLabelElement} - The new label element.
|
|
253
|
-
*/
|
|
254
|
-
createLabel(formProperties, input, errorBubble) {
|
|
255
|
-
// Create a new <label> element with the "inputBlock" class and the specified text
|
|
256
|
-
const label = document.createElement('label');
|
|
257
|
-
label.className = 'inputBlock';
|
|
258
|
-
label.innerText = formProperties.label;
|
|
259
|
-
// If the form property has no validation object, add an "optional" span element to the label
|
|
260
|
-
if (!formProperties.validation) {
|
|
261
|
-
const optionalSpan = document.createElement('span');
|
|
262
|
-
optionalSpan.className = 'optional';
|
|
263
|
-
optionalSpan.innerHTML = ' (optional)';
|
|
264
|
-
label.appendChild(optionalSpan);
|
|
265
|
-
}
|
|
266
|
-
// Append the input element and error bubble element to the label
|
|
267
|
-
label.appendChild(input);
|
|
268
|
-
label.appendChild(errorBubble);
|
|
269
|
-
// Return the label element
|
|
270
|
-
return label;
|
|
271
|
-
}
|
|
272
|
-
/**
|
|
273
|
-
* Creates a new <input> element with the "submit" type, the "primary-blue" class, and the
|
|
274
|
-
* specified label text (i.e., "Save" by default), and returns the new submit button element.
|
|
275
|
-
*
|
|
276
|
-
* @return {HTMLInputElement} - The new submit button element.
|
|
277
|
-
*/
|
|
278
|
-
createSubmitButton() {
|
|
279
|
-
// Create a new <input> element with the "submit" type and the specified class and value
|
|
280
|
-
const submitButton = document.createElement('input');
|
|
281
|
-
submitButton.type = 'submit';
|
|
282
|
-
submitButton.className = 'button primary-blue';
|
|
283
|
-
submitButton.value = 'Save';
|
|
284
|
-
// Return the submit button element
|
|
285
|
-
return submitButton;
|
|
286
|
-
}
|
|
287
|
-
/**
|
|
288
|
-
* Populates the form template with input fields and labels based on the properties of the
|
|
289
|
-
* current form schema. For each property in the schema, it creates an input element, applies
|
|
290
|
-
* any validation rules to it, creates an error bubble and label element, and appends them
|
|
291
|
-
* to the form template. Finally, it creates and appends a submit button element to the form.
|
|
292
|
-
*
|
|
293
|
-
* @return {void}
|
|
294
|
-
*/
|
|
295
|
-
populateFormFromSchema() {
|
|
296
|
-
// If there is no form schema, return early
|
|
297
|
-
if (!this._formSchema)
|
|
298
|
-
return;
|
|
299
|
-
// Get the properties of the form schema and their keys
|
|
300
|
-
const properties = this._formSchema.properties;
|
|
301
|
-
const propertyKeys = Object.keys(properties);
|
|
302
|
-
// Loop through each property key and create an input, label, and error bubble for it
|
|
303
|
-
propertyKeys.forEach(formKey => {
|
|
304
|
-
const formItem = properties[formKey];
|
|
305
|
-
const formProperties = formItem.form;
|
|
306
|
-
const input = this.createInput(formKey, formProperties);
|
|
307
|
-
// If the form property has validation, apply it to the input
|
|
308
|
-
if (formProperties.validation) {
|
|
309
|
-
this.applyValidation(input, formProperties.validation);
|
|
310
|
-
}
|
|
311
|
-
// Create an error bubble and label element for the input
|
|
312
|
-
const errorBubble = this.createErrorBubble();
|
|
313
|
-
const label = this.createLabel(formProperties, input, errorBubble);
|
|
314
|
-
// Append the label element to the form template
|
|
315
|
-
this.template.content.append(label);
|
|
316
|
-
});
|
|
317
|
-
// Create and append a submit button element to the form template
|
|
318
|
-
const submitButton = this.createSubmitButton();
|
|
319
|
-
this.template.content.append(submitButton);
|
|
320
|
-
}
|
|
321
|
-
/**
|
|
322
|
-
* Clones the form template and binds event listeners to its input elements. First, it checks if
|
|
323
|
-
* there is a form schema present. If so, it clones the template's content, binds events to form
|
|
324
|
-
* input elements, and appends the cloned form elements to the fieldset. The event listeners include
|
|
325
|
-
* "oninvalid" (to check input validity on submit), "onblur" (to check input validity on blur),
|
|
326
|
-
* "onkeyup" (to handle changes in input fields), and "onchange" (to handle changes in select fields).
|
|
327
|
-
*
|
|
328
|
-
* @return {void}
|
|
329
|
-
*/
|
|
330
|
-
componentDidRender() {
|
|
331
|
-
// If there's no form schema, return
|
|
332
|
-
if (!this._formSchema) {
|
|
333
|
-
return;
|
|
334
|
-
}
|
|
335
|
-
// Clone the template's content and store it in a variable
|
|
336
|
-
const formItems = this.template.content.cloneNode(true);
|
|
337
|
-
// Bind event listeners to form elements
|
|
338
|
-
const properties = this._formSchema.properties;
|
|
339
|
-
const propertyKeys = Object.keys(properties);
|
|
340
|
-
propertyKeys.forEach((formKey) => {
|
|
341
|
-
const formInput = formItems.querySelector(`[name=${formKey}]`);
|
|
342
|
-
// Bind events to form input elements
|
|
343
|
-
formInput.oninvalid = this.validityCheckWrapper.bind(this);
|
|
344
|
-
formInput.onblur = this.validityCheckWrapper.bind(this);
|
|
345
|
-
formInput.onkeyup = this.fieldChanged.bind(this);
|
|
346
|
-
formInput.onchange = this.fieldChanged.bind(this);
|
|
347
|
-
});
|
|
348
|
-
// Append the cloned form elements to the fieldset
|
|
349
|
-
this.fieldset.appendChild(formItems);
|
|
350
|
-
}
|
|
351
|
-
validityCheckWrapper(event) {
|
|
352
|
-
const { target, hasError, errorMessage } = validityCheck(event);
|
|
353
|
-
setErrorState(target, hasError, errorMessage);
|
|
354
|
-
}
|
|
355
|
-
/**
|
|
356
|
-
* Renders the component's template as a form element with a fieldset container. The form's
|
|
357
|
-
* "onSubmit" event is bound to the "doSubmit" function, which handles the form submission
|
|
358
|
-
* and emits a "dataSubmitted" event with the form data. The fieldset element is assigned
|
|
359
|
-
* to the "fieldset" instance variable using a ref, so it can be populated with form elements
|
|
360
|
-
* later on.
|
|
361
|
-
*
|
|
362
|
-
* @return {JSX.Element} - The rendered form template as a JSX element.
|
|
363
|
-
*/
|
|
364
|
-
render() {
|
|
365
|
-
return (h(Host, null, h("form", { onSubmit: this.doSubmit.bind(this) }, h("fieldset", { ref: el => (this.fieldset = el) }))));
|
|
366
|
-
}
|
|
367
|
-
static get watchers() { return {
|
|
368
|
-
"formschema": ["onFormSchemaChange"]
|
|
369
|
-
}; }
|
|
370
|
-
};
|
|
98
|
+
const TttxForm = class {
|
|
99
|
+
constructor(hostRef) {
|
|
100
|
+
registerInstance(this, hostRef);
|
|
101
|
+
this.dataSubmitted = createEvent(this, "dataSubmitted", 7);
|
|
102
|
+
this.dataChanged = createEvent(this, "dataChanged", 7);
|
|
103
|
+
// Create a new template element using the HTMLTemplateElement interface.
|
|
104
|
+
this.template = document.createElement('template');
|
|
105
|
+
this.formschema = undefined;
|
|
106
|
+
this.submitValue = undefined;
|
|
107
|
+
}
|
|
108
|
+
// This method is called whenever the "formschema" property changes
|
|
109
|
+
onFormSchemaChange(newValue) {
|
|
110
|
+
// Check if the new value is a string, indicating that it needs to be parsed
|
|
111
|
+
if (typeof newValue === 'string') {
|
|
112
|
+
// Parse the string and set the "_formSchema" property
|
|
113
|
+
this._formSchema = JSON.parse(newValue);
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
// If the new value is already an object, set the "_formSchema" property directly
|
|
117
|
+
this._formSchema = newValue;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Handles the focus event for a form field and emits a "dataChanged" event
|
|
122
|
+
* to the parent component with the field name and its new value.
|
|
123
|
+
*
|
|
124
|
+
* @param {ChangeEvent} event - The focus event triggered by the field.
|
|
125
|
+
* @return {void}
|
|
126
|
+
*/
|
|
127
|
+
fieldChanged(event) {
|
|
128
|
+
// Extract the name and value of the field from the event
|
|
129
|
+
const fieldName = event.target.name;
|
|
130
|
+
const fieldValue = event.target.value;
|
|
131
|
+
// Emit an event to signal that the field's data has changed
|
|
132
|
+
this.dataChanged.emit({ name: fieldName, value: fieldValue });
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Submits the form data to the server.
|
|
136
|
+
*
|
|
137
|
+
* @param {SubmitEvent} event - The event object for the form submission.
|
|
138
|
+
* @returns {void}
|
|
139
|
+
*
|
|
140
|
+
* @example
|
|
141
|
+
* const form = document.getElementById('myForm');
|
|
142
|
+
* form.addEventListener('submit', (event) => {
|
|
143
|
+
* doSubmit(event);
|
|
144
|
+
* });
|
|
145
|
+
*/
|
|
146
|
+
doSubmit(event) {
|
|
147
|
+
// prevent the form from submitting normally
|
|
148
|
+
event.preventDefault();
|
|
149
|
+
// create a new FormData object with the form data
|
|
150
|
+
const formData = new FormData(event.target);
|
|
151
|
+
// emit the form data through the `dataSubmitted` event
|
|
152
|
+
this.dataSubmitted.emit(formData);
|
|
153
|
+
}
|
|
154
|
+
// This method is called before the component is loaded into the DOM
|
|
155
|
+
componentWillLoad() {
|
|
156
|
+
// Initialize the form schema by calling the "onFormSchemaChange" method with the current "formschema" property
|
|
157
|
+
this.onFormSchemaChange(this.formschema);
|
|
158
|
+
}
|
|
159
|
+
// This method is called before the component is rendered
|
|
160
|
+
componentWillRender() {
|
|
161
|
+
// Clear the template to account for a potential re-render scenario
|
|
162
|
+
this.template = document.createElement('template');
|
|
163
|
+
// Populate the form from the form schema
|
|
164
|
+
this.populateFormFromSchema();
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Creates a new HTMLInputElement with the specified name, type, and placeholder (if any),
|
|
168
|
+
* and sets its autocomplete and autocapitalization properties to off.
|
|
169
|
+
*
|
|
170
|
+
* @param {string} formKey - The name of the input field, as specified in the form schema.
|
|
171
|
+
* @param {Object} formProperties - An object containing additional properties for the input field, such as its type and placeholder value.
|
|
172
|
+
* @param {string} formProperties.type - The type of the input field (e.g., "text", "email", "number", etc.).
|
|
173
|
+
* @param {string} [formProperties.placeholder] - An optional placeholder value to display in the input field.
|
|
174
|
+
* @return {HTMLInputElement} - The new input element.
|
|
175
|
+
*/
|
|
176
|
+
createInput(formKey, formProperties) {
|
|
177
|
+
var _a;
|
|
178
|
+
// Create a new <input> element with the specified name and type
|
|
179
|
+
const input = document.createElement('input');
|
|
180
|
+
input.name = formKey;
|
|
181
|
+
input.type = formProperties.type;
|
|
182
|
+
// Set the placeholder attribute to the specified value (if any)
|
|
183
|
+
input.placeholder = (_a = formProperties.placeholder) !== null && _a !== void 0 ? _a : '';
|
|
184
|
+
// Disable autocomplete and autocapitalization
|
|
185
|
+
input.autocomplete = 'off';
|
|
186
|
+
input.autocapitalize = 'off';
|
|
187
|
+
// Return the input element
|
|
188
|
+
return input;
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Applies validation attributes to an input element based on the specified validation object.
|
|
192
|
+
* If a certain property is present in the object, it will set the corresponding attribute on
|
|
193
|
+
* the input element (e.g., "required" will set the "required" and "data-required" attributes,
|
|
194
|
+
* "pattern" will set the "pattern" and "data-pattern" attributes, etc.).
|
|
195
|
+
*
|
|
196
|
+
* @param {HTMLInputElement} input - The input element to apply validation attributes to.
|
|
197
|
+
* @param {Object} validation - An object containing the validation rules for the input field.
|
|
198
|
+
* @param {Object} [validation.required] - An object containing a "message" property to display if the field is required.
|
|
199
|
+
* @param {Object} [validation.pattern] - An object containing a "pattern" property to match against the field value, and a "message" property to display if the pattern doesn't match.
|
|
200
|
+
* @param {Object} [validation.badInput] - An object containing a "message" property to display if the field value is invalid.
|
|
201
|
+
* @param {Object} [validation.minmax] - An object containing "min" and "max" properties to validate the field value against, and a "message" property to display if the value is out of range.
|
|
202
|
+
* @param {string} [validation.maxlength] - The maximum length of the input field.
|
|
203
|
+
* @return {void}
|
|
204
|
+
*/
|
|
205
|
+
applyValidation(input, validation) {
|
|
206
|
+
var _a, _b;
|
|
207
|
+
// If the "required" property is present, add the "required" attribute to the input element and
|
|
208
|
+
// set its "data-required" attribute to the specified message (if any)
|
|
209
|
+
if (validation.required) {
|
|
210
|
+
input.setAttribute('required', '');
|
|
211
|
+
input.setAttribute('data-required', (_a = validation.required.message) !== null && _a !== void 0 ? _a : '');
|
|
212
|
+
}
|
|
213
|
+
// If the "pattern" property is present, add the "pattern" attribute to the input element and set
|
|
214
|
+
// its "data-pattern" attribute to the specified message (if any)
|
|
215
|
+
if (validation.pattern) {
|
|
216
|
+
input.setAttribute('pattern', validation.pattern.pattern);
|
|
217
|
+
input.setAttribute('data-pattern', (_b = validation.pattern.message) !== null && _b !== void 0 ? _b : '');
|
|
218
|
+
}
|
|
219
|
+
// If the "badInput" property is present, set the input element's "data-badinput" attribute to
|
|
220
|
+
// the specified message
|
|
221
|
+
if (validation.badInput) {
|
|
222
|
+
input.setAttribute('data-badinput', validation.badInput.message);
|
|
223
|
+
}
|
|
224
|
+
// If the "minmax" property is present, add the "min" and "max" attributes to the input element
|
|
225
|
+
// and set its "data-range" attribute to the specified message (if any)
|
|
226
|
+
if (validation.minmax) {
|
|
227
|
+
input.setAttribute('min', validation.minmax.min);
|
|
228
|
+
input.setAttribute('max', validation.minmax.max);
|
|
229
|
+
input.setAttribute('data-range', validation.minmax.message);
|
|
230
|
+
}
|
|
231
|
+
// If the "maxlength" property is present, add the "maxlength" attribute to the input element
|
|
232
|
+
if (validation.maxlength) {
|
|
233
|
+
input.setAttribute('maxlength', validation.maxlength);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
// Create a new error bubble element
|
|
237
|
+
createErrorBubble() {
|
|
238
|
+
// Create a new <div> element with the "errorBubble" class
|
|
239
|
+
const errorBubble = document.createElement('div');
|
|
240
|
+
errorBubble.className = 'errorBubble';
|
|
241
|
+
// Return the error bubble element
|
|
242
|
+
return errorBubble;
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* Creates a new <label> element with the "inputBlock" class and the specified label text,
|
|
246
|
+
* and appends the input element and error bubble element to it. If the form property has
|
|
247
|
+
* no validation object, it adds an "optional" span element to the label.
|
|
248
|
+
*
|
|
249
|
+
* @param {Object} formProperties - An object containing properties for the form field, including its label text and validation rules.
|
|
250
|
+
* @param {HTMLInputElement} input - The input element to associate with the label.
|
|
251
|
+
* @param {HTMLDivElement} errorBubble - The error bubble element to display error messages in.
|
|
252
|
+
* @return {HTMLLabelElement} - The new label element.
|
|
253
|
+
*/
|
|
254
|
+
createLabel(formProperties, input, errorBubble) {
|
|
255
|
+
// Create a new <label> element with the "inputBlock" class and the specified text
|
|
256
|
+
const label = document.createElement('label');
|
|
257
|
+
label.className = 'inputBlock';
|
|
258
|
+
label.innerText = formProperties.label;
|
|
259
|
+
// If the form property has no validation object, add an "optional" span element to the label
|
|
260
|
+
if (!formProperties.validation) {
|
|
261
|
+
const optionalSpan = document.createElement('span');
|
|
262
|
+
optionalSpan.className = 'optional';
|
|
263
|
+
optionalSpan.innerHTML = ' (optional)';
|
|
264
|
+
label.appendChild(optionalSpan);
|
|
265
|
+
}
|
|
266
|
+
// Append the input element and error bubble element to the label
|
|
267
|
+
label.appendChild(input);
|
|
268
|
+
label.appendChild(errorBubble);
|
|
269
|
+
// Return the label element
|
|
270
|
+
return label;
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Creates a new <input> element with the "submit" type, the "primary-blue" class, and the
|
|
274
|
+
* specified label text (i.e., "Save" by default), and returns the new submit button element.
|
|
275
|
+
*
|
|
276
|
+
* @return {HTMLInputElement} - The new submit button element.
|
|
277
|
+
*/
|
|
278
|
+
createSubmitButton() {
|
|
279
|
+
// Create a new <input> element with the "submit" type and the specified class and value
|
|
280
|
+
const submitButton = document.createElement('input');
|
|
281
|
+
submitButton.type = 'submit';
|
|
282
|
+
submitButton.className = 'button primary-blue';
|
|
283
|
+
submitButton.value = 'Save';
|
|
284
|
+
// Return the submit button element
|
|
285
|
+
return submitButton;
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* Populates the form template with input fields and labels based on the properties of the
|
|
289
|
+
* current form schema. For each property in the schema, it creates an input element, applies
|
|
290
|
+
* any validation rules to it, creates an error bubble and label element, and appends them
|
|
291
|
+
* to the form template. Finally, it creates and appends a submit button element to the form.
|
|
292
|
+
*
|
|
293
|
+
* @return {void}
|
|
294
|
+
*/
|
|
295
|
+
populateFormFromSchema() {
|
|
296
|
+
// If there is no form schema, return early
|
|
297
|
+
if (!this._formSchema)
|
|
298
|
+
return;
|
|
299
|
+
// Get the properties of the form schema and their keys
|
|
300
|
+
const properties = this._formSchema.properties;
|
|
301
|
+
const propertyKeys = Object.keys(properties);
|
|
302
|
+
// Loop through each property key and create an input, label, and error bubble for it
|
|
303
|
+
propertyKeys.forEach(formKey => {
|
|
304
|
+
const formItem = properties[formKey];
|
|
305
|
+
const formProperties = formItem.form;
|
|
306
|
+
const input = this.createInput(formKey, formProperties);
|
|
307
|
+
// If the form property has validation, apply it to the input
|
|
308
|
+
if (formProperties.validation) {
|
|
309
|
+
this.applyValidation(input, formProperties.validation);
|
|
310
|
+
}
|
|
311
|
+
// Create an error bubble and label element for the input
|
|
312
|
+
const errorBubble = this.createErrorBubble();
|
|
313
|
+
const label = this.createLabel(formProperties, input, errorBubble);
|
|
314
|
+
// Append the label element to the form template
|
|
315
|
+
this.template.content.append(label);
|
|
316
|
+
});
|
|
317
|
+
// Create and append a submit button element to the form template
|
|
318
|
+
const submitButton = this.createSubmitButton();
|
|
319
|
+
this.template.content.append(submitButton);
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* Clones the form template and binds event listeners to its input elements. First, it checks if
|
|
323
|
+
* there is a form schema present. If so, it clones the template's content, binds events to form
|
|
324
|
+
* input elements, and appends the cloned form elements to the fieldset. The event listeners include
|
|
325
|
+
* "oninvalid" (to check input validity on submit), "onblur" (to check input validity on blur),
|
|
326
|
+
* "onkeyup" (to handle changes in input fields), and "onchange" (to handle changes in select fields).
|
|
327
|
+
*
|
|
328
|
+
* @return {void}
|
|
329
|
+
*/
|
|
330
|
+
componentDidRender() {
|
|
331
|
+
// If there's no form schema, return
|
|
332
|
+
if (!this._formSchema) {
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
// Clone the template's content and store it in a variable
|
|
336
|
+
const formItems = this.template.content.cloneNode(true);
|
|
337
|
+
// Bind event listeners to form elements
|
|
338
|
+
const properties = this._formSchema.properties;
|
|
339
|
+
const propertyKeys = Object.keys(properties);
|
|
340
|
+
propertyKeys.forEach((formKey) => {
|
|
341
|
+
const formInput = formItems.querySelector(`[name=${formKey}]`);
|
|
342
|
+
// Bind events to form input elements
|
|
343
|
+
formInput.oninvalid = this.validityCheckWrapper.bind(this);
|
|
344
|
+
formInput.onblur = this.validityCheckWrapper.bind(this);
|
|
345
|
+
formInput.onkeyup = this.fieldChanged.bind(this);
|
|
346
|
+
formInput.onchange = this.fieldChanged.bind(this);
|
|
347
|
+
});
|
|
348
|
+
// Append the cloned form elements to the fieldset
|
|
349
|
+
this.fieldset.appendChild(formItems);
|
|
350
|
+
}
|
|
351
|
+
validityCheckWrapper(event) {
|
|
352
|
+
const { target, hasError, errorMessage } = validityCheck(event);
|
|
353
|
+
setErrorState(target, hasError, errorMessage);
|
|
354
|
+
}
|
|
355
|
+
/**
|
|
356
|
+
* Renders the component's template as a form element with a fieldset container. The form's
|
|
357
|
+
* "onSubmit" event is bound to the "doSubmit" function, which handles the form submission
|
|
358
|
+
* and emits a "dataSubmitted" event with the form data. The fieldset element is assigned
|
|
359
|
+
* to the "fieldset" instance variable using a ref, so it can be populated with form elements
|
|
360
|
+
* later on.
|
|
361
|
+
*
|
|
362
|
+
* @return {JSX.Element} - The rendered form template as a JSX element.
|
|
363
|
+
*/
|
|
364
|
+
render() {
|
|
365
|
+
return (h(Host, null, h("form", { onSubmit: this.doSubmit.bind(this) }, h("fieldset", { ref: el => (this.fieldset = el) }))));
|
|
366
|
+
}
|
|
367
|
+
static get watchers() { return {
|
|
368
|
+
"formschema": ["onFormSchemaChange"]
|
|
369
|
+
}; }
|
|
370
|
+
};
|
|
371
371
|
TttxForm.style = tttxFormCss;
|
|
372
372
|
|
|
373
373
|
export { TttxForm as tttx_form };
|