@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
@@ -168,10 +168,6 @@ const parsePropertyValue = (propValue, propType) => {
168
168
  // but we'll cheat here and say that the string "false" is the boolean false
169
169
  return propValue === 'false' ? false : propValue === '' || !!propValue;
170
170
  }
171
- if (propType & 2 /* MEMBER_FLAGS.Number */) {
172
- // force it to be a number
173
- return parseFloat(propValue);
174
- }
175
171
  if (propType & 1 /* MEMBER_FLAGS.String */) {
176
172
  // could have been passed as a number or boolean
177
173
  // but we still want it as a string
@@ -302,6 +298,12 @@ const setAccessor = (elm, memberName, oldValue, newValue, isSvg, flags) => {
302
298
  classList.remove(...oldClasses.filter((c) => c && !newClasses.includes(c)));
303
299
  classList.add(...newClasses.filter((c) => c && !oldClasses.includes(c)));
304
300
  }
301
+ else if (memberName === 'ref') {
302
+ // minifier will clean this up
303
+ if (newValue) {
304
+ newValue(elm);
305
+ }
306
+ }
305
307
  else if ((!isProp ) &&
306
308
  memberName[0] === 'o' &&
307
309
  memberName[1] === 'n') {
@@ -468,6 +470,7 @@ const removeVnodes = (vnodes, startIdx, endIdx, vnode, elm) => {
468
470
  for (; startIdx <= endIdx; ++startIdx) {
469
471
  if ((vnode = vnodes[startIdx])) {
470
472
  elm = vnode.$elm$;
473
+ callNodeRefs(vnode);
471
474
  // remove the vnode's element from the dom
472
475
  elm.remove();
473
476
  }
@@ -719,6 +722,12 @@ const patch = (oldVNode, newVNode) => {
719
722
  elm.data = text;
720
723
  }
721
724
  };
725
+ const callNodeRefs = (vNode) => {
726
+ {
727
+ vNode.$attrs$ && vNode.$attrs$.ref && vNode.$attrs$.ref(null);
728
+ vNode.$children$ && vNode.$children$.map(callNodeRefs);
729
+ }
730
+ };
722
731
  const renderVdom = (hostRef, renderFnResults) => {
723
732
  const hostElm = hostRef.$hostElement$;
724
733
  const oldVNode = hostRef.$vnode$ || newVNode(null, null);
@@ -759,17 +768,13 @@ const dispatchHooks = (hostRef, isInitialLoad) => {
759
768
  const instance = hostRef.$lazyInstance$ ;
760
769
  let promise;
761
770
  if (isInitialLoad) {
762
- {
763
- hostRef.$flags$ |= 256 /* HOST_FLAGS.isListenReady */;
764
- if (hostRef.$queuedListeners$) {
765
- hostRef.$queuedListeners$.map(([methodName, event]) => safeCall(instance, methodName, event));
766
- hostRef.$queuedListeners$ = null;
767
- }
768
- }
769
771
  {
770
772
  promise = safeCall(instance, 'componentWillLoad');
771
773
  }
772
774
  }
775
+ {
776
+ promise = then(promise, () => safeCall(instance, 'componentWillRender'));
777
+ }
773
778
  endSchedule();
774
779
  return then(promise, () => updateComponent(hostRef, instance, isInitialLoad));
775
780
  };
@@ -837,7 +842,11 @@ const postUpdateComponent = (hostRef) => {
837
842
  const tagName = hostRef.$cmpMeta$.$tagName$;
838
843
  const elm = hostRef.$hostElement$;
839
844
  const endPostUpdate = createTime('postUpdate', tagName);
845
+ const instance = hostRef.$lazyInstance$ ;
840
846
  const ancestorComponent = hostRef.$ancestorComponent$;
847
+ {
848
+ safeCall(instance, 'componentDidRender');
849
+ }
841
850
  if (!(hostRef.$flags$ & 64 /* HOST_FLAGS.hasLoadedComponent */)) {
842
851
  hostRef.$flags$ |= 64 /* HOST_FLAGS.hasLoadedComponent */;
843
852
  {
@@ -899,6 +908,7 @@ const getValue = (ref, propName) => getHostRef(ref).$instanceValues$.get(propNam
899
908
  const setValue = (ref, propName, newVal, cmpMeta) => {
900
909
  // check our new property value against our internal value
901
910
  const hostRef = getHostRef(ref);
911
+ const elm = hostRef.$hostElement$ ;
902
912
  const oldVal = hostRef.$instanceValues$.get(propName);
903
913
  const flags = hostRef.$flags$;
904
914
  const instance = hostRef.$lazyInstance$ ;
@@ -911,6 +921,22 @@ const setValue = (ref, propName, newVal, cmpMeta) => {
911
921
  // set our new value!
912
922
  hostRef.$instanceValues$.set(propName, newVal);
913
923
  if (instance) {
924
+ // get an array of method names of watch functions to call
925
+ if (cmpMeta.$watchers$ && flags & 128 /* HOST_FLAGS.isWatchReady */) {
926
+ const watchMethods = cmpMeta.$watchers$[propName];
927
+ if (watchMethods) {
928
+ // this instance is watching for when this property changed
929
+ watchMethods.map((watchMethodName) => {
930
+ try {
931
+ // fire off each of the watch methods that are watching this property
932
+ instance[watchMethodName](newVal, oldVal, propName);
933
+ }
934
+ catch (e) {
935
+ consoleError(e, elm);
936
+ }
937
+ });
938
+ }
939
+ }
914
940
  if ((flags & (2 /* HOST_FLAGS.hasRendered */ | 16 /* HOST_FLAGS.isQueuedForUpdate */)) === 2 /* HOST_FLAGS.hasRendered */) {
915
941
  // looks like this value actually changed, so we've got work to do!
916
942
  // but only if we've already rendered, otherwise just chill out
@@ -933,6 +959,9 @@ const setValue = (ref, propName, newVal, cmpMeta) => {
933
959
  */
934
960
  const proxyComponent = (Cstr, cmpMeta, flags) => {
935
961
  if (cmpMeta.$members$) {
962
+ if (Cstr.watchers) {
963
+ cmpMeta.$watchers$ = Cstr.watchers;
964
+ }
936
965
  // It's better to have a const than two Object.entries()
937
966
  const members = Object.entries(cmpMeta.$members$);
938
967
  const prototype = Cstr.prototype;
@@ -1037,6 +1066,12 @@ const initializeComponent = async (elm, hostRef, cmpMeta, hmrVersionId, Cstr) =>
1037
1066
  endLoad();
1038
1067
  }
1039
1068
  if (!Cstr.isProxied) {
1069
+ // we've never proxied this Constructor before
1070
+ // let's add the getters/setters to its prototype before
1071
+ // the first time we create an instance of the implementation
1072
+ {
1073
+ cmpMeta.$watchers$ = Cstr.watchers;
1074
+ }
1040
1075
  proxyComponent(Cstr, cmpMeta, 2 /* PROXY_FLAGS.proxyState */);
1041
1076
  Cstr.isProxied = true;
1042
1077
  }
@@ -1060,6 +1095,9 @@ const initializeComponent = async (elm, hostRef, cmpMeta, hmrVersionId, Cstr) =>
1060
1095
  {
1061
1096
  hostRef.$flags$ &= ~8 /* HOST_FLAGS.isConstructingInstance */;
1062
1097
  }
1098
+ {
1099
+ hostRef.$flags$ |= 128 /* HOST_FLAGS.isWatchReady */;
1100
+ }
1063
1101
  endNewInstance();
1064
1102
  }
1065
1103
  if (Cstr.style) {
@@ -1127,24 +1165,12 @@ const connectedCallback = (elm) => {
1127
1165
  initializeComponent(elm, hostRef, cmpMeta);
1128
1166
  }
1129
1167
  }
1130
- else {
1131
- // not the first time this has connected
1132
- // reattach any event listeners to the host
1133
- // since they would have been removed when disconnected
1134
- addHostEventListeners(elm, hostRef, cmpMeta.$listeners$);
1135
- }
1136
1168
  endConnected();
1137
1169
  }
1138
1170
  };
1139
1171
  const disconnectedCallback = (elm) => {
1140
1172
  if ((plt.$flags$ & 1 /* PLATFORM_FLAGS.isTmpDisconnected */) === 0) {
1141
- const hostRef = getHostRef(elm);
1142
- {
1143
- if (hostRef.$rmListeners$) {
1144
- hostRef.$rmListeners$.map((rmListener) => rmListener());
1145
- hostRef.$rmListeners$ = undefined;
1146
- }
1147
- }
1173
+ getHostRef(elm);
1148
1174
  }
1149
1175
  };
1150
1176
  const bootstrapLazy = (lazyBundles, options = {}) => {
@@ -1172,7 +1198,7 @@ const bootstrapLazy = (lazyBundles, options = {}) => {
1172
1198
  cmpMeta.$members$ = compactMeta[2];
1173
1199
  }
1174
1200
  {
1175
- cmpMeta.$listeners$ = compactMeta[3];
1201
+ cmpMeta.$watchers$ = {};
1176
1202
  }
1177
1203
  const tagName = cmpMeta.$tagName$;
1178
1204
  const HostElement = class extends HTMLElement {
@@ -1239,40 +1265,6 @@ const bootstrapLazy = (lazyBundles, options = {}) => {
1239
1265
  // Fallback appLoad event
1240
1266
  endBootstrap();
1241
1267
  };
1242
- const addHostEventListeners = (elm, hostRef, listeners, attachParentListeners) => {
1243
- if (listeners) {
1244
- listeners.map(([flags, name, method]) => {
1245
- const target = getHostListenerTarget(elm, flags) ;
1246
- const handler = hostListenerProxy(hostRef, method);
1247
- const opts = hostListenerOpts(flags);
1248
- plt.ael(target, name, handler, opts);
1249
- (hostRef.$rmListeners$ = hostRef.$rmListeners$ || []).push(() => plt.rel(target, name, handler, opts));
1250
- });
1251
- }
1252
- };
1253
- const hostListenerProxy = (hostRef, methodName) => (ev) => {
1254
- try {
1255
- {
1256
- if (hostRef.$flags$ & 256 /* HOST_FLAGS.isListenReady */) {
1257
- // instance is ready, let's call it's member method for this event
1258
- hostRef.$lazyInstance$[methodName](ev);
1259
- }
1260
- else {
1261
- (hostRef.$queuedListeners$ = hostRef.$queuedListeners$ || []).push([methodName, ev]);
1262
- }
1263
- }
1264
- }
1265
- catch (e) {
1266
- consoleError(e);
1267
- }
1268
- };
1269
- const getHostListenerTarget = (elm, flags) => {
1270
- if (flags & 4 /* LISTENER_FLAGS.TargetDocument */)
1271
- return doc;
1272
- return elm;
1273
- };
1274
- // prettier-ignore
1275
- const hostListenerOpts = (flags) => (flags & 2 /* LISTENER_FLAGS.Capture */) !== 0;
1276
1268
  const hostRefs = /*@__PURE__*/ new WeakMap();
1277
1269
  const getHostRef = (ref) => hostRefs.get(ref);
1278
1270
  const registerInstance = (lazyInstance, hostRef) => hostRefs.set((hostRef.$lazyInstance$ = lazyInstance), hostRef);
@@ -1288,7 +1280,6 @@ const registerHost = (elm, cmpMeta) => {
1288
1280
  elm['s-p'] = [];
1289
1281
  elm['s-rc'] = [];
1290
1282
  }
1291
- addHostEventListeners(elm, hostRef, cmpMeta.$listeners$);
1292
1283
  return hostRefs.set(elm, hostRef);
1293
1284
  };
1294
1285
  const isMemberInElement = (elm, memberName) => memberName in elm;
@@ -2,7 +2,7 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- const index = require('./index-bc080fb4.js');
5
+ const index = require('./index-451f61dd.js');
6
6
 
7
7
  /*
8
8
  Stencil Client Patch Esm v2.20.0 | MIT Licensed | https://stenciljs.com
@@ -14,7 +14,7 @@ const patchEsm = () => {
14
14
  const defineCustomElements = (win, options) => {
15
15
  if (typeof window === 'undefined') return Promise.resolve();
16
16
  return patchEsm().then(() => {
17
- return index.bootstrapLazy([["tttx-icon.cjs",[[1,"tttx-icon",{"icon":[1],"color":[1]}]]],["tttx-button.cjs",[[1,"tttx-button",{"notext":[4],"icon":[1],"iconposition":[1],"design":[1]}]]],["tttx-list.cjs",[[1,"tttx-list",{"data":[1]}]]],["tttx-standalone-input.cjs",[[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.cjs",[[1,"tttx-table",{"headers":[16],"data":[16],"loading":[4],"selected":[2]},[[4,"keydown","handleKeyDown"]]]]],["tttx-keyvalue-block.cjs",[[1,"tttx-keyvalue-block",{"keyvalues":[8],"horizontal":[4]}]]],["tttx-loading-spinner.cjs",[[1,"tttx-loading-spinner",{"loadingMessage":[1028,"loading-message"],"size":[1025]}]]]], options);
17
+ return index.bootstrapLazy([["tttx-button.cjs",[[1,"tttx-button",{"notext":[4],"icon":[1],"iconposition":[1],"design":[1]}]]],["tttx-list.cjs",[[1,"tttx-list",{"data":[1025],"name":[1]}]]],["tttx-standalone-input.cjs",[[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.cjs",[[1,"tttx-form",{"formschema":[1032],"submitValue":[1032,"submit-value"]}]]],["tttx-keyvalue-block.cjs",[[1,"tttx-keyvalue-block",{"keyvalues":[8],"horizontal":[4]}]]],["tttx-loading-spinner.cjs",[[1,"tttx-loading-spinner",{"loadingMessage":[1028,"loading-message"],"size":[1025]}]]],["tttx-icon.cjs",[[1,"tttx-icon",{"icon":[1],"color":[1]}]]]], options);
18
18
  });
19
19
  };
20
20
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- const index = require('./index-bc080fb4.js');
5
+ const index = require('./index-451f61dd.js');
6
6
 
7
7
  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}";
8
8
 
@@ -0,0 +1,377 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ const index = require('./index-451f61dd.js');
6
+
7
+ /**
8
+ * Validates the input field on focusout event by checking its validity state,
9
+ * sets an error message if there's an issue, and emits a "dataChanged" event to
10
+ * the parent component with the field name and its new value.
11
+ *
12
+ * @param {Event} event - The focusout event triggered by the input field.
13
+ * @return {void}
14
+ */
15
+ function validityCheck(event) {
16
+ var _a, _b, _c, _d;
17
+ event.preventDefault();
18
+ const target = event.target;
19
+ let hasError = true;
20
+ let errorMessage = '';
21
+ // validity object on HTML5 inputs has the following options
22
+ // badInput
23
+ // customError
24
+ // patternMismatch
25
+ // rangeOverflow
26
+ // rangeUnderflow
27
+ // stepMismatch
28
+ // tooLong
29
+ // tooShort
30
+ // typeMismatch
31
+ // valid
32
+ // valueMissing
33
+ // customErrors can be set with
34
+ // target.setCustomValidity('custom error!');
35
+ // and cleared with
36
+ // target.setCustomValidity('');
37
+ // Check the validity of the input field and set an error message if needed
38
+ switch (true) {
39
+ // The field is required, but has no value
40
+ case target.validity.valueMissing:
41
+ errorMessage = (_a = target.dataset.required) !== null && _a !== void 0 ? _a : 'This field is required';
42
+ break;
43
+ // The field's value does not match the expected pattern
44
+ case target.validity.patternMismatch:
45
+ errorMessage = (_b = target.dataset.pattern) !== null && _b !== void 0 ? _b : 'Incorrect format';
46
+ break;
47
+ // The field's value is not of the correct input type
48
+ case target.validity.badInput:
49
+ // IE string in a number field
50
+ errorMessage = (_c = target.dataset.badinput) !== null && _c !== void 0 ? _c : 'Wrong input type';
51
+ break;
52
+ // The field's value is above or below the range set in the "min" and "max" attributes
53
+ case target.validity.rangeOverflow || target.validity.rangeUnderflow:
54
+ // IE date or number is above or below value set in min or max tags
55
+ errorMessage = (_d = target.dataset.range) !== null && _d !== void 0 ? _d : 'Invalid value';
56
+ break;
57
+ // No error detected
58
+ default:
59
+ hasError = false;
60
+ }
61
+ // Return the error state
62
+ return { target, hasError, errorMessage };
63
+ }
64
+
65
+ /**
66
+ * Sets the error state of an input field by updating its class and error message.
67
+ * If an error was detected, it sets the input field's class to "invalid" and
68
+ * displays the error message in an error bubble. If no error was detected,
69
+ * it removes the "invalid" class from the input field and clears the error bubble.
70
+ *
71
+ * @param {HTMLInputElement} target - The input field to update.
72
+ * @param {boolean} hasError - Whether an error was detected in the field.
73
+ * @param {string} errorMessage - The error message to display (if any).
74
+ * @return {void}
75
+ */
76
+ function setErrorState(target, hasError, errorMessage) {
77
+ // Find the error bubble element for the input field
78
+ const errorBubble = target.parentElement.querySelector('.errorBubble');
79
+ // If an error was detected, set the input field's class to "invalid" and display the error message in the error bubble
80
+ if (hasError) {
81
+ target.className = 'invalid';
82
+ const errorIcon = document.createElement('span');
83
+ // Set the class of the error icon to a pre-defined CSS class that specifies the icon's appearance
84
+ errorIcon.className = 'material-symbols-rounded';
85
+ // Set the text content of the error icon to the word "warning"
86
+ errorIcon.textContent = 'warning';
87
+ // errorBubble.replaceChildren cannot be used here because the tests don't support this new feature :(
88
+ errorBubble.innerHTML = '';
89
+ errorBubble.append(errorIcon);
90
+ errorBubble.append(errorMessage);
91
+ // errorBubble.replaceChildren(errorIcon, errorMessage);
92
+ }
93
+ // If no error was detected, remove the "invalid" class from the input field and clear the error bubble
94
+ else {
95
+ target.className = '';
96
+ errorBubble.innerHTML = '';
97
+ }
98
+ }
99
+
100
+ 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}";
101
+
102
+ const TttxForm = class {
103
+ constructor(hostRef) {
104
+ index.registerInstance(this, hostRef);
105
+ this.dataSubmitted = index.createEvent(this, "dataSubmitted", 7);
106
+ this.dataChanged = index.createEvent(this, "dataChanged", 7);
107
+ // Create a new template element using the HTMLTemplateElement interface.
108
+ this.template = document.createElement('template');
109
+ this.formschema = undefined;
110
+ this.submitValue = undefined;
111
+ }
112
+ // This method is called whenever the "formschema" property changes
113
+ onFormSchemaChange(newValue) {
114
+ // Check if the new value is a string, indicating that it needs to be parsed
115
+ if (typeof newValue === 'string') {
116
+ // Parse the string and set the "_formSchema" property
117
+ this._formSchema = JSON.parse(newValue);
118
+ }
119
+ else {
120
+ // If the new value is already an object, set the "_formSchema" property directly
121
+ this._formSchema = newValue;
122
+ }
123
+ }
124
+ /**
125
+ * Handles the focus event for a form field and emits a "dataChanged" event
126
+ * to the parent component with the field name and its new value.
127
+ *
128
+ * @param {ChangeEvent} event - The focus event triggered by the field.
129
+ * @return {void}
130
+ */
131
+ fieldChanged(event) {
132
+ // Extract the name and value of the field from the event
133
+ const fieldName = event.target.name;
134
+ const fieldValue = event.target.value;
135
+ // Emit an event to signal that the field's data has changed
136
+ this.dataChanged.emit({ name: fieldName, value: fieldValue });
137
+ }
138
+ /**
139
+ * Submits the form data to the server.
140
+ *
141
+ * @param {SubmitEvent} event - The event object for the form submission.
142
+ * @returns {void}
143
+ *
144
+ * @example
145
+ * const form = document.getElementById('myForm');
146
+ * form.addEventListener('submit', (event) => {
147
+ * doSubmit(event);
148
+ * });
149
+ */
150
+ doSubmit(event) {
151
+ // prevent the form from submitting normally
152
+ event.preventDefault();
153
+ // create a new FormData object with the form data
154
+ const formData = new FormData(event.target);
155
+ // emit the form data through the `dataSubmitted` event
156
+ this.dataSubmitted.emit(formData);
157
+ }
158
+ // This method is called before the component is loaded into the DOM
159
+ componentWillLoad() {
160
+ // Initialize the form schema by calling the "onFormSchemaChange" method with the current "formschema" property
161
+ this.onFormSchemaChange(this.formschema);
162
+ }
163
+ // This method is called before the component is rendered
164
+ componentWillRender() {
165
+ // Clear the template to account for a potential re-render scenario
166
+ this.template = document.createElement('template');
167
+ // Populate the form from the form schema
168
+ this.populateFormFromSchema();
169
+ }
170
+ /**
171
+ * Creates a new HTMLInputElement with the specified name, type, and placeholder (if any),
172
+ * and sets its autocomplete and autocapitalization properties to off.
173
+ *
174
+ * @param {string} formKey - The name of the input field, as specified in the form schema.
175
+ * @param {Object} formProperties - An object containing additional properties for the input field, such as its type and placeholder value.
176
+ * @param {string} formProperties.type - The type of the input field (e.g., "text", "email", "number", etc.).
177
+ * @param {string} [formProperties.placeholder] - An optional placeholder value to display in the input field.
178
+ * @return {HTMLInputElement} - The new input element.
179
+ */
180
+ createInput(formKey, formProperties) {
181
+ var _a;
182
+ // Create a new <input> element with the specified name and type
183
+ const input = document.createElement('input');
184
+ input.name = formKey;
185
+ input.type = formProperties.type;
186
+ // Set the placeholder attribute to the specified value (if any)
187
+ input.placeholder = (_a = formProperties.placeholder) !== null && _a !== void 0 ? _a : '';
188
+ // Disable autocomplete and autocapitalization
189
+ input.autocomplete = 'off';
190
+ input.autocapitalize = 'off';
191
+ // Return the input element
192
+ return input;
193
+ }
194
+ /**
195
+ * Applies validation attributes to an input element based on the specified validation object.
196
+ * If a certain property is present in the object, it will set the corresponding attribute on
197
+ * the input element (e.g., "required" will set the "required" and "data-required" attributes,
198
+ * "pattern" will set the "pattern" and "data-pattern" attributes, etc.).
199
+ *
200
+ * @param {HTMLInputElement} input - The input element to apply validation attributes to.
201
+ * @param {Object} validation - An object containing the validation rules for the input field.
202
+ * @param {Object} [validation.required] - An object containing a "message" property to display if the field is required.
203
+ * @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.
204
+ * @param {Object} [validation.badInput] - An object containing a "message" property to display if the field value is invalid.
205
+ * @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.
206
+ * @param {string} [validation.maxlength] - The maximum length of the input field.
207
+ * @return {void}
208
+ */
209
+ applyValidation(input, validation) {
210
+ var _a, _b;
211
+ // If the "required" property is present, add the "required" attribute to the input element and
212
+ // set its "data-required" attribute to the specified message (if any)
213
+ if (validation.required) {
214
+ input.setAttribute('required', '');
215
+ input.setAttribute('data-required', (_a = validation.required.message) !== null && _a !== void 0 ? _a : '');
216
+ }
217
+ // If the "pattern" property is present, add the "pattern" attribute to the input element and set
218
+ // its "data-pattern" attribute to the specified message (if any)
219
+ if (validation.pattern) {
220
+ input.setAttribute('pattern', validation.pattern.pattern);
221
+ input.setAttribute('data-pattern', (_b = validation.pattern.message) !== null && _b !== void 0 ? _b : '');
222
+ }
223
+ // If the "badInput" property is present, set the input element's "data-badinput" attribute to
224
+ // the specified message
225
+ if (validation.badInput) {
226
+ input.setAttribute('data-badinput', validation.badInput.message);
227
+ }
228
+ // If the "minmax" property is present, add the "min" and "max" attributes to the input element
229
+ // and set its "data-range" attribute to the specified message (if any)
230
+ if (validation.minmax) {
231
+ input.setAttribute('min', validation.minmax.min);
232
+ input.setAttribute('max', validation.minmax.max);
233
+ input.setAttribute('data-range', validation.minmax.message);
234
+ }
235
+ // If the "maxlength" property is present, add the "maxlength" attribute to the input element
236
+ if (validation.maxlength) {
237
+ input.setAttribute('maxlength', validation.maxlength);
238
+ }
239
+ }
240
+ // Create a new error bubble element
241
+ createErrorBubble() {
242
+ // Create a new <div> element with the "errorBubble" class
243
+ const errorBubble = document.createElement('div');
244
+ errorBubble.className = 'errorBubble';
245
+ // Return the error bubble element
246
+ return errorBubble;
247
+ }
248
+ /**
249
+ * Creates a new <label> element with the "inputBlock" class and the specified label text,
250
+ * and appends the input element and error bubble element to it. If the form property has
251
+ * no validation object, it adds an "optional" span element to the label.
252
+ *
253
+ * @param {Object} formProperties - An object containing properties for the form field, including its label text and validation rules.
254
+ * @param {HTMLInputElement} input - The input element to associate with the label.
255
+ * @param {HTMLDivElement} errorBubble - The error bubble element to display error messages in.
256
+ * @return {HTMLLabelElement} - The new label element.
257
+ */
258
+ createLabel(formProperties, input, errorBubble) {
259
+ // Create a new <label> element with the "inputBlock" class and the specified text
260
+ const label = document.createElement('label');
261
+ label.className = 'inputBlock';
262
+ label.innerText = formProperties.label;
263
+ // If the form property has no validation object, add an "optional" span element to the label
264
+ if (!formProperties.validation) {
265
+ const optionalSpan = document.createElement('span');
266
+ optionalSpan.className = 'optional';
267
+ optionalSpan.innerHTML = '&nbsp;(optional)';
268
+ label.appendChild(optionalSpan);
269
+ }
270
+ // Append the input element and error bubble element to the label
271
+ label.appendChild(input);
272
+ label.appendChild(errorBubble);
273
+ // Return the label element
274
+ return label;
275
+ }
276
+ /**
277
+ * Creates a new <input> element with the "submit" type, the "primary-blue" class, and the
278
+ * specified label text (i.e., "Save" by default), and returns the new submit button element.
279
+ *
280
+ * @return {HTMLInputElement} - The new submit button element.
281
+ */
282
+ createSubmitButton() {
283
+ // Create a new <input> element with the "submit" type and the specified class and value
284
+ const submitButton = document.createElement('input');
285
+ submitButton.type = 'submit';
286
+ submitButton.className = 'button primary-blue';
287
+ submitButton.value = 'Save';
288
+ // Return the submit button element
289
+ return submitButton;
290
+ }
291
+ /**
292
+ * Populates the form template with input fields and labels based on the properties of the
293
+ * current form schema. For each property in the schema, it creates an input element, applies
294
+ * any validation rules to it, creates an error bubble and label element, and appends them
295
+ * to the form template. Finally, it creates and appends a submit button element to the form.
296
+ *
297
+ * @return {void}
298
+ */
299
+ populateFormFromSchema() {
300
+ // If there is no form schema, return early
301
+ if (!this._formSchema)
302
+ return;
303
+ // Get the properties of the form schema and their keys
304
+ const properties = this._formSchema.properties;
305
+ const propertyKeys = Object.keys(properties);
306
+ // Loop through each property key and create an input, label, and error bubble for it
307
+ propertyKeys.forEach(formKey => {
308
+ const formItem = properties[formKey];
309
+ const formProperties = formItem.form;
310
+ const input = this.createInput(formKey, formProperties);
311
+ // If the form property has validation, apply it to the input
312
+ if (formProperties.validation) {
313
+ this.applyValidation(input, formProperties.validation);
314
+ }
315
+ // Create an error bubble and label element for the input
316
+ const errorBubble = this.createErrorBubble();
317
+ const label = this.createLabel(formProperties, input, errorBubble);
318
+ // Append the label element to the form template
319
+ this.template.content.append(label);
320
+ });
321
+ // Create and append a submit button element to the form template
322
+ const submitButton = this.createSubmitButton();
323
+ this.template.content.append(submitButton);
324
+ }
325
+ /**
326
+ * Clones the form template and binds event listeners to its input elements. First, it checks if
327
+ * there is a form schema present. If so, it clones the template's content, binds events to form
328
+ * input elements, and appends the cloned form elements to the fieldset. The event listeners include
329
+ * "oninvalid" (to check input validity on submit), "onblur" (to check input validity on blur),
330
+ * "onkeyup" (to handle changes in input fields), and "onchange" (to handle changes in select fields).
331
+ *
332
+ * @return {void}
333
+ */
334
+ componentDidRender() {
335
+ // If there's no form schema, return
336
+ if (!this._formSchema) {
337
+ return;
338
+ }
339
+ // Clone the template's content and store it in a variable
340
+ const formItems = this.template.content.cloneNode(true);
341
+ // Bind event listeners to form elements
342
+ const properties = this._formSchema.properties;
343
+ const propertyKeys = Object.keys(properties);
344
+ propertyKeys.forEach((formKey) => {
345
+ const formInput = formItems.querySelector(`[name=${formKey}]`);
346
+ // Bind events to form input elements
347
+ formInput.oninvalid = this.validityCheckWrapper.bind(this);
348
+ formInput.onblur = this.validityCheckWrapper.bind(this);
349
+ formInput.onkeyup = this.fieldChanged.bind(this);
350
+ formInput.onchange = this.fieldChanged.bind(this);
351
+ });
352
+ // Append the cloned form elements to the fieldset
353
+ this.fieldset.appendChild(formItems);
354
+ }
355
+ validityCheckWrapper(event) {
356
+ const { target, hasError, errorMessage } = validityCheck(event);
357
+ setErrorState(target, hasError, errorMessage);
358
+ }
359
+ /**
360
+ * Renders the component's template as a form element with a fieldset container. The form's
361
+ * "onSubmit" event is bound to the "doSubmit" function, which handles the form submission
362
+ * and emits a "dataSubmitted" event with the form data. The fieldset element is assigned
363
+ * to the "fieldset" instance variable using a ref, so it can be populated with form elements
364
+ * later on.
365
+ *
366
+ * @return {JSX.Element} - The rendered form template as a JSX element.
367
+ */
368
+ render() {
369
+ return (index.h(index.Host, null, index.h("form", { onSubmit: this.doSubmit.bind(this) }, index.h("fieldset", { ref: el => (this.fieldset = el) }))));
370
+ }
371
+ static get watchers() { return {
372
+ "formschema": ["onFormSchemaChange"]
373
+ }; }
374
+ };
375
+ TttxForm.style = tttxFormCss;
376
+
377
+ exports.tttx_form = TttxForm;
@@ -2,7 +2,7 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
- const index = require('./index-bc080fb4.js');
5
+ const index = require('./index-451f61dd.js');
6
6
 
7
7
  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}";
8
8