@optionfactory/fml 9.0.0-rc16 → 9.0.0-rc19
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/custom-elements.json +17 -3
- package/dist/fml.css +9 -9
- package/dist/fml.css.map +1 -1
- package/dist/fml.iife.js +132 -37
- package/dist/fml.iife.js.map +1 -1
- package/dist/fml.iife.min.js +1 -1
- package/dist/fml.iife.min.js.map +1 -1
- package/dist/ful.css +9 -9
- package/dist/ful.css.map +1 -1
- package/dist/ful.d.mts +41 -12
- package/dist/ful.iife.js +132 -37
- package/dist/ful.iife.js.map +1 -1
- package/dist/ful.iife.min.js +1 -1
- package/dist/ful.iife.min.js.map +1 -1
- package/dist/ful.min.mjs +1 -1
- package/dist/ful.min.mjs.map +1 -1
- package/dist/ful.mjs +132 -37
- package/dist/ful.mjs.map +1 -1
- package/dist/vscode.html-custom-data.json +1 -1
- package/dist/web-types.json +12 -4
- package/package.json +1 -1
package/dist/fml.iife.js
CHANGED
|
@@ -7848,6 +7848,8 @@ var fml = (function (exports) {
|
|
|
7848
7848
|
|
|
7849
7849
|
const INPUT_MODES = { numeric: 'numeric', decimal: 'decimal' };
|
|
7850
7850
|
|
|
7851
|
+
const SEGMENTED = new Set(['date', 'time', 'datetime-local', 'month', 'week']);
|
|
7852
|
+
|
|
7851
7853
|
const signed = (v, digits) => (v.startsWith('-') ? '-' : '') + digits(v);
|
|
7852
7854
|
|
|
7853
7855
|
const NUMERIC_DIGITS = {
|
|
@@ -7909,14 +7911,18 @@ var fml = (function (exports) {
|
|
|
7909
7911
|
* `autocomplete` attribute of the nearest enclosing `<form>`, which the
|
|
7910
7912
|
* platform does not pass on because the control carries `form=""`.
|
|
7911
7913
|
* - `uppercase`, `trim` and `v-type` shape the value as it is read; see `value`.
|
|
7912
|
-
*
|
|
7913
|
-
*
|
|
7914
|
+
* - The control's native `change` is stopped and the field dispatches its own
|
|
7915
|
+
* once the user commits a new value, as a text input does. A date, time,
|
|
7916
|
+
* datetime-local, month or week control fires its native `change` while its
|
|
7917
|
+
* segments are typed, as soon as they make a valid value; for those the field
|
|
7918
|
+
* reports when the control is left or Enter is pressed, at once for a value
|
|
7919
|
+
* picked from the browser's picker, and never a half-typed value.
|
|
7914
7920
|
*
|
|
7915
7921
|
* A subclass template may render more than one control, as the compare filters
|
|
7916
7922
|
* render the two bounds of a range: the first is `_input`, the one the field is
|
|
7917
|
-
* named by
|
|
7918
|
-
*
|
|
7919
|
-
*
|
|
7923
|
+
* named by, and every one of them gets the inputmode, `autocomplete`, the
|
|
7924
|
+
* `input-` passthrough, the keystroke filter, the placeholder and the `change`
|
|
7925
|
+
* reporting. The passthrough leaves `input-id` to the first alone, so no
|
|
7920
7926
|
* two controls share an id.
|
|
7921
7927
|
*/
|
|
7922
7928
|
class Input extends Field {
|
|
@@ -7983,10 +7989,6 @@ var fml = (function (exports) {
|
|
|
7983
7989
|
for (const control of this.#controls) {
|
|
7984
7990
|
this.#configure(control, mode, autocomplete, strip);
|
|
7985
7991
|
}
|
|
7986
|
-
this._input.addEventListener('change', (evt) => {
|
|
7987
|
-
evt.stopPropagation();
|
|
7988
|
-
this._notifyChange();
|
|
7989
|
-
});
|
|
7990
7992
|
return {
|
|
7991
7993
|
fragment,
|
|
7992
7994
|
control: this._input,
|
|
@@ -8010,6 +8012,7 @@ var fml = (function (exports) {
|
|
|
8010
8012
|
if (control !== this._input) {
|
|
8011
8013
|
Attributes.set(control, 'id', id || null);
|
|
8012
8014
|
}
|
|
8015
|
+
this.#reportChanges(control);
|
|
8013
8016
|
control.addEventListener('input', () => {
|
|
8014
8017
|
if (!strip) {
|
|
8015
8018
|
return;
|
|
@@ -8028,13 +8031,53 @@ var fml = (function (exports) {
|
|
|
8028
8031
|
control.setSelectionRange(caret, caret);
|
|
8029
8032
|
});
|
|
8030
8033
|
}
|
|
8034
|
+
/** @param {HTMLInputElement|HTMLTextAreaElement} control */
|
|
8035
|
+
#reportChanges(control) {
|
|
8036
|
+
if (!SEGMENTED.has(control.type)) {
|
|
8037
|
+
control.addEventListener('change', (evt) => {
|
|
8038
|
+
evt.stopPropagation();
|
|
8039
|
+
this._notifyChange();
|
|
8040
|
+
});
|
|
8041
|
+
return;
|
|
8042
|
+
}
|
|
8043
|
+
/** @type {string|null} */
|
|
8044
|
+
let committed = null;
|
|
8045
|
+
let typed = false;
|
|
8046
|
+
const commit = () => {
|
|
8047
|
+
typed = false;
|
|
8048
|
+
const now = JSON.stringify(this.value);
|
|
8049
|
+
if (now === committed) {
|
|
8050
|
+
return;
|
|
8051
|
+
}
|
|
8052
|
+
committed = now;
|
|
8053
|
+
this._notifyChange();
|
|
8054
|
+
};
|
|
8055
|
+
control.addEventListener('focus', () => {
|
|
8056
|
+
committed = JSON.stringify(this.value);
|
|
8057
|
+
});
|
|
8058
|
+
control.addEventListener('keydown', (/** @type any */ evt) => {
|
|
8059
|
+
if (evt.key === 'Enter' && !evt.isComposing) {
|
|
8060
|
+
commit();
|
|
8061
|
+
return;
|
|
8062
|
+
}
|
|
8063
|
+
typed = true;
|
|
8064
|
+
});
|
|
8065
|
+
control.addEventListener('blur', commit);
|
|
8066
|
+
control.addEventListener('change', (evt) => {
|
|
8067
|
+
evt.stopPropagation();
|
|
8068
|
+
if (!typed) {
|
|
8069
|
+
commit();
|
|
8070
|
+
}
|
|
8071
|
+
});
|
|
8072
|
+
}
|
|
8031
8073
|
/**
|
|
8032
8074
|
* The control's text, shaped in this order: upper cased under `uppercase`,
|
|
8033
8075
|
* trimmed under `trim`, `null` when that leaves it empty, every `,` read as
|
|
8034
8076
|
* `.` for `type="decimal"`, and decoded to a number under
|
|
8035
8077
|
* `v-type="number"`, where text that does not decode is answered as it is.
|
|
8036
8078
|
* Writing `null`, `undefined` or `''` empties the control; anything else is
|
|
8037
|
-
* written as its string
|
|
8079
|
+
* written as its string, replacing whatever was being typed, as a native
|
|
8080
|
+
* control's value does. Answers a `string`, a `number` or `null`; typed
|
|
8038
8081
|
* `any` because subclasses answer other values.
|
|
8039
8082
|
* @type {any}
|
|
8040
8083
|
*/
|
|
@@ -8055,7 +8098,7 @@ var fml = (function (exports) {
|
|
|
8055
8098
|
return normalized;
|
|
8056
8099
|
}
|
|
8057
8100
|
set value(value) {
|
|
8058
|
-
this._input.value = value === '' || value === undefined
|
|
8101
|
+
this._input.value = value === '' || value === undefined || value === null ? '' : `${value}`;
|
|
8059
8102
|
}
|
|
8060
8103
|
/**
|
|
8061
8104
|
* The control's placeholder, `null` when there is none. The control always
|
|
@@ -8324,7 +8367,7 @@ var fml = (function (exports) {
|
|
|
8324
8367
|
}
|
|
8325
8368
|
/** @param {string|null|undefined} v an ISO instant; a falsy value empties the input */
|
|
8326
8369
|
set value(v) {
|
|
8327
|
-
|
|
8370
|
+
super.value = v ? Instant.isoToLocal(v) : '';
|
|
8328
8371
|
}
|
|
8329
8372
|
/**
|
|
8330
8373
|
* The lower bound as a UTC ISO instant.
|
|
@@ -8357,7 +8400,6 @@ var fml = (function (exports) {
|
|
|
8357
8400
|
}
|
|
8358
8401
|
/** @param {string|null} v */
|
|
8359
8402
|
set step(v) {
|
|
8360
|
-
|
|
8361
8403
|
this._input.step = v ?? '';
|
|
8362
8404
|
}
|
|
8363
8405
|
}
|
|
@@ -10234,6 +10276,15 @@ var fml = (function (exports) {
|
|
|
10234
10276
|
#query() {
|
|
10235
10277
|
return this.#editing ? this.#input.value : '';
|
|
10236
10278
|
}
|
|
10279
|
+
/**
|
|
10280
|
+
* The text typed to search the vocabulary: what the dropdown was last
|
|
10281
|
+
* asked to match. `''` while the field is not being searched, its control
|
|
10282
|
+
* then showing the selection's label rather than a query.
|
|
10283
|
+
* @returns {string}
|
|
10284
|
+
*/
|
|
10285
|
+
get query() {
|
|
10286
|
+
return this.#query();
|
|
10287
|
+
}
|
|
10237
10288
|
#display() {
|
|
10238
10289
|
const entry = this.#values.values().next().value;
|
|
10239
10290
|
this.#input.value = this.#multiple ? '' : (entry?.label ?? '');
|
|
@@ -11910,10 +11961,6 @@ var fml = (function (exports) {
|
|
|
11910
11961
|
},
|
|
11911
11962
|
});
|
|
11912
11963
|
this.operators = this.declared('operators');
|
|
11913
|
-
this._value2.addEventListener('change', (evt) => {
|
|
11914
|
-
evt.stopPropagation();
|
|
11915
|
-
this._notifyChange();
|
|
11916
|
-
});
|
|
11917
11964
|
if (this._operator.value === null) {
|
|
11918
11965
|
this._showDefaultOperator();
|
|
11919
11966
|
}
|
|
@@ -12391,9 +12438,7 @@ var fml = (function (exports) {
|
|
|
12391
12438
|
*/
|
|
12392
12439
|
get criterion() {
|
|
12393
12440
|
const token = this._value.value;
|
|
12394
|
-
return asCriterion(labelTextOf(this), this._operator.value, [
|
|
12395
|
-
token === '' ? '' : booleanValueLabel(token),
|
|
12396
|
-
]);
|
|
12441
|
+
return asCriterion(labelTextOf(this), this._operator.value, [token === '' ? '' : booleanValueLabel(token)]);
|
|
12397
12442
|
}
|
|
12398
12443
|
/**
|
|
12399
12444
|
* The field's own disabled claim. Setting it disables the value button and
|
|
@@ -12682,6 +12727,18 @@ var fml = (function (exports) {
|
|
|
12682
12727
|
get section() {
|
|
12683
12728
|
return this.#section;
|
|
12684
12729
|
}
|
|
12730
|
+
/**
|
|
12731
|
+
* Dispatches the dismissal on the host and calls `close` unless a listener
|
|
12732
|
+
* prevented it. A dismissal that is not cancelable announces a close the
|
|
12733
|
+
* platform makes whatever the page does, so `close` is not called for it.
|
|
12734
|
+
* @param {CustomEvent} asked
|
|
12735
|
+
* @param {() => void} close
|
|
12736
|
+
*/
|
|
12737
|
+
dismiss(asked, close) {
|
|
12738
|
+
if (this.#host.dispatchEvent(asked) && asked.cancelable) {
|
|
12739
|
+
close();
|
|
12740
|
+
}
|
|
12741
|
+
}
|
|
12685
12742
|
/**
|
|
12686
12743
|
* Calls `dismiss` when a press and its release both land on the backdrop,
|
|
12687
12744
|
* so a selection dragged out of the panel and released outside does not.
|
|
@@ -12820,6 +12877,18 @@ var fml = (function (exports) {
|
|
|
12820
12877
|
* and a press and release both on the backdrop close the dialog, each as a
|
|
12821
12878
|
* dismissal, as Escape does.
|
|
12822
12879
|
*
|
|
12880
|
+
* Before any of those three gestures closes it, the element dispatches a
|
|
12881
|
+
* cancelable, non-bubbling `dialog:dismiss` with `detail: { reason }`, the
|
|
12882
|
+
* reason being `button`, `backdrop` or `escape`; a listener calling
|
|
12883
|
+
* `preventDefault()` keeps it open, to guard unsaved edits. A `data-result`
|
|
12884
|
+
* button, `close-on-submit` and `close()` answer rather than dismiss, and
|
|
12885
|
+
* dispatch none.
|
|
12886
|
+
*
|
|
12887
|
+
* The platform lets a page refuse Escape once per user interaction: a second
|
|
12888
|
+
* Escape with no click or keystroke in between closes the dialog whatever the
|
|
12889
|
+
* page does, `requires-answer` included. That close is still announced by a
|
|
12890
|
+
* `dialog:dismiss`, which is then not cancelable.
|
|
12891
|
+
*
|
|
12823
12892
|
* `requires-answer` withholds the close button and refuses Escape and the
|
|
12824
12893
|
* backdrop, so the dialog is closed only by a button carrying `data-result`
|
|
12825
12894
|
* or from code through `close()`.
|
|
@@ -12892,21 +12961,32 @@ var fml = (function (exports) {
|
|
|
12892
12961
|
this.#dialog.close(result);
|
|
12893
12962
|
}
|
|
12894
12963
|
});
|
|
12964
|
+
const dismiss = (/** @type {'button'|'backdrop'|'escape'} */ reason, platformCloses = false) =>
|
|
12965
|
+
this.#sections.dismiss(
|
|
12966
|
+
new CustomEvent('dialog:dismiss', { cancelable: !platformCloses, detail: { reason } }),
|
|
12967
|
+
() => this.#dialog.close(''),
|
|
12968
|
+
);
|
|
12895
12969
|
if (!requiresAnswer) {
|
|
12896
|
-
this.#sections.onBackdrop(() =>
|
|
12970
|
+
this.#sections.onBackdrop(() => dismiss('backdrop'));
|
|
12897
12971
|
}
|
|
12898
|
-
fragment
|
|
12899
|
-
.querySelector('[data-ref=close]')
|
|
12900
|
-
?.addEventListener('click', () => this.#dialog.close(''));
|
|
12972
|
+
fragment.querySelector('[data-ref=close]')?.addEventListener('click', () => dismiss('button'));
|
|
12901
12973
|
if (closeOnSubmit) {
|
|
12902
12974
|
this.#sections.onSubmitted((response) => {
|
|
12903
12975
|
this.#answer = { dismissed: false, result: null, response };
|
|
12904
12976
|
this.#dialog.close('submitted');
|
|
12905
12977
|
});
|
|
12906
12978
|
}
|
|
12907
|
-
|
|
12908
|
-
|
|
12909
|
-
|
|
12979
|
+
this.#dialog.addEventListener('cancel', (/** @type any */ e) => {
|
|
12980
|
+
if (!e.cancelable) {
|
|
12981
|
+
this.#dialog.returnValue = '';
|
|
12982
|
+
dismiss('escape', true);
|
|
12983
|
+
return;
|
|
12984
|
+
}
|
|
12985
|
+
e.preventDefault();
|
|
12986
|
+
if (!requiresAnswer) {
|
|
12987
|
+
dismiss('escape');
|
|
12988
|
+
}
|
|
12989
|
+
});
|
|
12910
12990
|
this.replaceChildren(fragment);
|
|
12911
12991
|
wireTargets();
|
|
12912
12992
|
}
|
|
@@ -13107,7 +13187,14 @@ var fml = (function (exports) {
|
|
|
13107
13187
|
* default, when absent) or `start`, following the writing direction.
|
|
13108
13188
|
*
|
|
13109
13189
|
* The close button, Escape, and a press and release both on the backdrop all
|
|
13110
|
-
* go through `close()
|
|
13190
|
+
* go through `close()`, once a cancelable, non-bubbling `drawer:dismiss` with
|
|
13191
|
+
* `detail: { reason }` (`button`, `backdrop` or `escape`) has been dispatched
|
|
13192
|
+
* on the element and no listener prevented it: `preventDefault()` keeps the
|
|
13193
|
+
* drawer open, to guard unsaved edits. `close()` and `close-on-submit`
|
|
13194
|
+
* dispatch none. The platform lets a page refuse Escape once per user
|
|
13195
|
+
* interaction: a second Escape with no click or keystroke in between closes
|
|
13196
|
+
* the drawer at once, without the slide, and its `drawer:dismiss` is then not
|
|
13197
|
+
* cancelable. Every close dispatches a non-bubbling `close` event on
|
|
13111
13198
|
* the element with `detail: { dismissed, response }`: `{ dismissed: false,
|
|
13112
13199
|
* response }` when a form closed it under `close-on-submit`, and
|
|
13113
13200
|
* `{ dismissed: true, response: null }` for any other close.
|
|
@@ -13163,13 +13250,23 @@ var fml = (function (exports) {
|
|
|
13163
13250
|
if (placement) {
|
|
13164
13251
|
this.#dialog.setAttribute('placement', placement);
|
|
13165
13252
|
}
|
|
13253
|
+
const dismiss = (/** @type {'button'|'backdrop'|'escape'} */ reason, platformCloses = false) =>
|
|
13254
|
+
this.#sections.dismiss(
|
|
13255
|
+
new CustomEvent('drawer:dismiss', { cancelable: !platformCloses, detail: { reason } }),
|
|
13256
|
+
() => this.close(),
|
|
13257
|
+
);
|
|
13166
13258
|
/** @type {HTMLElement} */ (fragment.querySelector('[data-ref=close]')).addEventListener('click', () =>
|
|
13167
|
-
|
|
13259
|
+
dismiss('button'),
|
|
13168
13260
|
);
|
|
13169
|
-
this.#sections.onBackdrop(() =>
|
|
13261
|
+
this.#sections.onBackdrop(() => dismiss('backdrop'));
|
|
13170
13262
|
this.#dialog.addEventListener('cancel', (e) => {
|
|
13263
|
+
if (!e.cancelable) {
|
|
13264
|
+
this.#stopSlidingOut();
|
|
13265
|
+
dismiss('escape', true);
|
|
13266
|
+
return;
|
|
13267
|
+
}
|
|
13171
13268
|
e.preventDefault();
|
|
13172
|
-
|
|
13269
|
+
dismiss('escape');
|
|
13173
13270
|
});
|
|
13174
13271
|
this.#dialog.addEventListener('close', () => {
|
|
13175
13272
|
this.dispatchEvent(
|
|
@@ -13852,11 +13949,9 @@ var fml = (function (exports) {
|
|
|
13852
13949
|
}
|
|
13853
13950
|
/**
|
|
13854
13951
|
* Moves to the section carrying `data-step="<ref>"`. A move makes that step
|
|
13855
|
-
* and section current, moves the focus to the section, dispatches
|
|
13856
|
-
* on the host (not bubbling) with detail `{ index, step }`,
|
|
13857
|
-
* section requests for it.
|
|
13858
|
-
* bubbles through the host under the same name, so a listener tells the
|
|
13859
|
-
* two apart by `e.target`.
|
|
13952
|
+
* and section current, moves the focus to the section, dispatches
|
|
13953
|
+
* `wizard:change` on the host (not bubbling) with detail `{ index, step }`,
|
|
13954
|
+
* then fires the section requests for it.
|
|
13860
13955
|
* @param {string} ref the section's `data-step`
|
|
13861
13956
|
* @returns {Promise<any[] | undefined> | undefined} a promise resolving to
|
|
13862
13957
|
* the answers once they are delivered, or to undefined when nobody
|
|
@@ -13913,7 +14008,7 @@ var fml = (function (exports) {
|
|
|
13913
14008
|
this.#apply(clamped);
|
|
13914
14009
|
this.#sections[this.#index].focus();
|
|
13915
14010
|
if (this.rendered) {
|
|
13916
|
-
this.dispatchEvent(new CustomEvent('change', { detail: { index: this.#index, step: this.step } }));
|
|
14011
|
+
this.dispatchEvent(new CustomEvent('wizard:change', { detail: { index: this.#index, step: this.step } }));
|
|
13917
14012
|
}
|
|
13918
14013
|
return this.#enter(clamped);
|
|
13919
14014
|
}
|