@3t-transform/threeteeui 0.2.97 → 0.2.99

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (28) hide show
  1. package/dist/cjs/tttx-form.cjs.entry.js +114 -29
  2. package/dist/cjs/tttx-icon.cjs.entry.js +6 -1
  3. package/dist/cjs/tttx-standalone-input.cjs.entry.js +1 -1
  4. package/dist/collection/components/atoms/tttx-icon/tttx-icon.js +6 -1
  5. package/dist/collection/components/atoms/tttx-icon/tttx-icon.stories.js +1 -1
  6. package/dist/collection/components/atoms/tttx-loading-spinner/tttx-loading-spinner.stories.js +8 -1
  7. package/dist/collection/components/molecules/tttx-form/lib/setErrorState.js +2 -0
  8. package/dist/collection/components/molecules/tttx-form/lib/validityCheck.js +10 -5
  9. package/dist/collection/components/molecules/tttx-form/tttx-form.css +7 -0
  10. package/dist/collection/components/molecules/tttx-form/tttx-form.js +101 -23
  11. package/dist/collection/components/molecules/tttx-form/tttx-form.stories.js +126 -3
  12. package/dist/collection/components/molecules/tttx-standalone-input/tttx-standalone-input.css +7 -0
  13. package/dist/components/tttx-form.js +114 -29
  14. package/dist/components/tttx-icon2.js +6 -1
  15. package/dist/components/tttx-standalone-input2.js +1 -1
  16. package/dist/esm/tttx-form.entry.js +114 -29
  17. package/dist/esm/tttx-icon.entry.js +6 -1
  18. package/dist/esm/tttx-standalone-input.entry.js +1 -1
  19. package/dist/tttx/{p-93e63568.entry.js → p-6e0fac85.entry.js} +1 -1
  20. package/dist/tttx/p-b2b0e16d.entry.js +1 -0
  21. package/dist/tttx/p-bcf3844e.entry.js +1 -0
  22. package/dist/tttx/tttx.esm.js +1 -1
  23. package/dist/types/components/atoms/tttx-loading-spinner/tttx-loading-spinner.stories.d.ts +10 -1
  24. package/dist/types/components/molecules/tttx-form/tttx-form.d.ts +12 -0
  25. package/dist/types/components/molecules/tttx-form/tttx-form.stories.d.ts +110 -0
  26. package/package.json +2 -2
  27. package/dist/tttx/p-a94f7efc.entry.js +0 -1
  28. package/dist/tttx/p-feea36cb.entry.js +0 -1
@@ -110,9 +110,9 @@ const formSchema = {
110
110
  label: 'Food category',
111
111
  options: [
112
112
  { label: 'Choose an option', value: '', placeholder: true },
113
- { label: 'Poultry', value: 'Chicken' },
114
- { label: 'Fish', value: 'Salmon' },
115
- { label: 'Veg', value: 'Lettuce' },
113
+ { label: 'Poultry', value: 'chicken' },
114
+ { label: 'Fish', value: 'salmon' },
115
+ { label: 'Veg', value: 'lettuce' },
116
116
  ],
117
117
  validation: {
118
118
  required: {
@@ -271,6 +271,52 @@ const formSchemaWithReadonly = {
271
271
  },
272
272
  },
273
273
  },
274
+ dropdown: {
275
+ form: {
276
+ type: 'select',
277
+ blankDefault: true,
278
+ label: 'Food category',
279
+ options: [
280
+ { label: 'Choose an option', value: '', placeholder: true },
281
+ { label: 'Poultry', value: 'chicken' },
282
+ { label: 'Fish', value: 'salmon' },
283
+ { label: 'Veg', value: 'lettuce' },
284
+ ],
285
+ validation: {
286
+ required: {
287
+ message: 'Must select a value',
288
+ },
289
+ },
290
+ },
291
+ },
292
+ permissions: {
293
+ form: {
294
+ type: 'checkbox',
295
+ label: 'Permissions',
296
+ inlineLabel: 'Please grant permissions to use data',
297
+ validation: {
298
+ required: {
299
+ message: 'Please grant permissions to use data',
300
+ },
301
+ },
302
+ },
303
+ },
304
+ expiration: {
305
+ type: 'radio',
306
+ form: {
307
+ type: 'radio',
308
+ label: 'Expiration',
309
+ options: [
310
+ { label: 'Never expires', value: 'neverExpires' },
311
+ { label: 'Will expire', value: 'willExpire' },
312
+ ],
313
+ validation: {
314
+ required: {
315
+ message: 'Please select validity',
316
+ },
317
+ },
318
+ },
319
+ },
274
320
  },
275
321
  };
