@3t-transform/threeteeui 0.0.24 → 0.0.25

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 (96) hide show
  1. package/dist/cjs/{index-bc080fb4.js → index-451f61dd.js} +51 -60
  2. package/dist/cjs/loader.cjs.js +2 -2
  3. package/dist/cjs/tttx-button.cjs.entry.js +1 -1
  4. package/dist/cjs/tttx-form.cjs.entry.js +377 -0
  5. package/dist/cjs/tttx-icon.cjs.entry.js +1 -1
  6. package/dist/cjs/tttx-keyvalue-block.cjs.entry.js +8 -5
  7. package/dist/cjs/tttx-list.cjs.entry.js +1677 -7
  8. package/dist/cjs/tttx-loading-spinner.cjs.entry.js +1 -1
  9. package/dist/cjs/tttx-standalone-input.cjs.entry.js +2 -1
  10. package/dist/cjs/tttx.cjs.js +2 -2
  11. package/dist/collection/collection-manifest.json +2 -2
  12. package/dist/collection/components/atoms/tttx-keyvalue-block/tttx-keyvalue-block.js +7 -4
  13. package/dist/collection/components/molecules/tttx-form/lib/setErrorState.js +35 -0
  14. package/dist/collection/components/molecules/tttx-form/lib/validityCheck.js +58 -0
  15. package/dist/collection/components/molecules/tttx-form/tttx-form.css +314 -0
  16. package/dist/collection/components/molecules/tttx-form/tttx-form.js +364 -0
  17. package/dist/collection/components/molecules/tttx-form/tttx-form.stories.js +127 -0
  18. package/dist/collection/components/molecules/tttx-list/tttx-list.css +8 -2
  19. package/dist/collection/components/molecules/tttx-list/tttx-list.js +33 -7
  20. package/dist/collection/components/molecules/tttx-list/tttx-list.stories.js +46 -14
  21. package/dist/collection/components/molecules/tttx-standalone-input/tttx-standalone-input.js +1 -0
  22. package/dist/collection/shared/domsanitiser.options.js +14 -0
  23. package/dist/components/index.d.ts +1 -1
  24. package/dist/components/index.js +1 -1
  25. package/dist/components/{tttx-table.d.ts → tttx-form.d.ts} +4 -4
  26. package/dist/components/tttx-form.js +394 -0
  27. package/dist/components/tttx-keyvalue-block.js +7 -4
  28. package/dist/components/tttx-list.js +1678 -7
  29. package/dist/components/tttx-standalone-input.js +1 -0
  30. package/dist/esm/{index-901bfd55.js → index-0350f122.js} +51 -60
  31. package/dist/esm/loader.js +2 -2
  32. package/dist/esm/tttx-button.entry.js +1 -1
  33. package/dist/esm/tttx-form.entry.js +373 -0
  34. package/dist/esm/tttx-icon.entry.js +1 -1
  35. package/dist/esm/tttx-keyvalue-block.entry.js +8 -5
  36. package/dist/esm/tttx-list.entry.js +1677 -7
  37. package/dist/esm/tttx-loading-spinner.entry.js +1 -1
  38. package/dist/esm/tttx-standalone-input.entry.js +2 -1
  39. package/dist/esm/tttx.js +2 -2
  40. package/dist/tttx/{p-a4077908.entry.js → p-1b015a9d.entry.js} +1 -1
  41. package/dist/tttx/p-4ec3aee3.entry.js +1 -0
  42. package/dist/tttx/p-62869344.js +2 -0
  43. package/dist/tttx/{p-0ae51ec5.entry.js → p-92465671.entry.js} +1 -1
  44. package/dist/tttx/p-a0179cb1.entry.js +1 -0
  45. package/dist/tttx/{p-9a382959.entry.js → p-ae71c5ef.entry.js} +1 -1
  46. package/dist/tttx/p-cd1565e0.entry.js +3 -0
  47. package/dist/tttx/p-f36c611b.entry.js +1 -0
  48. package/dist/tttx/tttx.esm.js +1 -1
  49. package/dist/types/components/molecules/tttx-form/lib/setErrorState.d.ts +13 -0
  50. package/dist/types/components/molecules/tttx-form/lib/validityCheck.d.ts +17 -0
  51. package/dist/types/components/molecules/tttx-form/tttx-form.d.ts +114 -0
  52. package/dist/types/components/molecules/{tttx-table/tttx-table.stories.d.ts → tttx-form/tttx-form.stories.d.ts} +2 -10
  53. package/dist/types/components/molecules/tttx-list/interfaces.d.ts +4 -2
  54. package/dist/types/components/molecules/tttx-list/tttx-list.d.ts +3 -1
  55. package/dist/types/components/molecules/tttx-list/tttx-list.stories.d.ts +7 -0
  56. package/dist/types/components.d.ts +26 -28
  57. package/dist/types/shared/domsanitiser.options.d.ts +10 -0
  58. package/package.json +1 -1
  59. package/dist/cjs/tttx-table.cjs.entry.js +0 -60
  60. package/dist/collection/components/atoms/tttx-button/test/tttx-button.e2e.js +0 -9
  61. package/dist/collection/components/atoms/tttx-button/test/tttx-button.spec.js +0 -43
  62. package/dist/collection/components/atoms/tttx-icon/test/tttx-icon.e2e.js +0 -9
  63. package/dist/collection/components/atoms/tttx-icon/test/tttx-icon.spec.js +0 -16
  64. package/dist/collection/components/atoms/tttx-keyvalue-block/test/tttx-keyvalue-block.spec.js +0 -164
  65. package/dist/collection/components/atoms/tttx-loading-spinner/Test/tttx-loading-spinner.spec.js +0 -64
  66. package/dist/collection/components/molecules/tttx-list/test/tttx-list.spec.js +0 -151
  67. package/dist/collection/components/molecules/tttx-standalone-input/test/tttx-standalone-input.e2e.js +0 -9
  68. package/dist/collection/components/molecules/tttx-standalone-input/test/tttx-standalone-input.spec.js +0 -146
  69. package/dist/collection/components/molecules/tttx-table/test/tttx-table.e2e.js +0 -9
  70. package/dist/collection/components/molecules/tttx-table/tttx-table.css +0 -166
  71. package/dist/collection/components/molecules/tttx-table/tttx-table.js +0 -174
  72. package/dist/collection/components/molecules/tttx-table/tttx-table.stories.js +0 -81
  73. package/dist/components/tttx-table.js +0 -85
  74. package/dist/esm/tttx-table.entry.js +0 -56
  75. package/dist/tttx/p-1ec23160.entry.js +0 -1
  76. package/dist/tttx/p-300ff6a8.entry.js +0 -1
  77. package/dist/tttx/p-32ad02d3.entry.js +0 -1
  78. package/dist/tttx/p-80cf5236.entry.js +0 -1
  79. package/dist/tttx/p-a1bd16a1.entry.js +0 -1
  80. package/dist/tttx/p-a6953900.entry.js +0 -1
  81. package/dist/tttx/p-b46e3c59.entry.js +0 -1
  82. package/dist/tttx/p-c290160b.js +0 -2
  83. package/dist/tttx/p-dc179257.entry.js +0 -1
  84. package/dist/tttx/p-e19eb07e.entry.js +0 -1
  85. package/dist/tttx/p-e4341658.entry.js +0 -1
  86. package/dist/types/components/atoms/tttx-button/test/tttx-button.e2e.d.ts +0 -1
  87. package/dist/types/components/atoms/tttx-button/test/tttx-button.spec.d.ts +0 -1
  88. package/dist/types/components/atoms/tttx-icon/test/tttx-icon.e2e.d.ts +0 -1
  89. package/dist/types/components/atoms/tttx-icon/test/tttx-icon.spec.d.ts +0 -1
  90. package/dist/types/components/atoms/tttx-keyvalue-block/test/tttx-keyvalue-block.spec.d.ts +0 -1
  91. package/dist/types/components/atoms/tttx-loading-spinner/Test/tttx-loading-spinner.spec.d.ts +0 -1
  92. package/dist/types/components/molecules/tttx-list/test/tttx-list.spec.d.ts +0 -1
  93. package/dist/types/components/molecules/tttx-standalone-input/test/tttx-standalone-input.e2e.d.ts +0 -1
  94. package/dist/types/components/molecules/tttx-standalone-input/test/tttx-standalone-input.spec.d.ts +0 -1
  95. package/dist/types/components/molecules/tttx-table/test/tttx-table.e2e.d.ts +0 -1
  96. package/dist/types/components/molecules/tttx-table/tttx-table.d.ts +0 -15
