@optionfactory/ful 3.0.0 → 4.0.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.css +1 -1
- package/dist/ful.css.map +1 -1
- package/dist/ful.iife.js +365 -159
- 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 +358 -158
- package/dist/ful.mjs.map +1 -1
- package/package.json +2 -2
package/dist/ful.mjs
CHANGED
|
@@ -721,69 +721,82 @@ class HttpMultipartRequestCustomizer {
|
|
|
721
721
|
}
|
|
722
722
|
}
|
|
723
723
|
|
|
724
|
-
class Storage {
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
this.storage = storage;
|
|
728
|
-
}
|
|
729
|
-
save(k, v) {
|
|
730
|
-
this.storage.setItem(`${this.prefix}-${k}`, JSON.stringify(v));
|
|
724
|
+
class LocalStorage extends Storage {
|
|
725
|
+
static save(k, v) {
|
|
726
|
+
localStorage.setItem(k, JSON.stringify(v));
|
|
731
727
|
}
|
|
732
|
-
load(k) {
|
|
733
|
-
const got =
|
|
734
|
-
return got ===
|
|
728
|
+
static load(k) {
|
|
729
|
+
const got = localStorage.getItem(k);
|
|
730
|
+
return got === null ? undefined : JSON.parse(got);
|
|
735
731
|
}
|
|
736
|
-
remove(k) {
|
|
737
|
-
|
|
732
|
+
static remove(k) {
|
|
733
|
+
localStorage.removeItem(k);
|
|
738
734
|
}
|
|
739
|
-
pop(k) {
|
|
740
|
-
const decoded =
|
|
741
|
-
|
|
735
|
+
static pop(k) {
|
|
736
|
+
const decoded = LocalStorage.load(k);
|
|
737
|
+
LocalStorage.remove(k);
|
|
742
738
|
return decoded;
|
|
743
739
|
}
|
|
744
|
-
}
|
|
745
740
|
|
|
746
|
-
class LocalStorage extends Storage {
|
|
747
|
-
constructor(prefix) {
|
|
748
|
-
super(prefix, localStorage);
|
|
749
|
-
}
|
|
750
741
|
}
|
|
751
742
|
|
|
743
|
+
|
|
744
|
+
|
|
752
745
|
class SessionStorage extends Storage {
|
|
753
|
-
|
|
754
|
-
|
|
746
|
+
static save(k, v) {
|
|
747
|
+
sessionStorage.setItem(k, JSON.stringify(v));
|
|
748
|
+
}
|
|
749
|
+
static load(k) {
|
|
750
|
+
const got = sessionStorage.getItem(k);
|
|
751
|
+
return got === null ? undefined : JSON.parse(got);
|
|
752
|
+
}
|
|
753
|
+
static remove(k) {
|
|
754
|
+
sessionStorage.removeItem(k);
|
|
755
|
+
}
|
|
756
|
+
static pop(k) {
|
|
757
|
+
const decoded = SessionStorage.load(k);
|
|
758
|
+
SessionStorage.remove(k);
|
|
759
|
+
return decoded;
|
|
755
760
|
}
|
|
756
761
|
}
|
|
757
762
|
|
|
758
|
-
class
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
async load(revision) {
|
|
767
|
-
const saved = this.storage.load(this.key);
|
|
768
|
-
if (!!saved && saved.revision === revision) {
|
|
769
|
-
this.cache = saved.value;
|
|
770
|
-
return;
|
|
763
|
+
class VersionedLocalStorage {
|
|
764
|
+
static save(key, revision, data){
|
|
765
|
+
LocalStorage.save(key, {revision, data});
|
|
766
|
+
}
|
|
767
|
+
static load(key, revision){
|
|
768
|
+
const stored = LocalStorage.load(key);
|
|
769
|
+
if(stored === undefined){
|
|
770
|
+
return undefined;
|
|
771
771
|
}
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
this.cache = freshData;
|
|
772
|
+
if(stored.revision !== revision){
|
|
773
|
+
localStorage.removeItem(key);
|
|
774
|
+
return undefined;
|
|
775
|
+
}
|
|
776
|
+
return stored.data;
|
|
778
777
|
}
|
|
779
|
-
|
|
780
|
-
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
class VersionedSessionStorage {
|
|
781
|
+
static save(key, revision, data){
|
|
782
|
+
SessionStorage.save(key, {revision, data});
|
|
783
|
+
}
|
|
784
|
+
static load(key, revision){
|
|
785
|
+
const stored = SessionStorage.load(key);
|
|
786
|
+
if(stored === undefined){
|
|
787
|
+
return undefined;
|
|
788
|
+
}
|
|
789
|
+
if(stored.revision !== revision){
|
|
790
|
+
localStorage.removeItem(key);
|
|
791
|
+
return undefined;
|
|
792
|
+
}
|
|
793
|
+
return stored.data;
|
|
781
794
|
}
|
|
782
795
|
}
|
|
783
796
|
|
|
784
797
|
class AuthorizationCodeFlow {
|
|
785
|
-
static forKeycloak(clientId, realmBaseUrl, redirectUri) {
|
|
786
|
-
const scope = "openid profile";
|
|
798
|
+
static forKeycloak(clientId, realmBaseUrl, redirectUri, maybeScope) {
|
|
799
|
+
const scope = maybeScope ?? "openid profile";
|
|
787
800
|
return new AuthorizationCodeFlow(clientId, scope, {
|
|
788
801
|
auth: new URL("protocol/openid-connect/auth", realmBaseUrl),
|
|
789
802
|
token: new URL("protocol/openid-connect/token", realmBaseUrl),
|
|
@@ -793,7 +806,6 @@ class AuthorizationCodeFlow {
|
|
|
793
806
|
});
|
|
794
807
|
}
|
|
795
808
|
constructor(clientId, scope, { auth, token, registration, logout, redirect }) {
|
|
796
|
-
this.storage = new SessionStorage(clientId);
|
|
797
809
|
this.clientId = clientId;
|
|
798
810
|
this.scope = scope;
|
|
799
811
|
this.uri = { auth, token, registration, logout, redirect };
|
|
@@ -802,7 +814,7 @@ class AuthorizationCodeFlow {
|
|
|
802
814
|
const pkceVerifier = Base64.encode(crypto.getRandomValues(new Uint8Array(32)).buffer);
|
|
803
815
|
const pkceChallenge = Base64.encode(await crypto.subtle.digest("SHA-256", new TextEncoder().encode(pkceVerifier)));
|
|
804
816
|
const state = this.clientId + Base64.encode(crypto.getRandomValues(new Uint8Array(16)).buffer);
|
|
805
|
-
|
|
817
|
+
SessionStorage.save(`${AuthorizationCodeFlow.PKCE_AND_STATE_KEY}-${this.clientId}`, {
|
|
806
818
|
state: state,
|
|
807
819
|
verifier: pkceVerifier
|
|
808
820
|
});
|
|
@@ -830,7 +842,7 @@ class AuthorizationCodeFlow {
|
|
|
830
842
|
}
|
|
831
843
|
async #tokenExchange(code, state) {
|
|
832
844
|
window.history.replaceState('', "", this.uri.redirect);
|
|
833
|
-
const stateAndVerifier =
|
|
845
|
+
const stateAndVerifier = SessionStorage.pop(`${AuthorizationCodeFlow.PKCE_AND_STATE_KEY}-${this.clientId}`);
|
|
834
846
|
if (stateAndVerifier.state !== state) {
|
|
835
847
|
throw new Error("State mismatch");
|
|
836
848
|
}
|
|
@@ -858,7 +870,7 @@ class AuthorizationCodeFlow {
|
|
|
858
870
|
async ensureLoggedIn() {
|
|
859
871
|
const url = new URL(window.location.href);
|
|
860
872
|
const code = url.searchParams.get("code");
|
|
861
|
-
if (code &&
|
|
873
|
+
if (code && SessionStorage.load(`${AuthorizationCodeFlow.PKCE_AND_STATE_KEY}-${this.clientId}`)) {
|
|
862
874
|
//if callback from keycloak and we have our state still stored
|
|
863
875
|
const state = url.searchParams.get("state");
|
|
864
876
|
return await this.#tokenExchange(code, state);
|
|
@@ -1023,24 +1035,22 @@ class AsyncEvents {
|
|
|
1023
1035
|
}
|
|
1024
1036
|
}
|
|
1025
1037
|
|
|
1026
|
-
|
|
1027
|
-
sleep(ms) {
|
|
1038
|
+
class Timing {
|
|
1039
|
+
static sleep(ms) {
|
|
1028
1040
|
return new Promise(resolve => setTimeout(resolve, ms));
|
|
1029
|
-
}
|
|
1030
|
-
DEBOUNCE_DEFAULT
|
|
1031
|
-
DEBOUNCE_IMMEDIATE
|
|
1041
|
+
}
|
|
1042
|
+
static DEBOUNCE_DEFAULT = 0;
|
|
1043
|
+
static DEBOUNCE_IMMEDIATE = 1;
|
|
1032
1044
|
/**
|
|
1033
1045
|
* Executes only after a period of inactivity (pause in events).
|
|
1034
|
-
* Delays execution until events stop for a set duration.
|
|
1035
|
-
* Consolidates multiple rapid events into a single execution.
|
|
1036
1046
|
* Respond to the "end" of a series of events.
|
|
1037
1047
|
* @param {*} timeoutMs
|
|
1038
1048
|
* @param {*} func
|
|
1039
1049
|
* @param {*} [options]
|
|
1040
1050
|
* @returns {[function, function]}
|
|
1041
1051
|
*/
|
|
1042
|
-
debounce(timeoutMs, func, options) {
|
|
1043
|
-
const opts = options ??
|
|
1052
|
+
static debounce(timeoutMs, func, options) {
|
|
1053
|
+
const opts = options ?? Timing.DEBOUNCE_DEFAULT;
|
|
1044
1054
|
let tid = null;
|
|
1045
1055
|
let args = [];
|
|
1046
1056
|
let previousTimestamp = 0;
|
|
@@ -1052,7 +1062,7 @@ const timing = {
|
|
|
1052
1062
|
return;
|
|
1053
1063
|
}
|
|
1054
1064
|
tid = null;
|
|
1055
|
-
if (opts !==
|
|
1065
|
+
if (opts !== Timing.DEBOUNCE_IMMEDIATE) {
|
|
1056
1066
|
func(...args);
|
|
1057
1067
|
}
|
|
1058
1068
|
// This check is needed because `func` can recursively invoke `debounced`.
|
|
@@ -1066,31 +1076,32 @@ const timing = {
|
|
|
1066
1076
|
previousTimestamp = new Date().getTime();
|
|
1067
1077
|
if (tid === null) {
|
|
1068
1078
|
tid = setTimeout(later, timeoutMs);
|
|
1069
|
-
if (opts ===
|
|
1079
|
+
if (opts === Timing.DEBOUNCE_IMMEDIATE) {
|
|
1070
1080
|
func(...args);
|
|
1071
1081
|
}
|
|
1072
1082
|
}
|
|
1073
1083
|
};
|
|
1074
1084
|
const abort = () => clearTimeout(tid);
|
|
1075
1085
|
return [debounced, abort];
|
|
1076
|
-
}
|
|
1077
|
-
THROTTLE_DEFAULT
|
|
1078
|
-
THROTTLE_NO_LEADING
|
|
1079
|
-
THROTTLE_NO_TRAILING
|
|
1086
|
+
}
|
|
1087
|
+
static THROTTLE_DEFAULT = 0;
|
|
1088
|
+
static THROTTLE_NO_LEADING = 1;
|
|
1089
|
+
static THROTTLE_NO_TRAILING = 2;
|
|
1080
1090
|
/**
|
|
1081
1091
|
* Executes at most once per specified time interval, regardless of ongoing events.
|
|
1082
|
-
*
|
|
1083
|
-
*
|
|
1084
|
-
*
|
|
1092
|
+
* @param {*} timeoutMs
|
|
1093
|
+
* @param {*} func
|
|
1094
|
+
* @param {*} [options]
|
|
1095
|
+
* @returns {[function, function]}
|
|
1085
1096
|
*/
|
|
1086
|
-
throttle(timeoutMs, func, options) {
|
|
1087
|
-
const opts = options ??
|
|
1097
|
+
static throttle(timeoutMs, func, options) {
|
|
1098
|
+
const opts = options ?? Timing.THROTTLE_DEFAULT;
|
|
1088
1099
|
let tid = null;
|
|
1089
1100
|
let args = [];
|
|
1090
1101
|
let previousTimestamp = 0;
|
|
1091
1102
|
|
|
1092
1103
|
const later = () => {
|
|
1093
|
-
previousTimestamp = (opts &
|
|
1104
|
+
previousTimestamp = (opts & Timing.THROTTLE_NO_LEADING) ? 0 : new Date().getTime();
|
|
1094
1105
|
tid = null;
|
|
1095
1106
|
func(...args);
|
|
1096
1107
|
if (tid === null) {
|
|
@@ -1099,7 +1110,7 @@ const timing = {
|
|
|
1099
1110
|
};
|
|
1100
1111
|
const throttled = function () {
|
|
1101
1112
|
const now = new Date().getTime();
|
|
1102
|
-
if (!previousTimestamp && (opts &
|
|
1113
|
+
if (!previousTimestamp && (opts & Timing.THROTTLE_NO_LEADING)) {
|
|
1103
1114
|
previousTimestamp = now;
|
|
1104
1115
|
}
|
|
1105
1116
|
const remaining = timeoutMs - (now - previousTimestamp);
|
|
@@ -1114,14 +1125,14 @@ const timing = {
|
|
|
1114
1125
|
if (tid === null) {
|
|
1115
1126
|
args = [];
|
|
1116
1127
|
}
|
|
1117
|
-
} else if (tid === null && !(opts &
|
|
1128
|
+
} else if (tid === null && !(opts & Timing.THROTTLE_NO_TRAILING)) {
|
|
1118
1129
|
tid = setTimeout(later, remaining);
|
|
1119
1130
|
}
|
|
1120
1131
|
};
|
|
1121
1132
|
const abort = () => clearTimeout(tid);
|
|
1122
1133
|
return [throttled, abort];
|
|
1123
1134
|
}
|
|
1124
|
-
}
|
|
1135
|
+
}
|
|
1125
1136
|
|
|
1126
1137
|
class Loaders {
|
|
1127
1138
|
static fromAttributes(el, defaultLoader, options) {
|
|
@@ -1436,24 +1447,30 @@ class Input extends ParsedElement {
|
|
|
1436
1447
|
<ful-field-error></ful-field-error>
|
|
1437
1448
|
`;
|
|
1438
1449
|
static formAssociated = true;
|
|
1439
|
-
|
|
1440
|
-
|
|
1450
|
+
_input;
|
|
1451
|
+
_fieldError;
|
|
1441
1452
|
constructor() {
|
|
1442
1453
|
super();
|
|
1443
1454
|
this.internals = this.attachInternals();
|
|
1444
1455
|
this.internals.role = 'presentation';
|
|
1445
1456
|
}
|
|
1457
|
+
_type() {
|
|
1458
|
+
return this.getAttribute("type") ?? 'text';
|
|
1459
|
+
}
|
|
1460
|
+
_fragment(type, slots) {
|
|
1461
|
+
return this.template().withOverlay({ type, slots }).render();
|
|
1462
|
+
}
|
|
1446
1463
|
render({ slots, observed, disabled }) {
|
|
1447
|
-
const type = this.
|
|
1448
|
-
const fragment = this.
|
|
1449
|
-
this
|
|
1464
|
+
const type = this._type();
|
|
1465
|
+
const fragment = this._fragment(type, slots);
|
|
1466
|
+
this._input = fragment.querySelector("input,textarea");
|
|
1450
1467
|
|
|
1451
|
-
Attributes.forward('input-', this, this
|
|
1468
|
+
Attributes.forward('input-', this, this._input);
|
|
1452
1469
|
this.disabled = disabled;
|
|
1453
1470
|
this.readonly = observed.readonly;
|
|
1454
1471
|
this.value = observed.value;
|
|
1455
1472
|
|
|
1456
|
-
this
|
|
1473
|
+
this._input.addEventListener('change', (evt) => {
|
|
1457
1474
|
evt.stopPropagation();
|
|
1458
1475
|
this.dispatchEvent(new CustomEvent('change', {
|
|
1459
1476
|
bubbles: true,
|
|
@@ -1465,59 +1482,187 @@ class Input extends ParsedElement {
|
|
|
1465
1482
|
});
|
|
1466
1483
|
const label = fragment.querySelector('label');
|
|
1467
1484
|
label.addEventListener('click', () => this.focus());
|
|
1468
|
-
this
|
|
1469
|
-
this
|
|
1470
|
-
this
|
|
1485
|
+
this._fieldError = fragment.querySelector('ful-field-error');
|
|
1486
|
+
this._input.ariaDescribedByElements = [this._fieldError];
|
|
1487
|
+
this._input.ariaLabelledByElements = [label];
|
|
1471
1488
|
this.replaceChildren(fragment);
|
|
1472
1489
|
}
|
|
1473
1490
|
get value() {
|
|
1474
|
-
return this
|
|
1491
|
+
return this._input.value === '' ? null : this._input.value;
|
|
1475
1492
|
}
|
|
1476
1493
|
set value(value) {
|
|
1477
|
-
this
|
|
1494
|
+
this._input.value = value === '' ? null : value;
|
|
1478
1495
|
}
|
|
1479
|
-
get readonly(){
|
|
1480
|
-
return this
|
|
1496
|
+
get readonly() {
|
|
1497
|
+
return this._input.readOnly;
|
|
1481
1498
|
}
|
|
1482
1499
|
set readonly(v) {
|
|
1483
|
-
this
|
|
1484
|
-
}
|
|
1485
|
-
get disabled(){
|
|
1486
|
-
return this.#input.hasAttribute('disabled');
|
|
1500
|
+
this._input.readOnly = v;
|
|
1487
1501
|
}
|
|
1488
|
-
|
|
1489
|
-
|
|
1502
|
+
//@ts-ignore
|
|
1503
|
+
get disabled() {
|
|
1504
|
+
return this._input.hasAttribute('disabled');
|
|
1505
|
+
}
|
|
1506
|
+
set disabled(d) {
|
|
1507
|
+
Attributes.toggle(this._input, 'disabled', d);
|
|
1490
1508
|
}
|
|
1491
1509
|
focus(options) {
|
|
1492
|
-
this
|
|
1510
|
+
this._input.focus(options);
|
|
1493
1511
|
}
|
|
1494
1512
|
setCustomValidity(error) {
|
|
1495
1513
|
if (!error) {
|
|
1496
1514
|
this.internals.setValidity({});
|
|
1497
|
-
this
|
|
1515
|
+
this._fieldError.innerText = "";
|
|
1498
1516
|
return;
|
|
1499
1517
|
}
|
|
1500
1518
|
this.internals.setValidity({ customError: true }, " ");
|
|
1501
|
-
this
|
|
1519
|
+
this._fieldError.innerText = error;
|
|
1502
1520
|
}
|
|
1503
|
-
formResetCallback(){
|
|
1521
|
+
formResetCallback() {
|
|
1504
1522
|
this.value = this.getAttribute("value");
|
|
1505
1523
|
}
|
|
1506
1524
|
}
|
|
1507
1525
|
|
|
1508
|
-
class
|
|
1526
|
+
class LocalDate extends ParsedElement {
|
|
1527
|
+
render() {
|
|
1528
|
+
const content = this.innerHTML.trim();
|
|
1529
|
+
if (content === '') {
|
|
1530
|
+
this.innerHTML = this.getAttribute('default') ?? '';
|
|
1531
|
+
return;
|
|
1532
|
+
}
|
|
1533
|
+
const locale = this.getAttribute("locale") ?? Intl.DateTimeFormat().resolvedOptions().locale;
|
|
1534
|
+
const formatter = new Intl.DateTimeFormat(locale, { year: 'numeric', month: 'numeric', day: 'numeric' });
|
|
1535
|
+
const [y, m, d] = content.split('-').map(Number);
|
|
1536
|
+
this.innerHTML = formatter.format(new Date(y, m - 1, d));
|
|
1537
|
+
}
|
|
1538
|
+
}
|
|
1539
|
+
|
|
1540
|
+
class Instant extends ParsedElement {
|
|
1541
|
+
render() {
|
|
1542
|
+
const content = this.innerHTML.trim();
|
|
1543
|
+
if (content === '') {
|
|
1544
|
+
this.innerHTML = this.getAttribute('default') ?? '';
|
|
1545
|
+
return;
|
|
1546
|
+
}
|
|
1547
|
+
const locale = this.getAttribute("locale") ?? Intl.DateTimeFormat().resolvedOptions().locale;
|
|
1548
|
+
const format = new Intl.DateTimeFormat(locale, {
|
|
1549
|
+
year: 'numeric',
|
|
1550
|
+
month: 'numeric',
|
|
1551
|
+
day: 'numeric',
|
|
1552
|
+
hour: 'numeric',
|
|
1553
|
+
minute: 'numeric',
|
|
1554
|
+
second: 'numeric',
|
|
1555
|
+
hour12: false
|
|
1556
|
+
});
|
|
1557
|
+
this.innerHTML = format.format(new Date(Instant.isoToLocal(content)));
|
|
1558
|
+
}
|
|
1559
|
+
static isoToLocal(iso) {
|
|
1560
|
+
//this is so sad
|
|
1561
|
+
const d = new Date(iso);
|
|
1562
|
+
const pad = (n, v) => String(v).padStart(n, '0');
|
|
1563
|
+
const date = `${d.getFullYear()}-${pad(2, d.getMonth() + 1)}-${pad(2, d.getDate())}`;
|
|
1564
|
+
const time = `${pad(2, d.getHours())}:${pad(2, d.getMinutes())}:${pad(2, d.getSeconds())}.${pad(3, d.getMilliseconds())}`;
|
|
1565
|
+
return `${date}T${time}`
|
|
1566
|
+
}
|
|
1567
|
+
}
|
|
1568
|
+
|
|
1569
|
+
|
|
1570
|
+
class InputLocalDate extends Input {
|
|
1571
|
+
static observed = ['value', 'readonly:presence', 'min', 'max', 'step'];
|
|
1572
|
+
_type() {
|
|
1573
|
+
return 'date';
|
|
1574
|
+
}
|
|
1575
|
+
get min() {
|
|
1576
|
+
const v = this._input.min;
|
|
1577
|
+
return v === '' ? null : v;
|
|
1578
|
+
}
|
|
1579
|
+
set min(v) {
|
|
1580
|
+
this._input.min = v;
|
|
1581
|
+
}
|
|
1582
|
+
get max() {
|
|
1583
|
+
const v = this._input.max;
|
|
1584
|
+
return v === '' ? null : v;
|
|
1585
|
+
}
|
|
1586
|
+
set max(v) {
|
|
1587
|
+
this._input.max = v;
|
|
1588
|
+
}
|
|
1589
|
+
get step() {
|
|
1590
|
+
const v = this._input.step;
|
|
1591
|
+
return v === '' ? null : v;
|
|
1592
|
+
}
|
|
1593
|
+
set step(v) {
|
|
1594
|
+
this._input.step = (v ?? '');
|
|
1595
|
+
}
|
|
1596
|
+
|
|
1597
|
+
}
|
|
1598
|
+
|
|
1599
|
+
class InputLocalTime extends InputLocalDate {
|
|
1600
|
+
_type() {
|
|
1601
|
+
return 'time';
|
|
1602
|
+
}
|
|
1603
|
+
}
|
|
1604
|
+
|
|
1605
|
+
|
|
1606
|
+
class InputInstant extends Input {
|
|
1607
|
+
static observed = ['value', 'readonly:presence', 'min', 'max', 'step'];
|
|
1608
|
+
_type() {
|
|
1609
|
+
return 'datetime-local';
|
|
1610
|
+
}
|
|
1611
|
+
get value() {
|
|
1612
|
+
const v = this._input.value;
|
|
1613
|
+
return v === '' ? null : new Date(v).toISOString();
|
|
1614
|
+
}
|
|
1615
|
+
set value(v) {
|
|
1616
|
+
this._input.value = v ? Instant.isoToLocal(v) : '';
|
|
1617
|
+
}
|
|
1618
|
+
get min() {
|
|
1619
|
+
const v = this._input.min;
|
|
1620
|
+
return v === '' ? null : new Date(v).toISOString();
|
|
1621
|
+
}
|
|
1622
|
+
set min(v) {
|
|
1623
|
+
this._input.min = v ? Instant.isoToLocal(v) : '';
|
|
1624
|
+
}
|
|
1625
|
+
get max() {
|
|
1626
|
+
const v = this._input.max;
|
|
1627
|
+
return v === '' ? null : new Date(v).toISOString();
|
|
1628
|
+
}
|
|
1629
|
+
set max(v) {
|
|
1630
|
+
this._input.max = v ? Instant.isoToLocal(v) : '';
|
|
1631
|
+
}
|
|
1632
|
+
get step() {
|
|
1633
|
+
const v = this._input.step;
|
|
1634
|
+
return v === '' ? null : v;
|
|
1635
|
+
}
|
|
1636
|
+
set step(v) {
|
|
1637
|
+
this._input.step = (v ?? '');
|
|
1638
|
+
}
|
|
1639
|
+
}
|
|
1640
|
+
|
|
1641
|
+
class RemoteLoader {
|
|
1509
1642
|
#http;
|
|
1510
1643
|
#url;
|
|
1511
1644
|
#method;
|
|
1512
1645
|
#responseMapper;
|
|
1513
1646
|
#prefetch;
|
|
1647
|
+
#revision;
|
|
1514
1648
|
#data;
|
|
1515
|
-
|
|
1649
|
+
static create({ el, http, responseMapper }) {
|
|
1650
|
+
return new RemoteLoader({
|
|
1651
|
+
http,
|
|
1652
|
+
url: el.getAttribute("src"),
|
|
1653
|
+
method: el.getAttribute("method") ?? 'POST',
|
|
1654
|
+
responseMapper,
|
|
1655
|
+
prefetch: el.hasAttribute("preload"),
|
|
1656
|
+
revision: el.getAttribute("revision")
|
|
1657
|
+
});
|
|
1658
|
+
}
|
|
1659
|
+
constructor({http, url, method, responseMapper, prefetch, revision}) {
|
|
1516
1660
|
this.#http = http;
|
|
1517
1661
|
this.#url = url;
|
|
1518
1662
|
this.#method = method;
|
|
1519
1663
|
this.#responseMapper = responseMapper;
|
|
1520
1664
|
this.#prefetch = prefetch;
|
|
1665
|
+
this.#revision = revision;
|
|
1521
1666
|
this.#data = null;
|
|
1522
1667
|
}
|
|
1523
1668
|
async prefetch() {
|
|
@@ -1528,37 +1673,47 @@ class CompleteSelectLoader {
|
|
|
1528
1673
|
}
|
|
1529
1674
|
async exact(...keys) {
|
|
1530
1675
|
await this.#ensureFetched();
|
|
1531
|
-
return this.#data.filter(([k, v]) => keys.
|
|
1676
|
+
return this.#data.filter(([k, v]) => keys.some(r => r == k));
|
|
1532
1677
|
}
|
|
1533
1678
|
async load(needle) {
|
|
1534
1679
|
await this.#ensureFetched();
|
|
1535
|
-
return this.#data.filter(([k, v]) => v.includes(needle?.toLowerCase()));
|
|
1680
|
+
return this.#data.filter(([k, v]) => (v ?? '').includes(needle?.toLowerCase()));
|
|
1536
1681
|
}
|
|
1537
1682
|
async #ensureFetched() {
|
|
1538
1683
|
if (this.#data !== null) {
|
|
1539
1684
|
return
|
|
1540
1685
|
}
|
|
1686
|
+
const storageKey = `${this.#method}@${this.#url}`;
|
|
1687
|
+
if(this.#revision !== null){
|
|
1688
|
+
const data = VersionedLocalStorage.load(storageKey, this.#revision);
|
|
1689
|
+
if(data !== undefined){
|
|
1690
|
+
this.#data = data;
|
|
1691
|
+
return;
|
|
1692
|
+
}
|
|
1693
|
+
}
|
|
1541
1694
|
const data = await this.#http.request(this.#method, this.#url)
|
|
1542
1695
|
.fetchJson();
|
|
1543
1696
|
this.#data = this.#responseMapper(data);
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
http,
|
|
1548
|
-
el.getAttribute("src"),
|
|
1549
|
-
el.getAttribute("method") ?? 'POST',
|
|
1550
|
-
responseMapper,
|
|
1551
|
-
el.hasAttribute("preload")
|
|
1552
|
-
);
|
|
1697
|
+
if(this.#revision !== null){
|
|
1698
|
+
VersionedLocalStorage.save(storageKey, this.#revision, this.#data);
|
|
1699
|
+
}
|
|
1553
1700
|
}
|
|
1554
1701
|
}
|
|
1555
1702
|
|
|
1556
|
-
class
|
|
1703
|
+
class PartialRemoteLoader {
|
|
1557
1704
|
#http;
|
|
1558
1705
|
#url;
|
|
1559
1706
|
#method;
|
|
1560
1707
|
#responseMapper;
|
|
1561
|
-
|
|
1708
|
+
static create({ el, http, responseMapper }) {
|
|
1709
|
+
return new PartialRemoteLoader({
|
|
1710
|
+
http,
|
|
1711
|
+
url: el.getAttribute("src"),
|
|
1712
|
+
method: el.getAttribute("method") ?? 'POST',
|
|
1713
|
+
responseMapper
|
|
1714
|
+
});
|
|
1715
|
+
}
|
|
1716
|
+
constructor({http, url, method, responseMapper}) {
|
|
1562
1717
|
this.#http = http;
|
|
1563
1718
|
this.#url = url;
|
|
1564
1719
|
this.#method = method;
|
|
@@ -1576,26 +1731,21 @@ class ChunkedSelectLoader {
|
|
|
1576
1731
|
.fetchJson();
|
|
1577
1732
|
return this.#responseMapper(data);
|
|
1578
1733
|
}
|
|
1579
|
-
static create({ el, http, responseMapper }) {
|
|
1580
|
-
return new ChunkedSelectLoader(
|
|
1581
|
-
http,
|
|
1582
|
-
el.getAttribute("src"),
|
|
1583
|
-
el.getAttribute("method") ?? 'POST',
|
|
1584
|
-
responseMapper
|
|
1585
|
-
);
|
|
1586
|
-
}
|
|
1587
1734
|
}
|
|
1588
1735
|
|
|
1589
|
-
class
|
|
1736
|
+
class InMemoryLoader {
|
|
1590
1737
|
#data
|
|
1591
1738
|
constructor(data) {
|
|
1592
1739
|
this.#data = data;
|
|
1593
1740
|
}
|
|
1594
|
-
|
|
1595
|
-
|
|
1741
|
+
update(data) {
|
|
1742
|
+
this.#data = data;
|
|
1596
1743
|
}
|
|
1597
|
-
|
|
1598
|
-
return this.#data.filter(([k, v]) =>
|
|
1744
|
+
exact(...keys) {
|
|
1745
|
+
return this.#data.filter(([k, v]) => keys.some(r => r == k));
|
|
1746
|
+
}
|
|
1747
|
+
load(needle) {
|
|
1748
|
+
return this.#data.filter(([k, v]) => (v ?? '').includes(needle?.toLowerCase()));
|
|
1599
1749
|
}
|
|
1600
1750
|
}
|
|
1601
1751
|
|
|
@@ -1607,10 +1757,10 @@ class SelectLoader {
|
|
|
1607
1757
|
const data = els.map(e => {
|
|
1608
1758
|
return [e.getAttribute("value") ?? e.innerText.trim(), e.innerText.trim()];
|
|
1609
1759
|
});
|
|
1610
|
-
return new
|
|
1760
|
+
return new InMemoryLoader(data);
|
|
1611
1761
|
}
|
|
1612
1762
|
const chunked = "chunked" == conf.el.getAttribute("mode");
|
|
1613
|
-
return chunked ?
|
|
1763
|
+
return chunked ? PartialRemoteLoader.create(conf) : RemoteLoader.create(conf);
|
|
1614
1764
|
}
|
|
1615
1765
|
}
|
|
1616
1766
|
|
|
@@ -1620,8 +1770,9 @@ class Dropdown extends ParsedElement {
|
|
|
1620
1770
|
<ful-spinner class="centered" hidden></ful-spinner>
|
|
1621
1771
|
<menu tabindex="-1" hidden></menu>
|
|
1622
1772
|
`;
|
|
1623
|
-
#spinner
|
|
1624
|
-
#menu
|
|
1773
|
+
#spinner;
|
|
1774
|
+
#menu;
|
|
1775
|
+
#options = new Map();
|
|
1625
1776
|
render({ slots }) {
|
|
1626
1777
|
const fragment = this.template().render();
|
|
1627
1778
|
this.#spinner = fragment.querySelector("ful-spinner");
|
|
@@ -1644,30 +1795,31 @@ class Dropdown extends ParsedElement {
|
|
|
1644
1795
|
if (values === undefined) {
|
|
1645
1796
|
throw new Error("null data");
|
|
1646
1797
|
}
|
|
1798
|
+
this.#options = new Map(values.map((v,i) => [String(i), v]));
|
|
1647
1799
|
if (values.length === 0) {
|
|
1648
1800
|
const el = document.createElement('div');
|
|
1649
1801
|
el.classList.add('text-center', 'py-2', 'bi', 'bi-database-slash');
|
|
1650
1802
|
this.#menu.replaceChildren(el);
|
|
1651
1803
|
return;
|
|
1652
1804
|
}
|
|
1653
|
-
this.#menu.replaceChildren(...values.map(([k, v], i) => {
|
|
1805
|
+
this.#menu.replaceChildren(...values.map(([k, v, m], i) => {
|
|
1654
1806
|
const el = document.createElement('li');
|
|
1655
1807
|
if (i === 0) {
|
|
1656
1808
|
el.setAttribute("selected", '');
|
|
1657
1809
|
}
|
|
1658
|
-
el.setAttribute("value",
|
|
1810
|
+
el.setAttribute("value", i);
|
|
1659
1811
|
el.innerText = v;
|
|
1660
1812
|
return el;
|
|
1661
1813
|
}));
|
|
1662
1814
|
}
|
|
1663
1815
|
#change(target) {
|
|
1664
|
-
const
|
|
1665
|
-
const
|
|
1816
|
+
const index = target.getAttribute('value');
|
|
1817
|
+
const data = this.#options.get(index);
|
|
1666
1818
|
this.hide();
|
|
1667
1819
|
this.dispatchEvent(new CustomEvent('change', {
|
|
1668
1820
|
bubbles: true,
|
|
1669
1821
|
cancelable: false,
|
|
1670
|
-
detail: {
|
|
1822
|
+
detail: { index, data }
|
|
1671
1823
|
}));
|
|
1672
1824
|
}
|
|
1673
1825
|
hide() {
|
|
@@ -1689,12 +1841,13 @@ class Dropdown extends ParsedElement {
|
|
|
1689
1841
|
}
|
|
1690
1842
|
}
|
|
1691
1843
|
async moveOrShow(forward, loader) {
|
|
1692
|
-
if (
|
|
1844
|
+
if (this.shown) {
|
|
1693
1845
|
const selected = this.#menu.querySelector('[selected]') ?? this.#menu.firstElementChild;
|
|
1694
1846
|
const candidate = selected[`${forward ? 'next' : 'previous'}ElementSibling`];
|
|
1695
1847
|
if (candidate) {
|
|
1696
1848
|
selected.removeAttribute('selected');
|
|
1697
1849
|
candidate.setAttribute("selected", "");
|
|
1850
|
+
candidate.scrollIntoView({block: "nearest", behavior: "smooth"});
|
|
1698
1851
|
}
|
|
1699
1852
|
return;
|
|
1700
1853
|
}
|
|
@@ -1713,14 +1866,16 @@ class Select extends ParsedElement {
|
|
|
1713
1866
|
<div class="input-group flex-nowrap" tabindex="-1">
|
|
1714
1867
|
<span data-tpl-if="slots.ibefore" class="input-group-text">{{{{ slots.ibefore }}}}</span>
|
|
1715
1868
|
{{{{ slots.before }}}}
|
|
1716
|
-
<div class="ful-select-input">
|
|
1717
|
-
<
|
|
1718
|
-
|
|
1869
|
+
<div class="ful-select-input-container">
|
|
1870
|
+
<div class="ful-select-input">
|
|
1871
|
+
<badges></badges>
|
|
1872
|
+
<input type="text" form="">
|
|
1873
|
+
</div>
|
|
1874
|
+
<ful-dropdown hidden popover="manual"></ful-dropdown>
|
|
1719
1875
|
</div>
|
|
1720
1876
|
{{{{ slots.after }}}}
|
|
1721
1877
|
<span data-tpl-if="slots.iafter" class="input-group-text">{{{{ slots.iafter }}}}</span>
|
|
1722
1878
|
</div>
|
|
1723
|
-
<ful-dropdown hidden></ful-dropdown>
|
|
1724
1879
|
<ful-field-error></ful-field-error>
|
|
1725
1880
|
`;
|
|
1726
1881
|
static mappers = {
|
|
@@ -1748,6 +1903,7 @@ class Select extends ParsedElement {
|
|
|
1748
1903
|
async render({ slots, observed, disabled }) {
|
|
1749
1904
|
const name = this.getAttribute("name");
|
|
1750
1905
|
this.#loader = Loaders.fromAttributes(this, 'loaders:select', { options: slots.options });
|
|
1906
|
+
this.#multiple = this.hasAttribute("multiple");
|
|
1751
1907
|
await this.#loader.prefetch?.();
|
|
1752
1908
|
const fragment = this.template().withOverlay({ slots, name }).render();
|
|
1753
1909
|
this.#input = fragment.querySelector('input');
|
|
@@ -1758,7 +1914,6 @@ class Select extends ParsedElement {
|
|
|
1758
1914
|
this.readonly = observed.readonly;
|
|
1759
1915
|
|
|
1760
1916
|
this.#ddmenu = fragment.querySelector('ful-dropdown');
|
|
1761
|
-
this.#multiple = this.hasAttribute("multiple");
|
|
1762
1917
|
const label = fragment.querySelector('label');
|
|
1763
1918
|
label.addEventListener('click', () => this.focus());
|
|
1764
1919
|
this.#fieldError = fragment.querySelector('ful-field-error');
|
|
@@ -1766,12 +1921,14 @@ class Select extends ParsedElement {
|
|
|
1766
1921
|
this.#input.ariaLabelledByElements = [label];
|
|
1767
1922
|
|
|
1768
1923
|
const self = this;
|
|
1769
|
-
const [dload, abortdload] =
|
|
1924
|
+
const [dload, abortdload] = Timing.throttle(400, () => self.#ddmenu.show(() => self.#loader.load(self.#input.value)));
|
|
1770
1925
|
this.addEventListener('click', (/** @type any */e) => {
|
|
1771
|
-
e.stopPropagation();
|
|
1772
1926
|
if (e.target.matches('input')) {
|
|
1773
1927
|
return;
|
|
1774
1928
|
}
|
|
1929
|
+
if(this.disabled || this.readonly){
|
|
1930
|
+
return;
|
|
1931
|
+
}
|
|
1775
1932
|
if (this.#ddmenu.shown) {
|
|
1776
1933
|
this.#ddmenu.hide();
|
|
1777
1934
|
return;
|
|
@@ -1781,15 +1938,20 @@ class Select extends ParsedElement {
|
|
|
1781
1938
|
});
|
|
1782
1939
|
this.#badges.addEventListener('click', (e) => {
|
|
1783
1940
|
e.stopPropagation();
|
|
1941
|
+
if(this.disabled || this.readonly){
|
|
1942
|
+
return;
|
|
1943
|
+
}
|
|
1784
1944
|
const idx = [...this.#badges.children].indexOf(e.target);
|
|
1785
1945
|
if (idx === -1) {
|
|
1786
1946
|
return;
|
|
1787
1947
|
}
|
|
1788
1948
|
this.#values.delete(Array.from(this.#values.keys()).pop());
|
|
1949
|
+
this.#changed();
|
|
1789
1950
|
this.#syncBadges();
|
|
1790
1951
|
});
|
|
1791
1952
|
|
|
1792
1953
|
this.#input.addEventListener('blur', e => {
|
|
1954
|
+
e.stopPropagation();
|
|
1793
1955
|
if (e.relatedTarget && this.contains(e.relatedTarget)) {
|
|
1794
1956
|
return;
|
|
1795
1957
|
}
|
|
@@ -1798,6 +1960,10 @@ class Select extends ParsedElement {
|
|
|
1798
1960
|
this.#input.value = '';
|
|
1799
1961
|
});
|
|
1800
1962
|
this.#input.addEventListener('keydown', e => {
|
|
1963
|
+
e.stopPropagation();
|
|
1964
|
+
if(this.disabled || this.readonly){
|
|
1965
|
+
return;
|
|
1966
|
+
}
|
|
1801
1967
|
switch (e.code) {
|
|
1802
1968
|
case 'ArrowUp': {
|
|
1803
1969
|
this.#ddmenu.moveOrShow(false, () => self.#loader.load(self.#input.value));
|
|
@@ -1820,6 +1986,7 @@ class Select extends ParsedElement {
|
|
|
1820
1986
|
//remove last if caret a position 0
|
|
1821
1987
|
if (this.#values.size && this.#input.selectionStart === 0 && this.#input.selectionEnd === 0) {
|
|
1822
1988
|
this.#values.delete(Array.from(this.#values.keys()).pop());
|
|
1989
|
+
this.#changed();
|
|
1823
1990
|
this.#syncBadges();
|
|
1824
1991
|
}
|
|
1825
1992
|
break;
|
|
@@ -1832,19 +1999,37 @@ class Select extends ParsedElement {
|
|
|
1832
1999
|
}
|
|
1833
2000
|
});
|
|
1834
2001
|
this.#input.addEventListener('input', e => {
|
|
2002
|
+
e.stopPropagation();
|
|
2003
|
+
if(this.disabled || this.readonly){
|
|
2004
|
+
return;
|
|
2005
|
+
}
|
|
1835
2006
|
dload();
|
|
1836
2007
|
});
|
|
1837
2008
|
this.#ddmenu.addEventListener('change', (e) => {
|
|
2009
|
+
e.stopPropagation();
|
|
1838
2010
|
if (!this.#multiple) {
|
|
1839
2011
|
this.#values.clear();
|
|
1840
2012
|
}
|
|
1841
|
-
this.#values.set(e.detail.
|
|
2013
|
+
this.#values.set(e.detail.data[0], e.detail.data.slice(1));
|
|
2014
|
+
this.#changed();
|
|
1842
2015
|
this.#syncBadges();
|
|
1843
2016
|
this.#input.focus();
|
|
1844
2017
|
this.#ddmenu.hide();
|
|
1845
2018
|
});
|
|
1846
2019
|
this.replaceChildren(fragment);
|
|
1847
2020
|
}
|
|
2021
|
+
withLoader(fn) {
|
|
2022
|
+
fn(this.#loader);
|
|
2023
|
+
}
|
|
2024
|
+
#changed() {
|
|
2025
|
+
const selection = [...this.#values.entries()].map(e => ({key: e[0], label: e[1][0], metadata: e[1].slice(1)}));
|
|
2026
|
+
const value = this.#multiple ? selection : (selection[0] ?? null);
|
|
2027
|
+
this.dispatchEvent(new CustomEvent('change', {
|
|
2028
|
+
bubbles: true,
|
|
2029
|
+
cancelable: false,
|
|
2030
|
+
detail: { value }
|
|
2031
|
+
}));
|
|
2032
|
+
}
|
|
1848
2033
|
#syncBadges() {
|
|
1849
2034
|
const badges = Array.from(this.#values.entries()).map(([k, v]) => {
|
|
1850
2035
|
const b = document.createElement('badge');
|
|
@@ -1856,14 +2041,14 @@ class Select extends ParsedElement {
|
|
|
1856
2041
|
this.#badges.innerHTML = '';
|
|
1857
2042
|
this.#badges.append(...badges);
|
|
1858
2043
|
}
|
|
1859
|
-
set value(
|
|
1860
|
-
if(
|
|
2044
|
+
set value(vs) {
|
|
2045
|
+
if(vs === null){
|
|
1861
2046
|
this.#values = new Map();
|
|
1862
2047
|
this.#syncBadges();
|
|
1863
2048
|
return;
|
|
1864
2049
|
}
|
|
1865
2050
|
(async () => {
|
|
1866
|
-
const entries = await (this.#multiple ? this.#loader.exact(...
|
|
2051
|
+
const entries = await (this.#multiple ? this.#loader.exact(...vs) : this.#loader.exact(vs));
|
|
1867
2052
|
this.#values = new Map(entries);
|
|
1868
2053
|
this.#syncBadges();
|
|
1869
2054
|
})();
|
|
@@ -1874,6 +2059,25 @@ class Select extends ParsedElement {
|
|
|
1874
2059
|
}
|
|
1875
2060
|
return [...this.#values.keys()][0] ?? null;
|
|
1876
2061
|
}
|
|
2062
|
+
get entry() {
|
|
2063
|
+
if (this.#multiple) {
|
|
2064
|
+
return [...this.#values.entries()];
|
|
2065
|
+
}
|
|
2066
|
+
return [...this.#values.entries()][0] ?? null;
|
|
2067
|
+
}
|
|
2068
|
+
//@ts-ignore
|
|
2069
|
+
get disabled(){
|
|
2070
|
+
return this.#input.hasAttribute('disabled');
|
|
2071
|
+
}
|
|
2072
|
+
set disabled(d){
|
|
2073
|
+
Attributes.toggle(this.#input, 'disabled', d);
|
|
2074
|
+
}
|
|
2075
|
+
get readonly(){
|
|
2076
|
+
return this.#input.readOnly;
|
|
2077
|
+
}
|
|
2078
|
+
set readonly(v) {
|
|
2079
|
+
this.#input.readOnly = v;
|
|
2080
|
+
}
|
|
1877
2081
|
focus(options) {
|
|
1878
2082
|
this.#input.focus(options);
|
|
1879
2083
|
}
|
|
@@ -2539,21 +2743,12 @@ class InstantFilter extends ParsedElement {
|
|
|
2539
2743
|
}
|
|
2540
2744
|
const [operator, ...values] = v;
|
|
2541
2745
|
this.#operator.setAttribute('value', operator);
|
|
2542
|
-
this.#value1.value = values[0] ?
|
|
2543
|
-
this.#value2.value = values[1] ?
|
|
2746
|
+
this.#value1.value = values[0] ? Instant.isoToLocal(values[0]) : values[0];
|
|
2747
|
+
this.#value2.value = values[1] ? Instant.isoToLocal(values[1]) : values[1];
|
|
2544
2748
|
this.reflect(() => {
|
|
2545
2749
|
this.setAttribute('value', JSON.stringify(v));
|
|
2546
2750
|
});
|
|
2547
2751
|
}
|
|
2548
|
-
|
|
2549
|
-
static isoToLocal(iso) {
|
|
2550
|
-
//this is so sad
|
|
2551
|
-
const d = new Date(iso);
|
|
2552
|
-
const pad = (n, v) => String(v).padStart(n, '0');
|
|
2553
|
-
const date = `${d.getFullYear()}-${pad(2, d.getMonth() + 1)}-${pad(2, d.getDate())}`;
|
|
2554
|
-
const time = `${pad(2, d.getHours())}:${pad(2, d.getMinutes())}:${pad(2, d.getSeconds())}.${pad(3, d.getMilliseconds())}`;
|
|
2555
|
-
return `${date}T${time}`
|
|
2556
|
-
}
|
|
2557
2752
|
focus(options) {
|
|
2558
2753
|
this.#value1.focus(options);
|
|
2559
2754
|
}
|
|
@@ -2762,6 +2957,11 @@ class Plugin {
|
|
|
2762
2957
|
.defineElement('ful-form', Form)
|
|
2763
2958
|
.defineElement('ful-checkbox', Checkbox)
|
|
2764
2959
|
.defineElement('ful-input', Input)
|
|
2960
|
+
.defineElement('ful-local-date', LocalDate)
|
|
2961
|
+
.defineElement('ful-instant', Instant)
|
|
2962
|
+
.defineElement('ful-input-local-date', InputLocalDate)
|
|
2963
|
+
.defineElement('ful-input-local-time', InputLocalTime)
|
|
2964
|
+
.defineElement('ful-input-instant', InputInstant)
|
|
2765
2965
|
.defineElement('ful-radio-group', RadioGroup)
|
|
2766
2966
|
.defineElement('ful-table', Table)
|
|
2767
2967
|
.defineElement('ful-pagination', Pagination)
|
|
@@ -2777,5 +2977,5 @@ class Plugin {
|
|
|
2777
2977
|
}
|
|
2778
2978
|
}
|
|
2779
2979
|
|
|
2780
|
-
export { AsyncEvents, AuthorizationCodeFlow, AuthorizationCodeFlowInterceptor, AuthorizationCodeFlowSession, Base64, Bindings, Checkbox, Dropdown, Failure, Form, FormLoader, Hex, HttpClient, HttpClientError, Input, InstantFilter, Loaders, LocalDateFilter, LocalStorage, MediaType, Pagination, Plugin, RadioGroup, Select, SelectLoader, SessionStorage, SortButton, Spinner, Table, TableSchemaParser, TextFilter,
|
|
2980
|
+
export { AsyncEvents, AuthorizationCodeFlow, AuthorizationCodeFlowInterceptor, AuthorizationCodeFlowSession, Base64, Bindings, Checkbox, Dropdown, Failure, Form, FormLoader, Hex, HttpClient, HttpClientError, Input, InputInstant, InputLocalDate, InputLocalTime, Instant, InstantFilter, Loaders, LocalDate, LocalDateFilter, LocalStorage, MediaType, Pagination, Plugin, RadioGroup, Select, SelectLoader, SessionStorage, SortButton, Spinner, Table, TableSchemaParser, TextFilter, Timing, VersionedLocalStorage, VersionedSessionStorage };
|
|
2781
2981
|
//# sourceMappingURL=ful.mjs.map
|