@3t-transform/threeteeui 0.1.21 → 0.1.23

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 (120) hide show
  1. package/dist/cjs/{index-b8a62ede.js → index-dc6cc829.js} +2 -88
  2. package/dist/cjs/loader.cjs.js +3 -4
  3. package/dist/cjs/tttx-button.cjs.entry.js +24 -24
  4. package/dist/cjs/tttx-filter.cjs.entry.js +152 -152
  5. package/dist/cjs/tttx-form.cjs.entry.js +363 -363
  6. package/dist/cjs/tttx-icon.cjs.entry.js +11 -11
  7. package/dist/cjs/tttx-keyvalue-block.cjs.entry.js +59 -59
  8. package/dist/cjs/tttx-list.cjs.entry.js +43 -43
  9. package/dist/cjs/tttx-loading-spinner.cjs.entry.js +16 -16
  10. package/dist/cjs/tttx-sorter.cjs.entry.js +112 -0
  11. package/dist/cjs/tttx-standalone-input.cjs.entry.js +60 -60
  12. package/dist/cjs/tttx-toolbar.cjs.entry.js +10 -10
  13. package/dist/cjs/tttx.cjs.js +3 -7
  14. package/dist/collection/collection-manifest.json +3 -2
  15. package/dist/collection/components/atoms/tttx-button/tttx-button.js +110 -110
  16. package/dist/collection/components/atoms/tttx-button/tttx-button.stories.js +14 -14
  17. package/dist/collection/components/atoms/tttx-icon/tttx-icon.js +62 -62
  18. package/dist/collection/components/atoms/tttx-icon/tttx-icon.stories.js +22 -22
  19. package/dist/collection/components/atoms/tttx-keyvalue-block/tttx-keyvalue-block.js +109 -109
  20. package/dist/collection/components/atoms/tttx-keyvalue-block/tttx-keyvalue-block.stories.js +38 -38
  21. package/dist/collection/components/atoms/tttx-loading-spinner/tttx-loading-spinner.js +67 -67
  22. package/dist/collection/components/atoms/tttx-loading-spinner/tttx-loading-spinner.stories.js +17 -17
  23. package/dist/collection/components/molecules/tttx-filter/tttx-filter.js +325 -325
  24. package/dist/collection/components/molecules/tttx-filter/tttx-filter.stories.js +89 -89
  25. package/dist/collection/components/molecules/tttx-form/lib/setErrorState.js +35 -35
  26. package/dist/collection/components/molecules/tttx-form/lib/validityCheck.js +58 -58
  27. package/dist/collection/components/molecules/tttx-form/tttx-form.js +364 -364
  28. package/dist/collection/components/molecules/tttx-form/tttx-form.stories.js +127 -127
  29. package/dist/collection/components/molecules/tttx-list/tttx-list.js +105 -105
  30. package/dist/collection/components/molecules/tttx-list/tttx-list.stories.js +43 -43
  31. package/dist/collection/components/molecules/tttx-sorter/tttx-sorter.css +108 -0
  32. package/dist/collection/components/molecules/tttx-sorter/tttx-sorter.js +224 -0
  33. package/dist/collection/components/molecules/tttx-sorter/tttx-sorter.stories.js +49 -0
  34. package/dist/collection/components/molecules/tttx-standalone-input/tttx-standalone-input.js +627 -627
  35. package/dist/collection/components/molecules/tttx-standalone-input/tttx-standalone-input.stories.js +157 -157
  36. package/dist/collection/components/molecules/tttx-toolbar/tttx-toolbar.js +44 -44
  37. package/dist/collection/components/molecules/tttx-toolbar/tttx-toolbar.stories.js +14 -14
  38. package/dist/collection/components/palette.stories.js +7 -7
  39. package/dist/collection/docs/gettingstarted-developer.stories.js +5 -5
  40. package/dist/collection/icons.js +2838 -2838
  41. package/dist/collection/index.js +1 -1
  42. package/dist/collection/shared/domsanitiser.options.js +14 -14
  43. package/dist/components/index.d.ts +1 -9
  44. package/dist/components/index.js +2 -1
  45. package/dist/components/tttx-button.js +48 -48
  46. package/dist/components/tttx-filter.js +184 -184
  47. package/dist/components/tttx-form.js +380 -380
  48. package/dist/components/tttx-icon2.js +28 -28
  49. package/dist/components/tttx-keyvalue-block.js +76 -76
  50. package/dist/components/tttx-list.js +65 -65
  51. package/dist/components/tttx-loading-spinner.js +33 -33
  52. package/dist/components/tttx-sorter.d.ts +11 -0
  53. package/dist/components/tttx-sorter.js +141 -0
  54. package/dist/components/tttx-standalone-input.js +107 -107
  55. package/dist/components/tttx-toolbar.js +26 -26
  56. package/dist/esm/{index-e888a5f4.js → index-86faeaab.js} +3 -88
  57. package/dist/esm/loader.js +3 -4
  58. package/dist/esm/polyfills/core-js.js +0 -0
  59. package/dist/esm/polyfills/css-shim.js +1 -1
  60. package/dist/esm/polyfills/dom.js +0 -0
  61. package/dist/esm/polyfills/es5-html-element.js +0 -0
  62. package/dist/esm/polyfills/index.js +0 -0
  63. package/dist/esm/polyfills/system.js +0 -0
  64. package/dist/esm/tttx-button.entry.js +24 -24
  65. package/dist/esm/tttx-filter.entry.js +152 -152
  66. package/dist/esm/tttx-form.entry.js +363 -363
  67. package/dist/esm/tttx-icon.entry.js +11 -11
  68. package/dist/esm/tttx-keyvalue-block.entry.js +59 -59
  69. package/dist/esm/tttx-list.entry.js +43 -43
  70. package/dist/esm/tttx-loading-spinner.entry.js +16 -16
  71. package/dist/esm/tttx-sorter.entry.js +108 -0
  72. package/dist/esm/tttx-standalone-input.entry.js +60 -60
  73. package/dist/esm/tttx-toolbar.entry.js +10 -10
  74. package/dist/esm/tttx.js +3 -4
  75. package/dist/tttx/p-12fc0b16.entry.js +3 -0
  76. package/dist/tttx/p-52a47b7c.js +2 -0
  77. package/dist/tttx/{p-41f5b296.entry.js → p-603f6ebe.entry.js} +1 -1
  78. package/dist/tttx/{p-e145951b.entry.js → p-72b4c98a.entry.js} +1 -1
  79. package/dist/tttx/{p-043f9b8a.entry.js → p-8f3badad.entry.js} +1 -1
  80. package/dist/tttx/{p-4cf3e1e0.entry.js → p-ae48fe5a.entry.js} +1 -1
  81. package/dist/tttx/{p-01f4628e.entry.js → p-bdb054b2.entry.js} +1 -1
  82. package/dist/tttx/{p-dc5c356b.entry.js → p-c72d1a03.entry.js} +1 -1
  83. package/dist/tttx/{p-96bbf1ed.entry.js → p-e25d5fe2.entry.js} +1 -1
  84. package/dist/tttx/p-f19194f8.entry.js +1 -0
  85. package/dist/tttx/{p-b3a03986.entry.js → p-f1d7eb35.entry.js} +1 -1
  86. package/dist/tttx/tttx.esm.js +1 -1
  87. package/dist/types/components/atoms/tttx-button/tttx-button.d.ts +10 -10
  88. package/dist/types/components/atoms/tttx-button/tttx-button.stories.d.ts +10 -10
  89. package/dist/types/components/atoms/tttx-icon/tttx-icon.d.ts +5 -5
  90. package/dist/types/components/atoms/tttx-icon/tttx-icon.stories.d.ts +20 -20
  91. package/dist/types/components/atoms/tttx-keyvalue-block/tttx-keyvalue-block.d.ts +7 -7
  92. package/dist/types/components/atoms/tttx-keyvalue-block/tttx-keyvalue-block.stories.d.ts +9 -9
  93. package/dist/types/components/atoms/tttx-loading-spinner/tttx-loading-spinner.d.ts +6 -6
  94. package/dist/types/components/atoms/tttx-loading-spinner/tttx-loading-spinner.stories.d.ts +17 -17
  95. package/dist/types/components/molecules/tttx-filter/tttx-filter.d.ts +37 -37
  96. package/dist/types/components/molecules/tttx-filter/tttx-filter.stories.d.ts +43 -43
  97. package/dist/types/components/molecules/tttx-form/lib/setErrorState.d.ts +13 -13
  98. package/dist/types/components/molecules/tttx-form/lib/validityCheck.d.ts +17 -17
  99. package/dist/types/components/molecules/tttx-form/tttx-form.d.ts +114 -114
  100. package/dist/types/components/molecules/tttx-form/tttx-form.stories.d.ts +13 -13
  101. package/dist/types/components/molecules/tttx-list/tttx-list.d.ts +11 -11
  102. package/dist/types/components/molecules/tttx-list/tttx-list.stories.d.ts +14 -14
  103. package/dist/types/components/molecules/tttx-sorter/interfaces.d.ts +9 -0
  104. package/dist/types/components/molecules/tttx-sorter/tttx-sorter.d.ts +19 -0
  105. package/dist/types/components/molecules/tttx-sorter/tttx-sorter.stories.d.ts +30 -0
  106. package/dist/types/components/molecules/tttx-standalone-input/tttx-standalone-input.d.ts +56 -56
  107. package/dist/types/components/molecules/tttx-standalone-input/tttx-standalone-input.stories.d.ts +123 -123
  108. package/dist/types/components/molecules/tttx-toolbar/tttx-toolbar.d.ts +4 -4
  109. package/dist/types/components/molecules/tttx-toolbar/tttx-toolbar.stories.d.ts +13 -13
  110. package/dist/types/components/palette.stories.d.ts +6 -6
  111. package/dist/types/components.d.ts +27 -0
  112. package/dist/types/docs/gettingstarted-developer.stories.d.ts +5 -5
  113. package/dist/types/icons.d.ts +2 -2
  114. package/dist/types/index.d.ts +1 -1
  115. package/dist/types/shared/domsanitiser.options.d.ts +10 -10
  116. package/dist/types/stencil-public-runtime.d.ts +3 -59
  117. package/loader/index.d.ts +0 -9
  118. package/package.json +1 -1
  119. package/dist/tttx/p-6dff6b5a.entry.js +0 -3
  120. package/dist/tttx/p-f764ffc4.js +0 -2
