@optionfactory/ful 4.0.14 → 4.0.15

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
@@ -1461,7 +1461,7 @@ class Input extends ParsedElement {
1461
1461
  _fragment(type, slots) {
1462
1462
  return this.template().withOverlay({ type, slots }).render();
1463
1463
  }
1464
- render({ slots, observed, disabled }) {
1464
+ render({ slots, observed, disabled, skipValueSetup }) {
1465
1465
  const type = this._type();
1466
1466
  const fragment = this._fragment(type, slots);
1467
1467
  this._input = fragment.querySelector("input,textarea");
@@ -1469,7 +1469,9 @@ class Input extends ParsedElement {
1469
1469
  Attributes.forward('input-', this, this._input);
1470
1470
  this.disabled = disabled;
1471
1471
  this.readonly = observed.readonly;
1472
- this.value = observed.value;
1472
+ if(!skipValueSetup){
1473
+ this.value = observed.value;
1474
+ }
1473
1475
 
1474
1476
  this._input.addEventListener('change', (evt) => {
1475
1477
  evt.stopPropagation();
@@ -2164,7 +2166,7 @@ class Select extends ParsedElement {
2164
2166
  static templates = {
2165
2167
  items: `
2166
2168
  <ful-item data-tpl-each="entries" data-tpl-var="entry" data-tpl-data-key="entry[0]">
2167
- <div>{{ entry[1] }}</div>
2169
+ <div>{{ entry[1][0] }}</div>
2168
2170
  <button type="button" class="btn btn-sm btn-outline-danger bi bi-x-lg"></button>
2169
2171
  </ful-item>
2170
2172
  `
@@ -3044,15 +3046,16 @@ class Table extends ParsedElement {
3044
3046
  }
3045
3047
  }
3046
3048
 
3047
- class InstantFilter extends ParsedElement {
3048
- static observed = ["value:json"];
3049
- static slots = true;
3049
+ class InstantFilter extends Input {
3050
+ static observed = ['value:json', 'readonly:presence'];
3050
3051
  static template = `
3051
- <div class="form-label" data-tpl-if="label">
3052
- <label>{{{{ label }}}}</label>
3052
+ <div class="form-label">
3053
+ <label>{{{{ slots.default }}}}</label>
3053
3054
  {{{{ slots.info }}}}
3054
3055
  </div>
3055
3056
  <div class="input-group">
3057
+ <span data-tpl-if="slots.ibefore" class="input-group-text">{{{{ slots.ibefore }}}}</span>
3058
+ {{{{ slots.before }}}}
3056
3059
  <button data-ref="operator" class="btn btn-outline-secondary dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false" value="LTE" form="">&PrecedesSlantEqual;</button>
3057
3060
  <ul class="dropdown-menu">
3058
3061
  <li><a class="dropdown-item" role="button" value="EQ">=</a></li>
@@ -3065,32 +3068,21 @@ class InstantFilter extends ParsedElement {
3065
3068
  </ul>
3066
3069
  <input data-ref="value1" type="datetime-local" class="form-control" form="">
3067
3070
  <input data-ref="value2" type="datetime-local" class="form-control" form="" hidden>
3068
- <span class="input-group-text"><i class="bi bi-search"></i></span>
3071
+ {{{{ slots.after }}}}
3072
+ <span data-tpl-if="slots.iafter" class="input-group-text">{{{{ slots.iafter }}}}</span>
3069
3073
  </div>
3070
3074
  <ful-field-error></ful-field-error>
3071
3075
  `;
3072
- static formAssociated = true;
3073
3076
  #operator;
3074
3077
  #value1;
3075
3078
  #value2;
3076
- #fieldError;
3077
- constructor() {
3078
- super();
3079
- this.internals = this.attachInternals();
3080
- }
3081
- render({ slots }) {
3082
- const label = Fragments.toHtml(slots.default.cloneNode(true)).trim().length === 0 ? null : slots.default;
3083
- const name = this.getAttribute("name");
3084
- const fragment = this.template().withOverlay({ slots, label, name }).render();
3085
- this.#operator = fragment.querySelector('[data-ref=operator]');
3086
- this.#value1 = fragment.querySelector('[data-ref=value1]');
3087
- this.#value2 = fragment.querySelector('[data-ref=value2]');
3088
- this.#fieldError = fragment.querySelector('ful-field-error');
3089
- const labelEl = fragment.querySelector('label');
3090
- labelEl?.addEventListener('click', () => this.focus());
3091
- this.#value1.ariaDescribedByElements = [this.#fieldError];
3092
- this.#value1.ariaLabelledByElements = labelEl ? [labelEl] : [];
3093
- this.replaceChildren(fragment);
3079
+ render(conf) {
3080
+ super.render({...conf, skipValueSetup: true});
3081
+ this.#operator = this.querySelector('[data-ref=operator]');
3082
+ this.#value1 = this.querySelector('[data-ref=value1]');
3083
+ this.#value2 = this.querySelector('[data-ref=value2]');
3084
+ this.value = conf.observed.value;
3085
+
3094
3086
  this.addEventListener('click', (evt) => {
3095
3087
  const target = /** @type HTMLElement */ (evt.target);
3096
3088
  if (!target.matches('ul > li > a')) {
@@ -3113,42 +3105,25 @@ class InstantFilter extends ParsedElement {
3113
3105
  if (v === null || v === undefined) {
3114
3106
  this.#value1.value = '';
3115
3107
  this.#value2.value = '';
3116
- this.reflect(() => {
3117
- this.removeAttribute('value');
3118
- });
3119
3108
  return;
3120
3109
  }
3121
3110
  const [operator, ...values] = v;
3122
3111
  this.#operator.setAttribute('value', operator);
3123
3112
  this.#value1.value = values[0] ? Instant.isoToLocal(values[0]) : values[0];
3124
3113
  this.#value2.value = values[1] ? Instant.isoToLocal(values[1]) : values[1];
3125
- this.reflect(() => {
3126
- this.setAttribute('value', JSON.stringify(v));
3127
- });
3128
- }
3129
- focus(options) {
3130
- this.#value1.focus(options);
3131
- }
3132
- setCustomValidity(error) {
3133
- if (!error) {
3134
- this.internals.setValidity({});
3135
- this.#fieldError.innerText = "";
3136
- return;
3137
- }
3138
- this.internals.setValidity({ customError: true }, " ");
3139
- this.#fieldError.innerText = error;
3140
3114
  }
3141
3115
  }
3142
3116
 
3143
- class LocalDateFilter extends ParsedElement {
3144
- static observed = ["value:json"];
3145
- static slots = true;
3117
+ class LocalDateFilter extends Input {
3118
+ static observed = ["value:json", 'readonly:presence'];
3146
3119
  static template = `
3147
- <div class="form-label" data-tpl-if="label">
3148
- <label>{{{{ label }}}}</label>
3120
+ <div class="form-label">
3121
+ <label>{{{{ slots.default }}}}</label>
3149
3122
  {{{{ slots.info }}}}
3150
3123
  </div>
3151
3124
  <div class="input-group">
3125
+ <span data-tpl-if="slots.ibefore" class="input-group-text">{{{{ slots.ibefore }}}}</span>
3126
+ {{{{ slots.before }}}}
3152
3127
  <button data-ref="operator" class="btn btn-outline-secondary dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false" value="EQ" form="">=</button>
3153
3128
  <ul class="dropdown-menu">
3154
3129
  <li><a class="dropdown-item" role="button" value="EQ">=</a></li>
@@ -3161,32 +3136,22 @@ class LocalDateFilter extends ParsedElement {
3161
3136
  </ul>
3162
3137
  <input data-ref="value1" type="date" class="form-control" form="">
3163
3138
  <input data-ref="value2" type="date" class="form-control" form="" hidden>
3164
- <span class="input-group-text"><i class="bi bi-search"></i></span>
3139
+ {{{{ slots.after }}}}
3140
+ <span data-tpl-if="slots.iafter" class="input-group-text">{{{{ slots.iafter }}}}</span>
3165
3141
  </div>
3166
3142
  <ful-field-error></ful-field-error>
3167
3143
  `;
3168
- static formAssociated = true;
3169
3144
  #operator;
3170
3145
  #value1;
3171
3146
  #value2;
3172
- #fieldError;
3173
- constructor() {
3174
- super();
3175
- this.internals = this.attachInternals();
3176
- }
3177
- render({ slots }) {
3178
- const label = Fragments.toHtml(slots.default.cloneNode(true)).trim().length === 0 ? null : slots.default;
3179
- const name = this.getAttribute("name");
3180
- const fragment = this.template().withOverlay({ slots, label, name }).render();
3181
- this.#operator = fragment.querySelector('[data-ref=operator]');
3182
- this.#value1 = fragment.querySelector('[data-ref=value1]');
3183
- this.#value2 = fragment.querySelector('[data-ref=value2]');
3184
- this.#fieldError = fragment.querySelector('ful-field-error');
3185
- const labelEl = fragment.querySelector('label');
3186
- labelEl?.addEventListener('click', () => this.focus());
3187
- this.#value1.ariaDescribedByElements = [this.#fieldError];
3188
- this.#value1.ariaLabelledByElements = labelEl ? [labelEl] : [];
3189
- this.replaceChildren(fragment);
3147
+ render(conf) {
3148
+ super.render({...conf, skipValueSetup: true});
3149
+
3150
+ this.#operator = this.querySelector('[data-ref=operator]');
3151
+ this.#value1 = this.querySelector('[data-ref=value1]');
3152
+ this.#value2 = this.querySelector('[data-ref=value2]');
3153
+ this.value = conf.observed.value;
3154
+
3190
3155
  this.addEventListener('click', (evt) => {
3191
3156
  const target = /** @type HTMLElement */(evt.target);
3192
3157
  if (!target.matches('ul > li > a')) {
@@ -3208,42 +3173,25 @@ class LocalDateFilter extends ParsedElement {
3208
3173
  if (v === null || v === undefined) {
3209
3174
  this.#value1.value = '';
3210
3175
  this.#value2.value = '';
3211
- this.reflect(() => {
3212
- this.removeAttribute('value');
3213
- });
3214
3176
  return;
3215
3177
  }
3216
3178
  const [operator, ...values] = v;
3217
3179
  this.#operator.setAttibute('value', operator);
3218
3180
  this.#value1.value = values[0];
3219
3181
  this.#value2.value = values[1];
3220
- this.reflect(() => {
3221
- this.setAttribute('value', JSON.stringify(v));
3222
- });
3223
- }
3224
- focus(options) {
3225
- this.#value1.focus(options);
3226
- }
3227
- setCustomValidity(error) {
3228
- if (!error) {
3229
- this.internals.setValidity({});
3230
- this.#fieldError.innerText = "";
3231
- return;
3232
- }
3233
- this.internals.setValidity({ customError: true }, " ");
3234
- this.#fieldError.innerText = error;
3235
3182
  }
3236
3183
  }
3237
3184
 
3238
- class TextFilter extends ParsedElement {
3239
- static observed = ["value:json"];
3240
- static slots = true;
3185
+ class TextFilter extends Input {
3186
+ static observed = ["value:json", 'readonly:presence'];
3241
3187
  static template = `
3242
- <div class="form-label" data-tpl-if="label">
3243
- <label>{{{{ label }}}}</label>
3188
+ <div class="form-label">
3189
+ <label>{{{{ slots.default }}}}</label>
3244
3190
  {{{{ slots.info }}}}
3245
3191
  </div>
3246
3192
  <div class="input-group">
3193
+ <span data-tpl-if="slots.ibefore" class="input-group-text">{{{{ slots.ibefore }}}}</span>
3194
+ {{{{ slots.before }}}}
3247
3195
  <button data-ref="operator" class="btn btn-outline-secondary dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false" value="CONTAINS" form="">&mldr;a&mldr;</button>
3248
3196
  <ul class="dropdown-menu">
3249
3197
  <li><a class="dropdown-item" role="button" value="CONTAINS">&mldr;a&mldr;</a></li>
@@ -3252,30 +3200,20 @@ class TextFilter extends ParsedElement {
3252
3200
  <li><a class="dropdown-item" role="button" value="EQ">=</a></li>
3253
3201
  </ul>
3254
3202
  <input data-ref="value" type="text" class="form-control" form="">
3255
- <span class="input-group-text"><i class="bi bi-search"></i></span>
3203
+ {{{{ slots.after }}}}
3204
+ <span data-tpl-if="slots.iafter" class="input-group-text">{{{{ slots.iafter }}}}</span>
3256
3205
  </div>
3257
3206
  <ful-field-error></ful-field-error>
3258
3207
  `;
3259
- static formAssociated = true;
3260
3208
  #operator;
3261
3209
  #value;
3262
- #fieldError;
3263
- constructor() {
3264
- super();
3265
- this.internals = this.attachInternals();
3266
- }
3267
- render({ slots }) {
3268
- const label = Fragments.toHtml(slots.default.cloneNode(true)).trim().length === 0 ? null : slots.default;
3269
- const name = this.getAttribute("name");
3270
- const fragment = this.template().withOverlay({ slots, label, name }).render();
3271
- this.#operator = fragment.querySelector('[data-ref=operator]');
3272
- this.#value = fragment.querySelector('[data-ref=value]');
3273
- this.#fieldError = fragment.querySelector('ful-field-error');
3274
- const labelEl = fragment.querySelector('label');
3275
- labelEl?.addEventListener('click', () => this.focus());
3276
- this.#value.ariaDescribedByElements = [this.#fieldError];
3277
- this.#value.ariaLabelledByElements = labelEl ? [labelEl] : [];
3278
- this.replaceChildren(fragment);
3210
+ render(conf) {
3211
+ super.render({...conf, skipValueSetup: true});
3212
+
3213
+ this.#operator = this.querySelector('[data-ref=operator]');
3214
+ this.#value = this.querySelector('[data-ref=value]');
3215
+ this.value = conf.observed.value;
3216
+
3279
3217
  this.addEventListener('click', (evt) => {
3280
3218
  const target = /** @type HTMLElement */(evt.target);
3281
3219
  if (!target.matches('ul > li > a')) {
@@ -3296,29 +3234,11 @@ class TextFilter extends ParsedElement {
3296
3234
  set value(v) {
3297
3235
  if (v === null || v === undefined) {
3298
3236
  this.#value.value = '';
3299
- this.reflect(() => {
3300
- this.removeAttribute('value');
3301
- });
3302
3237
  return;
3303
3238
  }
3304
3239
  const [operator, sensitivity, value] = v;
3305
3240
  this.#operator.setAttribute('value', operator);
3306
3241
  this.#value.value = value;
3307
- this.reflect(() => {
3308
- this.setAttribute('value', JSON.stringify(v));
3309
- });
3310
- }
3311
- focus(options) {
3312
- this.#value.focus(options);
3313
- }
3314
- setCustomValidity(error) {
3315
- if (!error) {
3316
- this.internals.setValidity({});
3317
- this.#fieldError.innerText = "";
3318
- return;
3319
- }
3320
- this.internals.setValidity({ customError: true }, " ");
3321
- this.#fieldError.innerText = error;
3322
3242
  }
3323
3243
  }
3324
3244