@3t-transform/threeteeui 0.1.43 → 0.1.45

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (147) hide show
  1. package/dist/cjs/_commonjsHelpers-537d719a.js +20 -0
  2. package/dist/cjs/{domsanitiser.options-975e3317.js → domsanitiser.options-b2d88e35.js} +16 -30
  3. package/dist/cjs/{index-457ca775.js → index-1a35850c.js} +62 -1
  4. package/dist/cjs/loader.cjs.js +2 -2
  5. package/dist/cjs/tttx-button.cjs.entry.js +24 -24
  6. package/dist/cjs/tttx-dialog-box.cjs.entry.js +81 -0
  7. package/dist/cjs/tttx-filter.cjs.entry.js +177 -177
  8. package/dist/cjs/tttx-form.cjs.entry.js +459 -458
  9. package/dist/cjs/tttx-icon.cjs.entry.js +11 -11
  10. package/dist/cjs/tttx-keyvalue-block.cjs.entry.js +59 -59
  11. package/dist/cjs/tttx-list.cjs.entry.js +33 -32
  12. package/dist/cjs/tttx-loading-spinner.cjs.entry.js +16 -16
  13. package/dist/cjs/tttx-qrcode.cjs.entry.js +37 -0
  14. package/dist/cjs/tttx-sorter.cjs.entry.js +102 -102
  15. package/dist/cjs/tttx-standalone-input.cjs.entry.js +79 -79
  16. package/dist/cjs/tttx-toolbar.cjs.entry.js +10 -10
  17. package/dist/cjs/tttx.cjs.js +2 -2
  18. package/dist/collection/collection-manifest.json +2 -0
  19. package/dist/collection/components/atoms/tttx-button/tttx-button.js +110 -110
  20. package/dist/collection/components/atoms/tttx-button/tttx-button.stories.js +14 -14
  21. package/dist/collection/components/atoms/tttx-icon/tttx-icon.js +62 -62
  22. package/dist/collection/components/atoms/tttx-icon/tttx-icon.stories.js +22 -22
  23. package/dist/collection/components/atoms/tttx-keyvalue-block/tttx-keyvalue-block.js +109 -109
  24. package/dist/collection/components/atoms/tttx-keyvalue-block/tttx-keyvalue-block.stories.js +38 -38
  25. package/dist/collection/components/atoms/tttx-loading-spinner/tttx-loading-spinner.js +67 -67
  26. package/dist/collection/components/atoms/tttx-loading-spinner/tttx-loading-spinner.stories.js +17 -17
  27. package/dist/collection/components/atoms/tttx-qrcode/tttx-qrcode.css +0 -0
  28. package/dist/collection/components/atoms/tttx-qrcode/tttx-qrcode.js +74 -0
  29. package/dist/collection/components/atoms/tttx-qrcode/tttx-qrcode.stories.js +22 -0
  30. package/dist/collection/components/molecules/tttx-dialog-box/tttx-dialog-box.css +146 -0
  31. package/dist/collection/components/molecules/tttx-dialog-box/tttx-dialog-box.js +172 -0
  32. package/dist/collection/components/molecules/tttx-dialog-box/tttx-dialog-box.stories.js +380 -0
  33. package/dist/collection/components/molecules/tttx-filter/tttx-filter.js +369 -369
  34. package/dist/collection/components/molecules/tttx-filter/tttx-filter.stories.js +72 -72
  35. package/dist/collection/components/molecules/tttx-form/lib/setErrorState.js +37 -37
  36. package/dist/collection/components/molecules/tttx-form/lib/validityCheck.js +61 -61
  37. package/dist/collection/components/molecules/tttx-form/tttx-form.js +479 -479
  38. package/dist/collection/components/molecules/tttx-form/tttx-form.stories.js +272 -272
  39. package/dist/collection/components/molecules/tttx-list/tttx-list.js +105 -105
  40. package/dist/collection/components/molecules/tttx-list/tttx-list.stories.js +43 -43
  41. package/dist/collection/components/molecules/tttx-sorter/tttx-sorter.js +224 -224
  42. package/dist/collection/components/molecules/tttx-sorter/tttx-sorter.stories.js +42 -42
  43. package/dist/collection/components/molecules/tttx-standalone-input/tttx-standalone-input.js +759 -759
  44. package/dist/collection/components/molecules/tttx-standalone-input/tttx-standalone-input.stories.js +172 -172
  45. package/dist/collection/components/molecules/tttx-toolbar/tttx-toolbar.js +44 -44
  46. package/dist/collection/components/molecules/tttx-toolbar/tttx-toolbar.stories.js +14 -14
  47. package/dist/collection/components/palette.stories.js +7 -7
  48. package/dist/collection/docs/gettingstarted-developer.stories.js +5 -5
  49. package/dist/collection/icons.js +2838 -2838
  50. package/dist/collection/index.js +1 -1
  51. package/dist/collection/shared/domsanitiser.options.js +14 -14
  52. package/dist/components/_commonjsHelpers.js +17 -0
  53. package/dist/components/domsanitiser.options.js +13 -27
  54. package/dist/components/index.d.ts +2 -0
  55. package/dist/components/index.js +2 -0
  56. package/dist/components/tttx-button.js +1 -54
  57. package/dist/components/tttx-button2.js +56 -0
  58. package/dist/components/tttx-dialog-box.d.ts +11 -0
  59. package/dist/components/tttx-dialog-box.js +110 -0
  60. package/dist/components/tttx-filter.js +210 -210
  61. package/dist/components/tttx-form.js +475 -475
  62. package/dist/components/tttx-icon2.js +28 -28
  63. package/dist/components/tttx-keyvalue-block.js +76 -76
  64. package/dist/components/tttx-list.js +53 -53
  65. package/dist/components/tttx-loading-spinner.js +33 -33
  66. package/dist/components/tttx-qrcode.d.ts +11 -0
  67. package/dist/components/tttx-qrcode.js +53 -0
  68. package/dist/components/tttx-sorter.js +130 -130
  69. package/dist/components/tttx-standalone-input.js +130 -130
  70. package/dist/components/tttx-toolbar.js +26 -26
  71. package/dist/esm/_commonjsHelpers-9943807e.js +17 -0
  72. package/dist/esm/{domsanitiser.options-3c7ded83.js → domsanitiser.options-81611f82.js} +13 -27
  73. package/dist/esm/{index-d784fb3e.js → index-a848bfb4.js} +62 -1
  74. package/dist/esm/loader.js +3 -3
  75. package/dist/esm/polyfills/core-js.js +0 -0
  76. package/dist/esm/polyfills/dom.js +0 -0
  77. package/dist/esm/polyfills/es5-html-element.js +0 -0
  78. package/dist/esm/polyfills/index.js +0 -0
  79. package/dist/esm/polyfills/system.js +0 -0
  80. package/dist/esm/tttx-button.entry.js +24 -24
  81. package/dist/esm/tttx-dialog-box.entry.js +77 -0
  82. package/dist/esm/tttx-filter.entry.js +177 -177
  83. package/dist/esm/tttx-form.entry.js +459 -458
  84. package/dist/esm/tttx-icon.entry.js +11 -11
  85. package/dist/esm/tttx-keyvalue-block.entry.js +59 -59
  86. package/dist/esm/tttx-list.entry.js +33 -32
  87. package/dist/esm/tttx-loading-spinner.entry.js +16 -16
  88. package/dist/esm/tttx-qrcode.entry.js +33 -0
  89. package/dist/esm/tttx-sorter.entry.js +102 -102
  90. package/dist/esm/tttx-standalone-input.entry.js +79 -79
  91. package/dist/esm/tttx-toolbar.entry.js +10 -10
  92. package/dist/esm/tttx.js +3 -3
  93. package/dist/tttx/p-0b25ac9c.js +3 -0
  94. package/dist/tttx/p-112455b1.js +1 -0
  95. package/dist/tttx/{p-b720c4ad.entry.js → p-120a0732.entry.js} +1 -1
  96. package/dist/tttx/p-2d130f82.entry.js +1 -0
  97. package/dist/tttx/{p-aaf02902.entry.js → p-42349ae5.entry.js} +1 -1
  98. package/dist/tttx/{p-92cade7f.entry.js → p-623b9147.entry.js} +1 -1
  99. package/dist/tttx/{p-cac26a1b.entry.js → p-7428fc97.entry.js} +1 -1
  100. package/dist/tttx/{p-ab6ce9f6.entry.js → p-77fb8e0f.entry.js} +1 -1
  101. package/dist/tttx/p-83563ce9.entry.js +1 -0
  102. package/dist/tttx/p-a092cd71.entry.js +1 -0
  103. package/dist/tttx/p-ab4652a8.js +2 -0
  104. package/dist/tttx/p-af7ff3b3.entry.js +1 -0
  105. package/dist/tttx/{p-563605b2.entry.js → p-d0ca435d.entry.js} +1 -1
  106. package/dist/tttx/{p-798a098a.entry.js → p-d2b0ec0a.entry.js} +1 -1
  107. package/dist/tttx/{p-ec253eea.entry.js → p-e1efb888.entry.js} +1 -1
  108. package/dist/tttx/tttx.esm.js +1 -1
  109. package/dist/types/components/atoms/tttx-button/tttx-button.d.ts +10 -10
  110. package/dist/types/components/atoms/tttx-button/tttx-button.stories.d.ts +10 -10
  111. package/dist/types/components/atoms/tttx-icon/tttx-icon.d.ts +5 -5
  112. package/dist/types/components/atoms/tttx-icon/tttx-icon.stories.d.ts +20 -20
  113. package/dist/types/components/atoms/tttx-keyvalue-block/tttx-keyvalue-block.d.ts +7 -7
  114. package/dist/types/components/atoms/tttx-keyvalue-block/tttx-keyvalue-block.stories.d.ts +9 -9
  115. package/dist/types/components/atoms/tttx-loading-spinner/tttx-loading-spinner.d.ts +6 -6
  116. package/dist/types/components/atoms/tttx-loading-spinner/tttx-loading-spinner.stories.d.ts +17 -17
  117. package/dist/types/components/atoms/tttx-qrcode/tttx-qrcode.d.ts +6 -0
  118. package/dist/types/components/atoms/tttx-qrcode/tttx-qrcode.stories.d.ts +23 -0
  119. package/dist/types/components/molecules/tttx-dialog-box/interfaces.d.ts +25 -0
  120. package/dist/types/components/molecules/tttx-dialog-box/tttx-dialog-box.d.ts +18 -0
  121. package/dist/types/components/molecules/tttx-dialog-box/tttx-dialog-box.stories.d.ts +23 -0
  122. package/dist/types/components/molecules/tttx-filter/tttx-filter.d.ts +41 -41
  123. package/dist/types/components/molecules/tttx-form/lib/setErrorState.d.ts +13 -13
  124. package/dist/types/components/molecules/tttx-form/lib/validityCheck.d.ts +17 -17
  125. package/dist/types/components/molecules/tttx-form/tttx-form.d.ts +133 -133
  126. package/dist/types/components/molecules/tttx-list/tttx-list.d.ts +11 -11
  127. package/dist/types/components/molecules/tttx-sorter/tttx-sorter.d.ts +19 -19
  128. package/dist/types/components/molecules/tttx-standalone-input/tttx-standalone-input.d.ts +69 -69
  129. package/dist/types/components/molecules/tttx-standalone-input/tttx-standalone-input.stories.d.ts +143 -143
  130. package/dist/types/components/molecules/tttx-toolbar/tttx-toolbar.d.ts +4 -4
  131. package/dist/types/components/molecules/tttx-toolbar/tttx-toolbar.stories.d.ts +13 -13
  132. package/dist/types/components/palette.stories.d.ts +6 -6
  133. package/dist/types/components.d.ts +41 -0
  134. package/dist/types/docs/gettingstarted-developer.stories.d.ts +5 -5
  135. package/dist/types/icons.d.ts +2 -2
  136. package/dist/types/index.d.ts +1 -1
  137. package/dist/types/shared/domsanitiser.options.d.ts +10 -10
  138. package/package.json +7 -5
  139. package/readme.md +19 -7
  140. package/dist/tttx/p-0ebffdfc.js +0 -2
  141. package/dist/tttx/p-1db3704e.entry.js +0 -1
  142. package/dist/tttx/p-350ddb03.js +0 -3
  143. package/dist/tttx/p-f702df4f.entry.js +0 -1
  144. package/dist/types/components/molecules/tttx-filter/tttx-filter.stories.d.ts +0 -70
  145. package/dist/types/components/molecules/tttx-form/tttx-form.stories.d.ts +0 -278
  146. package/dist/types/components/molecules/tttx-list/tttx-list.stories.d.ts +0 -14
  147. package/dist/types/components/molecules/tttx-sorter/tttx-sorter.stories.d.ts +0 -30