276
322
  const data = {
@@ -280,6 +326,9 @@ const data = {
280
326
  postcode: 'AB10',
281
327
  age: '50',
282
328
  dob: '1973-06-02',
329
+ dropdown: 'chicken',
330
+ permissions: 'on',
331
+ expiration: 'willExpire'
283
332
  };
284
333
  export const PrePopulateForm = args => `<tttx-form id='form' formSchema='${JSON.stringify(args.formSchema)}' data='${JSON.stringify(args.data)}'></tttx-form>
285
334
  <hr/>
@@ -302,3 +351,77 @@ PrePopulateForm.args = {
302
351
  data,
303
352
  formSchema: formSchemaWithReadonly,
304
353
  };
354
+ const radioFormSchema = {
355
+ properties: {
356
+ name: {
357
+ type: 'string',
358
+ format: 'string',
359
+ form: {
360
+ type: 'text',
361
+ placeholder: 'Enter a name',
362
+ label: 'Name',
363
+ validation: {
364
+ required: {
365
+ message: 'Please enter name',
366
+ },
367
+ },
368
+ },
369
+ },
370
+ requiresEvidence: {
371
+ type: 'checkbox',
372
+ form: {
373
+ type: 'checkbox',
374
+ label: '',
375
+ inlineLabel: 'Requires Evidence',
376
+ },
377
+ },
378
+ validity: {
379
+ type: 'radio',
380
+ form: {
381
+ type: 'radio',
382
+ label: 'Validity',
383
+ options: [
384
+ { label: 'Never expires', value: 'neverExpires' },
385
+ { label: 'Validity duration', value: 'validityDuration' },
386
+ ],
387
+ validation: {
388
+ required: {
389
+ message: 'Please select validity',
390
+ },
391
+ },
392
+ },
393
+ },
394
+ option2: {
395
+ type: 'radio',
396
+ form: {
397
+ type: 'radio',
398
+ label: 'Option 2',
399
+ options: [
400
+ { label: 'Opt 2a', value: 'opt2a' },
401
+ { label: 'Opt 2b', value: 'opt2b' },
402
+ { label: 'Opt 2c', value: 'opt2c' },
403
+ ],
404
+ },
405
+ },
406
+ },
407
+ };
408
+ export const FormWithRadio = args => `<tttx-form id='form' formSchema='${JSON.stringify(args.formSchema)}'></tttx-form>
409
+ <hr/>
410
+ <button type='button' id='button'>Submit Form</button>
411
+ <script>
412
+ if (window['tttxform'] === undefined && window['submitButton'] === undefined) {
413
+ let tttxform = document.getElementById('form');
414
+ tttxform.addEventListener('dataSubmitted', (event) => {
415
+ for(var entry of event.detail.entries()) {
416
+ console.log(entry[0], entry[1]);
417
+ }
418
+ });
419
+ let submitButton = document.getElementById('button');
420
+ submitButton.onclick = () => {
421
+ tttxform.submit();
422
+ }
423
+ }
424
+ </script>`;
425
+ FormWithRadio.args = {
426
+ formSchema: radioFormSchema,
427
+ };
@@ -70,6 +70,10 @@ label .outer-container input:not([type=submit]) {
70
70
  font-size: 16px;
71
71
  line-height: 19px;
72
72
  }
73
+ label .outer-container input[type=radio] {
74
+ width: 20px;
75
+ height: 20px;
76
+ }
73
77
  label .outer-container input[type=date] {
74
78
  background: white;
75
79
  display: block;
@@ -102,6 +106,9 @@ label .outer-container.inputBlock.readonly {
102
106
  user-select: none;
103
107
  color: gray;
104
108
  }
109
+ label .outer-container.inputBlock.radioBlock {
110
+ display: block;
111
+ }
105
112
  label .outer-container.inputInline {
106
113
  display: flex;
107
114
  white-space: nowrap;
@@ -33,6 +33,16 @@ function validityCheck(event) {
33
33
  // target.setCustomValidity('custom error!');
34
34
  // and cleared with
35
35
  // target.setCustomValidity('');
36
+ //handle whitespace-only input
37
+ if (target.value.length && !target.value.replace(/\s/g, '').length) {
38
+ errorMessage = 'This field cannot be left blank';
39
+ target.setCustomValidity(errorMessage);
40
+ }
41
+ else {
42
+ errorMessage = '';
43
+ if (target.setCustomValidity) // tests are dumb as a brick
44
+ target.setCustomValidity('');
45
+ }
36
46
  // Check the validity of the input field and set an error message if needed
37
47
  switch (true) {
38
48
  // The field is required, but has no value
@@ -60,11 +70,6 @@ function validityCheck(event) {
60
70
  default:
61
71
  hasError = false;
62
72
  }
63
- //handle whitespace-only input
64
- if (!target.value.replace(/\s/g, '').length && target.value.length !== 0) {
65
- errorMessage = 'Whitespace-only not allowed';
66
- hasError = true;
67
- }
68
73
  // Return the error state
69
74
  return { target, hasError, errorMessage };
70
75
  }
@@ -94,6 +99,8 @@ function setErrorState(target, hasError, errorMessage, parent = undefined) {
94
99
  errorBubble = target.parentElement.parentElement.querySelector('.errorBubble');
95
100
  }
96
101
  }
102
+ if (!errorBubble)
103
+ return;
97
104
  // If an error was detected, set the input field's class to "invalid" and display the error message in the error bubble
98
105
  if (hasError) {
99
106
  target.classList.add('invalid');
@@ -117,7 +124,7 @@ function setErrorState(target, hasError, errorMessage, parent = undefined) {
117
124
  }
118
125
  }
119
126
 
120
- const tttxFormCss = ".material-symbols-rounded{font-variation-settings:\"FILL\" 1, \"wght\" 400, \"GRAD\" 0, \"opsz\" 24}.material-symbols-rounded{font-variation-settings:\"FILL\" 1, \"wght\" 400, \"GRAD\" 0, \"opsz\" 24}label{font-weight:500;font-size:16px;line-height:19px;color:#212121}label .optional{color:#757575;font-weight:normal}label .outer-container{position:relative}label .outer-container .left-icons,label .outer-container .right-icons{display:flex;position:absolute;height:24px;gap:8px}label .outer-container .left-icons tttx-icon,label .outer-container .right-icons tttx-icon{height:24px;width:24px}label .outer-container .left-icons{left:8px}label .outer-container .right-icons{right:8px}label .outer-container input{color:#212121;box-sizing:border-box;border:1px solid #d5d5d5;border-radius:4px;padding:0;padding-left:16px;padding-right:16px;margin-top:4px;}label .outer-container input.has-input-icon{padding-left:40px}label .outer-container input.has-input-icon.has-left-icon{padding-left:72px}label .outer-container input.has-left-icon{padding-left:40px}label .outer-container input.has-right-icon{padding-right:40px}label .outer-container input.invalid{border:1px solid #dc0000}label .outer-container input:not([type=submit]){font-family:\"Roboto\", serif;width:100%;height:36px;font-size:16px;line-height:19px}label .outer-container input[type=date]{background:white;display:block;min-width:calc(100% - 18px);line-height:37px}label .outer-container input[readonly]{cursor:default;pointer-events:none;user-select:none;color:gray}label .outer-container input:focus{border-color:#1479c6}label .outer-container input:focus-visible{outline:none}label .outer-container.inputBlock{display:flex;align-items:center;line-height:21px}label .outer-container.inputBlock .left-icons,label .outer-container.inputBlock .right-icons{margin-top:4px}label .outer-container.inputBlock.readonly{pointer-events:none;user-select:none;color:gray}label .outer-container.inputInline{display:flex;white-space:nowrap;align-items:center;margin:0}label .outer-container.inputInline input{margin-top:0}label .secondarylabel{color:#757575;font-size:14px;line-height:16px;font-weight:normal;display:flex;margin-top:4px}label .errorBubble{position:relative;font-size:14px;line-height:16px;font-weight:normal;width:100%;font-family:\"Roboto\", sans-serif;color:#dc0000;display:flex;align-content:center;align-items:center;justify-items:center;margin-top:4px}label .errorBubble:not(.visible){display:none}label .errorBubble span{color:#dc0000;font-size:16px;margin-right:4px}.material-symbols-rounded{font-family:\"Material Symbols Rounded\", sans-serif;font-weight:400;font-style:normal;font-size:24px;line-height:1;letter-spacing:normal;text-transform:none;display:inline-block;white-space:nowrap;word-wrap:normal;direction:ltr;text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased;color:#9e9e9e}button{cursor:pointer}.button{font-family:Roboto, serif;box-sizing:border-box;height:36px;min-width:36px;padding:0;margin:0;background:transparent;color:#212121;border:1px solid #c8c8c8;border-radius:4px;text-transform:uppercase;display:flex;justify-content:left;align-items:center;font-size:14px;font-weight:500}.button-content{display:block;padding:0 16px}.icon-left,.icon-right{margin-top:4px}.iconleft{padding-left:8px}.iconleft .button-content{padding-left:4px}.iconright{padding-right:8px}.iconright .button-content{padding-right:4px}.notext{padding:0 6px}.button:active{background:rgba(17, 17, 17, 0.2);border:1px solid #d5d5d5}.primary{background:#1479c6;border:1px solid #1479c6;color:white}.primary:active{background:#1464a2;border:1px solid #1464a2}.borderless{background:transparent;border:none;color:#212121}.borderless:active{background:rgba(17, 17, 17, 0.2);border:none}.borderless-circle{background:transparent;border:none;color:#212121;border-radius:50%}.borderless-circle:active{border:none}.borderless-circle:focus{border-color:transparent}.danger{background:#dc0000;border:1px solid #dc0000;color:white}.danger:active{background:#b00000;border:1px solid #b00000}.disabled{background:#aeaeae;border:none;color:#4c4c4c;cursor:not-allowed}.disabled:active{background:#aeaeae;border:none;color:#4c4c4c;cursor:not-allowed}@media (hover: hover){.button:hover{background:rgba(17, 17, 17, 0.1);border:1px solid #d5d5d5}.primary:hover{background:#146eb3;border:1px solid #146eb3}.borderless:hover{background:rgba(17, 17, 17, 0.1);border:none}.borderless-circle:hover{background:rgba(17, 17, 17, 0.1);border:none}.danger:hover{background:#c60000;border:1px solid #c60000}.disabled:hover{background:#aeaeae;border:none;color:#4c4c4c;cursor:not-allowed}}:host{display:block}fieldset{margin:0;padding:0;border:none}label{display:block;position:relative;margin-bottom:16px}.inlineLabel{font-weight:400;display:inline-block;vertical-align:top;padding-top:4px}input[type=checkbox]{width:18px;height:18px}input~label{font-weight:400}select{font-family:\"Roboto\", serif;box-sizing:border-box;width:100%;height:36px;padding:0 16px;font-size:16px;border:1px solid #d5d5d5;border-radius:4px;margin-top:4px}.placeholder{color:#9e9e9e}.placeholder option{color:initial}select.invalid:invalid{border:1px solid #dc0000}select~.errorBubble{position:relative;font-size:14px;font-weight:normal;width:100%;font-family:\"Roboto\", sans-serif;color:#dc0000;display:flex;align-content:center;align-items:center;justify-items:center}select~.errorBubble:not(.visible){visibility:hidden}select~.errorBubble span{color:#dc0000;font-size:16px;margin-right:4px;height:16px}select.invalid:invalid~.errorBubble{position:relative;font-size:14px;font-weight:normal;width:100%;font-family:\"Roboto\", sans-serif;color:#dc0000;visibility:visible}select:focus{border-color:#1479c6}select:focus-visible{outline:none}.button{padding:0 16px}.footer{display:flex;gap:16px;flex-direction:row-reverse}";
127
+ const tttxFormCss = ".material-symbols-rounded{font-variation-settings:\"FILL\" 1, \"wght\" 400, \"GRAD\" 0, \"opsz\" 24}.material-symbols-rounded{font-variation-settings:\"FILL\" 1, \"wght\" 400, \"GRAD\" 0, \"opsz\" 24}label{font-weight:500;font-size:16px;line-height:19px;color:#212121}label .optional{color:#757575;font-weight:normal}label .outer-container{position:relative}label .outer-container .left-icons,label .outer-container .right-icons{display:flex;position:absolute;height:24px;gap:8px}label .outer-container .left-icons tttx-icon,label .outer-container .right-icons tttx-icon{height:24px;width:24px}label .outer-container .left-icons{left:8px}label .outer-container .right-icons{right:8px}label .outer-container input{color:#212121;box-sizing:border-box;border:1px solid #d5d5d5;border-radius:4px;padding:0;padding-left:16px;padding-right:16px;margin-top:4px;}label .outer-container input.has-input-icon{padding-left:40px}label .outer-container input.has-input-icon.has-left-icon{padding-left:72px}label .outer-container input.has-left-icon{padding-left:40px}label .outer-container input.has-right-icon{padding-right:40px}label .outer-container input.invalid{border:1px solid #dc0000}label .outer-container input:not([type=submit]){font-family:\"Roboto\", serif;width:100%;height:36px;font-size:16px;line-height:19px}label .outer-container input[type=radio]{width:20px;height:20px}label .outer-container input[type=date]{background:white;display:block;min-width:calc(100% - 18px);line-height:37px}label .outer-container input[readonly]{cursor:default;pointer-events:none;user-select:none;color:gray}label .outer-container input:focus{border-color:#1479c6}label .outer-container input:focus-visible{outline:none}label .outer-container.inputBlock{display:flex;align-items:center;line-height:21px}label .outer-container.inputBlock .left-icons,label .outer-container.inputBlock .right-icons{margin-top:4px}label .outer-container.inputBlock.readonly{pointer-events:none;user-select:none;color:gray}label .outer-container.inputBlock.radioBlock{display:block}label .outer-container.inputInline{display:flex;white-space:nowrap;align-items:center;margin:0}label .outer-container.inputInline input{margin-top:0}label .secondarylabel{color:#757575;font-size:14px;line-height:16px;font-weight:normal;display:flex;margin-top:4px}label .errorBubble{position:relative;font-size:14px;line-height:16px;font-weight:normal;width:100%;font-family:\"Roboto\", sans-serif;color:#dc0000;display:flex;align-content:center;align-items:center;justify-items:center;margin-top:4px}label .errorBubble:not(.visible){display:none}label .errorBubble span{color:#dc0000;font-size:16px;margin-right:4px}.material-symbols-rounded{font-family:\"Material Symbols Rounded\", sans-serif;font-weight:400;font-style:normal;font-size:24px;line-height:1;letter-spacing:normal;text-transform:none;display:inline-block;white-space:nowrap;word-wrap:normal;direction:ltr;text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased;color:#9e9e9e}button{cursor:pointer}.button{font-family:Roboto, serif;box-sizing:border-box;height:36px;min-width:36px;padding:0;margin:0;background:transparent;color:#212121;border:1px solid #c8c8c8;border-radius:4px;text-transform:uppercase;display:flex;justify-content:left;align-items:center;font-size:14px;font-weight:500}.button-content{display:block;padding:0 16px}.icon-left,.icon-right{margin-top:4px}.iconleft{padding-left:8px}.iconleft .button-content{padding-left:4px}.iconright{padding-right:8px}.iconright .button-content{padding-right:4px}.notext{padding:0 6px}.button:active{background:rgba(17, 17, 17, 0.2);border:1px solid #d5d5d5}.primary{background:#1479c6;border:1px solid #1479c6;color:white}.primary:active{background:#1464a2;border:1px solid #1464a2}.borderless{background:transparent;border:none;color:#212121}.borderless:active{background:rgba(17, 17, 17, 0.2);border:none}.borderless-circle{background:transparent;border:none;color:#212121;border-radius:50%}.borderless-circle:active{border:none}.borderless-circle:focus{border-color:transparent}.danger{background:#dc0000;border:1px solid #dc0000;color:white}.danger:active{background:#b00000;border:1px solid #b00000}.disabled{background:#aeaeae;border:none;color:#4c4c4c;cursor:not-allowed}.disabled:active{background:#aeaeae;border:none;color:#4c4c4c;cursor:not-allowed}@media (hover: hover){.button:hover{background:rgba(17, 17, 17, 0.1);border:1px solid #d5d5d5}.primary:hover{background:#146eb3;border:1px solid #146eb3}.borderless:hover{background:rgba(17, 17, 17, 0.1);border:none}.borderless-circle:hover{background:rgba(17, 17, 17, 0.1);border:none}.danger:hover{background:#c60000;border:1px solid #c60000}.disabled:hover{background:#aeaeae;border:none;color:#4c4c4c;cursor:not-allowed}}:host{display:block}fieldset{margin:0;padding:0;border:none}label{display:block;position:relative;margin-bottom:16px}.inlineLabel{font-weight:400;display:inline-block;vertical-align:top;padding-top:4px}input[type=checkbox]{width:18px;height:18px}input~label{font-weight:400}select{font-family:\"Roboto\", serif;box-sizing:border-box;width:100%;height:36px;padding:0 16px;font-size:16px;border:1px solid #d5d5d5;border-radius:4px;margin-top:4px}.placeholder{color:#9e9e9e}.placeholder option{color:initial}select.invalid:invalid{border:1px solid #dc0000}select~.errorBubble{position:relative;font-size:14px;font-weight:normal;width:100%;font-family:\"Roboto\", sans-serif;color:#dc0000;display:flex;align-content:center;align-items:center;justify-items:center}select~.errorBubble:not(.visible){visibility:hidden}select~.errorBubble span{color:#dc0000;font-size:16px;margin-right:4px;height:16px}select.invalid:invalid~.errorBubble{position:relative;font-size:14px;font-weight:normal;width:100%;font-family:\"Roboto\", sans-serif;color:#dc0000;visibility:visible}select:focus{border-color:#1479c6}select:focus-visible{outline:none}.button{padding:0 16px}.footer{display:flex;gap:16px;flex-direction:row-reverse}";
121
128
 
122
129
  const TttxForm$1 = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement {
123
130
  constructor() {
@@ -192,6 +199,23 @@ const TttxForm$1 = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement {
192
199
  event.preventDefault();
193
200
  // create a new FormData object with the form data
194
201
  const formData = new FormData(event.target);
202
+ // get a list of checkboxes, if any, so we can manually set unchecked box data
203
+ const checkboxSchemaItems = [];
204
+ const formProperties = this._formSchema.properties;
205
+ for (const formKey of Object.keys(formProperties)) {
206
+ if (formProperties[formKey].form.type === 'checkbox') {
207
+ checkboxSchemaItems.push(formKey);
208
+ }
209
+ }
210
+ const allFormKeys = [];
211
+ for (const key of formData.keys()) {
212
+ allFormKeys.push(key);
213
+ }
214
+ for (const checkItem of checkboxSchemaItems) {
215
+ if (allFormKeys.indexOf(checkItem) === -1) {
216
+ formData.append(checkItem, 'off');
217
+ }
218
+ }
195
219
  // emit the form data through the `dataSubmitted` event
196
220
  this.dataSubmitted.emit(formData);
197
221
  }
@@ -376,17 +400,21 @@ const TttxForm$1 = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement {
376
400
  */
377
401
  createLabel(formProperties, input, errorBubble) {
378
402
  const outerContainer = document.createElement('div');
379
- outerContainer.className = 'outer-container inputBlock';
403
+ let outerContainerClassName = 'outer-container inputBlock';
380
404
  // Create a new <label> element with the "inputBlock" class and the specified text
381
405
  const label = document.createElement('label');
382
406
  label.innerText = formProperties.label;
383
407
  // If the form property has no validation object, add an "optional" span element to the label
384
- if (!formProperties.validation) {
408
+ if (!formProperties.validation && formProperties.label) {
385
409
  const optionalSpan = document.createElement('span');
386
410
  optionalSpan.className = 'optional';
387
411
  optionalSpan.innerHTML = '&nbsp;(optional)';
388
412
  label.appendChild(optionalSpan);
389
413
  }
414
+ if (formProperties.type === 'radio') {
415
+ outerContainerClassName += ' radioBlock';
416
+ }
417
+ outerContainer.className = outerContainerClassName;
390
418
  if (formProperties.readonly) {
391
419
  label.classList.add('readonly');
392
420
  }
@@ -404,6 +432,38 @@ const TttxForm$1 = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement {
404
432
  // Return the label element
405
433
  return label;
406
434
  }
435
+ /**
436
+ * Creates a new radio input with a set of options.
437
+ *
438
+ * @param {string} formKey - The name of the dropdown field, as specified in the form schema.
439
+ * @param {Object} formProperties - An object containing additional properties, such as the field type and options properties.
440
+ * @param {'radio'} formProperties.type - The type of form field. In this case, it will always be "radio".
441
+ * @param {Object} formProperties.validation - A set of validation rules for the field.
442
+ * @param {Object[]} formProperties.options - A list of properties to pass to the select options.
443
+ * @param {string} formProperties.options.label - The visible value of the option.
444
+ * @param {string} formProperties.options.value - The actual value of the option.
445
+ */
446
+ createRadio(formKey, formProperties) {
447
+ var _a, _b;
448
+ const fragment = new DocumentFragment();
449
+ for (const optionProperties of formProperties.options) {
450
+ // Create a new <input> element with the specified name and type
451
+ const input = document.createElement('input');
452
+ input.type = 'radio';
453
+ input.name = formKey;
454
+ input.value = optionProperties.value;
455
+ if ((_a = formProperties === null || formProperties === void 0 ? void 0 : formProperties.validation) === null || _a === void 0 ? void 0 : _a.required) {
456
+ input.setAttribute('required', 'required');
457
+ input.setAttribute('data-required', (_b = formProperties.validation.required.message) !== null && _b !== void 0 ? _b : '');
458
+ }
459
+ const span = document.createElement('span');
460
+ span.innerText = optionProperties.label;
461
+ fragment.appendChild(input);
462
+ fragment.appendChild(span);
463
+ fragment.appendChild(document.createElement('br'));
464
+ }
465
+ return fragment;
466
+ }
407
467
  /**
408
468
  * Populates the form template with input fields and labels based on the properties of the
409
469
  * current form schema. For each property in the schema, it creates an input element, applies
@@ -423,9 +483,19 @@ const TttxForm$1 = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement {
423
483
  propertyKeys.forEach(formKey => {
424
484
  const formItem = properties[formKey];
425
485
  const formProperties = formItem.form;
426
- const input = formProperties.type === 'select' ? this.createSelect(formKey, formProperties) : this.createInput(formKey, formProperties);
486
+ let input;
487
+ switch (formProperties.type) {
488
+ case 'select':
489
+ input = this.createSelect(formKey, formProperties);
490
+ break;
491
+ case 'radio':
492
+ input = this.createRadio(formKey, formProperties);
493
+ break;
494
+ default:
495
+ input = this.createInput(formKey, formProperties);
496
+ }
427
497
  // If the form property has validation, apply it to the input
428
- if (formProperties.validation) {
498
+ if (formProperties.validation && formProperties.type !== 'radio') {
429
499
  this.applyValidation(input, formProperties.validation);
430
500
  }
431
501
  // Create an error bubble and label element for the input
@@ -456,25 +526,40 @@ const TttxForm$1 = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement {
456
526
  const propertyKeys = Object.keys(properties);
457
527
  propertyKeys.forEach(formKey => {
458
528
  var _a, _b;
459
- const formInput = formItems.querySelector(`[name=${formKey}]`);
460
- // Bind events to form input elements
461
- formInput.oninvalid = this.validityCheckWrapper.bind(this);
462
- formInput.onblur = this.validityCheckWrapper.bind(this);
463
- formInput.onkeyup = this.fieldChanged.bind(this);
464
- formInput.onchange = this.fieldChanged.bind(this);
465
- if (((_a = this._data) === null || _a === void 0 ? void 0 : _a[formKey]) !== undefined && this._data[formKey] !== null) {
466
- formInput.value = this._data[formKey];
467
- }
468
- // If explicitly setting input as invalid, set invalid state and error message on render
469
- if ((_b = properties[formKey].form.validation) === null || _b === void 0 ? void 0 : _b.invalid) {
470
- const errorMessage = properties[formKey].form.validation.invalid.message;
471
- formInput.setCustomValidity(errorMessage); // Prevents the invalid styling from resetting on blur
472
- setErrorState(formInput, true, errorMessage);
473
- }
474
- if (properties[formKey].form.type === 'select' && formInput.classList.contains('placeholder')) {
475
- formInput.addEventListener('change', () => {
476
- formInput.classList.remove('placeholder');
477
- });
529
+ const formInputs = formItems.querySelectorAll(`[name=${formKey}]`);
530
+ for (const formInput of formInputs) {
531
+ // Bind events to form input elements
532
+ formInput.oninvalid = this.validityCheckWrapper.bind(this);
533
+ formInput.onblur = this.validityCheckWrapper.bind(this);
534
+ formInput.onkeyup = this.fieldChanged.bind(this);
535
+ formInput.onchange = this.fieldChanged.bind(this);
536
+ if ((_a = this._data) === null || _a === void 0 ? void 0 : _a[formKey]) {
537
+ switch (formInput.type) {
538
+ case 'checkbox':
539
+ if (this._data[formKey] === 'on') {
540
+ formInput.checked = true;
541
+ }
542
+ break;
543
+ case 'radio':
544
+ if (formInput.value === this._data[formKey]) {
545
+ formInput.checked = true;
546
+ }
547
+ break;
548
+ default:
549
+ formInput.value = this._data[formKey];
550
+ }
551
+ }
552
+ // If explicitly setting input as invalid, set invalid state and error message on render
553
+ if ((_b = properties[formKey].form.validation) === null || _b === void 0 ? void 0 : _b.invalid) {
554
+ const errorMessage = properties[formKey].form.validation.invalid.message;
555
+ formInput.setCustomValidity(errorMessage); // Prevents the invalid styling from resetting on blur
556
+ setErrorState(formInput, true, errorMessage);
557
+ }
558
+ if (properties[formKey].form.type === 'select' && formInput.classList.contains('placeholder')) {
559
+ formInput.addEventListener('change', () => {
560
+ formInput.classList.remove('placeholder');
561
+ });
562
+ }
478
563
  }
479
564
  });
480
565
  // Append the cloned form elements to the fieldset
@@ -11,7 +11,12 @@ const TttxIcon = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement {
11
11
  this.color = 'grey';
12
12
  }
13
13
  render() {
14
- return (h(Host, null, h("span", { class: `material-symbols-rounded ${this.color ? this.color : ''}` }, this.icon)));
14
+ if (this.color.startsWith('#')) {
15
+ return (h(Host, null, h("span", { class: 'material-symbols-rounded', style: { color: this.color } }, this.icon)));
16
+ }
17
+ else {
18
+ return (h(Host, null, h("span", { class: `material-symbols-rounded ${this.color}` }, this.icon)));
19
+ }
15
20
  }
16
21
  static get style() { return tttxIconCss; }
17
22
  }, [1, "tttx-icon", {
@@ -1,7 +1,7 @@
1
1
  import { proxyCustomElement, HTMLElement, createEvent, h, Host } from '@stencil/core/internal/client';
2
2
  import { d as defineCustomElement$1 } from './tttx-icon2.js';
3
3
 
4
- const tttxStandaloneInputCss = ".material-symbols-rounded.sc-tttx-standalone-input{font-variation-settings:\"FILL\" 1, \"wght\" 400, \"GRAD\" 0, \"opsz\" 24}.material-symbols-rounded.sc-tttx-standalone-input{font-variation-settings:\"FILL\" 1, \"wght\" 400, \"GRAD\" 0, \"opsz\" 24}label.sc-tttx-standalone-input{font-weight:500;font-size:16px;line-height:19px;color:#212121}label.sc-tttx-standalone-input .optional.sc-tttx-standalone-input{color:#757575;font-weight:normal}label.sc-tttx-standalone-input .outer-container.sc-tttx-standalone-input{position:relative}label.sc-tttx-standalone-input .outer-container.sc-tttx-standalone-input .left-icons.sc-tttx-standalone-input,label.sc-tttx-standalone-input .outer-container.sc-tttx-standalone-input .right-icons.sc-tttx-standalone-input{display:flex;position:absolute;height:24px;gap:8px}label.sc-tttx-standalone-input .outer-container.sc-tttx-standalone-input .left-icons.sc-tttx-standalone-input tttx-icon.sc-tttx-standalone-input,label.sc-tttx-standalone-input .outer-container.sc-tttx-standalone-input .right-icons.sc-tttx-standalone-input tttx-icon.sc-tttx-standalone-input{height:24px;width:24px}label.sc-tttx-standalone-input .outer-container.sc-tttx-standalone-input .left-icons.sc-tttx-standalone-input{left:8px}label.sc-tttx-standalone-input .outer-container.sc-tttx-standalone-input .right-icons.sc-tttx-standalone-input{right:8px}label.sc-tttx-standalone-input .outer-container.sc-tttx-standalone-input input.sc-tttx-standalone-input{color:#212121;box-sizing:border-box;border:1px solid #d5d5d5;border-radius:4px;padding:0;padding-left:16px;padding-right:16px;margin-top:4px}label.sc-tttx-standalone-input .outer-container.sc-tttx-standalone-input input.has-input-icon.sc-tttx-standalone-input{padding-left:40px}label.sc-tttx-standalone-input .outer-container.sc-tttx-standalone-input input.has-input-icon.has-left-icon.sc-tttx-standalone-input{padding-left:72px}label.sc-tttx-standalone-input .outer-container.sc-tttx-standalone-input input.has-left-icon.sc-tttx-standalone-input{padding-left:40px}label.sc-tttx-standalone-input .outer-container.sc-tttx-standalone-input input.has-right-icon.sc-tttx-standalone-input{padding-right:40px}label.sc-tttx-standalone-input .outer-container.sc-tttx-standalone-input input.invalid.sc-tttx-standalone-input{border:1px solid #dc0000}label.sc-tttx-standalone-input .outer-container.sc-tttx-standalone-input input.sc-tttx-standalone-input:not([type=submit]){font-family:\"Roboto\", serif;width:100%;height:36px;font-size:16px;line-height:19px}label.sc-tttx-standalone-input .outer-container.sc-tttx-standalone-input input[type=date].sc-tttx-standalone-input{background:white;display:block;min-width:calc(100% - 18px);line-height:37px}label.sc-tttx-standalone-input .outer-container.sc-tttx-standalone-input input[readonly].sc-tttx-standalone-input{cursor:default;pointer-events:none;user-select:none;color:gray}label.sc-tttx-standalone-input .outer-container.sc-tttx-standalone-input input.sc-tttx-standalone-input:focus{border-color:#1479c6}label.sc-tttx-standalone-input .outer-container.sc-tttx-standalone-input input.sc-tttx-standalone-input:focus-visible{outline:none}label.sc-tttx-standalone-input .outer-container.inputBlock.sc-tttx-standalone-input{display:flex;align-items:center;line-height:21px}label.sc-tttx-standalone-input .outer-container.inputBlock.sc-tttx-standalone-input .left-icons.sc-tttx-standalone-input,label.sc-tttx-standalone-input .outer-container.inputBlock.sc-tttx-standalone-input .right-icons.sc-tttx-standalone-input{margin-top:4px}label.sc-tttx-standalone-input .outer-container.inputBlock.readonly.sc-tttx-standalone-input{pointer-events:none;user-select:none;color:gray}label.sc-tttx-standalone-input .outer-container.inputInline.sc-tttx-standalone-input{display:flex;white-space:nowrap;align-items:center;margin:0}label.sc-tttx-standalone-input .outer-container.inputInline.sc-tttx-standalone-input input.sc-tttx-standalone-input{margin-top:0}label.sc-tttx-standalone-input .secondarylabel.sc-tttx-standalone-input{color:#757575;font-size:14px;line-height:16px;font-weight:normal;display:flex;margin-top:4px}label.sc-tttx-standalone-input .errorBubble.sc-tttx-standalone-input{position:relative;font-size:14px;line-height:16px;font-weight:normal;width:100%;font-family:\"Roboto\", sans-serif;color:#dc0000;display:flex;align-content:center;align-items:center;justify-items:center;margin-top:4px}label.sc-tttx-standalone-input .errorBubble.sc-tttx-standalone-input:not(.visible){display:none}label.sc-tttx-standalone-input .errorBubble.sc-tttx-standalone-input span.sc-tttx-standalone-input{color:#dc0000;font-size:16px;margin-right:4px}.material-symbols-rounded.sc-tttx-standalone-input{font-family:\"Material Symbols Rounded\", sans-serif;font-weight:400;font-style:normal;font-size:24px;line-height:1;letter-spacing:normal;text-transform:none;display:inline-block;white-space:nowrap;word-wrap:normal;direction:ltr;text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased;color:#9e9e9e}.sc-tttx-standalone-input-h{display:block}";
4
+ const tttxStandaloneInputCss = ".material-symbols-rounded.sc-tttx-standalone-input{font-variation-settings:\"FILL\" 1, \"wght\" 400, \"GRAD\" 0, \"opsz\" 24}.material-symbols-rounded.sc-tttx-standalone-input{font-variation-settings:\"FILL\" 1, \"wght\" 400, \"GRAD\" 0, \"opsz\" 24}label.sc-tttx-standalone-input{font-weight:500;font-size:16px;line-height:19px;color:#212121}label.sc-tttx-standalone-input .optional.sc-tttx-standalone-input{color:#757575;font-weight:normal}label.sc-tttx-standalone-input .outer-container.sc-tttx-standalone-input{position:relative}label.sc-tttx-standalone-input .outer-container.sc-tttx-standalone-input .left-icons.sc-tttx-standalone-input,label.sc-tttx-standalone-input .outer-container.sc-tttx-standalone-input .right-icons.sc-tttx-standalone-input{display:flex;position:absolute;height:24px;gap:8px}label.sc-tttx-standalone-input .outer-container.sc-tttx-standalone-input .left-icons.sc-tttx-standalone-input tttx-icon.sc-tttx-standalone-input,label.sc-tttx-standalone-input .outer-container.sc-tttx-standalone-input .right-icons.sc-tttx-standalone-input tttx-icon.sc-tttx-standalone-input{height:24px;width:24px}label.sc-tttx-standalone-input .outer-container.sc-tttx-standalone-input .left-icons.sc-tttx-standalone-input{left:8px}label.sc-tttx-standalone-input .outer-container.sc-tttx-standalone-input .right-icons.sc-tttx-standalone-input{right:8px}label.sc-tttx-standalone-input .outer-container.sc-tttx-standalone-input input.sc-tttx-standalone-input{color:#212121;box-sizing:border-box;border:1px solid #d5d5d5;border-radius:4px;padding:0;padding-left:16px;padding-right:16px;margin-top:4px}label.sc-tttx-standalone-input .outer-container.sc-tttx-standalone-input input.has-input-icon.sc-tttx-standalone-input{padding-left:40px}label.sc-tttx-standalone-input .outer-container.sc-tttx-standalone-input input.has-input-icon.has-left-icon.sc-tttx-standalone-input{padding-left:72px}label.sc-tttx-standalone-input .outer-container.sc-tttx-standalone-input input.has-left-icon.sc-tttx-standalone-input{padding-left:40px}label.sc-tttx-standalone-input .outer-container.sc-tttx-standalone-input input.has-right-icon.sc-tttx-standalone-input{padding-right:40px}label.sc-tttx-standalone-input .outer-container.sc-tttx-standalone-input input.invalid.sc-tttx-standalone-input{border:1px solid #dc0000}label.sc-tttx-standalone-input .outer-container.sc-tttx-standalone-input input.sc-tttx-standalone-input:not([type=submit]){font-family:\"Roboto\", serif;width:100%;height:36px;font-size:16px;line-height:19px}label.sc-tttx-standalone-input .outer-container.sc-tttx-standalone-input input[type=radio].sc-tttx-standalone-input{width:20px;height:20px}label.sc-tttx-standalone-input .outer-container.sc-tttx-standalone-input input[type=date].sc-tttx-standalone-input{background:white;display:block;min-width:calc(100% - 18px);line-height:37px}label.sc-tttx-standalone-input .outer-container.sc-tttx-standalone-input input[readonly].sc-tttx-standalone-input{cursor:default;pointer-events:none;user-select:none;color:gray}label.sc-tttx-standalone-input .outer-container.sc-tttx-standalone-input input.sc-tttx-standalone-input:focus{border-color:#1479c6}label.sc-tttx-standalone-input .outer-container.sc-tttx-standalone-input input.sc-tttx-standalone-input:focus-visible{outline:none}label.sc-tttx-standalone-input .outer-container.inputBlock.sc-tttx-standalone-input{display:flex;align-items:center;line-height:21px}label.sc-tttx-standalone-input .outer-container.inputBlock.sc-tttx-standalone-input .left-icons.sc-tttx-standalone-input,label.sc-tttx-standalone-input .outer-container.inputBlock.sc-tttx-standalone-input .right-icons.sc-tttx-standalone-input{margin-top:4px}label.sc-tttx-standalone-input .outer-container.inputBlock.readonly.sc-tttx-standalone-input{pointer-events:none;user-select:none;color:gray}label.sc-tttx-standalone-input .outer-container.inputBlock.radioBlock.sc-tttx-standalone-input{display:block}label.sc-tttx-standalone-input .outer-container.inputInline.sc-tttx-standalone-input{display:flex;white-space:nowrap;align-items:center;margin:0}label.sc-tttx-standalone-input .outer-container.inputInline.sc-tttx-standalone-input input.sc-tttx-standalone-input{margin-top:0}label.sc-tttx-standalone-input .secondarylabel.sc-tttx-standalone-input{color:#757575;font-size:14px;line-height:16px;font-weight:normal;display:flex;margin-top:4px}label.sc-tttx-standalone-input .errorBubble.sc-tttx-standalone-input{position:relative;font-size:14px;line-height:16px;font-weight:normal;width:100%;font-family:\"Roboto\", sans-serif;color:#dc0000;display:flex;align-content:center;align-items:center;justify-items:center;margin-top:4px}label.sc-tttx-standalone-input .errorBubble.sc-tttx-standalone-input:not(.visible){display:none}label.sc-tttx-standalone-input .errorBubble.sc-tttx-standalone-input span.sc-tttx-standalone-input{color:#dc0000;font-size:16px;margin-right:4px}.material-symbols-rounded.sc-tttx-standalone-input{font-family:\"Material Symbols Rounded\", sans-serif;font-weight:400;font-style:normal;font-size:24px;line-height:1;letter-spacing:normal;text-transform:none;display:inline-block;white-space:nowrap;word-wrap:normal;direction:ltr;text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased;color:#9e9e9e}.sc-tttx-standalone-input-h{display:block}";
5
5
 
6
6
  const TttxInput = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement {
7
7
  constructor() {