@@ -51,6 +51,7 @@ const TttxInput = /*@__PURE__*/ proxyCustomElement(class extends HTMLElement {
51
51
  this.blurChanged.emit(target.value);
52
52
  }
53
53
  handleInvalid(event) {
54
+ event.preventDefault();
54
55
  const target = event.target;
55
56
  this.invalidChanged.emit(target.value);
56
57
  }
@@ -146,10 +146,6 @@ const parsePropertyValue = (propValue, propType) => {
146
146
  // but we'll cheat here and say that the string "false" is the boolean false
147
147
  return propValue === 'false' ? false : propValue === '' || !!propValue;
148
148
  }
149
- if (propType & 2 /* MEMBER_FLAGS.Number */) {
150
- // force it to be a number
151
- return parseFloat(propValue);
152
- }
153
149
  if (propType & 1 /* MEMBER_FLAGS.String */) {
154
150
  // could have been passed as a number or boolean
155
151
  // but we still want it as a string
@@ -280,6 +276,12 @@ const setAccessor = (elm, memberName, oldValue, newValue, isSvg, flags) => {
280
276
  classList.remove(...oldClasses.filter((c) => c && !newClasses.includes(c)));
281
277
  classList.add(...newClasses.filter((c) => c && !oldClasses.includes(c)));
282
278
  }
279
+ else if (memberName === 'ref') {
280
+ // minifier will clean this up
281
+ if (newValue) {
282
+ newValue(elm);
283
+ }
284
+ }
283
285
  else if ((!isProp ) &&
284
286
  memberName[0] === 'o' &&
285
287
  memberName[1] === 'n') {
@@ -446,6 +448,7 @@ const removeVnodes = (vnodes, startIdx, endIdx, vnode, elm) => {
446
448
  for (; startIdx <= endIdx; ++startIdx) {
447
449
  if ((vnode = vnodes[startIdx])) {
448
450
  elm = vnode.$elm$;
451
+ callNodeRefs(vnode);
449
452
  // remove the vnode's element from the dom
450
453
  elm.remove();
451
454
  }
@@ -697,6 +700,12 @@ const patch = (oldVNode, newVNode) => {
697
700
  elm.data = text;
698
701
  }
699
702
  };
703
+ const callNodeRefs = (vNode) => {
704
+ {
705
+ vNode.$attrs$ && vNode.$attrs$.ref && vNode.$attrs$.ref(null);
706
+ vNode.$children$ && vNode.$children$.map(callNodeRefs);
707
+ }
708
+ };
700
709
  const renderVdom = (hostRef, renderFnResults) => {
701
710
  const hostElm = hostRef.$hostElement$;
702
711
  const oldVNode = hostRef.$vnode$ || newVNode(null, null);
@@ -737,17 +746,13 @@ const dispatchHooks = (hostRef, isInitialLoad) => {
737
746
  const instance = hostRef.$lazyInstance$ ;
738
747
  let promise;
739
748
  if (isInitialLoad) {
740
- {
741
- hostRef.$flags$ |= 256 /* HOST_FLAGS.isListenReady */;
742
- if (hostRef.$queuedListeners$) {
743
- hostRef.$queuedListeners$.map(([methodName, event]) => safeCall(instance, methodName, event));
744
- hostRef.$queuedListeners$ = null;
745
- }
746
- }
747
749
  {
748
750
  promise = safeCall(instance, 'componentWillLoad');
749
751
  }
750
752
  }
753
+ {
754
+ promise = then(promise, () => safeCall(instance, 'componentWillRender'));
755
+ }
751
756
  endSchedule();
752
757
  return then(promise, () => updateComponent(hostRef, instance, isInitialLoad));
753
758
  };
@@ -815,7 +820,11 @@ const postUpdateComponent = (hostRef) => {
815
820
  const tagName = hostRef.$cmpMeta$.$tagName$;
816
821
  const elm = hostRef.$hostElement$;
817
822
  const endPostUpdate = createTime('postUpdate', tagName);
823
+ const instance = hostRef.$lazyInstance$ ;
818
824
  const ancestorComponent = hostRef.$ancestorComponent$;
825
+ {
826
+ safeCall(instance, 'componentDidRender');
827
+ }
819
828
  if (!(hostRef.$flags$ & 64 /* HOST_FLAGS.hasLoadedComponent */)) {
820
829
  hostRef.$flags$ |= 64 /* HOST_FLAGS.hasLoadedComponent */;
821
830
  {
@@ -877,6 +886,7 @@ const getValue = (ref, propName) => getHostRef(ref).$instanceValues$.get(propNam
877
886
  const setValue = (ref, propName, newVal, cmpMeta) => {
878
887
  // check our new property value against our internal value
879
888
  const hostRef = getHostRef(ref);
889
+ const elm = hostRef.$hostElement$ ;
880
890
  const oldVal = hostRef.$instanceValues$.get(propName);
881
891
  const flags = hostRef.$flags$;
882
892
  const instance = hostRef.$lazyInstance$ ;
@@ -889,6 +899,22 @@ const setValue = (ref, propName, newVal, cmpMeta) => {
889
899
  // set our new value!
890
900
  hostRef.$instanceValues$.set(propName, newVal);
891
901
  if (instance) {
902
+ // get an array of method names of watch functions to call
903
+ if (cmpMeta.$watchers$ && flags & 128 /* HOST_FLAGS.isWatchReady */) {
904
+ const watchMethods = cmpMeta.$watchers$[propName];
905
+ if (watchMethods) {
906
+ // this instance is watching for when this property changed
907
+ watchMethods.map((watchMethodName) => {
908
+ try {
909
+ // fire off each of the watch methods that are watching this property
910
+ instance[watchMethodName](newVal, oldVal, propName);
911
+ }
912
+ catch (e) {
913
+ consoleError(e, elm);
914
+ }
915
+ });
916
+ }
917
+ }
892
918
  if ((flags & (2 /* HOST_FLAGS.hasRendered */ | 16 /* HOST_FLAGS.isQueuedForUpdate */)) === 2 /* HOST_FLAGS.hasRendered */) {
893
919
  // looks like this value actually changed, so we've got work to do!
894
920
  // but only if we've already rendered, otherwise just chill out
@@ -911,6 +937,9 @@ const setValue = (ref, propName, newVal, cmpMeta) => {
911
937
  */
912
938
  const proxyComponent = (Cstr, cmpMeta, flags) => {
913
939
  if (cmpMeta.$members$) {
940
+ if (Cstr.watchers) {
941
+ cmpMeta.$watchers$ = Cstr.watchers;
942
+ }
914
943
  // It's better to have a const than two Object.entries()
915
944
  const members = Object.entries(cmpMeta.$members$);
916
945
  const prototype = Cstr.prototype;
@@ -1015,6 +1044,12 @@ const initializeComponent = async (elm, hostRef, cmpMeta, hmrVersionId, Cstr) =>
1015
1044
  endLoad();
1016
1045
  }
1017
1046
  if (!Cstr.isProxied) {
1047
+ // we've never proxied this Constructor before
1048
+ // let's add the getters/setters to its prototype before
1049
+ // the first time we create an instance of the implementation
1050
+ {
1051
+ cmpMeta.$watchers$ = Cstr.watchers;
1052
+ }
1018
1053
  proxyComponent(Cstr, cmpMeta, 2 /* PROXY_FLAGS.proxyState */);
1019
1054
  Cstr.isProxied = true;
1020
1055
  }
@@ -1038,6 +1073,9 @@ const initializeComponent = async (elm, hostRef, cmpMeta, hmrVersionId, Cstr) =>
1038
1073
  {
1039
1074
  hostRef.$flags$ &= ~8 /* HOST_FLAGS.isConstructingInstance */;
1040
1075
  }
1076
+ {
1077
+ hostRef.$flags$ |= 128 /* HOST_FLAGS.isWatchReady */;
1078
+ }
1041
1079
  endNewInstance();
1042
1080
  }
1043
1081
  if (Cstr.style) {
@@ -1105,24 +1143,12 @@ const connectedCallback = (elm) => {
1105
1143
  initializeComponent(elm, hostRef, cmpMeta);
1106
1144
  }
1107
1145
  }
1108
- else {
1109
- // not the first time this has connected
1110
- // reattach any event listeners to the host
1111
- // since they would have been removed when disconnected
1112
- addHostEventListeners(elm, hostRef, cmpMeta.$listeners$);
1113
- }
1114
1146
  endConnected();
1115
1147
  }
1116
1148
  };
1117
1149
  const disconnectedCallback = (elm) => {
1118
1150
  if ((plt.$flags$ & 1 /* PLATFORM_FLAGS.isTmpDisconnected */) === 0) {
1119
- const hostRef = getHostRef(elm);
1120
- {
1121
- if (hostRef.$rmListeners$) {
1122
- hostRef.$rmListeners$.map((rmListener) => rmListener());
1123
- hostRef.$rmListeners$ = undefined;
1124
- }
1125
- }
1151
+ getHostRef(elm);
1126
1152
  }
1127
1153
  };
1128
1154
  const bootstrapLazy = (lazyBundles, options = {}) => {
@@ -1150,7 +1176,7 @@ const bootstrapLazy = (lazyBundles, options = {}) => {
1150
1176
  cmpMeta.$members$ = compactMeta[2];
1151
1177
  }
1152
1178
  {
1153
- cmpMeta.$listeners$ = compactMeta[3];
1179
+ cmpMeta.$watchers$ = {};
1154
1180
  }
1155
1181
  const tagName = cmpMeta.$tagName$;
1156
1182
  const HostElement = class extends HTMLElement {
@@ -1217,40 +1243,6 @@ const bootstrapLazy = (lazyBundles, options = {}) => {
1217
1243
  // Fallback appLoad event
1218
1244
  endBootstrap();
1219
1245
  };
1220
- const addHostEventListeners = (elm, hostRef, listeners, attachParentListeners) => {
1221
- if (listeners) {
1222
- listeners.map(([flags, name, method]) => {
1223
- const target = getHostListenerTarget(elm, flags) ;
1224
- const handler = hostListenerProxy(hostRef, method);
1225
- const opts = hostListenerOpts(flags);
1226
- plt.ael(target, name, handler, opts);
1227
- (hostRef.$rmListeners$ = hostRef.$rmListeners$ || []).push(() => plt.rel(target, name, handler, opts));
1228
- });
1229
- }
1230
- };
1231
- const hostListenerProxy = (hostRef, methodName) => (ev) => {
1232
- try {
1233
- {
1234
- if (hostRef.$flags$ & 256 /* HOST_FLAGS.isListenReady */) {
1235
- // instance is ready, let's call it's member method for this event
1236
- hostRef.$lazyInstance$[methodName](ev);
1237
- }
1238
- else {
1239
- (hostRef.$queuedListeners$ = hostRef.$queuedListeners$ || []).push([methodName, ev]);
1240
- }
1241
- }
1242
- }
1243
- catch (e) {
1244
- consoleError(e);
1245
- }
1246
- };
1247
- const getHostListenerTarget = (elm, flags) => {
1248
- if (flags & 4 /* LISTENER_FLAGS.TargetDocument */)
1249
- return doc;
1250
- return elm;
1251
- };
1252
- // prettier-ignore
1253
- const hostListenerOpts = (flags) => (flags & 2 /* LISTENER_FLAGS.Capture */) !== 0;
1254
1246
  const hostRefs = /*@__PURE__*/ new WeakMap();
1255
1247
  const getHostRef = (ref) => hostRefs.get(ref);
1256
1248
  const registerInstance = (lazyInstance, hostRef) => hostRefs.set((hostRef.$lazyInstance$ = lazyInstance), hostRef);
@@ -1266,7 +1258,6 @@ const registerHost = (elm, cmpMeta) => {
1266
1258
  elm['s-p'] = [];
1267
1259
  elm['s-rc'] = [];
1268
1260
  }
1269
- addHostEventListeners(elm, hostRef, cmpMeta.$listeners$);
1270
1261
  return hostRefs.set(elm, hostRef);
1271
1262
  };
1272
1263
  const isMemberInElement = (elm, memberName) => memberName in elm;
@@ -1,4 +1,4 @@
1
- import { p as promiseResolve, b as bootstrapLazy } from './index-901bfd55.js';
1
+ import { p as promiseResolve, b as bootstrapLazy } from './index-0350f122.js';
2
2
 
3
3
  /*
4
4
  Stencil Client Patch Esm v2.20.0 | MIT Licensed | https://stenciljs.com
@@ -10,7 +10,7 @@ const patchEsm = () => {
10
10
  const defineCustomElements = (win, options) => {
11
11
  if (typeof window === 'undefined') return Promise.resolve();
12
12
  return patchEsm().then(() => {
13
- return bootstrapLazy([["tttx-icon",[[1,"tttx-icon",{"icon":[1],"color":[1]}]]],["tttx-button",[[1,"tttx-button",{"notext":[4],"icon":[1],"iconposition":[1],"design":[1]}]]],["tttx-list",[[1,"tttx-list",{"data":[1]}]]],["tttx-standalone-input",[[2,"tttx-standalone-input",{"label":[1],"showerrormsg":[4],"errormsg":[1],"iconleft":[1],"iconright":[1],"inputAutocapitalize":[1,"input-autocapitalize"],"inputAutofocus":[4,"input-autofocus"],"inputKeyhint":[1,"input-keyhint"],"inputIndex":[8,"input-index"],"inputTitle":[1,"input-title"],"autocomplete":[1],"checked":[4],"disabled":[4],"max":[8],"maxlength":[8],"min":[8],"minlength":[8],"name":[1],"pattern":[1],"placeholder":[1],"readonly":[8],"required":[4],"step":[8],"type":[1],"value":[1032]}]]],["tttx-table",[[1,"tttx-table",{"headers":[16],"data":[16],"loading":[4],"selected":[2]},[[4,"keydown","handleKeyDown"]]]]],["tttx-keyvalue-block",[[1,"tttx-keyvalue-block",{"keyvalues":[8],"horizontal":[4]}]]],["tttx-loading-spinner",[[1,"tttx-loading-spinner",{"loadingMessage":[1028,"loading-message"],"size":[1025]}]]]], options);
13
+ return bootstrapLazy([["tttx-button",[[1,"tttx-button",{"notext":[4],"icon":[1],"iconposition":[1],"design":[1]}]]],["tttx-list",[[1,"tttx-list",{"data":[1025],"name":[1]}]]],["tttx-standalone-input",[[2,"tttx-standalone-input",{"label":[1],"showerrormsg":[4],"errormsg":[1],"iconleft":[1],"iconright":[1],"inputAutocapitalize":[1,"input-autocapitalize"],"inputAutofocus":[4,"input-autofocus"],"inputKeyhint":[1,"input-keyhint"],"inputIndex":[8,"input-index"],"inputTitle":[1,"input-title"],"autocomplete":[1],"checked":[4],"disabled":[4],"max":[8],"maxlength":[8],"min":[8],"minlength":[8],"name":[1],"pattern":[1],"placeholder":[1],"readonly":[8],"required":[4],"step":[8],"type":[1],"value":[1032]}]]],["tttx-form",[[1,"tttx-form",{"formschema":[1032],"submitValue":[1032,"submit-value"]}]]],["tttx-keyvalue-block",[[1,"tttx-keyvalue-block",{"keyvalues":[8],"horizontal":[4]}]]],["tttx-loading-spinner",[[1,"tttx-loading-spinner",{"loadingMessage":[1028,"loading-message"],"size":[1025]}]]],["tttx-icon",[[1,"tttx-icon",{"icon":[1],"color":[1]}]]]], options);
14
14
  });
15
15
  };
16
16
 
@@ -1,4 +1,4 @@
1
- import { r as registerInstance, h, H as Host } from './index-901bfd55.js';
1
+ import { r as registerInstance, h, H as Host } from './index-0350f122.js';
2
2
 
3
3
  const tttxButtonCss = ".material-symbols-rounded{font-variation-settings:\"FILL\" 1, \"wght\" 400, \"GRAD\" 0, \"opsz\" 24}.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:inline-block}.spacingleft{margin-left:8px}";
4
4
 
@@ -0,0 +1,373 @@
1
+ import { r as registerInstance, c as createEvent, h, H as Host } from './index-0350f122.js';
2
+
3
+ /**
4
+ * Validates the input field on focusout event by checking its validity state,
5
+ * sets an error message if there's an issue, and emits a "dataChanged" event to
6
+ * the parent component with the field name and its new value.
7
+ *
8
+ * @param {Event} event - The focusout event triggered by the input field.
9
+ * @return {void}
10
+ */
11
+ function validityCheck(event) {
12
+ var _a, _b, _c, _d;
13
+ event.preventDefault();
14
+ const target = event.target;
15
+ let hasError = true;
16
+ let errorMessage = '';
17
+ // validity object on HTML5 inputs has the following options
18
+ // badInput
19
+ // customError
20
+ // patternMismatch
21
+ // rangeOverflow
22
+ // rangeUnderflow
23
+ // stepMismatch
24
+ // tooLong
25
+ // tooShort
26
+ // typeMismatch
27
+ // valid
28
+ // valueMissing
29
+ // customErrors can be set with
30
+ // target.setCustomValidity('custom error!');
31
+ // and cleared with
32
+ // target.setCustomValidity('');
33
+ // Check the validity of the input field and set an error message if needed
34
+ switch (true) {
35
+ // The field is required, but has no value
36
+ case target.validity.valueMissing:
37
+ errorMessage = (_a = target.dataset.required) !== null && _a !== void 0 ? _a : 'This field is required';
38
+ break;
39
+ // The field's value does not match the expected pattern
40
+ case target.validity.patternMismatch:
41
+ errorMessage = (_b = target.dataset.pattern) !== null && _b !== void 0 ? _b : 'Incorrect format';
42
+ break;
43
+ // The field's value is not of the correct input type
44
+ case target.validity.badInput:
45
+ // IE string in a number field
46
+ errorMessage = (_c = target.dataset.badinput) !== null && _c !== void 0 ? _c : 'Wrong input type';
47
+ break;
48
+ // The field's value is above or below the range set in the "min" and "max" attributes
49
+ case target.validity.rangeOverflow || target.validity.rangeUnderflow:
50
+ // IE date or number is above or below value set in min or max tags
51
+ errorMessage = (_d = target.dataset.range) !== null && _d !== void 0 ? _d : 'Invalid value';
52
+ break;
53
+ // No error detected
54
+ default:
55
+ hasError = false;
56
+ }
57
+ // Return the error state
58
+ return { target, hasError, errorMessage };
59
+ }
60
+
61
+ /**
62
+ * Sets the error state of an input field by updating its class and error message.
63
+ * If an error was detected, it sets the input field's class to "invalid" and
64
+ * displays the error message in an error bubble. If no error was detected,
65
+ * it removes the "invalid" class from the input field and clears the error bubble.
66
+ *
67
+ * @param {HTMLInputElement} target - The input field to update.
68
+ * @param {boolean} hasError - Whether an error was detected in the field.
69
+ * @param {string} errorMessage - The error message to display (if any).
70
+ * @return {void}
71
+ */
72
+ function setErrorState(target, hasError, errorMessage) {
73
+ // Find the error bubble element for the input field
74
+ const errorBubble = target.parentElement.querySelector('.errorBubble');
75
+ // If an error was detected, set the input field's class to "invalid" and display the error message in the error bubble
76
+ if (hasError) {
77
+ target.className = 'invalid';
78
+ const errorIcon = document.createElement('span');
79
+ // Set the class of the error icon to a pre-defined CSS class that specifies the icon's appearance
80
+ errorIcon.className = 'material-symbols-rounded';
81
+ // Set the text content of the error icon to the word "warning"
82
+ errorIcon.textContent = 'warning';
83
+ // errorBubble.replaceChildren cannot be used here because the tests don't support this new feature :(
84
+ errorBubble.innerHTML = '';
85
+ errorBubble.append(errorIcon);
86
+ errorBubble.append(errorMessage);
87
+ // errorBubble.replaceChildren(errorIcon, errorMessage);
88
+ }
89
+ // If no error was detected, remove the "invalid" class from the input field and clear the error bubble
90
+ else {
91
+ target.className = '';
92
+ errorBubble.innerHTML = '';
93
+ }
94
+ }
95
+
96
+ const tttxFormCss = ".material-symbols-rounded{font-variation-settings:\"FILL\" 1, \"wght\" 400, \"GRAD\" 0, \"opsz\" 24}.material-symbols-rounded{font-family:\"Material Symbols Rounded\", sans-serif;font-weight:400;font-style:normal;font-size:24px;line-height:1;letter-spacing:normal;text-transform:none;display:inline-block;white-space:nowrap;word-wrap:normal;direction:ltr;text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased;color:#9e9e9e}.icon-left,.icon-right{flex-basis:24px}.icon-left span,.icon-right span{font-size:24px;line-height:24px;text-align:center;display:block;width:24px;height:24px;margin-top:4px}.icon-left span{margin-left:4px}.icon-right span{margin-right:4px}.icon-right{margin-top:5px;margin-right:4px}.icon-left{margin-top:5px;margin-left:4px}.iconleft .input{padding-left:4px}.iconright .input{padding-right:4px}.focused{border-color:#1479c6}.errormsg{display:flex;justify-content:center;align-items:center;float:left;margin-bottom:16px;box-sizing:border-box;background-color:transparent;height:26px;font-size:14px;border-radius:none;z-index:2;color:#dc0000}.errormsg .validationicon{width:16px;height:16px;font-size:16px;margin-right:4px;vertical-align:middle;color:#dc0000}.danger{color:#dc0000}.optional{color:#757575;font-weight:normal}label.inputBlock{display:block;position:relative;line-height:21px}label{font-weight:500;font-size:16px}input:not([type=submit]){font-family:\"Roboto\", serif;box-sizing:border-box;width:100%;height:36px;padding:0 16px;font-size:16px;border:1px solid #d5d5d5;border-radius:4px;margin-top:4px}input[type=date]{background:white;display:block;min-width:calc(100% - 18px);line-height:37px}input.invalid:invalid,input.standalone.invalid{border:1px solid #dc0000}input~.errorBubble{min-height:27px;position:relative;font-size:14px;font-weight:normal;width:100%;font-family:\"Roboto\", sans-serif;color:#dc0000;display:flex;align-content:center;align-items:center;justify-items:center}input~.errorBubble:not(.visible){visibility:hidden}input~.errorBubble span{color:#dc0000;font-size:16px;margin-right:4px;height:16px}input.invalid:invalid~.errorBubble{position:relative;font-size:14px;font-weight:normal;width:100%;font-family:\"Roboto\", sans-serif;color:#dc0000;visibility:visible}input:focus{border-color:#1479c6}.button{font-family:Roboto, serif;box-sizing:border-box;height:36px;min-width:36px;padding:0;margin:0;background:transparent;color:#212121;border:1px solid #c8c8c8;border-radius:4px;text-transform:uppercase;display:flex;justify-content:left;align-items:center;font-size:14px;font-weight:400}.button-content{display:block;padding:0 16px}.icon-left,.icon-right{margin-top:4px}.iconleft{padding-left:8px}.iconleft .button-content{padding-left:4px}.iconright{padding-right:8px}.iconright .button-content{padding-right:4px}.notext{padding:0 6px}.button:hover{background:rgba(17, 17, 17, 0.1);border:1px solid #D5D5D5}.button:active{background:rgba(17, 17, 17, 0.2);border:1px solid #D5D5D5}.primary{background:#1479c6;border:1px solid #1479c6;color:white}.primary:hover{background:#146EB3;border:1px solid #146EB3}.primary:active{background:#1464A2;border:1px solid #1464A2}.borderless{background:transparent;border:none;color:#212121}.borderless:hover{background:rgba(17, 17, 17, 0.1);border:none}.borderless:active{background:rgba(17, 17, 17, 0.2);border:none}.danger{background:#DC0000;border:1px solid #DC0000;color:white}.danger:hover{background:#C60000;border:1px solid #C60000}.danger:active{background:#B00000;border:1px solid #B00000}.disabled{background:#aeaeae;border:none;color:#4c4c4c;cursor:not-allowed}.disabled:hover{background:#aeaeae;border:none;color:#4c4c4c;cursor:not-allowed}.disabled:active{background:#aeaeae;border:none;color:#4c4c4c;cursor:not-allowed}:host{display:block}fieldset{margin:0;padding:0;border:none}input[type=submit]{margin-left:auto}";
97
+
98
+ const TttxForm = class {
99
+ constructor(hostRef) {
100
+ registerInstance(this, hostRef);
101
+ this.dataSubmitted = createEvent(this, "dataSubmitted", 7);
102
+ this.dataChanged = createEvent(this, "dataChanged", 7);
103
+ // Create a new template element using the HTMLTemplateElement interface.
104
+ this.template = document.createElement('template');
105
+ this.formschema = undefined;
106
+ this.submitValue = undefined;
107
+ }
108
+ // This method is called whenever the "formschema" property changes
109
+ onFormSchemaChange(newValue) {
110
+ // Check if the new value is a string, indicating that it needs to be parsed
111
+ if (typeof newValue === 'string') {
112
+ // Parse the string and set the "_formSchema" property
113
+ this._formSchema = JSON.parse(newValue);
114
+ }
115
+ else {
116
+ // If the new value is already an object, set the "_formSchema" property directly
117
+ this._formSchema = newValue;
118
+ }
119
+ }
120
+ /**
121
+ * Handles the focus event for a form field and emits a "dataChanged" event
122
+ * to the parent component with the field name and its new value.
123
+ *
124
+ * @param {ChangeEvent} event - The focus event triggered by the field.
125
+ * @return {void}
126
+ */
127
+ fieldChanged(event) {
128
+ // Extract the name and value of the field from the event
129
+ const fieldName = event.target.name;
130
+ const fieldValue = event.target.value;
131
+ // Emit an event to signal that the field's data has changed
132
+ this.dataChanged.emit({ name: fieldName, value: fieldValue });
133
+ }
134
+ /**
135
+ * Submits the form data to the server.
136
+ *
137
+ * @param {SubmitEvent} event - The event object for the form submission.
138
+ * @returns {void}
139
+ *
140
+ * @example
141
+ * const form = document.getElementById('myForm');
142
+ * form.addEventListener('submit', (event) => {
143
+ * doSubmit(event);
144
+ * });
145
+ */
146
+ doSubmit(event) {
147
+ // prevent the form from submitting normally
148
+ event.preventDefault();
149
+ // create a new FormData object with the form data
150
+ const formData = new FormData(event.target);
151
+ // emit the form data through the `dataSubmitted` event
152
+ this.dataSubmitted.emit(formData);
153
+ }
154
+ // This method is called before the component is loaded into the DOM
155
+ componentWillLoad() {
156
+ // Initialize the form schema by calling the "onFormSchemaChange" method with the current "formschema" property
157
+ this.onFormSchemaChange(this.formschema);
158
+ }
159
+ // This method is called before the component is rendered
160
+ componentWillRender() {
161
+ // Clear the template to account for a potential re-render scenario
162
+ this.template = document.createElement('template');
163
+ // Populate the form from the form schema
164
+ this.populateFormFromSchema();
165
+ }
166
+ /**
167
+ * Creates a new HTMLInputElement with the specified name, type, and placeholder (if any),
168
+ * and sets its autocomplete and autocapitalization properties to off.
169
+ *
170
+ * @param {string} formKey - The name of the input field, as specified in the form schema.
171
+ * @param {Object} formProperties - An object containing additional properties for the input field, such as its type and placeholder value.
172
+ * @param {string} formProperties.type - The type of the input field (e.g., "text", "email", "number", etc.).
173
+ * @param {string} [formProperties.placeholder] - An optional placeholder value to display in the input field.
174
+ * @return {HTMLInputElement} - The new input element.
175
+ */
176
+ createInput(formKey, formProperties) {
177
+ var _a;
178
+ // Create a new <input> element with the specified name and type
179
+ const input = document.createElement('input');
180
+ input.name = formKey;
181
+ input.type = formProperties.type;
182
+ // Set the placeholder attribute to the specified value (if any)
183
+ input.placeholder = (_a = formProperties.placeholder) !== null && _a !== void 0 ? _a : '';
184
+ // Disable autocomplete and autocapitalization
185
+ input.autocomplete = 'off';
186
+ input.autocapitalize = 'off';
187
+ // Return the input element
188
+ return input;
189
+ }
190
+ /**
191
+ * Applies validation attributes to an input element based on the specified validation object.
192
+ * If a certain property is present in the object, it will set the corresponding attribute on
193
+ * the input element (e.g., "required" will set the "required" and "data-required" attributes,
194
+ * "pattern" will set the "pattern" and "data-pattern" attributes, etc.).
195
+ *
196
+ * @param {HTMLInputElement} input - The input element to apply validation attributes to.
197
+ * @param {Object} validation - An object containing the validation rules for the input field.
198
+ * @param {Object} [validation.required] - An object containing a "message" property to display if the field is required.
199
+ * @param {Object} [validation.pattern] - An object containing a "pattern" property to match against the field value, and a "message" property to display if the pattern doesn't match.
200
+ * @param {Object} [validation.badInput] - An object containing a "message" property to display if the field value is invalid.
201
+ * @param {Object} [validation.minmax] - An object containing "min" and "max" properties to validate the field value against, and a "message" property to display if the value is out of range.
202
+ * @param {string} [validation.maxlength] - The maximum length of the input field.
203
+ * @return {void}
204
+ */
205
+ applyValidation(input, validation) {
206
+ var _a, _b;
207
+ // If the "required" property is present, add the "required" attribute to the input element and
208
+ // set its "data-required" attribute to the specified message (if any)
209
+ if (validation.required) {
210
+ input.setAttribute('required', '');
211
+ input.setAttribute('data-required', (_a = validation.required.message) !== null && _a !== void 0 ? _a : '');
212
+ }
213
+ // If the "pattern" property is present, add the "pattern" attribute to the input element and set
214
+ // its "data-pattern" attribute to the specified message (if any)
215
+ if (validation.pattern) {
216
+ input.setAttribute('pattern', validation.pattern.pattern);
217
+ input.setAttribute('data-pattern', (_b = validation.pattern.message) !== null && _b !== void 0 ? _b : '');
218
+ }
219
+ // If the "badInput" property is present, set the input element's "data-badinput" attribute to
220
+ // the specified message
221
+ if (validation.badInput) {
222
+ input.setAttribute('data-badinput', validation.badInput.message);
223
+ }
224
+ // If the "minmax" property is present, add the "min" and "max" attributes to the input element
225
+ // and set its "data-range" attribute to the specified message (if any)
226
+ if (validation.minmax) {
227
+ input.setAttribute('min', validation.minmax.min);
228
+ input.setAttribute('max', validation.minmax.max);
229
+ input.setAttribute('data-range', validation.minmax.message);
230
+ }
231
+ // If the "maxlength" property is present, add the "maxlength" attribute to the input element
232
+ if (validation.maxlength) {
233
+ input.setAttribute('maxlength', validation.maxlength);
234
+ }
235
+ }
236
+ // Create a new error bubble element
237
+ createErrorBubble() {
238
+ // Create a new <div> element with the "errorBubble" class
239
+ const errorBubble = document.createElement('div');
240
+ errorBubble.className = 'errorBubble';
241
+ // Return the error bubble element
242
+ return errorBubble;
243
+ }
244
+ /**
245
+ * Creates a new <label> element with the "inputBlock" class and the specified label text,
246
+ * and appends the input element and error bubble element to it. If the form property has
247
+ * no validation object, it adds an "optional" span element to the label.
248
+ *
249
+ * @param {Object} formProperties - An object containing properties for the form field, including its label text and validation rules.
250
+ * @param {HTMLInputElement} input - The input element to associate with the label.
251
+ * @param {HTMLDivElement} errorBubble - The error bubble element to display error messages in.
252
+ * @return {HTMLLabelElement} - The new label element.
253
+ */
254
+ createLabel(formProperties, input, errorBubble) {
255
+ // Create a new <label> element with the "inputBlock" class and the specified text
256
+ const label = document.createElement('label');
257
+ label.className = 'inputBlock';
258
+ label.innerText = formProperties.label;
259
+ // If the form property has no validation object, add an "optional" span element to the label
260
+ if (!formProperties.validation) {
261
+ const optionalSpan = document.createElement('span');
262
+ optionalSpan.className = 'optional';
263
+ optionalSpan.innerHTML = '&nbsp;(optional)';
264
+ label.appendChild(optionalSpan);
265
+ }
266
+ // Append the input element and error bubble element to the label
267
+ label.appendChild(input);
268
+ label.appendChild(errorBubble);
269
+ // Return the label element
270
+ return label;
271
+ }
272
+ /**
273
+ * Creates a new <input> element with the "submit" type, the "primary-blue" class, and the
274
+ * specified label text (i.e., "Save" by default), and returns the new submit button element.
275
+ *
276
+ * @return {HTMLInputElement} - The new submit button element.
277
+ */
278
+ createSubmitButton() {
279
+ // Create a new <input> element with the "submit" type and the specified class and value
280
+ const submitButton = document.createElement('input');
281
+ submitButton.type = 'submit';
282
+ submitButton.className = 'button primary-blue';
283
+ submitButton.value = 'Save';
284
+ // Return the submit button element
285
+ return submitButton;
286
+ }
287
+ /**
288
+ * Populates the form template with input fields and labels based on the properties of the
289
+ * current form schema. For each property in the schema, it creates an input element, applies
290
+ * any validation rules to it, creates an error bubble and label element, and appends them
291
+ * to the form template. Finally, it creates and appends a submit button element to the form.
292
+ *
293
+ * @return {void}
294
+ */
295
+ populateFormFromSchema() {
296
+ // If there is no form schema, return early
297
+ if (!this._formSchema)
298
+ return;
299
+ // Get the properties of the form schema and their keys
300
+ const properties = this._formSchema.properties;
301
+ const propertyKeys = Object.keys(properties);
302
+ // Loop through each property key and create an input, label, and error bubble for it
303
+ propertyKeys.forEach(formKey => {
304
+ const formItem = properties[formKey];
305
+ const formProperties = formItem.form;
306
+ const input = this.createInput(formKey, formProperties);
307
+ // If the form property has validation, apply it to the input
308
+ if (formProperties.validation) {
309
+ this.applyValidation(input, formProperties.validation);
310
+ }
311
+ // Create an error bubble and label element for the input
312
+ const errorBubble = this.createErrorBubble();
313
+ const label = this.createLabel(formProperties, input, errorBubble);
314
+ // Append the label element to the form template
315
+ this.template.content.append(label);
316
+ });
317
+ // Create and append a submit button element to the form template
318
+ const submitButton = this.createSubmitButton();
319
+ this.template.content.append(submitButton);
320
+ }
321
+ /**
322
+ * Clones the form template and binds event listeners to its input elements. First, it checks if
323
+ * there is a form schema present. If so, it clones the template's content, binds events to form
324
+ * input elements, and appends the cloned form elements to the fieldset. The event listeners include
325
+ * "oninvalid" (to check input validity on submit), "onblur" (to check input validity on blur),
326
+ * "onkeyup" (to handle changes in input fields), and "onchange" (to handle changes in select fields).
327
+ *
328
+ * @return {void}
329
+ */
330
+ componentDidRender() {
331
+ // If there's no form schema, return
332
+ if (!this._formSchema) {
333
+ return;
334
+ }
335
+ // Clone the template's content and store it in a variable
336
+ const formItems = this.template.content.cloneNode(true);
337
+ // Bind event listeners to form elements
338
+ const properties = this._formSchema.properties;
339
+ const propertyKeys = Object.keys(properties);
340
+ propertyKeys.forEach((formKey) => {
341
+ const formInput = formItems.querySelector(`[name=${formKey}]`);
342
+ // Bind events to form input elements
343
+ formInput.oninvalid = this.validityCheckWrapper.bind(this);
344
+ formInput.onblur = this.validityCheckWrapper.bind(this);
345
+ formInput.onkeyup = this.fieldChanged.bind(this);
346
+ formInput.onchange = this.fieldChanged.bind(this);
347
+ });
348
+ // Append the cloned form elements to the fieldset
349
+ this.fieldset.appendChild(formItems);
350
+ }
351
+ validityCheckWrapper(event) {
352
+ const { target, hasError, errorMessage } = validityCheck(event);
353
+ setErrorState(target, hasError, errorMessage);
354
+ }
355
+ /**
356
+ * Renders the component's template as a form element with a fieldset container. The form's
357
+ * "onSubmit" event is bound to the "doSubmit" function, which handles the form submission
358
+ * and emits a "dataSubmitted" event with the form data. The fieldset element is assigned
359
+ * to the "fieldset" instance variable using a ref, so it can be populated with form elements
360
+ * later on.
361
+ *
362
+ * @return {JSX.Element} - The rendered form template as a JSX element.
363
+ */
364
+ render() {
365
+ return (h(Host, null, h("form", { onSubmit: this.doSubmit.bind(this) }, h("fieldset", { ref: el => (this.fieldset = el) }))));
366
+ }
367
+ static get watchers() { return {
368
+ "formschema": ["onFormSchemaChange"]
369
+ }; }
370
+ };
371
+ TttxForm.style = tttxFormCss;
372
+
373
+ export { TttxForm as tttx_form };
@@ -1,4 +1,4 @@
1
- import { r as registerInstance, h, H as Host } from './index-901bfd55.js';
1
+ import { r as registerInstance, h, H as Host } from './index-0350f122.js';
2
2
 
3
3
  const tttxIconCss = ".material-symbols-rounded{font-variation-settings:\"FILL\" 1, \"wght\" 400, \"GRAD\" 0, \"opsz\" 24}.material-symbols-rounded{font-family:\"Material Symbols Rounded\", sans-serif;font-weight:400;font-style:normal;font-size:24px;line-height:1;letter-spacing:normal;text-transform:none;display:inline-block;white-space:nowrap;word-wrap:normal;direction:ltr;text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased;color:#9e9e9e}:host{display:inline-block;cursor:default;user-select:none}.icon-size{width:24px;height:24px}.tooltip{background:#ffffff;color:#343434;font-weight:bold;padding:8px 16px;font-size:13px;border-radius:4px;box-shadow:0 0 5px 1px rgba(0, 0, 0, 0.3);display:none}.tooltip[data-show]{display:block}.arrow,.arrow::before{position:absolute;width:8px;height:8px;background:inherit}.arrow{visibility:hidden}.arrow::before{visibility:visible;content:\"\";transform:rotate(45deg)}.tooltip[data-popper-placement^=top]>.arrow{bottom:-4px}.tooltip[data-popper-placement^=bottom]>.arrow{top:-4px}.tooltip[data-popper-placement^=left]>.arrow{right:-4px}.tooltip[data-popper-placement^=right]>.arrow{left:-4px}.red{color:#dc0000}.orange{color:#f59500}.blue{color:#1479c6}.green{color:#a2bb31}.gray{color:#757575}.black{color:#212121}.white{color:white}";
4
4