@@ -1,364 +1,364 @@
1
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
2
- import { h, Host } from '@stencil/core';
3
- import validityCheck from './lib/validityCheck';
4
- import setErrorState from './lib/setErrorState';
5
- export class TttxForm {
6
- constructor() {
7
- // Create a new template element using the HTMLTemplateElement interface.
8
- this.template = document.createElement('template');
9
- this.formschema = undefined;
10
- this.submitValue = undefined;
11
- }
12
- // This method is called whenever the "formschema" property changes
13
- onFormSchemaChange(newValue) {
14
- // Check if the new value is a string, indicating that it needs to be parsed
15
- if (typeof newValue === 'string') {
16
- // Parse the string and set the "_formSchema" property
17
- this._formSchema = JSON.parse(newValue);
18
- }
19
- else {
20
- // If the new value is already an object, set the "_formSchema" property directly
21
- this._formSchema = newValue;
22
- }
23
- }
24
- /**
25
- * Handles the focus event for a form field and emits a "dataChanged" event
26
- * to the parent component with the field name and its new value.
27
- *
28
- * @param {ChangeEvent} event - The focus event triggered by the field.
29
- * @return {void}
30
- */
31
- fieldChanged(event) {
32
- // Extract the name and value of the field from the event
33
- const fieldName = event.target.name;
34
- const fieldValue = event.target.value;
35
- // Emit an event to signal that the field's data has changed
36
- this.dataChanged.emit({ name: fieldName, value: fieldValue });
37
- }
38
- /**
39
- * Submits the form data to the server.
40
- *
41
- * @param {SubmitEvent} event - The event object for the form submission.
42
- * @returns {void}
43
- *
44
- * @example
45
- * const form = document.getElementById('myForm');
46
- * form.addEventListener('submit', (event) => {
47
- * doSubmit(event);
48
- * });
49
- */
50
- doSubmit(event) {
51
- // prevent the form from submitting normally
52
- event.preventDefault();
53
- // create a new FormData object with the form data
54
- const formData = new FormData(event.target);
55
- // emit the form data through the `dataSubmitted` event
56
- this.dataSubmitted.emit(formData);
57
- }
58
- // This method is called before the component is loaded into the DOM
59
- componentWillLoad() {
60
- // Initialize the form schema by calling the "onFormSchemaChange" method with the current "formschema" property
61
- this.onFormSchemaChange(this.formschema);
62
- }
63
- // This method is called before the component is rendered
64
- componentWillRender() {
65
- // Clear the template to account for a potential re-render scenario
66
- this.template = document.createElement('template');
67
- // Populate the form from the form schema
68
- this.populateFormFromSchema();
69
- }
70
- /**
71
- * Creates a new HTMLInputElement with the specified name, type, and placeholder (if any),
72
- * and sets its autocomplete and autocapitalization properties to off.
73
- *
74
- * @param {string} formKey - The name of the input field, as specified in the form schema.
75
- * @param {Object} formProperties - An object containing additional properties for the input field, such as its type and placeholder value.
76
- * @param {string} formProperties.type - The type of the input field (e.g., "text", "email", "number", etc.).
77
- * @param {string} [formProperties.placeholder] - An optional placeholder value to display in the input field.
78
- * @return {HTMLInputElement} - The new input element.
79
- */
80
- createInput(formKey, formProperties) {
81
- var _a;
82
- // Create a new <input> element with the specified name and type
83
- const input = document.createElement('input');
84
- input.name = formKey;
85
- input.type = formProperties.type;
86
- // Set the placeholder attribute to the specified value (if any)
87
- input.placeholder = (_a = formProperties.placeholder) !== null && _a !== void 0 ? _a : '';
88
- // Disable autocomplete and autocapitalization
89
- input.autocomplete = 'off';
90
- input.autocapitalize = 'off';
91
- // Return the input element
92
- return input;
93
- }
94
- /**
95
- * Applies validation attributes to an input element based on the specified validation object.
96
- * If a certain property is present in the object, it will set the corresponding attribute on
97
- * the input element (e.g., "required" will set the "required" and "data-required" attributes,
98
- * "pattern" will set the "pattern" and "data-pattern" attributes, etc.).
99
- *
100
- * @param {HTMLInputElement} input - The input element to apply validation attributes to.
101
- * @param {Object} validation - An object containing the validation rules for the input field.
102
- * @param {Object} [validation.required] - An object containing a "message" property to display if the field is required.
103
- * @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.
104
- * @param {Object} [validation.badInput] - An object containing a "message" property to display if the field value is invalid.
105
- * @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.
106
- * @param {string} [validation.maxlength] - The maximum length of the input field.
107
- * @return {void}
108
- */
109
- applyValidation(input, validation) {
110
- var _a, _b;
111
- // If the "required" property is present, add the "required" attribute to the input element and
112
- // set its "data-required" attribute to the specified message (if any)
113
- if (validation.required) {
114
- input.setAttribute('required', '');
115
- input.setAttribute('data-required', (_a = validation.required.message) !== null && _a !== void 0 ? _a : '');
116
- }
117
- // If the "pattern" property is present, add the "pattern" attribute to the input element and set
118
- // its "data-pattern" attribute to the specified message (if any)
119
- if (validation.pattern) {
120
- input.setAttribute('pattern', validation.pattern.pattern);
121
- input.setAttribute('data-pattern', (_b = validation.pattern.message) !== null && _b !== void 0 ? _b : '');
122
- }
123
- // If the "badInput" property is present, set the input element's "data-badinput" attribute to
124
- // the specified message
125
- if (validation.badInput) {
126
- input.setAttribute('data-badinput', validation.badInput.message);
127
- }
128
- // If the "minmax" property is present, add the "min" and "max" attributes to the input element
129
- // and set its "data-range" attribute to the specified message (if any)
130
- if (validation.minmax) {
131
- input.setAttribute('min', validation.minmax.min);
132
- input.setAttribute('max', validation.minmax.max);
133
- input.setAttribute('data-range', validation.minmax.message);
134
- }
135
- // If the "maxlength" property is present, add the "maxlength" attribute to the input element
136
- if (validation.maxlength) {
137
- input.setAttribute('maxlength', validation.maxlength);
138
- }
139
- }
140
- // Create a new error bubble element
141
- createErrorBubble() {
142
- // Create a new <div> element with the "errorBubble" class
143
- const errorBubble = document.createElement('div');
144
- errorBubble.className = 'errorBubble';
145
- // Return the error bubble element
146
- return errorBubble;
147
- }
148
- /**
149
- * Creates a new <label> element with the "inputBlock" class and the specified label text,
150
- * and appends the input element and error bubble element to it. If the form property has
151
- * no validation object, it adds an "optional" span element to the label.
152
- *
153
- * @param {Object} formProperties - An object containing properties for the form field, including its label text and validation rules.
154
- * @param {HTMLInputElement} input - The input element to associate with the label.
155
- * @param {HTMLDivElement} errorBubble - The error bubble element to display error messages in.
156
- * @return {HTMLLabelElement} - The new label element.
157
- */
158
- createLabel(formProperties, input, errorBubble) {
159
- // Create a new <label> element with the "inputBlock" class and the specified text
160
- const label = document.createElement('label');
161
- label.className = 'inputBlock';
162
- label.innerText = formProperties.label;
163
- // If the form property has no validation object, add an "optional" span element to the label
164
- if (!formProperties.validation) {
165
- const optionalSpan = document.createElement('span');
166
- optionalSpan.className = 'optional';
167
- optionalSpan.innerHTML = '&nbsp;(optional)';
168
- label.appendChild(optionalSpan);
169
- }
170
- // Append the input element and error bubble element to the label
171
- label.appendChild(input);
172
- label.appendChild(errorBubble);
173
- // Return the label element
174
- return label;
175
- }
176
- /**
177
- * Creates a new <input> element with the "submit" type, the "primary-blue" class, and the
178
- * specified label text (i.e., "Save" by default), and returns the new submit button element.
179
- *
180
- * @return {HTMLInputElement} - The new submit button element.
181
- */
182
- createSubmitButton() {
183
- // Create a new <input> element with the "submit" type and the specified class and value
184
- const submitButton = document.createElement('input');
185
- submitButton.type = 'submit';
186
- submitButton.className = 'button primary-blue';
187
- submitButton.value = 'Save';
188
- // Return the submit button element
189
- return submitButton;
190
- }
191
- /**
192
- * Populates the form template with input fields and labels based on the properties of the
193
- * current form schema. For each property in the schema, it creates an input element, applies
194
- * any validation rules to it, creates an error bubble and label element, and appends them
195
- * to the form template. Finally, it creates and appends a submit button element to the form.
196
- *
197
- * @return {void}
198
- */
199
- populateFormFromSchema() {
200
- // If there is no form schema, return early
201
- if (!this._formSchema)
202
- return;
203
- // Get the properties of the form schema and their keys
204
- const properties = this._formSchema.properties;
205
- const propertyKeys = Object.keys(properties);
206
- // Loop through each property key and create an input, label, and error bubble for it
207
- propertyKeys.forEach(formKey => {
208
- const formItem = properties[formKey];
209
- const formProperties = formItem.form;
210
- const input = this.createInput(formKey, formProperties);
211
- // If the form property has validation, apply it to the input
212
- if (formProperties.validation) {
213
- this.applyValidation(input, formProperties.validation);
214
- }
215
- // Create an error bubble and label element for the input
216
- const errorBubble = this.createErrorBubble();
217
- const label = this.createLabel(formProperties, input, errorBubble);
218
- // Append the label element to the form template
219
- this.template.content.append(label);
220
- });
221
- // Create and append a submit button element to the form template
222
- const submitButton = this.createSubmitButton();
223
- this.template.content.append(submitButton);
224
- }
225
- /**
226
- * Clones the form template and binds event listeners to its input elements. First, it checks if
227
- * there is a form schema present. If so, it clones the template's content, binds events to form
228
- * input elements, and appends the cloned form elements to the fieldset. The event listeners include
229
- * "oninvalid" (to check input validity on submit), "onblur" (to check input validity on blur),
230
- * "onkeyup" (to handle changes in input fields), and "onchange" (to handle changes in select fields).
231
- *
232
- * @return {void}
233
- */
234
- componentDidRender() {
235
- // If there's no form schema, return
236
- if (!this._formSchema) {
237
- return;
238
- }
239
- // Clone the template's content and store it in a variable
240
- const formItems = this.template.content.cloneNode(true);
241
- // Bind event listeners to form elements
242
- const properties = this._formSchema.properties;
243
- const propertyKeys = Object.keys(properties);
244
- propertyKeys.forEach((formKey) => {
245
- const formInput = formItems.querySelector(`[name=${formKey}]`);
246
- // Bind events to form input elements
247
- formInput.oninvalid = this.validityCheckWrapper.bind(this);
248
- formInput.onblur = this.validityCheckWrapper.bind(this);
249
- formInput.onkeyup = this.fieldChanged.bind(this);
250
- formInput.onchange = this.fieldChanged.bind(this);
251
- });
252
- // Append the cloned form elements to the fieldset
253
- this.fieldset.appendChild(formItems);
254
- }
255
- validityCheckWrapper(event) {
256
- const { target, hasError, errorMessage } = validityCheck(event);
257
- setErrorState(target, hasError, errorMessage);
258
- }
259
- /**
260
- * Renders the component's template as a form element with a fieldset container. The form's
261
- * "onSubmit" event is bound to the "doSubmit" function, which handles the form submission
262
- * and emits a "dataSubmitted" event with the form data. The fieldset element is assigned
263
- * to the "fieldset" instance variable using a ref, so it can be populated with form elements
264
- * later on.
265
- *
266
- * @return {JSX.Element} - The rendered form template as a JSX element.
267
- */
268
- render() {
269
- return (h(Host, null, h("form", { onSubmit: this.doSubmit.bind(this) }, h("fieldset", { ref: el => (this.fieldset = el) }))));
270
- }
271
- static get is() { return "tttx-form"; }
272
- static get encapsulation() { return "shadow"; }
273
- static get originalStyleUrls() {
274
- return {
275
- "$": ["tttx-form.scss"]
276
- };
277
- }
278
- static get styleUrls() {
279
- return {
280
- "$": ["tttx-form.css"]
281
- };
282
- }
283
- static get properties() {
284
- return {
285
- "formschema": {
286
- "type": "any",
287
- "mutable": true,
288
- "complexType": {
289
- "original": "any",
290
- "resolved": "any",
291
- "references": {}
292
- },
293
- "required": false,
294
- "optional": false,
295
- "docs": {
296
- "tags": [],
297
- "text": ""
298
- },
299
- "attribute": "formschema",
300
- "reflect": false
301
- },
302
- "submitValue": {
303
- "type": "any",
304
- "mutable": true,
305
- "complexType": {
306
- "original": "any",
307
- "resolved": "any",
308
- "references": {}
309
- },
310
- "required": false,
311
- "optional": false,
312
- "docs": {
313
- "tags": [],
314
- "text": ""
315
- },
316
- "attribute": "submit-value",
317
- "reflect": false
318
- }
319
- };
320
- }
321
- static get events() {
322
- return [{
323
- "method": "dataSubmitted",
324
- "name": "dataSubmitted",
325
- "bubbles": true,
326
- "cancelable": true,
327
- "composed": true,
328
- "docs": {
329
- "tags": [],
330
- "text": ""
331
- },
332
- "complexType": {
333
- "original": "FormData",
334
- "resolved": "FormData",
335
- "references": {
336
- "FormData": {
337
- "location": "global"
338
- }
339
- }
340
- }
341
- }, {
342
- "method": "dataChanged",
343
- "name": "dataChanged",
344
- "bubbles": true,
345
- "cancelable": true,
346
- "composed": true,
347
- "docs": {
348
- "tags": [],
349
- "text": ""
350
- },
351
- "complexType": {
352
- "original": "{ name: string, value: any }",
353
- "resolved": "{ name: string; value: any; }",
354
- "references": {}
355
- }
356
- }];
357
- }
358
- static get watchers() {
359
- return [{
360
- "propName": "formschema",
361
- "methodName": "onFormSchemaChange"
362
- }];
363
- }
364
- }
1
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
2
+ import { h, Host } from '@stencil/core';
3
+ import validityCheck from './lib/validityCheck';
4
+ import setErrorState from './lib/setErrorState';
5
+ export class TttxForm {
6
+ constructor() {
7
+ // Create a new template element using the HTMLTemplateElement interface.
8
+ this.template = document.createElement('template');
9
+ this.formschema = undefined;
10
+ this.submitValue = undefined;
11
+ }
12
+ // This method is called whenever the "formschema" property changes
13
+ onFormSchemaChange(newValue) {
14
+ // Check if the new value is a string, indicating that it needs to be parsed
15
+ if (typeof newValue === 'string') {
16
+ // Parse the string and set the "_formSchema" property
17
+ this._formSchema = JSON.parse(newValue);
18
+ }
19
+ else {
20
+ // If the new value is already an object, set the "_formSchema" property directly
21
+ this._formSchema = newValue;
22
+ }
23
+ }
24
+ /**
25
+ * Handles the focus event for a form field and emits a "dataChanged" event
26
+ * to the parent component with the field name and its new value.
27
+ *
28
+ * @param {ChangeEvent} event - The focus event triggered by the field.
29
+ * @return {void}
30
+ */
31
+ fieldChanged(event) {
32
+ // Extract the name and value of the field from the event
33
+ const fieldName = event.target.name;
34
+ const fieldValue = event.target.value;
35
+ // Emit an event to signal that the field's data has changed
36
+ this.dataChanged.emit({ name: fieldName, value: fieldValue });
37
+ }
38
+ /**
39
+ * Submits the form data to the server.
40
+ *
41
+ * @param {SubmitEvent} event - The event object for the form submission.
42
+ * @returns {void}
43
+ *
44
+ * @example
45
+ * const form = document.getElementById('myForm');
46
+ * form.addEventListener('submit', (event) => {
47
+ * doSubmit(event);
48
+ * });
49
+ */
50
+ doSubmit(event) {
51
+ // prevent the form from submitting normally
52
+ event.preventDefault();
53
+ // create a new FormData object with the form data
54
+ const formData = new FormData(event.target);
55
+ // emit the form data through the `dataSubmitted` event
56
+ this.dataSubmitted.emit(formData);
57
+ }
58
+ // This method is called before the component is loaded into the DOM
59
+ componentWillLoad() {
60
+ // Initialize the form schema by calling the "onFormSchemaChange" method with the current "formschema" property
61
+ this.onFormSchemaChange(this.formschema);
62
+ }
63
+ // This method is called before the component is rendered
64
+ componentWillRender() {
65
+ // Clear the template to account for a potential re-render scenario
66
+ this.template = document.createElement('template');
67
+ // Populate the form from the form schema
68
+ this.populateFormFromSchema();
69
+ }
70
+ /**
71
+ * Creates a new HTMLInputElement with the specified name, type, and placeholder (if any),
72
+ * and sets its autocomplete and autocapitalization properties to off.
73
+ *
74
+ * @param {string} formKey - The name of the input field, as specified in the form schema.
75
+ * @param {Object} formProperties - An object containing additional properties for the input field, such as its type and placeholder value.
76
+ * @param {string} formProperties.type - The type of the input field (e.g., "text", "email", "number", etc.).
77
+ * @param {string} [formProperties.placeholder] - An optional placeholder value to display in the input field.
78
+ * @return {HTMLInputElement} - The new input element.
79
+ */
80
+ createInput(formKey, formProperties) {
81
+ var _a;
82
+ // Create a new <input> element with the specified name and type
83
+ const input = document.createElement('input');
84
+ input.name = formKey;
85
+ input.type = formProperties.type;
86
+ // Set the placeholder attribute to the specified value (if any)
87
+ input.placeholder = (_a = formProperties.placeholder) !== null && _a !== void 0 ? _a : '';
88
+ // Disable autocomplete and autocapitalization
89
+ input.autocomplete = 'off';
90
+ input.autocapitalize = 'off';
91
+ // Return the input element
92
+ return input;
93
+ }
94
+ /**
95
+ * Applies validation attributes to an input element based on the specified validation object.
96
+ * If a certain property is present in the object, it will set the corresponding attribute on
97
+ * the input element (e.g., "required" will set the "required" and "data-required" attributes,
98
+ * "pattern" will set the "pattern" and "data-pattern" attributes, etc.).
99
+ *
100
+ * @param {HTMLInputElement} input - The input element to apply validation attributes to.
101
+ * @param {Object} validation - An object containing the validation rules for the input field.
102
+ * @param {Object} [validation.required] - An object containing a "message" property to display if the field is required.
103
+ * @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.
104
+ * @param {Object} [validation.badInput] - An object containing a "message" property to display if the field value is invalid.
105
+ * @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.
106
+ * @param {string} [validation.maxlength] - The maximum length of the input field.
107
+ * @return {void}
108
+ */
109
+ applyValidation(input, validation) {
110
+ var _a, _b;
111
+ // If the "required" property is present, add the "required" attribute to the input element and
112
+ // set its "data-required" attribute to the specified message (if any)
113
+ if (validation.required) {
114
+ input.setAttribute('required', '');
115
+ input.setAttribute('data-required', (_a = validation.required.message) !== null && _a !== void 0 ? _a : '');
116
+ }
117
+ // If the "pattern" property is present, add the "pattern" attribute to the input element and set
118
+ // its "data-pattern" attribute to the specified message (if any)
119
+ if (validation.pattern) {
120
+ input.setAttribute('pattern', validation.pattern.pattern);
121
+ input.setAttribute('data-pattern', (_b = validation.pattern.message) !== null && _b !== void 0 ? _b : '');
122
+ }
123
+ // If the "badInput" property is present, set the input element's "data-badinput" attribute to
124
+ // the specified message
125
+ if (validation.badInput) {
126
+ input.setAttribute('data-badinput', validation.badInput.message);
127
+ }
128
+ // If the "minmax" property is present, add the "min" and "max" attributes to the input element
129
+ // and set its "data-range" attribute to the specified message (if any)
130
+ if (validation.minmax) {
131
+ input.setAttribute('min', validation.minmax.min);
132
+ input.setAttribute('max', validation.minmax.max);
133
+ input.setAttribute('data-range', validation.minmax.message);
134
+ }
135
+ // If the "maxlength" property is present, add the "maxlength" attribute to the input element
136
+ if (validation.maxlength) {
137
+ input.setAttribute('maxlength', validation.maxlength);
138
+ }
139
+ }
140
+ // Create a new error bubble element
141
+ createErrorBubble() {
142
+ // Create a new <div> element with the "errorBubble" class
143
+ const errorBubble = document.createElement('div');
144
+ errorBubble.className = 'errorBubble';
145
+ // Return the error bubble element
146
+ return errorBubble;
147
+ }
148
+ /**
149
+ * Creates a new <label> element with the "inputBlock" class and the specified label text,
150
+ * and appends the input element and error bubble element to it. If the form property has
151
+ * no validation object, it adds an "optional" span element to the label.
152
+ *
153
+ * @param {Object} formProperties - An object containing properties for the form field, including its label text and validation rules.
154
+ * @param {HTMLInputElement} input - The input element to associate with the label.
155
+ * @param {HTMLDivElement} errorBubble - The error bubble element to display error messages in.
156
+ * @return {HTMLLabelElement} - The new label element.
157
+ */
158
+ createLabel(formProperties, input, errorBubble) {
159
+ // Create a new <label> element with the "inputBlock" class and the specified text
160
+ const label = document.createElement('label');
161
+ label.className = 'inputBlock';
162
+ label.innerText = formProperties.label;
163
+ // If the form property has no validation object, add an "optional" span element to the label
164
+ if (!formProperties.validation) {
165
+ const optionalSpan = document.createElement('span');
166
+ optionalSpan.className = 'optional';
167
+ optionalSpan.innerHTML = '&nbsp;(optional)';
168
+ label.appendChild(optionalSpan);
169
+ }
170
+ // Append the input element and error bubble element to the label
171
+ label.appendChild(input);
172
+ label.appendChild(errorBubble);
173
+ // Return the label element
174
+ return label;
175
+ }
176
+ /**
177
+ * Creates a new <input> element with the "submit" type, the "primary-blue" class, and the
178
+ * specified label text (i.e., "Save" by default), and returns the new submit button element.
179
+ *
180
+ * @return {HTMLInputElement} - The new submit button element.
181
+ */
182
+ createSubmitButton() {
183
+ // Create a new <input> element with the "submit" type and the specified class and value
184
+ const submitButton = document.createElement('input');
185
+ submitButton.type = 'submit';
186
+ submitButton.className = 'button primary-blue';
187
+ submitButton.value = 'Save';
188
+ // Return the submit button element
189
+ return submitButton;
190
+ }
191
+ /**
192
+ * Populates the form template with input fields and labels based on the properties of the
193
+ * current form schema. For each property in the schema, it creates an input element, applies
194
+ * any validation rules to it, creates an error bubble and label element, and appends them
195
+ * to the form template. Finally, it creates and appends a submit button element to the form.
196
+ *
197
+ * @return {void}
198
+ */
199
+ populateFormFromSchema() {
200
+ // If there is no form schema, return early
201
+ if (!this._formSchema)
202
+ return;
203
+ // Get the properties of the form schema and their keys
204
+ const properties = this._formSchema.properties;
205
+ const propertyKeys = Object.keys(properties);
206
+ // Loop through each property key and create an input, label, and error bubble for it
207
+ propertyKeys.forEach(formKey => {
208
+ const formItem = properties[formKey];
209
+ const formProperties = formItem.form;
210
+ const input = this.createInput(formKey, formProperties);
211
+ // If the form property has validation, apply it to the input
212
+ if (formProperties.validation) {
213
+ this.applyValidation(input, formProperties.validation);
214
+ }
215
+ // Create an error bubble and label element for the input
216
+ const errorBubble = this.createErrorBubble();
217
+ const label = this.createLabel(formProperties, input, errorBubble);
218
+ // Append the label element to the form template
219
+ this.template.content.append(label);
220
+ });
221
+ // Create and append a submit button element to the form template
222
+ const submitButton = this.createSubmitButton();
223
+ this.template.content.append(submitButton);
224
+ }
225
+ /**
226
+ * Clones the form template and binds event listeners to its input elements. First, it checks if
227
+ * there is a form schema present. If so, it clones the template's content, binds events to form
228
+ * input elements, and appends the cloned form elements to the fieldset. The event listeners include
229
+ * "oninvalid" (to check input validity on submit), "onblur" (to check input validity on blur),
230
+ * "onkeyup" (to handle changes in input fields), and "onchange" (to handle changes in select fields).
231
+ *
232
+ * @return {void}
233
+ */
234
+ componentDidRender() {
235
+ // If there's no form schema, return
236
+ if (!this._formSchema) {
237
+ return;
238
+ }
239
+ // Clone the template's content and store it in a variable
240
+ const formItems = this.template.content.cloneNode(true);
241
+ // Bind event listeners to form elements
242
+ const properties = this._formSchema.properties;
243
+ const propertyKeys = Object.keys(properties);
244
+ propertyKeys.forEach((formKey) => {
245
+ const formInput = formItems.querySelector(`[name=${formKey}]`);
246
+ // Bind events to form input elements
247
+ formInput.oninvalid = this.validityCheckWrapper.bind(this);
248
+ formInput.onblur = this.validityCheckWrapper.bind(this);
249
+ formInput.onkeyup = this.fieldChanged.bind(this);
250
+ formInput.onchange = this.fieldChanged.bind(this);
251
+ });
252
+ // Append the cloned form elements to the fieldset
253
+ this.fieldset.appendChild(formItems);
254
+ }
255
+ validityCheckWrapper(event) {
256
+ const { target, hasError, errorMessage } = validityCheck(event);
257
+ setErrorState(target, hasError, errorMessage);
258
+ }
259
+ /**
260
+ * Renders the component's template as a form element with a fieldset container. The form's
261
+ * "onSubmit" event is bound to the "doSubmit" function, which handles the form submission
262
+ * and emits a "dataSubmitted" event with the form data. The fieldset element is assigned
263
+ * to the "fieldset" instance variable using a ref, so it can be populated with form elements
264
+ * later on.
265
+ *
266
+ * @return {JSX.Element} - The rendered form template as a JSX element.
267
+ */
268
+ render() {
269
+ return (h(Host, null, h("form", { onSubmit: this.doSubmit.bind(this) }, h("fieldset", { ref: el => (this.fieldset = el) }))));
270
+ }
271
+ static get is() { return "tttx-form"; }
272
+ static get encapsulation() { return "shadow"; }
273
+ static get originalStyleUrls() {
274
+ return {
275
+ "$": ["tttx-form.scss"]
276
+ };
277
+ }
278
+ static get styleUrls() {
279
+ return {
280
+ "$": ["tttx-form.css"]
281
+ };
282
+ }
283
+ static get properties() {
284
+ return {
285
+ "formschema": {
286
+ "type": "any",
287
+ "mutable": true,
288
+ "complexType": {
289
+ "original": "any",
290
+ "resolved": "any",
291
+ "references": {}
292
+ },
293
+ "required": false,
294
+ "optional": false,
295
+ "docs": {
296
+ "tags": [],
297
+ "text": ""
298
+ },
299
+ "attribute": "formschema",
300
+ "reflect": false
301
+ },
302
+ "submitValue": {
303
+ "type": "any",
304
+ "mutable": true,
305
+ "complexType": {
306
+ "original": "any",
307
+ "resolved": "any",
308
+ "references": {}
309
+ },
310
+ "required": false,
311
+ "optional": false,
312
+ "docs": {
313
+ "tags": [],
314
+ "text": ""
315
+ },
316
+ "attribute": "submit-value",
317
+ "reflect": false
318
+ }
319
+ };
320
+ }
321
+ static get events() {
322
+ return [{
323
+ "method": "dataSubmitted",
324
+ "name": "dataSubmitted",
325
+ "bubbles": true,
326
+ "cancelable": true,
327
+ "composed": true,
328
+ "docs": {
329
+ "tags": [],
330
+ "text": ""
331
+ },
332
+ "complexType": {
333
+ "original": "FormData",
334
+ "resolved": "FormData",
335
+ "references": {
336
+ "FormData": {
337
+ "location": "global"
338
+ }
339
+ }
340
+ }
341
+ }, {
342
+ "method": "dataChanged",
343
+ "name": "dataChanged",
344
+ "bubbles": true,
345
+ "cancelable": true,
346
+ "composed": true,
347
+ "docs": {
348
+ "tags": [],
349
+ "text": ""
350
+ },
351
+ "complexType": {
352
+ "original": "{ name: string, value: any }",
353
+ "resolved": "{ name: string; value: any; }",
354
+ "references": {}
355
+ }
356
+ }];
357
+ }
358
+ static get watchers() {
359
+ return [{
360
+ "propName": "formschema",
361
+ "methodName": "onFormSchemaChange"
362
+ }];
363
+ }
364
+ }