@@ -2,471 +2,472 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- const index = require('./index-457ca775.js');
6
- const domsanitiser_options = require('./domsanitiser.options-975e3317.js');
5
+ const index = require('./index-1a35850c.js');
6
+ const domsanitiser_options = require('./domsanitiser.options-b2d88e35.js');
7
+ require('./_commonjsHelpers-537d719a.js');
7
8
 
8
- /**
9
- * Validates the input field on focusout event by checking its validity state,
10
- * sets an error message if there's an issue, and emits a "dataChanged" event to
11
- * the parent component with the field name and its new value.
12
- *
13
- * @param {Event} event - The focusout event triggered by the input field.
14
- * @return {void}
15
- */
16
- function validityCheck(event) {
17
- var _a, _b, _c, _d;
18
- event.preventDefault();
19
- const target = event.target;
20
- let hasError = true;
21
- let errorMessage = '';
22
- // validity object on HTML5 inputs has the following options
23
- // badInput
24
- // customError
25
- // patternMismatch
26
- // rangeOverflow
27
- // rangeUnderflow
28
- // stepMismatch
29
- // tooLong
30
- // tooShort
31
- // typeMismatch
32
- // valid
33
- // valueMissing
34
- // customErrors can be set with
35
- // target.setCustomValidity('custom error!');
36
- // and cleared with
37
- // target.setCustomValidity('');
38
- // Check the validity of the input field and set an error message if needed
39
- switch (true) {
40
- // The field is required, but has no value
41
- case target.validity.valueMissing:
42
- errorMessage = (_a = target.dataset.required) !== null && _a !== void 0 ? _a : 'This field is required';
43
- break;
44
- // The field's value does not match the expected pattern
45
- case target.validity.patternMismatch:
46
- errorMessage = (_b = target.dataset.pattern) !== null && _b !== void 0 ? _b : 'Incorrect format';
47
- break;
48
- // The field's value is not of the correct input type
49
- case target.validity.badInput:
50
- // IE string in a number field
51
- errorMessage = (_c = target.dataset.badinput) !== null && _c !== void 0 ? _c : 'Wrong input type';
52
- break;
53
- // The field's value is above or below the range set in the "min" and "max" attributes
54
- case target.validity.rangeOverflow || target.validity.rangeUnderflow:
55
- // IE date or number is above or below value set in min or max tags
56
- errorMessage = (_d = target.dataset.range) !== null && _d !== void 0 ? _d : 'Invalid value';
57
- break;
58
- case target.validity.customError:
59
- errorMessage = target.validationMessage;
60
- break;
61
- // No error detected
62
- default:
63
- hasError = false;
64
- }
65
- // Return the error state
66
- return { target, hasError, errorMessage };
9
+ /**
10
+ * Validates the input field on focusout event by checking its validity state,
11
+ * sets an error message if there's an issue, and emits a "dataChanged" event to
12
+ * the parent component with the field name and its new value.
13
+ *
14
+ * @param {Event} event - The focusout event triggered by the input field.
15
+ * @return {void}
16
+ */
17
+ function validityCheck(event) {
18
+ var _a, _b, _c, _d;
19
+ event.preventDefault();
20
+ const target = event.target;
21
+ let hasError = true;
22
+ let errorMessage = '';
23
+ // validity object on HTML5 inputs has the following options
24
+ // badInput
25
+ // customError
26
+ // patternMismatch
27
+ // rangeOverflow
28
+ // rangeUnderflow
29
+ // stepMismatch
30
+ // tooLong
31
+ // tooShort
32
+ // typeMismatch
33
+ // valid
34
+ // valueMissing
35
+ // customErrors can be set with
36
+ // target.setCustomValidity('custom error!');
37
+ // and cleared with
38
+ // target.setCustomValidity('');
39
+ // Check the validity of the input field and set an error message if needed
40
+ switch (true) {
41
+ // The field is required, but has no value
42
+ case target.validity.valueMissing:
43
+ errorMessage = (_a = target.dataset.required) !== null && _a !== void 0 ? _a : 'This field is required';
44
+ break;
45
+ // The field's value does not match the expected pattern
46
+ case target.validity.patternMismatch:
47
+ errorMessage = (_b = target.dataset.pattern) !== null && _b !== void 0 ? _b : 'Incorrect format';
48
+ break;
49
+ // The field's value is not of the correct input type
50
+ case target.validity.badInput:
51
+ // IE string in a number field
52
+ errorMessage = (_c = target.dataset.badinput) !== null && _c !== void 0 ? _c : 'Wrong input type';
53
+ break;
54
+ // The field's value is above or below the range set in the "min" and "max" attributes
55
+ case target.validity.rangeOverflow || target.validity.rangeUnderflow:
56
+ // IE date or number is above or below value set in min or max tags
57
+ errorMessage = (_d = target.dataset.range) !== null && _d !== void 0 ? _d : 'Invalid value';
58
+ break;
59
+ case target.validity.customError:
60
+ errorMessage = target.validationMessage;
61
+ break;
62
+ // No error detected
63
+ default:
64
+ hasError = false;
65
+ }
66
+ // Return the error state
67
+ return { target, hasError, errorMessage };
67
68
  }
68
69
 
69
- /**
70
- * Sets the error state of an input field by updating its class and error message.
71
- * If an error was detected, it sets the input field's class to "invalid" and
72
- * displays the error message in an error bubble. If no error was detected,
73
- * it removes the "invalid" class from the input field and clears the error bubble.
74
- *
75
- * @param {HTMLInputElement} target - The input field to update.
76
- * @param {boolean} hasError - Whether an error was detected in the field.
77
- * @param {string} errorMessage - The error message to display (if any).
78
- * @return {void}
79
- */
80
- function setErrorState(target, hasError, errorMessage) {
81
- // Find the error bubble element for the input field
82
- const errorBubble = target.parentElement.querySelector('.errorBubble');
83
- // If an error was detected, set the input field's class to "invalid" and display the error message in the error bubble
84
- if (hasError) {
85
- target.classList.add('invalid');
86
- errorBubble.classList.add('visible');
87
- const errorIcon = document.createElement('span');
88
- // Set the class of the error icon to a pre-defined CSS class that specifies the icon's appearance
89
- errorIcon.className = 'material-symbols-rounded';
90
- // Set the text content of the error icon to the word "warning"
91
- errorIcon.textContent = 'warning';
92
- // errorBubble.replaceChildren cannot be used here because the tests don't support this new feature :(
93
- errorBubble.innerHTML = '';
94
- errorBubble.append(errorIcon);
95
- errorBubble.append(errorMessage);
96
- // errorBubble.replaceChildren(errorIcon, errorMessage);
97
- }
98
- // If no error was detected, remove the "invalid" class from the input field and clear the error bubble
99
- else {
100
- errorBubble.classList.remove('visible');
101
- target.classList.remove('invalid');
102
- errorBubble.innerHTML = '';
103
- }
70
+ /**
71
+ * Sets the error state of an input field by updating its class and error message.
72
+ * If an error was detected, it sets the input field's class to "invalid" and
73
+ * displays the error message in an error bubble. If no error was detected,
74
+ * it removes the "invalid" class from the input field and clears the error bubble.
75
+ *
76
+ * @param {HTMLInputElement} target - The input field to update.
77
+ * @param {boolean} hasError - Whether an error was detected in the field.
78
+ * @param {string} errorMessage - The error message to display (if any).
79
+ * @return {void}
80
+ */
81
+ function setErrorState(target, hasError, errorMessage) {
82
+ // Find the error bubble element for the input field
83
+ const errorBubble = target.parentElement.querySelector('.errorBubble');
84
+ // If an error was detected, set the input field's class to "invalid" and display the error message in the error bubble
85
+ if (hasError) {
86
+ target.classList.add('invalid');
87
+ errorBubble.classList.add('visible');
88
+ const errorIcon = document.createElement('span');
89
+ // Set the class of the error icon to a pre-defined CSS class that specifies the icon's appearance
90
+ errorIcon.className = 'material-symbols-rounded';
91
+ // Set the text content of the error icon to the word "warning"
92
+ errorIcon.textContent = 'warning';
93
+ // errorBubble.replaceChildren cannot be used here because the tests don't support this new feature :(
94
+ errorBubble.innerHTML = '';
95
+ errorBubble.append(errorIcon);
96
+ errorBubble.append(errorMessage);
97
+ // errorBubble.replaceChildren(errorIcon, errorMessage);
98
+ }
99
+ // If no error was detected, remove the "invalid" class from the input field and clear the error bubble
100
+ else {
101
+ errorBubble.classList.remove('visible');
102
+ target.classList.remove('invalid');
103
+ errorBubble.innerHTML = '';
104
+ }
104
105
  }
105
106
 
106
107
  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}.material-symbols-rounded{font-family:\"Material Symbols Rounded\", sans-serif;font-weight:normal;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;line-height:16px;border-radius:none;z-index:2;color:#dc0000}.errormsg .validationicon{width:16px;height:16px;font-size:16px;line-height:19px;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;line-height:19px;margin-bottom:16px}input:not([type=submit]){font-family:\"Roboto\", serif;box-sizing:border-box;width:100%;height:36px;padding:0 16px;font-size:16px;line-height:19px;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{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}input~.errorBubble:not(.visible){display:none}input~.errorBubble span{color:#dc0000;font-size:16px;margin-right:4px}input.invalid:invalid~.errorBubble{position:relative;font-size:14px;font-weight:normal;width:100%;font-family:\"Roboto\", sans-serif;color:#dc0000}input:focus{border-color:#1479c6}input:focus-visible{outline:none}.secondarylabel{color:#757575;font-size:14px;line-height:16px;font-weight:normal;display:flex;margin-top:4px}label.inputBlock.readonly{pointer-events:none;user-select:none;color:gray}input[readonly]{cursor:default;pointer-events:none;user-select:none;color:gray}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: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}label.inputBlock.inlineBlock{display:inline-block}.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}";
107
108
 
108
- const TttxForm = class {
109
- constructor(hostRef) {
110
- index.registerInstance(this, hostRef);
111
- this.dataSubmitted = index.createEvent(this, "dataSubmitted", 7);
112
- this.dataChanged = index.createEvent(this, "dataChanged", 7);
113
- // Create a new template element using the HTMLTemplateElement interface.
114
- this.template = document.createElement('template');
115
- this.formschema = undefined;
116
- this.data = undefined;
117
- }
118
- // This method is called whenever the "formschema" property changes
119
- onFormSchemaChange(newValue) {
120
- // If the formSchema changes and the form data is uncontrolled, store the data since the fields will be removed to avoid form duplication
121
- if (!this.data && this.form && this._formSchema) {
122
- const formData = new FormData(this.form);
123
- this._data = Object.fromEntries(Object.keys(this._formSchema.properties).map((formKey) => {
124
- return [
125
- formKey,
126
- formData.get(formKey)
127
- ];
128
- }));
129
- }
130
- // Check if the new value is a string, indicating that it needs to be parsed
131
- if (typeof newValue === 'string') {
132
- // Parse the string and set the "_formSchema" property
133
- this._formSchema = JSON.parse(newValue);
134
- }
135
- else {
136
- // If the new value is already an object, set the "_formSchema" property directly
137
- this._formSchema = newValue;
138
- }
139
- }
140
- onDataChange(newValue) {
141
- if (typeof newValue === 'string') {
142
- this._data = JSON.parse(newValue);
143
- }
144
- else {
145
- this._data = newValue;
146
- }
147
- }
148
- /**
149
- * Handles the focus event for a form field and emits a "dataChanged" event
150
- * to the parent component with the field name and its new value.
151
- *
152
- * @param {ChangeEvent} event - The focus event triggered by the field.
153
- * @return {void}
154
- */
155
- fieldChanged(event) {
156
- // Extract the name and value of the field from the event
157
- const fieldName = event.target.name;
158
- const fieldValue = event.target.value;
159
- // Emit an event to signal that the field's data has changed
160
- this.dataChanged.emit({ name: fieldName, value: fieldValue });
161
- }
162
- async submit() {
163
- this.submitButton.click();
164
- }
165
- /**
166
- * Submits the form data to the server.
167
- *
168
- * @param {SubmitEvent} event - The event object for the form submission.
169
- * @returns {void}
170
- *
171
- * @example
172
- * const form = document.getElementById('myForm');
173
- * form.addEventListener('submit', (event) => {
174
- * doSubmit(event);
175
- * });
176
- */
177
- doSubmit(event) {
178
- // prevent the form from submitting normally
179
- event.preventDefault();
180
- // create a new FormData object with the form data
181
- const formData = new FormData(event.target);
182
- // emit the form data through the `dataSubmitted` event
183
- this.dataSubmitted.emit(formData);
184
- }
185
- // This method is called before the component is loaded into the DOM
186
- componentWillLoad() {
187
- // Initialize the form schema by calling the "onFormSchemaChange" method with the current "formschema" property
188
- this.onFormSchemaChange(this.formschema);
189
- if (this.data) {
190
- this.onDataChange(this.data);
191
- }
192
- }
193
- // This method is called before the component is rendered
194
- componentWillRender() {
195
- // Clear the template to account for a potential re-render scenario
196
- this.template = document.createElement('template');
197
- // Populate the form from the form schema
198
- this.populateFormFromSchema();
199
- }
200
- /**
201
- * Creates a new HTMLSelectElement with a set of options.
202
- *
203
- * @param {string} formKey - The name of the dropdown field, as specified in the form schema.
204
- * @param {Object} formProperties - An object containing additional properties, such as the field type and options properties.
205
- * @param {'select'} formProperties.type - The type of form field. In this case, it will always be "select".
206
- * @param {Object} formProperties.validation - A set of validation rules for the field.
207
- * @param {Object[]} formProperties.options - A list of properties to pass to the select options.
208
- * @param {string} formProperties.options.label - The visible value of the option.
209
- * @param {string} formProperties.options.value - The actual value of the option.
210
- */
211
- createSelect(formKey, formProperties) {
212
- const select = document.createElement('select');
213
- select.setAttribute('name', formKey);
214
- formProperties.options.forEach(optionProperties => {
215
- this.appendOption(select, optionProperties);
216
- });
217
- if (this._data && this._data[formKey])
218
- select.classList.remove('placeholder');
219
- return select;
220
- }
221
- /**
222
- * Appends an option to a select element
223
- *
224
- * @param {HTMLSelectElement} select - The select elements to attach the option to.
225
- * @param {value} value - The value of the option.
226
- * @param {label} label - The label which will be displayed on the form for the option.
227
- */
228
- appendOption(select, optionProperties) {
229
- const option = document.createElement('option');
230
- option.setAttribute('value', optionProperties.value);
231
- if (optionProperties.placeholder) {
232
- option.setAttribute('disabled', '');
233
- option.setAttribute('selected', '');
234
- option.setAttribute('hidden', '');
235
- select.classList.add('placeholder');
236
- }
237
- if (optionProperties.label)
238
- option.innerHTML = domsanitiser_options.purify.sanitize(optionProperties.label, domsanitiser_options.domSanitiserOptions);
239
- select.appendChild(option);
240
- }
241
- /**
242
- * Creates a new HTMLInputElement with the specified name, type, and placeholder (if any),
243
- * and sets its autocomplete and autocapitalization properties to off.
244
- *
245
- * @param {string} formKey - The name of the input field, as specified in the form schema.
246
- * @param {Object} formProperties - An object containing additional properties for the input field, such as its type and placeholder value.
247
- * @param {string} formProperties.type - The type of the input field (e.g., "text", "email", "number", etc.).
248
- * @param {string} [formProperties.placeholder] - An optional placeholder value to display in the input field.
249
- * @return {HTMLInputElement} - The new input element.
250
- */
251
- createInput(formKey, formProperties) {
252
- var _a;
253
- // Create a new <input> element with the specified name and type
254
- const input = document.createElement('input');
255
- input.name = formKey;
256
- input.type = formProperties.type;
257
- // Set the placeholder attribute to the specified value (if any)
258
- input.placeholder = (_a = formProperties.placeholder) !== null && _a !== void 0 ? _a : '';
259
- // Disable autocomplete and autocapitalization
260
- input.autocomplete = 'off';
261
- input.autocapitalize = 'off';
262
- if (formProperties.readonly) {
263
- input.readOnly = true;
264
- }
265
- // Return the input element
266
- return input;
267
- }
268
- /**
269
- * Applies validation attributes to an input element based on the specified validation object.
270
- * If a certain property is present in the object, it will set the corresponding attribute on
271
- * the input element (e.g., "required" will set the "required" and "data-required" attributes,
272
- * "pattern" will set the "pattern" and "data-pattern" attributes, etc.).
273
- *
274
- * @param {HTMLInputElement} input - The input element to apply validation attributes to.
275
- * @param {Object} validation - An object containing the validation rules for the input field.
276
- * @param {Object} [validation.required] - An object containing a "message" property to display if the field is required.
277
- * @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.
278
- * @param {Object} [validation.badInput] - An object containing a "message" property to display if the field value is invalid.
279
- * @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.
280
- * @param {string} [validation.maxlength] - The maximum length of the input field.
281
- * @return {void}
282
- */
283
- applyValidation(input, validation) {
284
- var _a, _b;
285
- // If the "required" property is present, add the "required" attribute to the input element and
286
- // set its "data-required" attribute to the specified message (if any)
287
- if (validation.required) {
288
- input.setAttribute('required', '');
289
- input.setAttribute('data-required', (_a = validation.required.message) !== null && _a !== void 0 ? _a : '');
290
- }
291
- // If the "pattern" property is present, add the "pattern" attribute to the input element and set
292
- // its "data-pattern" attribute to the specified message (if any)
293
- if (validation.pattern) {
294
- input.setAttribute('pattern', validation.pattern.pattern);
295
- input.setAttribute('data-pattern', (_b = validation.pattern.message) !== null && _b !== void 0 ? _b : '');
296
- }
297
- // If the "badInput" property is present, set the input element's "data-badinput" attribute to
298
- // the specified message
299
- if (validation.badInput) {
300
- input.setAttribute('data-badinput', validation.badInput.message);
301
- }
302
- // If the "minmax" property is present, add the "min" and "max" attributes to the input element
303
- // and set its "data-range" attribute to the specified message (if any)
304
- if (validation.minmax) {
305
- input.setAttribute('min', validation.minmax.min);
306
- input.setAttribute('max', validation.minmax.max);
307
- input.setAttribute('data-range', validation.minmax.message);
308
- }
309
- // If the "maxlength" property is present, add the "maxlength" attribute to the input element
310
- if (validation.maxlength) {
311
- input.setAttribute('maxlength', validation.maxlength);
312
- }
313
- }
314
- // Create a new error bubble element
315
- createErrorBubble() {
316
- // Create a new <div> element with the "errorBubble" class
317
- const errorBubble = document.createElement('div');
318
- errorBubble.className = 'errorBubble';
319
- // Return the error bubble element
320
- return errorBubble;
321
- }
322
- appendCheckboxInput(formProperties, input, label) {
323
- if (formProperties.label) {
324
- const lineBreak = document.createElement('br');
325
- label.appendChild(lineBreak);
326
- }
327
- // Append the input element and error bubble element to the label
328
- label.appendChild(input);
329
- if (!formProperties.inlineLabel)
330
- return;
331
- const inlineLabel = document.createElement('span');
332
- inlineLabel.className = 'inlineLabel';
333
- inlineLabel.textContent = formProperties.inlineLabel;
334
- label.appendChild(inlineLabel);
335
- }
336
- /**
337
- * Creates a new <label> element with the "inputBlock" class and the specified label text,
338
- * and appends the input element and error bubble element to it. If the form property has
339
- * no validation object, it adds an "optional" span element to the label.
340
- *
341
- * @param {Object} formProperties - An object containing properties for the form field, including its label text and validation rules.
342
- * @param {HTMLInputElement} input - The input element to associate with the label.
343
- * @param {HTMLDivElement} errorBubble - The error bubble element to display error messages in.
344
- * @return {HTMLLabelElement} - The new label element.
345
- */
346
- createLabel(formProperties, input, errorBubble) {
347
- // Create a new <label> element with the "inputBlock" class and the specified text
348
- const label = document.createElement('label');
349
- label.className = 'inputBlock';
350
- label.innerText = formProperties.label;
351
- // If the form property has no validation object, add an "optional" span element to the label
352
- if (!formProperties.validation) {
353
- const optionalSpan = document.createElement('span');
354
- optionalSpan.className = 'optional';
355
- optionalSpan.innerHTML = '&nbsp;(optional)';
356
- label.appendChild(optionalSpan);
357
- }
358
- if (formProperties.readonly) {
359
- label.classList.add('readonly');
360
- }
361
- if (formProperties.type === 'checkbox') {
362
- label.className += ' inlineBlock';
363
- this.appendCheckboxInput(formProperties, input, label);
364
- }
365
- else {
366
- // Append the input element and error bubble element to the label
367
- label.appendChild(input);
368
- }
369
- label.appendChild(errorBubble);
370
- // Return the label element
371
- return label;
372
- }
373
- /**
374
- * Populates the form template with input fields and labels based on the properties of the
375
- * current form schema. For each property in the schema, it creates an input element, applies
376
- * any validation rules to it, creates an error bubble and label element, and appends them
377
- * to the form template. Finally, it creates and appends a submit button element to the form.
378
- *
379
- * @return {void}
380
- */
381
- populateFormFromSchema() {
382
- // If there is no form schema, return early
383
- if (!this._formSchema)
384
- return;
385
- // Get the properties of the form schema and their keys
386
- const properties = this._formSchema.properties;
387
- const propertyKeys = Object.keys(properties);
388
- // Loop through each property key and create an input, label, and error bubble for it
389
- propertyKeys.forEach(formKey => {
390
- const formItem = properties[formKey];
391
- const formProperties = formItem.form;
392
- const input = formProperties.type === 'select' ? this.createSelect(formKey, formProperties) : this.createInput(formKey, formProperties);
393
- // If the form property has validation, apply it to the input
394
- if (formProperties.validation) {
395
- this.applyValidation(input, formProperties.validation);
396
- }
397
- // Create an error bubble and label element for the input
398
- const errorBubble = this.createErrorBubble();
399
- const label = this.createLabel(formProperties, input, errorBubble);
400
- // Append the label element to the form template
401
- this.template.content.append(label);
402
- });
403
- }
404
- /**
405
- * Clones the form template and binds event listeners to its input elements. First, it checks if
406
- * there is a form schema present. If so, it clones the template's content, binds events to form
407
- * input elements, and appends the cloned form elements to the fieldset. The event listeners include
408
- * "oninvalid" (to check input validity on submit), "onblur" (to check input validity on blur),
409
- * "onkeyup" (to handle changes in input fields), and "onchange" (to handle changes in select fields).
410
- *
411
- * @return {void}
412
- */
413
- componentDidRender() {
414
- // If there's no form schema, return
415
- if (!this._formSchema) {
416
- return;
417
- }
418
- // Clone the template's content and store it in a variable
419
- const formItems = this.template.content.cloneNode(true);
420
- // Bind event listeners to form elements
421
- const properties = this._formSchema.properties;
422
- const propertyKeys = Object.keys(properties);
423
- propertyKeys.forEach(formKey => {
424
- var _a;
425
- const formInput = formItems.querySelector(`[name=${formKey}]`);
426
- // Bind events to form input elements
427
- formInput.oninvalid = this.validityCheckWrapper.bind(this);
428
- formInput.onblur = this.validityCheckWrapper.bind(this);
429
- formInput.onkeyup = this.fieldChanged.bind(this);
430
- formInput.onchange = this.fieldChanged.bind(this);
431
- if (this._data && this._data[formKey] !== undefined && this._data[formKey] !== null) {
432
- formInput.value = this._data[formKey];
433
- }
434
- // If explicitly setting input as invalid, set invalid state and error message on render
435
- if ((_a = properties[formKey].form.validation) === null || _a === void 0 ? void 0 : _a.invalid) {
436
- const errorMessage = properties[formKey].form.validation.invalid.message;
437
- formInput.setCustomValidity(errorMessage); // Prevents the invalid styling from resetting on blur
438
- setErrorState(formInput, true, errorMessage);
439
- }
440
- if (properties[formKey].form.type === 'select' && formInput.classList.contains('placeholder')) {
441
- formInput.addEventListener('change', () => {
442
- formInput.classList.remove('placeholder');
443
- });
444
- }
445
- });
446
- // Append the cloned form elements to the fieldset
447
- this.fieldset.replaceChildren(formItems);
448
- }
449
- validityCheckWrapper(event) {
450
- const { target, hasError, errorMessage } = validityCheck(event);
451
- setErrorState(target, hasError, errorMessage);
452
- }
453
- /**
454
- * Renders the component's template as a form element with a fieldset container. The form's
455
- * "onSubmit" event is bound to the "doSubmit" function, which handles the form submission
456
- * and emits a "dataSubmitted" event with the form data. The fieldset element is assigned
457
- * to the "fieldset" instance variable using a ref, so it can be populated with form elements
458
- * later on.
459
- *
460
- * @return {JSX.Element} - The rendered form template as a JSX element.
461
- */
462
- render() {
463
- return (index.h(index.Host, null, index.h("form", { ref: el => (this.form = el), onSubmit: this.doSubmit.bind(this) }, index.h("fieldset", { ref: el => (this.fieldset = el) }), index.h("input", { type: "submit", ref: el => (this.submitButton = el), style: { display: 'none' } }))));
464
- }
465
- static get watchers() { return {
466
- "formschema": ["onFormSchemaChange"],
467
- "data": ["onDataChange"]
468
- }; }
469
- };
109
+ const TttxForm = class {
110
+ constructor(hostRef) {
111
+ index.registerInstance(this, hostRef);
112
+ this.dataSubmitted = index.createEvent(this, "dataSubmitted", 7);
113
+ this.dataChanged = index.createEvent(this, "dataChanged", 7);
114
+ // Create a new template element using the HTMLTemplateElement interface.
115
+ this.template = document.createElement('template');
116
+ this.formschema = undefined;
117
+ this.data = undefined;
118
+ }
119
+ // This method is called whenever the "formschema" property changes
120
+ onFormSchemaChange(newValue) {
121
+ // If the formSchema changes and the form data is uncontrolled, store the data since the fields will be removed to avoid form duplication
122
+ if (!this.data && this.form && this._formSchema) {
123
+ const formData = new FormData(this.form);
124
+ this._data = Object.fromEntries(Object.keys(this._formSchema.properties).map((formKey) => {
125
+ return [
126
+ formKey,
127
+ formData.get(formKey)
128
+ ];
129
+ }));
130
+ }
131
+ // Check if the new value is a string, indicating that it needs to be parsed
132
+ if (typeof newValue === 'string') {
133
+ // Parse the string and set the "_formSchema" property
134
+ this._formSchema = JSON.parse(newValue);
135
+ }
136
+ else {
137
+ // If the new value is already an object, set the "_formSchema" property directly
138
+ this._formSchema = newValue;
139
+ }
140
+ }
141
+ onDataChange(newValue) {
142
+ if (typeof newValue === 'string') {
143
+ this._data = JSON.parse(newValue);
144
+ }
145
+ else {
146
+ this._data = newValue;
147
+ }
148
+ }
149
+ /**
150
+ * Handles the focus event for a form field and emits a "dataChanged" event
151
+ * to the parent component with the field name and its new value.
152
+ *
153
+ * @param {ChangeEvent} event - The focus event triggered by the field.
154
+ * @return {void}
155
+ */
156
+ fieldChanged(event) {
157
+ // Extract the name and value of the field from the event
158
+ const fieldName = event.target.name;
159
+ const fieldValue = event.target.value;
160
+ // Emit an event to signal that the field's data has changed
161
+ this.dataChanged.emit({ name: fieldName, value: fieldValue });
162
+ }
163
+ async submit() {
164
+ this.submitButton.click();
165
+ }
166
+ /**
167
+ * Submits the form data to the server.
168
+ *
169
+ * @param {SubmitEvent} event - The event object for the form submission.
170
+ * @returns {void}
171
+ *
172
+ * @example
173
+ * const form = document.getElementById('myForm');
174
+ * form.addEventListener('submit', (event) => {
175
+ * doSubmit(event);
176
+ * });
177
+ */
178
+ doSubmit(event) {
179
+ // prevent the form from submitting normally
180
+ event.preventDefault();
181
+ // create a new FormData object with the form data
182
+ const formData = new FormData(event.target);
183
+ // emit the form data through the `dataSubmitted` event
184
+ this.dataSubmitted.emit(formData);
185
+ }
186
+ // This method is called before the component is loaded into the DOM
187
+ componentWillLoad() {
188
+ // Initialize the form schema by calling the "onFormSchemaChange" method with the current "formschema" property
189
+ this.onFormSchemaChange(this.formschema);
190
+ if (this.data) {
191
+ this.onDataChange(this.data);
192
+ }
193
+ }
194
+ // This method is called before the component is rendered
195
+ componentWillRender() {
196
+ // Clear the template to account for a potential re-render scenario
197
+ this.template = document.createElement('template');
198
+ // Populate the form from the form schema
199
+ this.populateFormFromSchema();
200
+ }
201
+ /**
202
+ * Creates a new HTMLSelectElement with a set of options.
203
+ *
204
+ * @param {string} formKey - The name of the dropdown field, as specified in the form schema.
205
+ * @param {Object} formProperties - An object containing additional properties, such as the field type and options properties.
206
+ * @param {'select'} formProperties.type - The type of form field. In this case, it will always be "select".
207
+ * @param {Object} formProperties.validation - A set of validation rules for the field.
208
+ * @param {Object[]} formProperties.options - A list of properties to pass to the select options.
209
+ * @param {string} formProperties.options.label - The visible value of the option.
210
+ * @param {string} formProperties.options.value - The actual value of the option.
211
+ */
212
+ createSelect(formKey, formProperties) {
213
+ const select = document.createElement('select');
214
+ select.setAttribute('name', formKey);
215
+ formProperties.options.forEach(optionProperties => {
216
+ this.appendOption(select, optionProperties);
217
+ });
218
+ if (this._data && this._data[formKey])
219
+ select.classList.remove('placeholder');
220
+ return select;
221
+ }
222
+ /**
223
+ * Appends an option to a select element
224
+ *
225
+ * @param {HTMLSelectElement} select - The select elements to attach the option to.
226
+ * @param {value} value - The value of the option.
227
+ * @param {label} label - The label which will be displayed on the form for the option.
228
+ */
229
+ appendOption(select, optionProperties) {
230
+ const option = document.createElement('option');
231
+ option.setAttribute('value', optionProperties.value);
232
+ if (optionProperties.placeholder) {
233
+ option.setAttribute('disabled', '');
234
+ option.setAttribute('selected', '');
235
+ option.setAttribute('hidden', '');
236
+ select.classList.add('placeholder');
237
+ }
238
+ if (optionProperties.label)
239
+ option.innerHTML = domsanitiser_options.purify.sanitize(optionProperties.label, domsanitiser_options.domSanitiserOptions);
240
+ select.appendChild(option);
241
+ }
242
+ /**
243
+ * Creates a new HTMLInputElement with the specified name, type, and placeholder (if any),
244
+ * and sets its autocomplete and autocapitalization properties to off.
245
+ *
246
+ * @param {string} formKey - The name of the input field, as specified in the form schema.
247
+ * @param {Object} formProperties - An object containing additional properties for the input field, such as its type and placeholder value.
248
+ * @param {string} formProperties.type - The type of the input field (e.g., "text", "email", "number", etc.).
249
+ * @param {string} [formProperties.placeholder] - An optional placeholder value to display in the input field.
250
+ * @return {HTMLInputElement} - The new input element.
251
+ */
252
+ createInput(formKey, formProperties) {
253
+ var _a;
254
+ // Create a new <input> element with the specified name and type
255
+ const input = document.createElement('input');
256
+ input.name = formKey;
257
+ input.type = formProperties.type;
258
+ // Set the placeholder attribute to the specified value (if any)
259
+ input.placeholder = (_a = formProperties.placeholder) !== null && _a !== void 0 ? _a : '';
260
+ // Disable autocomplete and autocapitalization
261
+ input.autocomplete = 'off';
262
+ input.autocapitalize = 'off';
263
+ if (formProperties.readonly) {
264
+ input.readOnly = true;
265
+ }
266
+ // Return the input element
267
+ return input;
268
+ }
269
+ /**
270
+ * Applies validation attributes to an input element based on the specified validation object.
271
+ * If a certain property is present in the object, it will set the corresponding attribute on
272
+ * the input element (e.g., "required" will set the "required" and "data-required" attributes,
273
+ * "pattern" will set the "pattern" and "data-pattern" attributes, etc.).
274
+ *
275
+ * @param {HTMLInputElement} input - The input element to apply validation attributes to.
276
+ * @param {Object} validation - An object containing the validation rules for the input field.
277
+ * @param {Object} [validation.required] - An object containing a "message" property to display if the field is required.
278
+ * @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.
279
+ * @param {Object} [validation.badInput] - An object containing a "message" property to display if the field value is invalid.
280
+ * @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.
281
+ * @param {string} [validation.maxlength] - The maximum length of the input field.
282
+ * @return {void}
283
+ */
284
+ applyValidation(input, validation) {
285
+ var _a, _b;
286
+ // If the "required" property is present, add the "required" attribute to the input element and
287
+ // set its "data-required" attribute to the specified message (if any)
288
+ if (validation.required) {
289
+ input.setAttribute('required', '');
290
+ input.setAttribute('data-required', (_a = validation.required.message) !== null && _a !== void 0 ? _a : '');
291
+ }
292
+ // If the "pattern" property is present, add the "pattern" attribute to the input element and set
293
+ // its "data-pattern" attribute to the specified message (if any)
294
+ if (validation.pattern) {
295
+ input.setAttribute('pattern', validation.pattern.pattern);
296
+ input.setAttribute('data-pattern', (_b = validation.pattern.message) !== null && _b !== void 0 ? _b : '');
297
+ }
298
+ // If the "badInput" property is present, set the input element's "data-badinput" attribute to
299
+ // the specified message
300
+ if (validation.badInput) {
301
+ input.setAttribute('data-badinput', validation.badInput.message);
302
+ }
303
+ // If the "minmax" property is present, add the "min" and "max" attributes to the input element
304
+ // and set its "data-range" attribute to the specified message (if any)
305
+ if (validation.minmax) {
306
+ input.setAttribute('min', validation.minmax.min);
307
+ input.setAttribute('max', validation.minmax.max);
308
+ input.setAttribute('data-range', validation.minmax.message);
309
+ }
310
+ // If the "maxlength" property is present, add the "maxlength" attribute to the input element
311
+ if (validation.maxlength) {
312
+ input.setAttribute('maxlength', validation.maxlength);
313
+ }
314
+ }
315
+ // Create a new error bubble element
316
+ createErrorBubble() {
317
+ // Create a new <div> element with the "errorBubble" class
318
+ const errorBubble = document.createElement('div');
319
+ errorBubble.className = 'errorBubble';
320
+ // Return the error bubble element
321
+ return errorBubble;
322
+ }
323
+ appendCheckboxInput(formProperties, input, label) {
324
+ if (formProperties.label) {
325
+ const lineBreak = document.createElement('br');
326
+ label.appendChild(lineBreak);
327
+ }
328
+ // Append the input element and error bubble element to the label
329
+ label.appendChild(input);
330
+ if (!formProperties.inlineLabel)
331
+ return;
332
+ const inlineLabel = document.createElement('span');
333
+ inlineLabel.className = 'inlineLabel';
334
+ inlineLabel.textContent = formProperties.inlineLabel;
335
+ label.appendChild(inlineLabel);
336
+ }
337
+ /**
338
+ * Creates a new <label> element with the "inputBlock" class and the specified label text,
339
+ * and appends the input element and error bubble element to it. If the form property has
340
+ * no validation object, it adds an "optional" span element to the label.
341
+ *
342
+ * @param {Object} formProperties - An object containing properties for the form field, including its label text and validation rules.
343
+ * @param {HTMLInputElement} input - The input element to associate with the label.
344
+ * @param {HTMLDivElement} errorBubble - The error bubble element to display error messages in.
345
+ * @return {HTMLLabelElement} - The new label element.
346
+ */
347
+ createLabel(formProperties, input, errorBubble) {
348
+ // Create a new <label> element with the "inputBlock" class and the specified text
349
+ const label = document.createElement('label');
350
+ label.className = 'inputBlock';
351
+ label.innerText = formProperties.label;
352
+ // If the form property has no validation object, add an "optional" span element to the label
353
+ if (!formProperties.validation) {
354
+ const optionalSpan = document.createElement('span');
355
+ optionalSpan.className = 'optional';
356
+ optionalSpan.innerHTML = '&nbsp;(optional)';
357
+ label.appendChild(optionalSpan);
358
+ }
359
+ if (formProperties.readonly) {
360
+ label.classList.add('readonly');
361
+ }
362
+ if (formProperties.type === 'checkbox') {
363
+ label.className += ' inlineBlock';
364
+ this.appendCheckboxInput(formProperties, input, label);
365
+ }
366
+ else {
367
+ // Append the input element and error bubble element to the label
368
+ label.appendChild(input);
369
+ }
370
+ label.appendChild(errorBubble);
371
+ // Return the label element
372
+ return label;
373
+ }
374
+ /**
375
+ * Populates the form template with input fields and labels based on the properties of the
376
+ * current form schema. For each property in the schema, it creates an input element, applies
377
+ * any validation rules to it, creates an error bubble and label element, and appends them
378
+ * to the form template. Finally, it creates and appends a submit button element to the form.
379
+ *
380
+ * @return {void}
381
+ */
382
+ populateFormFromSchema() {
383
+ // If there is no form schema, return early
384
+ if (!this._formSchema)
385
+ return;
386
+ // Get the properties of the form schema and their keys
387
+ const properties = this._formSchema.properties;
388
+ const propertyKeys = Object.keys(properties);
389
+ // Loop through each property key and create an input, label, and error bubble for it
390
+ propertyKeys.forEach(formKey => {
391
+ const formItem = properties[formKey];
392
+ const formProperties = formItem.form;
393
+ const input = formProperties.type === 'select' ? this.createSelect(formKey, formProperties) : this.createInput(formKey, formProperties);
394
+ // If the form property has validation, apply it to the input
395
+ if (formProperties.validation) {
396
+ this.applyValidation(input, formProperties.validation);
397
+ }
398
+ // Create an error bubble and label element for the input
399
+ const errorBubble = this.createErrorBubble();
400
+ const label = this.createLabel(formProperties, input, errorBubble);
401
+ // Append the label element to the form template
402
+ this.template.content.append(label);
403
+ });
404
+ }
405
+ /**
406
+ * Clones the form template and binds event listeners to its input elements. First, it checks if
407
+ * there is a form schema present. If so, it clones the template's content, binds events to form
408
+ * input elements, and appends the cloned form elements to the fieldset. The event listeners include
409
+ * "oninvalid" (to check input validity on submit), "onblur" (to check input validity on blur),
410
+ * "onkeyup" (to handle changes in input fields), and "onchange" (to handle changes in select fields).
411
+ *
412
+ * @return {void}
413
+ */
414
+ componentDidRender() {
415
+ // If there's no form schema, return
416
+ if (!this._formSchema) {
417
+ return;
418
+ }
419
+ // Clone the template's content and store it in a variable
420
+ const formItems = this.template.content.cloneNode(true);
421
+ // Bind event listeners to form elements
422
+ const properties = this._formSchema.properties;
423
+ const propertyKeys = Object.keys(properties);
424
+ propertyKeys.forEach(formKey => {
425
+ var _a;
426
+ const formInput = formItems.querySelector(`[name=${formKey}]`);
427
+ // Bind events to form input elements
428
+ formInput.oninvalid = this.validityCheckWrapper.bind(this);
429
+ formInput.onblur = this.validityCheckWrapper.bind(this);
430
+ formInput.onkeyup = this.fieldChanged.bind(this);
431
+ formInput.onchange = this.fieldChanged.bind(this);
432
+ if (this._data && this._data[formKey] !== undefined && this._data[formKey] !== null) {
433
+ formInput.value = this._data[formKey];
434
+ }
435
+ // If explicitly setting input as invalid, set invalid state and error message on render
436
+ if ((_a = properties[formKey].form.validation) === null || _a === void 0 ? void 0 : _a.invalid) {
437
+ const errorMessage = properties[formKey].form.validation.invalid.message;
438
+ formInput.setCustomValidity(errorMessage); // Prevents the invalid styling from resetting on blur
439
+ setErrorState(formInput, true, errorMessage);
440
+ }
441
+ if (properties[formKey].form.type === 'select' && formInput.classList.contains('placeholder')) {
442
+ formInput.addEventListener('change', () => {
443
+ formInput.classList.remove('placeholder');
444
+ });
445
+ }
446
+ });
447
+ // Append the cloned form elements to the fieldset
448
+ this.fieldset.replaceChildren(formItems);
449
+ }
450
+ validityCheckWrapper(event) {
451
+ const { target, hasError, errorMessage } = validityCheck(event);
452
+ setErrorState(target, hasError, errorMessage);
453
+ }
454
+ /**
455
+ * Renders the component's template as a form element with a fieldset container. The form's
456
+ * "onSubmit" event is bound to the "doSubmit" function, which handles the form submission
457
+ * and emits a "dataSubmitted" event with the form data. The fieldset element is assigned
458
+ * to the "fieldset" instance variable using a ref, so it can be populated with form elements
459
+ * later on.
460
+ *
461
+ * @return {JSX.Element} - The rendered form template as a JSX element.
462
+ */
463
+ render() {
464
+ return (index.h(index.Host, null, index.h("form", { ref: el => (this.form = el), onSubmit: this.doSubmit.bind(this) }, index.h("fieldset", { ref: el => (this.fieldset = el) }), index.h("input", { type: "submit", ref: el => (this.submitButton = el), style: { display: 'none' } }))));
465
+ }
466
+ static get watchers() { return {
467
+ "formschema": ["onFormSchemaChange"],
468
+ "data": ["onDataChange"]
469
+ }; }
470
+ };
470
471
  TttxForm.style = tttxFormCss;
471
472
 
472
473
  exports.tttx_form = TttxForm;