@supersoniks/concorde 2.0.2 → 2.0.3
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/README.md +1 -0
- package/concorde-core.bundle.js +748 -690
- package/concorde-core.es.js +3897 -3116
- package/core/_types/types.d.ts +2 -4
- package/core/components/functional/date/date.d.ts +4 -2
- package/core/components/functional/date/date.js +28 -13
- package/core/components/functional/fetch/fetch.d.ts +9 -10
- package/core/components/functional/fetch/fetch.js +21 -5
- package/core/components/functional/list/list.d.ts +7 -10
- package/core/components/functional/list/list.js +19 -4
- package/core/components/functional/queue/queue.d.ts +3 -2
- package/core/components/functional/queue/queue.js +66 -61
- package/core/components/functional/router/router.d.ts +1 -0
- package/core/components/functional/router/router.js +12 -1
- package/core/components/functional/sdui/sdui.d.ts +2 -7
- package/core/components/functional/submit/submit.js +11 -4
- package/core/components/ui/_css/scroll.js +13 -11
- package/core/components/ui/_css/size.js +1 -1
- package/core/components/ui/alert/alert.d.ts +14 -3
- package/core/components/ui/alert/alert.js +34 -4
- package/core/components/ui/badge/badge.js +10 -3
- package/core/components/ui/button/button.d.ts +19 -10
- package/core/components/ui/button/button.js +77 -22
- package/core/components/ui/captcha/captcha.d.ts +5 -4
- package/core/components/ui/captcha/captcha.js +33 -9
- package/core/components/ui/divider/divider.d.ts +2 -0
- package/core/components/ui/divider/divider.js +17 -2
- package/core/components/ui/form/checkbox/checkbox.d.ts +24 -9
- package/core/components/ui/form/checkbox/checkbox.js +4 -6
- package/core/components/ui/form/css/form-control.js +40 -7
- package/core/components/ui/form/fieldset/fieldset.d.ts +1 -0
- package/core/components/ui/form/fieldset/fieldset.js +14 -1
- package/core/components/ui/form/fieldset/legend-description.js +3 -3
- package/core/components/ui/form/fieldset/legend.js +2 -8
- package/core/components/ui/form/input/input.d.ts +4 -5
- package/core/components/ui/form/input/input.js +17 -13
- package/core/components/ui/form/input-autocomplete/input-autocomplete.d.ts +3 -5
- package/core/components/ui/form/input-autocomplete/input-autocomplete.js +9 -9
- package/core/components/ui/form/select/select.d.ts +4 -1
- package/core/components/ui/form/select/select.js +25 -18
- package/core/components/ui/form/textarea/textarea.d.ts +4 -5
- package/core/components/ui/form/textarea/textarea.js +19 -10
- package/core/components/ui/group/group.js +3 -3
- package/core/components/ui/icon/icon.js +2 -1
- package/core/components/ui/icon/icons.d.ts +0 -4
- package/core/components/ui/icon/icons.js +3 -16
- package/core/components/ui/link/link.d.ts +5 -2
- package/core/components/ui/link/link.js +31 -2
- package/core/components/ui/loader/loader.d.ts +4 -1
- package/core/components/ui/loader/loader.js +11 -3
- package/core/components/ui/loader/styles/inline.js +14 -16
- package/core/components/ui/menu/menu-item.js +2 -1
- package/core/components/ui/menu/menu.js +6 -22
- package/core/components/ui/modal/modal-close.js +2 -1
- package/core/components/ui/modal/modal.d.ts +13 -1
- package/core/components/ui/modal/modal.js +70 -10
- package/core/components/ui/pop/pop.d.ts +9 -3
- package/core/components/ui/pop/pop.js +46 -23
- package/core/components/ui/table/table-tr.d.ts +10 -2
- package/core/components/ui/table/table-tr.js +30 -2
- package/core/components/ui/table/table.d.ts +1 -0
- package/core/components/ui/table/table.js +7 -1
- package/core/components/ui/theme/theme-collection/core-variables.js +8 -19
- package/core/components/ui/theme/theme.d.ts +6 -0
- package/core/components/ui/theme/theme.js +11 -13
- package/core/components/ui/toast/message-subscriber.d.ts +0 -8
- package/core/components/ui/toast/message-subscriber.js +0 -46
- package/core/components/ui/toast/toast-item.js +31 -40
- package/core/components/ui/toast/toast.d.ts +5 -1
- package/core/components/ui/toast/toast.js +80 -13
- package/core/components/ui/tooltip/tooltip.d.ts +3 -1
- package/core/components/ui/tooltip/tooltip.js +22 -0
- package/core/decorators/Subscriber.d.ts +3 -3
- package/core/decorators/Subscriber.js +64 -21
- package/core/directives/DataProvider.d.ts +12 -7
- package/core/directives/DataProvider.js +23 -8
- package/core/directives/Wording.d.ts +42 -0
- package/core/directives/Wording.js +202 -0
- package/core/mixins/Fetcher.d.ts +8 -11
- package/core/mixins/Fetcher.js +38 -22
- package/core/mixins/FormCheckable.d.ts +1 -4
- package/core/mixins/FormElement.d.ts +1 -0
- package/core/mixins/FormElement.js +3 -6
- package/core/mixins/FormInput.d.ts +3 -5
- package/core/mixins/FormInput.js +4 -0
- package/core/mixins/Subscriber.d.ts +0 -4
- package/core/mixins/Subscriber.js +13 -89
- package/core/mixins/TemplatesContainer.js +9 -0
- package/core/utils/Format.d.ts +1 -0
- package/core/utils/Format.js +16 -0
- package/core/utils/HTML.d.ts +13 -0
- package/core/utils/HTML.js +42 -3
- package/core/utils/Objects.d.ts +1 -0
- package/core/utils/Objects.js +5 -0
- package/core/utils/PublisherProxy.d.ts +16 -10
- package/core/utils/PublisherProxy.js +100 -64
- package/core/utils/Utils.d.ts +1 -0
- package/core/utils/Utils.js +5 -0
- package/core/utils/api.d.ts +26 -0
- package/core/utils/api.js +135 -3
- package/mixins.d.ts +6 -16
- package/package.json +7 -2
|
@@ -19,19 +19,22 @@ function getObservables(observable) {
|
|
|
19
19
|
set.add(publisher);
|
|
20
20
|
return set;
|
|
21
21
|
}
|
|
22
|
-
return new Set(observable);
|
|
22
|
+
return new Set([observable]);
|
|
23
23
|
}
|
|
24
24
|
class ObserveDirective extends AsyncDirective {
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
unsubscribe() {
|
|
26
|
+
this.observables.forEach((publisher) => publisher.offAssign(this.onAssign));
|
|
27
|
+
}
|
|
28
|
+
/* eslint-disable @typescript-eslint/no-explicit-any*/
|
|
29
|
+
constructor(partInfo) {
|
|
30
|
+
super(partInfo);
|
|
27
31
|
this.observables = new Set();
|
|
28
32
|
this.onAssign = (v) => {
|
|
29
33
|
this.setValue(v);
|
|
30
34
|
};
|
|
35
|
+
this.node = partInfo.options?.host;
|
|
31
36
|
}
|
|
32
|
-
|
|
33
|
-
this.observables.forEach((publisher) => publisher.offAssign(this.onAssign));
|
|
34
|
-
}
|
|
37
|
+
/* eslint-enable @typescript-eslint/no-explicit-any*/
|
|
35
38
|
render(observable) {
|
|
36
39
|
if (this.observable !== observable) {
|
|
37
40
|
this.observable = observable;
|
|
@@ -63,7 +66,7 @@ class ObserveDirective extends AsyncDirective {
|
|
|
63
66
|
// When the directive is disconnected from the DOM, unsubscribe to ensure
|
|
64
67
|
// the directive instance can be garbage collected
|
|
65
68
|
disconnected() {
|
|
66
|
-
this.unsubscribe
|
|
69
|
+
this.unsubscribe();
|
|
67
70
|
}
|
|
68
71
|
// If the subtree the directive is in was disconnected and subsequently
|
|
69
72
|
// re-connected, re-subscribe to make the directive operable again
|
|
@@ -82,6 +85,18 @@ export const sub = dir;
|
|
|
82
85
|
export const get = (id) => {
|
|
83
86
|
return getObservables(id).values().next().value.get();
|
|
84
87
|
};
|
|
85
|
-
const deepee = (id) =>
|
|
88
|
+
const deepee = (id, defaultValue) => {
|
|
89
|
+
const value = getObservables(id).values().next().value;
|
|
90
|
+
if (defaultValue !== undefined) {
|
|
91
|
+
const innerValue = value.get();
|
|
92
|
+
if (Objects.isEmpty(innerValue)) {
|
|
93
|
+
value.set(defaultValue);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return value;
|
|
97
|
+
};
|
|
86
98
|
export const dataProvider = deepee;
|
|
87
99
|
export const dp = deepee;
|
|
100
|
+
export const set = (id, value) => {
|
|
101
|
+
getObservables(id).values().next().value.set(value);
|
|
102
|
+
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { AsyncDirective } from "lit/async-directive.js";
|
|
2
|
+
import { APIConfiguration } from "@supersoniks/concorde/core/utils/api";
|
|
3
|
+
import API from "@supersoniks/concorde/core/utils/api";
|
|
4
|
+
import { SearchableDomElement } from "../utils/HTML";
|
|
5
|
+
type ApiCallKey = {
|
|
6
|
+
apiConfiguration: APIConfiguration;
|
|
7
|
+
wordingProvider: string | null;
|
|
8
|
+
wordingVersionProvider: string | null;
|
|
9
|
+
};
|
|
10
|
+
type ApiCallValue = {
|
|
11
|
+
api: API;
|
|
12
|
+
keysToTranslate: Set<string>;
|
|
13
|
+
translatedKeys: Set<string>;
|
|
14
|
+
wordingProvider: string | null;
|
|
15
|
+
callIndex: number;
|
|
16
|
+
wordingVersionProvider: string | null;
|
|
17
|
+
apiCallKey: ApiCallKey;
|
|
18
|
+
};
|
|
19
|
+
export declare const loadingString = "";
|
|
20
|
+
export declare const isWordingReady: (key: string) => boolean;
|
|
21
|
+
export default class WordingDirective extends AsyncDirective {
|
|
22
|
+
static publisher: any;
|
|
23
|
+
unsubscribe(): void;
|
|
24
|
+
key?: string;
|
|
25
|
+
node?: SearchableDomElement;
|
|
26
|
+
useUnsafeHTML: boolean;
|
|
27
|
+
constructor(partInfo: any);
|
|
28
|
+
render(key: string, useUnsafeHTML?: boolean): symbol;
|
|
29
|
+
static firstCall: boolean;
|
|
30
|
+
static callApi(node: SearchableDomElement | null, key: string, relaunch?: boolean, usedApiCall?: ApiCallValue): Promise<void>;
|
|
31
|
+
static versionProviderHandlers: Map<ApiCallValue, (v: number) => void>;
|
|
32
|
+
static handleVersionProvider(node: SearchableDomElement): ((v: number) => void) | undefined;
|
|
33
|
+
onAssign: (v: unknown) => void;
|
|
34
|
+
subscribe(key: string): void;
|
|
35
|
+
disconnected(): void;
|
|
36
|
+
reconnected(): void;
|
|
37
|
+
}
|
|
38
|
+
export declare const wording: (key: string, useUnsafeHTML?: boolean | undefined) => import("lit-html/directive").DirectiveResult<typeof WordingDirective>;
|
|
39
|
+
export declare const unsafeWording: (key: string) => import("lit-html/directive").DirectiveResult<typeof WordingDirective>;
|
|
40
|
+
export declare const t: (key: string, useUnsafeHTML?: boolean | undefined) => import("lit-html/directive").DirectiveResult<typeof WordingDirective>;
|
|
41
|
+
export declare const w: (key: string, useUnsafeHTML?: boolean | undefined) => import("lit-html/directive").DirectiveResult<typeof WordingDirective>;
|
|
42
|
+
export {};
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import { AsyncDirective } from "lit/async-directive.js";
|
|
2
|
+
import { directive } from "lit/directive.js";
|
|
3
|
+
import { PublisherManager } from "@supersoniks/concorde/core/utils/PublisherProxy";
|
|
4
|
+
import { dp } from "@supersoniks/concorde/core/directives/DataProvider";
|
|
5
|
+
import { noChange } from "lit";
|
|
6
|
+
import API from "@supersoniks/concorde/core/utils/api";
|
|
7
|
+
import Objects from "../utils/Objects";
|
|
8
|
+
import HTML from "../utils/HTML";
|
|
9
|
+
import { unsafeHTML } from "lit/directives/unsafe-html.js";
|
|
10
|
+
const apiCalls = new Map();
|
|
11
|
+
const getApiCall = (node) => {
|
|
12
|
+
if (!node)
|
|
13
|
+
return null;
|
|
14
|
+
const configuration = HTML.getApiConfiguration(node);
|
|
15
|
+
const wordingProvider = HTML.getAncestorAttributeValue(node, "wordingProvider");
|
|
16
|
+
const wordingVersionProvider = HTML.getAncestorAttributeValue(node, "wordingVersionProvider");
|
|
17
|
+
const searchedKey = { apiConfiguration: configuration, wordingProvider: wordingProvider, wordingVersionProvider: wordingVersionProvider };
|
|
18
|
+
//touver une api avec la même configuration en comparant les avec l'utilitaire Objects deepEqual
|
|
19
|
+
let apiCall = null;
|
|
20
|
+
for (const [key, value] of apiCalls) {
|
|
21
|
+
if (Objects.deepEqual(key, searchedKey)) {
|
|
22
|
+
apiCall = value;
|
|
23
|
+
break;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
if (!apiCall) {
|
|
27
|
+
const api = new API(configuration);
|
|
28
|
+
apiCall = {
|
|
29
|
+
api,
|
|
30
|
+
keysToTranslate: new Set(),
|
|
31
|
+
translatedKeys: new Set(),
|
|
32
|
+
wordingProvider,
|
|
33
|
+
callIndex: 0,
|
|
34
|
+
wordingVersionProvider: wordingVersionProvider,
|
|
35
|
+
apiCallKey: searchedKey,
|
|
36
|
+
};
|
|
37
|
+
apiCalls.set(searchedKey, apiCall);
|
|
38
|
+
}
|
|
39
|
+
return apiCall;
|
|
40
|
+
};
|
|
41
|
+
export const loadingString = "";
|
|
42
|
+
export const isWordingReady = (key) => {
|
|
43
|
+
const value = WordingDirective.publisher["wording_" + key].get();
|
|
44
|
+
return value !== loadingString && value != null;
|
|
45
|
+
};
|
|
46
|
+
class WordingDirective extends AsyncDirective {
|
|
47
|
+
unsubscribe() {
|
|
48
|
+
WordingDirective.publisher["wording_" + this.key].offAssign(this.onAssign);
|
|
49
|
+
}
|
|
50
|
+
/* eslint-disable @typescript-eslint/no-explicit-any*/
|
|
51
|
+
constructor(partInfo) {
|
|
52
|
+
super(partInfo);
|
|
53
|
+
this.useUnsafeHTML = false;
|
|
54
|
+
this.onAssign = (v) => {
|
|
55
|
+
const value = this.useUnsafeHTML ? unsafeHTML(v) : v;
|
|
56
|
+
this.setValue(value);
|
|
57
|
+
};
|
|
58
|
+
this.node = partInfo.options.host; // options n'est pas déclaré sur PartInfo mais exist en réalité d'où le typage "any"
|
|
59
|
+
}
|
|
60
|
+
/* eslint-enable @typescript-eslint/no-explicit-any*/
|
|
61
|
+
render(key, useUnsafeHTML = false) {
|
|
62
|
+
this.useUnsafeHTML = useUnsafeHTML;
|
|
63
|
+
if (this.key !== key) {
|
|
64
|
+
this.key = key;
|
|
65
|
+
if (this.isConnected) {
|
|
66
|
+
this.subscribe(key);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return noChange;
|
|
70
|
+
}
|
|
71
|
+
static async callApi(node, key, relaunch = true, usedApiCall) {
|
|
72
|
+
await PublisherManager.getInstance().isLocalStrorageReady;
|
|
73
|
+
if (WordingDirective.firstCall) {
|
|
74
|
+
WordingDirective.firstCall = false;
|
|
75
|
+
//clean keys of the publisher that are equivalent to the loading string
|
|
76
|
+
const keys = Object.keys(WordingDirective.publisher.get());
|
|
77
|
+
for (const key of keys) {
|
|
78
|
+
if (WordingDirective.publisher.get()[key] === loadingString) {
|
|
79
|
+
delete WordingDirective.publisher[key];
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
if (node) {
|
|
84
|
+
const wordingVersionProvider = HTML.getAncestorAttributeValue(node, "wordingVersionProvider");
|
|
85
|
+
if (wordingVersionProvider) {
|
|
86
|
+
dp(wordingVersionProvider).onAssign(WordingDirective.handleVersionProvider(node));
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
let hasWordingForKey = WordingDirective.publisher.get()["wording_" + key] != null;
|
|
90
|
+
const apiCall = usedApiCall || getApiCall(node);
|
|
91
|
+
if (!apiCall)
|
|
92
|
+
return;
|
|
93
|
+
if (hasWordingForKey && key !== "") {
|
|
94
|
+
apiCall.translatedKeys.add(key);
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
apiCall.callIndex++;
|
|
98
|
+
const callIndex = apiCall.callIndex;
|
|
99
|
+
const wordingProvider = apiCall.wordingProvider ?? "";
|
|
100
|
+
// if the wording provider is unfortunately not set, we don't call the api now.
|
|
101
|
+
// We will try later
|
|
102
|
+
if (!wordingProvider && relaunch) {
|
|
103
|
+
window.setTimeout(async () => {
|
|
104
|
+
WordingDirective.callApi(null, key, false, apiCall);
|
|
105
|
+
}, 1000);
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
//
|
|
109
|
+
//
|
|
110
|
+
const api = apiCall.api;
|
|
111
|
+
window.queueMicrotask(async () => {
|
|
112
|
+
hasWordingForKey = WordingDirective.publisher["wording_" + key].get() != null;
|
|
113
|
+
if (!hasWordingForKey && key !== "") {
|
|
114
|
+
apiCall.keysToTranslate.add(key);
|
|
115
|
+
WordingDirective.publisher["wording_" + key] = loadingString;
|
|
116
|
+
}
|
|
117
|
+
if (callIndex !== apiCall.callIndex)
|
|
118
|
+
return;
|
|
119
|
+
const wordings = Array.from(apiCall.keysToTranslate);
|
|
120
|
+
if (!wordings.length)
|
|
121
|
+
return;
|
|
122
|
+
const splittedUrl = wordingProvider.split("?");
|
|
123
|
+
const locationURL = splittedUrl.shift();
|
|
124
|
+
const queryString = (splittedUrl.length > 0 ? splittedUrl.join("?") + "&" : "") + "labels[]=" + wordings.join("&labels[]=");
|
|
125
|
+
const calledURL = locationURL + "?" + queryString;
|
|
126
|
+
apiCall.translatedKeys = new Set([...apiCall.translatedKeys, ...apiCall.keysToTranslate]);
|
|
127
|
+
apiCall.keysToTranslate.clear();
|
|
128
|
+
const result = (await api.get(calledURL));
|
|
129
|
+
for (const key in result) {
|
|
130
|
+
WordingDirective.publisher["wording_" + key] = result[key];
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
//check if the wording version has changed
|
|
135
|
+
static handleVersionProvider(node) {
|
|
136
|
+
const apiCall = getApiCall(node);
|
|
137
|
+
if (!apiCall)
|
|
138
|
+
return;
|
|
139
|
+
if (WordingDirective.versionProviderHandlers.has(apiCall)) {
|
|
140
|
+
return WordingDirective.versionProviderHandlers.get(apiCall);
|
|
141
|
+
}
|
|
142
|
+
const versionProviderHandler = function (version) {
|
|
143
|
+
const wordingVersionProvider = apiCall.wordingVersionProvider;
|
|
144
|
+
if (!wordingVersionProvider)
|
|
145
|
+
return;
|
|
146
|
+
//
|
|
147
|
+
const currentVersions = WordingDirective.publisher.get().__wording_versions__ ?? [];
|
|
148
|
+
if (version == null)
|
|
149
|
+
return;
|
|
150
|
+
const currentVersionData = currentVersions.find((v) => v.serviceURL === apiCall.api.serviceURL) || {
|
|
151
|
+
serviceURL: apiCall.api.serviceURL,
|
|
152
|
+
version: 0,
|
|
153
|
+
};
|
|
154
|
+
if (!currentVersions.includes(currentVersionData))
|
|
155
|
+
currentVersions.push(currentVersionData);
|
|
156
|
+
if (version === currentVersionData.version) {
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
currentVersionData.version = version;
|
|
160
|
+
WordingDirective.publisher.set({ __wording_versions__: currentVersions });
|
|
161
|
+
for (const apiCall of apiCalls.values()) {
|
|
162
|
+
apiCall.keysToTranslate = new Set(apiCall.translatedKeys);
|
|
163
|
+
if (apiCall.keysToTranslate.size > 0) {
|
|
164
|
+
WordingDirective.callApi(null, "", false, apiCall);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
WordingDirective.versionProviderHandlers.set(apiCall, versionProviderHandler);
|
|
169
|
+
return versionProviderHandler;
|
|
170
|
+
}
|
|
171
|
+
// Subscribes to the key, calling the directive's asynchronous
|
|
172
|
+
// setValue API each time the value changes
|
|
173
|
+
subscribe(key) {
|
|
174
|
+
this.unsubscribe();
|
|
175
|
+
// this.onAssign = (v: unknown) => {
|
|
176
|
+
// this.setValue(v);
|
|
177
|
+
// };
|
|
178
|
+
WordingDirective.publisher["wording_" + key].onAssign(this.onAssign);
|
|
179
|
+
WordingDirective.callApi(this.node, key);
|
|
180
|
+
}
|
|
181
|
+
// When the directive is disconnected from the DOM, unsubscribe to ensure
|
|
182
|
+
// the directive instance can be garbage collected
|
|
183
|
+
disconnected() {
|
|
184
|
+
this.unsubscribe();
|
|
185
|
+
}
|
|
186
|
+
// If the subtree the directive is in was disconnected and subsequently
|
|
187
|
+
// re-connected, re-subscribe to make the directive operable again
|
|
188
|
+
reconnected() {
|
|
189
|
+
if (!this.key)
|
|
190
|
+
return;
|
|
191
|
+
this.subscribe(this.key);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
WordingDirective.publisher = PublisherManager.get("sonic-wording", { localStorageMode: "enabled" });
|
|
195
|
+
WordingDirective.firstCall = true;
|
|
196
|
+
WordingDirective.versionProviderHandlers = new Map();
|
|
197
|
+
export default WordingDirective;
|
|
198
|
+
//autoUpdate directive
|
|
199
|
+
export const wording = directive(WordingDirective);
|
|
200
|
+
export const unsafeWording = (key) => wording(key, true);
|
|
201
|
+
export const t = wording;
|
|
202
|
+
export const w = wording;
|
package/core/mixins/Fetcher.d.ts
CHANGED
|
@@ -2,11 +2,13 @@
|
|
|
2
2
|
import "@supersoniks/concorde/core/components/ui/button/button";
|
|
3
3
|
import { SubscriberInterface } from "@supersoniks/concorde/core/mixins/Subscriber";
|
|
4
4
|
import API from "@supersoniks/concorde/core/utils/api";
|
|
5
|
-
import { PublisherContentType } from "../_types/types";
|
|
6
5
|
import { MixinArgsType } from "../_types/types";
|
|
7
6
|
import { ResultTypeInterface } from "@supersoniks/concorde/core/utils/api";
|
|
8
7
|
type Constructor<T> = new (...args: MixinArgsType[]) => T;
|
|
9
|
-
declare const
|
|
8
|
+
export declare const invalidateFetchersInError: () => void;
|
|
9
|
+
export declare const onFetchError: (errorListener: (apiResponse: Response) => void) => void;
|
|
10
|
+
export declare const offFetchError: (errorListener: (apiResponse: Response) => void) => void;
|
|
11
|
+
declare const Fetcher: <T extends Constructor<SubscriberInterface<PropsType>>, PropsType extends unknown = unknown>(superClass: T, propsType?: PropsType | undefined) => {
|
|
10
12
|
new (...args: MixinArgsType[]): {
|
|
11
13
|
api: API | null;
|
|
12
14
|
/**
|
|
@@ -23,20 +25,19 @@ declare const Fetcher: <T extends Constructor<SubscriberInterface<PropsType>>, P
|
|
|
23
25
|
*/
|
|
24
26
|
isLoading: boolean;
|
|
25
27
|
lazyLoad?: boolean | undefined;
|
|
26
|
-
noLoader?: boolean | undefined;
|
|
27
28
|
/**
|
|
28
29
|
* IObserver est l'intersection observer qui permet de charger les données au scroll si l'attribut lazyload est renseigné
|
|
29
30
|
*/
|
|
30
31
|
iObserver: IntersectionObserver | null;
|
|
31
|
-
/**
|
|
32
|
-
* un loader est affiché par défaut si l'attribut noLoader n'est pas renseigné
|
|
33
|
-
*/
|
|
34
|
-
isDefaultLoaderEnabled: boolean;
|
|
35
32
|
/**
|
|
36
33
|
* On peut désactiver le fetch programmatiquement via cette propriété.
|
|
37
34
|
* Cela est le cas pour le composant sonic-list qui ne fetch que si l'attribut fetch est renseigné
|
|
38
35
|
*/
|
|
39
36
|
isFetchEnabled: boolean;
|
|
37
|
+
/**
|
|
38
|
+
* Result of the fetch
|
|
39
|
+
*/
|
|
40
|
+
fetchedData: any;
|
|
40
41
|
_endPoint: string;
|
|
41
42
|
props: (PropsType & ResultTypeInterface) | null;
|
|
42
43
|
endPoint: string;
|
|
@@ -84,10 +85,6 @@ declare const Fetcher: <T extends Constructor<SubscriberInterface<PropsType>>, P
|
|
|
84
85
|
getAttribute(name: string): string;
|
|
85
86
|
hasAttribute(attributeName: string): boolean;
|
|
86
87
|
getBoundingClientRect(): DOMRect;
|
|
87
|
-
onConnected(callback: (component: any) => void): void;
|
|
88
|
-
offConnected(callback: (component: any) => void): void;
|
|
89
|
-
onDisconnected(callback: (component: any) => void): void;
|
|
90
|
-
offDisconnected(callback: (component: any) => void): void;
|
|
91
88
|
};
|
|
92
89
|
} & T;
|
|
93
90
|
export default Fetcher;
|
package/core/mixins/Fetcher.js
CHANGED
|
@@ -5,12 +5,31 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
5
5
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
6
|
};
|
|
7
7
|
import "@supersoniks/concorde/core/components/ui/button/button";
|
|
8
|
-
import { Loader } from "@supersoniks/concorde/core/components/ui/loader/loader";
|
|
9
8
|
import { SonicToast } from "@supersoniks/concorde/core/components/ui/toast/toast";
|
|
10
9
|
import API from "@supersoniks/concorde/core/utils/api";
|
|
11
10
|
import Objects from "@supersoniks/concorde/core/utils/Objects";
|
|
12
11
|
import { PublisherManager } from "@supersoniks/concorde/utils";
|
|
13
12
|
import { property } from "lit/decorators.js";
|
|
13
|
+
const fetchersInError = new Set();
|
|
14
|
+
export const invalidateFetchersInError = () => {
|
|
15
|
+
const fetchersInErrorCopy = new Set(fetchersInError);
|
|
16
|
+
fetchersInError.clear();
|
|
17
|
+
for (const fetcher of fetchersInErrorCopy) {
|
|
18
|
+
fetcher._fetchData();
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
const errorsListeners = new Set();
|
|
22
|
+
export const onFetchError = (errorListener) => {
|
|
23
|
+
errorsListeners.add(errorListener);
|
|
24
|
+
};
|
|
25
|
+
export const offFetchError = (errorListener) => {
|
|
26
|
+
errorsListeners.delete(errorListener);
|
|
27
|
+
};
|
|
28
|
+
const dispatchFetchError = (apiResponse) => {
|
|
29
|
+
for (const listener of errorsListeners) {
|
|
30
|
+
listener(apiResponse);
|
|
31
|
+
}
|
|
32
|
+
};
|
|
14
33
|
const Fetcher = (superClass, propsType) => {
|
|
15
34
|
propsType;
|
|
16
35
|
class FetcherElement extends superClass {
|
|
@@ -34,15 +53,15 @@ const Fetcher = (superClass, propsType) => {
|
|
|
34
53
|
* IObserver est l'intersection observer qui permet de charger les données au scroll si l'attribut lazyload est renseigné
|
|
35
54
|
*/
|
|
36
55
|
this.iObserver = null;
|
|
37
|
-
/**
|
|
38
|
-
* un loader est affiché par défaut si l'attribut noLoader n'est pas renseigné
|
|
39
|
-
*/
|
|
40
|
-
this.isDefaultLoaderEnabled = true;
|
|
41
56
|
/**
|
|
42
57
|
* On peut désactiver le fetch programmatiquement via cette propriété.
|
|
43
58
|
* Cela est le cas pour le composant sonic-list qui ne fetch que si l'attribut fetch est renseigné
|
|
44
59
|
*/
|
|
45
60
|
this.isFetchEnabled = true;
|
|
61
|
+
/**
|
|
62
|
+
* Result of the fetch
|
|
63
|
+
*/
|
|
64
|
+
this.fetchedData = null;
|
|
46
65
|
this._endPoint = "";
|
|
47
66
|
this.requestId = 0;
|
|
48
67
|
this.refetchEveryMs = 0;
|
|
@@ -70,6 +89,7 @@ const Fetcher = (superClass, propsType) => {
|
|
|
70
89
|
* Un Toast est affiché si le chargement échoue
|
|
71
90
|
*/
|
|
72
91
|
async _fetchData() {
|
|
92
|
+
this.requestUpdate();
|
|
73
93
|
if (!this.isFetchEnabled)
|
|
74
94
|
return;
|
|
75
95
|
this.api = new API(this.getApiConfiguration());
|
|
@@ -82,10 +102,6 @@ const Fetcher = (superClass, propsType) => {
|
|
|
82
102
|
}
|
|
83
103
|
if (!this.isConnected)
|
|
84
104
|
return;
|
|
85
|
-
const hasLoader = this.isDefaultLoaderEnabled && !this.noLoader;
|
|
86
|
-
if (hasLoader) {
|
|
87
|
-
Loader.show();
|
|
88
|
-
}
|
|
89
105
|
const headerData = PublisherManager.getInstance().get(this.getAncestorAttributeValue("headersDataProvider")).get();
|
|
90
106
|
this.isLoading = true;
|
|
91
107
|
if (Objects.isObject(this.props) && Object.keys(this.props || {}).length > 0 && this.isFirstLoad) {
|
|
@@ -96,33 +112,33 @@ const Fetcher = (superClass, propsType) => {
|
|
|
96
112
|
});
|
|
97
113
|
}
|
|
98
114
|
let data = await this.api.get(this.endPoint || this.dataProvider || "", headerData);
|
|
115
|
+
this.fetchedData = data;
|
|
116
|
+
if (this.api.lastResult && !this.api.lastResult.ok) {
|
|
117
|
+
fetchersInError.add(this);
|
|
118
|
+
dispatchFetchError(this.api.lastResult);
|
|
119
|
+
}
|
|
99
120
|
if (!this.isConnected) {
|
|
100
|
-
if (hasLoader)
|
|
101
|
-
Loader.hide();
|
|
102
121
|
return;
|
|
103
122
|
}
|
|
104
|
-
// Je garde ça mais normalement ça n'arrive jamais
|
|
105
123
|
if (!data) {
|
|
106
|
-
|
|
124
|
+
// Cela n'arrive normalement que lorsque l'on quitte une page pendant un fetch on n'affiche donc pas de message
|
|
107
125
|
this.isLoading = false;
|
|
108
|
-
if (
|
|
109
|
-
|
|
126
|
+
if (this.refetchEveryMs && this.isConnected) {
|
|
127
|
+
this.refetchTimeOutId = setTimeout(() => this._fetchData(), this.refetchEveryMs);
|
|
110
128
|
}
|
|
111
129
|
return;
|
|
112
130
|
}
|
|
113
|
-
// Si data ne contient que la réponse HTTP, avec un statut not ok, on affiche un message
|
|
114
131
|
else if (data._sonic_http_response_ && !data._sonic_http_response_.ok && Object.keys(data).length === 1) {
|
|
132
|
+
// Si data ne contient que la réponse HTTP, avec un statut not ok, on affiche un message
|
|
115
133
|
SonicToast.add({ text: "Network Error", status: "error" });
|
|
116
134
|
}
|
|
117
|
-
if (hasLoader) {
|
|
118
|
-
Loader.hide();
|
|
119
|
-
}
|
|
120
135
|
if (this.key) {
|
|
121
136
|
const response = data._sonic_http_response_;
|
|
122
137
|
/* preserveOtherKeys s'exprime lorsque le paramètre "key" est défini
|
|
123
138
|
* Conserve les autres propriétés de l'objet reçu, en plus des propriétés définies sous "key"
|
|
124
139
|
*/
|
|
125
|
-
|
|
140
|
+
const path = this.key.split(".");
|
|
141
|
+
data = Objects.traverse(data, path, this.hasAttribute("preserveOtherKeys"));
|
|
126
142
|
if (data && Objects.isObject(data) && response)
|
|
127
143
|
data._sonic_http_response_ = response;
|
|
128
144
|
}
|
|
@@ -143,12 +159,11 @@ const Fetcher = (superClass, propsType) => {
|
|
|
143
159
|
connectedCallback() {
|
|
144
160
|
// this.noShadowDom = "";
|
|
145
161
|
this.lazyLoad = this.lazyLoad !== undefined ? this.lazyLoad : this.hasAttribute("lazyload");
|
|
146
|
-
this.noLoader = this.noLoader !== undefined ? this.noLoader : this.hasAttribute("noloader");
|
|
147
162
|
super.connectedCallback();
|
|
148
163
|
if (!this.isFetchEnabled) {
|
|
149
164
|
return;
|
|
150
165
|
}
|
|
151
|
-
this.key = this.getAttribute("key");
|
|
166
|
+
this.key = this.key != "" ? this.key : this.getAttribute("key");
|
|
152
167
|
if (this.props) {
|
|
153
168
|
this.publisher.set(this.props);
|
|
154
169
|
}
|
|
@@ -174,6 +189,7 @@ const Fetcher = (superClass, propsType) => {
|
|
|
174
189
|
const options = {
|
|
175
190
|
root: null,
|
|
176
191
|
rootMargin: Math.max(window.innerWidth * boundsRatio, window.innerHeight * boundsRatio) + "px",
|
|
192
|
+
threshold: 0.9,
|
|
177
193
|
};
|
|
178
194
|
this.iObserver = new IntersectionObserver((entries) => this.onIntersection(entries), options);
|
|
179
195
|
let elt = (this.shadowRoot ? this.shadowRoot.children[0] : this.children[0]);
|
|
@@ -46,6 +46,7 @@ declare const Form: <T extends Constructor<FormElementInterface>>(superClass: T)
|
|
|
46
46
|
getFormPublisher(): any;
|
|
47
47
|
updateDataValue(): void;
|
|
48
48
|
handleBlur(e?: Event | undefined): void;
|
|
49
|
+
setValueFromPublisher(value: string | object | string[] | null | undefined): void;
|
|
49
50
|
focus?: (() => void) | undefined;
|
|
50
51
|
shadowRoot?: ShadowRoot | undefined;
|
|
51
52
|
error: boolean;
|
|
@@ -82,10 +83,6 @@ declare const Form: <T extends Constructor<FormElementInterface>>(superClass: T)
|
|
|
82
83
|
getAttribute(name: string): string;
|
|
83
84
|
hasAttribute(attributeName: string): boolean;
|
|
84
85
|
getBoundingClientRect(): DOMRect;
|
|
85
|
-
onConnected(callback: (component: any) => void): void;
|
|
86
|
-
offConnected(callback: (component: any) => void): void;
|
|
87
|
-
onDisconnected(callback: (component: any) => void): void;
|
|
88
|
-
offDisconnected(callback: (component: any) => void): void;
|
|
89
86
|
};
|
|
90
87
|
} & T;
|
|
91
88
|
export default Form;
|
|
@@ -9,6 +9,7 @@ export interface FormElementInterface extends SubscriberInterface {
|
|
|
9
9
|
handleChange(e?: Event): void;
|
|
10
10
|
handleBlur(e?: Event): void;
|
|
11
11
|
getValueForFormPublisher(): FormElementValue;
|
|
12
|
+
setValueFromPublisher(value: FormElementValue): void;
|
|
12
13
|
validateFormElement(): void;
|
|
13
14
|
focus?: () => void;
|
|
14
15
|
forceAutoFill: boolean;
|
|
@@ -39,7 +39,7 @@ const Form = (superClass) => {
|
|
|
39
39
|
this.onValueAssign = (value) => {
|
|
40
40
|
this.setValueFromPublisher(value);
|
|
41
41
|
};
|
|
42
|
-
this.onFormValueAssign = (value) => {
|
|
42
|
+
this.onFormValueAssign = async (value) => {
|
|
43
43
|
this.setFormValueFromPublisher(value);
|
|
44
44
|
};
|
|
45
45
|
this.onFormDataInValidate = () => {
|
|
@@ -74,8 +74,7 @@ const Form = (superClass) => {
|
|
|
74
74
|
}
|
|
75
75
|
getFormPublisher() {
|
|
76
76
|
if (!this.formDataProvider)
|
|
77
|
-
this.formDataProvider =
|
|
78
|
-
this.getAncestorAttributeValue("formDataProvider");
|
|
77
|
+
this.formDataProvider = this.getAncestorAttributeValue("formDataProvider");
|
|
79
78
|
if (this.formDataProvider) {
|
|
80
79
|
return PublisherManager.get(this.formDataProvider);
|
|
81
80
|
}
|
|
@@ -121,9 +120,7 @@ const Form = (superClass) => {
|
|
|
121
120
|
}
|
|
122
121
|
initPublisher() {
|
|
123
122
|
let formPublisher = this.getFormPublisher();
|
|
124
|
-
const value = this.hasAncestorAttribute("initFromPublisher") &&
|
|
125
|
-
this._name &&
|
|
126
|
-
formPublisher[this._name].get()
|
|
123
|
+
const value = this.hasAncestorAttribute("initFromPublisher") && this._name && formPublisher[this._name].get()
|
|
127
124
|
? formPublisher[this._name].get()
|
|
128
125
|
: this.getAttribute("value");
|
|
129
126
|
if (this._name && this.publisher)
|
|
@@ -16,13 +16,15 @@ declare const Form: <T extends Constructor<FormElementInterface>>(superClass: T)
|
|
|
16
16
|
description: string | undefined;
|
|
17
17
|
_label?: string | undefined;
|
|
18
18
|
label: string | undefined;
|
|
19
|
+
status: "default" | "success" | "error" | "warning" | "info";
|
|
19
20
|
tabindex?: number | undefined;
|
|
20
|
-
autocomplete?: "url" | "name" | "on" | "additional-name" | "address-level1" | "address-level2" | "address-level3" | "address-level4" | "address-line1" | "address-line2" | "address-line3" | "bday-day" | "bday-month" | "bday-year" | "cc-csc" | "cc-exp" | "cc-exp-month" | "cc-exp-year" | "cc-family-name" | "cc-given-name" | "cc-name" | "cc-number" | "cc-type" | "country" | "country-name" | "current-password" | "family-name" | "given-name" | "honorific-prefix" | "honorific-suffix" | "new-password" | "one-time-code" | "organization" | "postal-code" | "street-address" | "transaction-amount" | "transaction-currency" | "username" | "email" | "tel" | "tel-area-code" | "tel-country-code" | "tel-extension" | "tel-local" | "tel-national" | "language" | "nickname" | "organization-title" | "cc-additional-name" | "bday" | "sex" | "impp" | "photo" | undefined;
|
|
21
|
+
autocomplete?: "url" | "name" | "off" | "on" | "additional-name" | "address-level1" | "address-level2" | "address-level3" | "address-level4" | "address-line1" | "address-line2" | "address-line3" | "bday-day" | "bday-month" | "bday-year" | "cc-csc" | "cc-exp" | "cc-exp-month" | "cc-exp-year" | "cc-family-name" | "cc-given-name" | "cc-name" | "cc-number" | "cc-type" | "country" | "country-name" | "current-password" | "family-name" | "given-name" | "honorific-prefix" | "honorific-suffix" | "new-password" | "one-time-code" | "organization" | "postal-code" | "street-address" | "transaction-amount" | "transaction-currency" | "username" | "email" | "tel" | "tel-area-code" | "tel-country-code" | "tel-extension" | "tel-local" | "tel-national" | "language" | "nickname" | "organization-title" | "cc-additional-name" | "bday" | "sex" | "impp" | "photo" | undefined;
|
|
21
22
|
getFormPublisher(): any;
|
|
22
23
|
updateDataValue(): void;
|
|
23
24
|
handleChange(e?: Event | undefined): void;
|
|
24
25
|
handleBlur(e?: Event | undefined): void;
|
|
25
26
|
getValueForFormPublisher(): string | object | string[] | null | undefined;
|
|
27
|
+
setValueFromPublisher(value: string | object | string[] | null | undefined): void;
|
|
26
28
|
focus?: (() => void) | undefined;
|
|
27
29
|
shadowRoot?: ShadowRoot | undefined;
|
|
28
30
|
error: boolean;
|
|
@@ -63,10 +65,6 @@ declare const Form: <T extends Constructor<FormElementInterface>>(superClass: T)
|
|
|
63
65
|
hasAttribute(attributeName: string): boolean;
|
|
64
66
|
disconnectedCallback(): void;
|
|
65
67
|
getBoundingClientRect(): DOMRect;
|
|
66
|
-
onConnected(callback: (component: any) => void): void;
|
|
67
|
-
offConnected(callback: (component: any) => void): void;
|
|
68
|
-
onDisconnected(callback: (component: any) => void): void;
|
|
69
|
-
offDisconnected(callback: (component: any) => void): void;
|
|
70
68
|
};
|
|
71
69
|
} & T;
|
|
72
70
|
export default Form;
|
package/core/mixins/FormInput.js
CHANGED
|
@@ -15,6 +15,7 @@ const Form = (superClass) => {
|
|
|
15
15
|
* On peut essayer text, date, color, email par exemple, mais pas radio/checkbox/range a priori
|
|
16
16
|
*/
|
|
17
17
|
this._type = "text";
|
|
18
|
+
this.status = "default";
|
|
18
19
|
args;
|
|
19
20
|
}
|
|
20
21
|
validateFormElement() {
|
|
@@ -66,6 +67,9 @@ const Form = (superClass) => {
|
|
|
66
67
|
__decorate([
|
|
67
68
|
property()
|
|
68
69
|
], FormInput.prototype, "label", null);
|
|
70
|
+
__decorate([
|
|
71
|
+
property({ type: String, reflect: true })
|
|
72
|
+
], FormInput.prototype, "status", void 0);
|
|
69
73
|
__decorate([
|
|
70
74
|
property({ type: Number })
|
|
71
75
|
], FormInput.prototype, "tabindex", void 0);
|
|
@@ -31,10 +31,6 @@ export interface SubscriberInterface<PropsType = CoreJSType> {
|
|
|
31
31
|
hasAttribute(attributeName: string): boolean;
|
|
32
32
|
disconnectedCallback(): void;
|
|
33
33
|
getBoundingClientRect(): DOMRect;
|
|
34
|
-
onConnected(callback: (component: any) => void): void;
|
|
35
|
-
offConnected(callback: (component: any) => void): void;
|
|
36
|
-
onDisconnected(callback: (component: any) => void): void;
|
|
37
|
-
offDisconnected(callback: (component: any) => void): void;
|
|
38
34
|
}
|
|
39
35
|
declare const Subscriber: <PropsType = CoreJSType, T extends Constructor<LitElement> = Constructor<LitElement>>(superClass: T, type?: PropsType | undefined) => Constructor<SubscriberInterface<PropsType>> & T;
|
|
40
36
|
export default Subscriber;
|