@3t-transform/threeteeui 0.1.37 → 0.1.41

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