@optionfactory/ful 0.52.0 → 0.54.0

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.
package/dist/ful.mjs CHANGED
@@ -641,14 +641,6 @@ class Attributes {
641
641
  static uid(prefix) {
642
642
  return `${prefix}-${++Attributes.id}`;
643
643
  }
644
- /**
645
- *
646
- * @param {any} value
647
- * @returns
648
- */
649
- static asBoolean(value) {
650
- return value !== null && value !== undefined && value !== false;
651
- }
652
644
  /**
653
645
  *
654
646
  * @param {HTMLElement} el
@@ -751,36 +743,36 @@ class ElementsRegistry {
751
743
  #tagToclass;
752
744
  #configured;
753
745
  #id = 0;
754
- constructor(){
746
+ constructor() {
755
747
  this.#templates = new TemplatesRegistry();
756
748
  this.#tagToclass = {};
757
749
  }
758
- defineTemplate(html){
759
- if(html === null || html === undefined){
750
+ defineTemplate(html) {
751
+ if (html === null || html === undefined) {
760
752
  return undefined;
761
753
  }
762
754
  const name = `unnamed-${++this.#id}`;
763
755
  this.#templates.put(name, Fragments.fromHtml(html));
764
756
  return name;
765
757
  }
766
- template(k){
767
- if(k === null || k === undefined){
758
+ template(k) {
759
+ if (k === null || k === undefined) {
768
760
  return undefined;
769
761
  }
770
762
  return this.#templates.get(k);
771
763
  }
772
- define(tag, klass){
773
- if(!this.#configured){
764
+ define(tag, klass) {
765
+ if (!this.#configured) {
774
766
  this.#tagToclass[tag] = klass;
775
767
  return this;
776
768
  }
777
- customElements.define(tag, klass);
769
+ customElements.define(tag, klass);
778
770
  return this;
779
771
  }
780
772
  configure(ec) {
781
773
  this.#templates.configure(ec);
782
- for(const [tag, klass] of Object.entries(this.#tagToclass)) {
783
- customElements.define(tag, klass);
774
+ for (const [tag, klass] of Object.entries(this.#tagToclass)) {
775
+ customElements.define(tag, klass);
784
776
  delete this.#tagToclass[tag];
785
777
  }
786
778
  this.#configured = true;
@@ -808,18 +800,34 @@ class UpgradeQueue {
808
800
 
809
801
  const upgradeQueue = new UpgradeQueue();
810
802
 
803
+ const mappers = {
804
+ 'string': attr => attr,
805
+ 'number': attr => attr === null ? null : Number(attr),
806
+ 'bool': attr => attr !== null,
807
+ 'json': attr => JSON.parse(attr)
808
+ };
809
+
811
810
  const ParsedElement = (conf) => {
812
- const {states, attributes, template, slots} = conf || {};
811
+ const { observed, template, slots } = conf || {};
812
+
813
+ const attrsAndTypes = (observed || []).map(a => {
814
+ const [attr, maybeType] = a.split(":");
815
+ const type = maybeType?.trim() || 'string';
816
+ if (!(type in mappers)) {
817
+ throw new Error(`unsupported attribute type: ${type}`);
818
+ }
819
+ return [attr.trim(), type];
820
+ });
821
+
822
+ const attrsAndMappers = attrsAndTypes.map(([attr, type]) => [attr, mappers[type]]);
813
823
 
814
- const observed_states = states || [];
815
- const observed_attributes = attributes || [];
816
- const observed = [].concat(observed_states).concat(observed_attributes);
824
+ const attrToMapper = Object.fromEntries(attrsAndMappers);
817
825
 
818
826
  const templateId = elements.defineTemplate(template);
819
827
 
820
828
  const k = class extends HTMLElement {
821
829
  static get observedAttributes() {
822
- return observed;
830
+ return Object.keys(attrToMapper);
823
831
  }
824
832
  #parsed;
825
833
  #initialized;
@@ -828,7 +836,7 @@ const ParsedElement = (conf) => {
828
836
  super(...args);
829
837
  this.#internals = this.attachInternals();
830
838
  }
831
- get initialized(){
839
+ get initialized() {
832
840
  return this.#initialized;
833
841
  }
834
842
  get internals() {
@@ -855,11 +863,12 @@ const ParsedElement = (conf) => {
855
863
  });
856
864
  observer.observe(this.parentNode, { childList: true, subtree: true });
857
865
  }
858
- attributeChangedCallback(name, oldValue, newValue) {
866
+ attributeChangedCallback(attr, oldValue, newValue) {
859
867
  if (!this.#parsed || oldValue === newValue) {
860
868
  return;
861
869
  }
862
- this[name] = newValue;
870
+ const mapper = attrToMapper[attr];
871
+ this[attr] = mapper(newValue);
863
872
  }
864
873
  async upgrade() {
865
874
  if (this.#parsed) {
@@ -867,34 +876,29 @@ const ParsedElement = (conf) => {
867
876
  }
868
877
  this.#parsed = true;
869
878
  await this.render(elements.template(templateId), slots ? LightSlots.from(this) : undefined);
870
- for (const flag of observed_states) {
871
- if (this.hasAttribute(flag)) {
872
- this[flag] = true;
873
- }
874
- }
875
- for (const other of observed_attributes) {
876
- if (this.hasAttribute(other)) {
877
- this[other] = this.getAttribute(other);
879
+
880
+ for (const [attr, mapper] of attrsAndMappers) {
881
+ if (this.hasAttribute(attr)) {
882
+ this[attr] = mapper(this.getAttribute(attr));
878
883
  }
879
884
  }
880
885
  this.#initialized = true;
881
886
  }
882
887
  };
883
888
 
884
- for (const state of observed_states) {
885
- Object.defineProperty(k.prototype, state, {
889
+ for (const [attr, type] of attrsAndTypes.filter(([a, t]) => t === 'bool')) {
890
+ Object.defineProperty(k.prototype, attr, {
886
891
  enumerable: true,
887
892
  configurable: true,
888
893
  get() {
889
- return this.internals.states.has(`--${state}`);
894
+ return this.internals.states.has(`--${attr}`);
890
895
  },
891
896
  set(value) {
892
- const v = Attributes.asBoolean(value);
893
897
  const et = this.initialized ? 'changed' : 'init';
894
- const event = new SyncEvent(`${state}:${et}`, {
895
- detail: {
898
+ const event = new SyncEvent(`${attr}:${et}`, {
899
+ detail: {
896
900
  target: this,
897
- value: v
901
+ value: value
898
902
  }
899
903
  });
900
904
  (async () => {
@@ -903,7 +907,7 @@ const ParsedElement = (conf) => {
903
907
  return;
904
908
  }
905
909
  //see https://developer.mozilla.org/en-US/docs/Web/API/CustomStateSet#using_double_dash_prefixed_idents
906
- this.internals.states[v ? 'add' : 'delete'](`--${state}`);
910
+ this.internals.states[v ? 'add' : 'delete'](`--${attr}`);
907
911
  })();
908
912
  }
909
913
  });
@@ -1091,8 +1095,7 @@ const makeInputFragment = (el, template, slots) => {
1091
1095
  };
1092
1096
 
1093
1097
  class Input extends ParsedElement({
1094
- states: [],
1095
- attributes: ['value'],
1098
+ observed: ['value'],
1096
1099
  slots: true,
1097
1100
  template: INPUT_TEMPLATE
1098
1101
  }){
@@ -1114,8 +1117,7 @@ class Input extends ParsedElement({
1114
1117
  */
1115
1118
 
1116
1119
  class Select extends ParsedElement({
1117
- states: [],
1118
- attributes: ["value"],
1120
+ observed: ["value"],
1119
1121
  slots: true,
1120
1122
  template: `
1121
1123
  <label data-tpl-for="tsId" class="form-label">{{{{ slots.default }}}}</label>
@@ -1215,8 +1217,7 @@ class Select extends ParsedElement({
1215
1217
  }
1216
1218
 
1217
1219
  class RadioGroup extends ParsedElement({
1218
- states: ['disabled'],
1219
- attributes: ['value'],
1220
+ observed: ['value', 'disabled:bool'],
1220
1221
  slots: true,
1221
1222
  template: `
1222
1223
  <fieldset>
@@ -1227,10 +1228,12 @@ class RadioGroup extends ParsedElement({
1227
1228
  {{{{ slots.header }}}}
1228
1229
  </header>
1229
1230
  <section>
1230
- <label data-tpl-each="inputsAndLabels" data-tpl-var="ial">
1231
- {{{{ ial[0] }}}}
1232
- {{{{ ial[1] }}}}
1233
- </label>
1231
+ <div class="label-wrapper" data-tpl-each="inputsAndLabels" data-tpl-var="ial">
1232
+ <label>
1233
+ {{{{ ial[0] }}}}
1234
+ {{{{ ial[1] }}}}
1235
+ </label>
1236
+ </div>
1234
1237
  </section>
1235
1238
  <ful-field-error data-tpl-if="name" data-tpl-field="name"></ful-field-error>
1236
1239
  <footer data-tpl-if="slots.footer">