@supersoniks/concorde 3.1.61 → 3.1.62
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/build-infos.json +1 -1
- package/concorde-core.bundle.js +187 -222
- package/concorde-core.es.js +1449 -1561
- package/dist/concorde-core.bundle.js +187 -222
- package/dist/concorde-core.es.js +1449 -1561
- package/package.json +24 -3
- package/scripts/generate-routes.js +206 -0
- package/scripts/post-build-docs.js +0 -0
- package/scripts/pre-publish.mjs +0 -0
- package/src/core/components/functional/date/date.ts +0 -0
- package/src/core/components/functional/functional.ts +0 -0
- package/src/core/components/functional/if/if.md +0 -0
- package/src/core/components/functional/if/if.test.ts +0 -0
- package/src/core/components/functional/list/list.demo.ts +58 -0
- package/src/core/components/functional/list/list.spec.ts +215 -0
- package/src/core/components/functional/list/list.ts +83 -32
- package/src/core/components/functional/queue/queue.demo.ts +38 -0
- package/src/core/components/functional/queue/queue.ts +7 -0
- package/src/core/components/functional/router/router.demo.ts +62 -0
- package/src/core/components/functional/router/router.md +22 -1
- package/src/core/components/functional/router/router.spec.ts +214 -0
- package/src/core/components/functional/router/router.ts +102 -8
- package/src/core/components/functional/sonic-scope/sonic-scope.ts +0 -0
- package/src/core/components/functional/states/states.demo.ts +83 -0
- package/src/core/components/functional/states/states.md +0 -0
- package/src/core/components/functional/states/states.spec.ts +141 -0
- package/src/core/components/functional/states/states.ts +74 -9
- package/src/core/components/functional/translation/translation.ts +0 -0
- package/src/core/components/ui/_css/scroll.ts +0 -0
- package/src/core/components/ui/_css/shadow.ts +0 -0
- package/src/core/components/ui/_css/size.ts +1 -1
- package/src/core/components/ui/_css/type.ts +0 -0
- package/src/core/components/ui/alert/alert.md +0 -0
- package/src/core/components/ui/alert/alert.ts +0 -0
- package/src/core/components/ui/alert-messages/alert-messages.md +0 -0
- package/src/core/components/ui/alert-messages/alert-messages.ts +0 -0
- package/src/core/components/ui/badge/badge.md +0 -0
- package/src/core/components/ui/button/button.md +0 -0
- package/src/core/components/ui/button/button.ts +5 -1
- package/src/core/components/ui/card/card-footer.ts +0 -0
- package/src/core/components/ui/card/card-header-descripton.ts +0 -0
- package/src/core/components/ui/card/card-header.ts +0 -0
- package/src/core/components/ui/card/card-main.ts +0 -0
- package/src/core/components/ui/card/card.md +0 -0
- package/src/core/components/ui/card/card.ts +0 -0
- package/src/core/components/ui/divider/divider.ts +0 -0
- package/src/core/components/ui/form/checkbox/checkbox.md +0 -0
- package/src/core/components/ui/form/checkbox/checkbox.ts +0 -0
- package/src/core/components/ui/form/css/form-control.ts +4 -1
- package/src/core/components/ui/form/fieldset/legend-description.ts +0 -0
- package/src/core/components/ui/form/fieldset/legend.ts +0 -0
- package/src/core/components/ui/form/form-layout/form-layout.md +0 -0
- package/src/core/components/ui/form/input/input.md +0 -0
- package/src/core/components/ui/form/input-autocomplete/input-autocomplete.ts +0 -0
- package/src/core/components/ui/form/radio/radio.md +0 -0
- package/src/core/components/ui/form/radio/radio.ts +0 -0
- package/src/core/components/ui/form/select/select.md +0 -0
- package/src/core/components/ui/form/select/select.ts +0 -0
- package/src/core/components/ui/form/switch/switch.md +0 -0
- package/src/core/components/ui/form/textarea/textarea.ts +0 -0
- package/src/core/components/ui/group/group.ts +0 -0
- package/src/core/components/ui/icon/icon.ts +4 -0
- package/src/core/components/ui/icon/icons.ts +0 -0
- package/src/core/components/ui/image/image.md +0 -0
- package/src/core/components/ui/image/image.ts +0 -0
- package/src/core/components/ui/loader/loader.md +0 -0
- package/src/core/components/ui/loader/loader.ts +0 -0
- package/src/core/components/ui/loader/styles/fixed.ts +0 -0
- package/src/core/components/ui/loader/styles/inline.ts +0 -0
- package/src/core/components/ui/menu/menu.ts +0 -0
- package/src/core/components/ui/modal/modal-actions.ts +0 -0
- package/src/core/components/ui/modal/modal-subtitle.ts +0 -0
- package/src/core/components/ui/modal/modal-title.ts +0 -0
- package/src/core/components/ui/modal/modal.md +0 -0
- package/src/core/components/ui/modal/modal.ts +0 -0
- package/src/core/components/ui/pop/pop.ts +21 -0
- package/src/core/components/ui/progress/progress.ts +0 -0
- package/src/core/components/ui/table/table-tbody.ts +0 -0
- package/src/core/components/ui/table/table-th.ts +0 -0
- package/src/core/components/ui/table/table.ts +0 -0
- package/src/core/components/ui/theme/theme-collection/core-variables.ts +0 -0
- package/src/core/components/ui/theme/theme-collection/dark.ts +0 -0
- package/src/core/components/ui/theme/theme-collection/light.ts +0 -0
- package/src/core/components/ui/theme/theme.ts +0 -0
- package/src/core/components/ui/toast/message-subscriber.ts +0 -0
- package/src/core/components/ui/toast/toast-item.ts +0 -0
- package/src/core/components/ui/toast/toast.ts +0 -0
- package/src/core/components/ui/tooltip/tooltip.ts +0 -0
- package/src/core/components/ui/ui.ts +0 -0
- package/src/core/directives/DataProvider.ts +0 -0
- package/src/core/directives/Wording.ts +0 -0
- package/src/core/mixins/FormCheckable.ts +0 -0
- package/src/core/mixins/FormElement.ts +1 -1
- package/src/core/mixins/Subscriber.ts +0 -0
- package/src/core/mixins/TemplatesContainer.ts +19 -10
- package/src/core/utils/HTML.ts +0 -0
- package/src/core/utils/LocationHandler.ts +3 -1
- package/src/core/utils/Utils.ts +0 -0
- package/src/core/utils/route.ts +0 -0
- package/src/docs/code.ts +0 -0
- package/src/docs/docs.ts +0 -0
- package/src/docs/header/header.ts +0 -0
- package/src/docs/layout.ts +0 -0
- package/src/docs/navigation/navigation.ts +0 -0
- package/src/docs/search/docs-search.json +15 -0
- package/src/docs/search/markdown-renderer.ts +0 -0
- package/src/docs/search/page.ts +1 -0
- package/src/docs/search/search.ts +0 -0
- package/src/docs/tailwind/css/tailwind.css +0 -0
- package/src/docs/tailwind/css.d.ts +4 -0
- package/src/docs/tailwind/index.ts +2 -1
- package/src/test-utils/TestUtils.ts +2 -2
- package/src/tsconfig-model.json +1 -1
- package/src/tsconfig.json +69 -1
- package/src/tsconfig.tsbuildinfo +1 -1
- package/tailwind.config.js +0 -0
- package/templates-test.html +32 -0
- package/vite/config.js +30 -0
- package/docs/assets/index-D9bBwsCn.js +0 -4537
- package/docs/assets/index-DCRPZO3x.css +0 -1
- package/docs/css/docs.css +0 -0
- package/docs/fonts/ClashGrotesk-Bold.eot +0 -0
- package/docs/fonts/ClashGrotesk-Bold.ttf +0 -0
- package/docs/fonts/ClashGrotesk-Bold.woff +0 -0
- package/docs/fonts/ClashGrotesk-Bold.woff2 +0 -0
- package/docs/fonts/ClashGrotesk-Extralight.eot +0 -0
- package/docs/fonts/ClashGrotesk-Extralight.ttf +0 -0
- package/docs/fonts/ClashGrotesk-Extralight.woff +0 -0
- package/docs/fonts/ClashGrotesk-Extralight.woff2 +0 -0
- package/docs/fonts/ClashGrotesk-Light.eot +0 -0
- package/docs/fonts/ClashGrotesk-Light.ttf +0 -0
- package/docs/fonts/ClashGrotesk-Light.woff +0 -0
- package/docs/fonts/ClashGrotesk-Light.woff2 +0 -0
- package/docs/fonts/ClashGrotesk-Medium.eot +0 -0
- package/docs/fonts/ClashGrotesk-Medium.ttf +0 -0
- package/docs/fonts/ClashGrotesk-Medium.woff +0 -0
- package/docs/fonts/ClashGrotesk-Medium.woff2 +0 -0
- package/docs/fonts/ClashGrotesk-Regular.eot +0 -0
- package/docs/fonts/ClashGrotesk-Regular.ttf +0 -0
- package/docs/fonts/ClashGrotesk-Regular.woff +0 -0
- package/docs/fonts/ClashGrotesk-Regular.woff2 +0 -0
- package/docs/fonts/ClashGrotesk-Semibold.eot +0 -0
- package/docs/fonts/ClashGrotesk-Semibold.ttf +0 -0
- package/docs/fonts/ClashGrotesk-Semibold.woff +0 -0
- package/docs/fonts/ClashGrotesk-Semibold.woff2 +0 -0
- package/docs/fonts/ClashGrotesk-Variable.eot +0 -0
- package/docs/fonts/ClashGrotesk-Variable.ttf +0 -0
- package/docs/fonts/ClashGrotesk-Variable.woff +0 -0
- package/docs/fonts/ClashGrotesk-Variable.woff2 +0 -0
- package/docs/img/concorde-icon.svg +0 -5
- package/docs/img/concorde-logo.svg +0 -1
- package/docs/img/concorde.png +0 -0
- package/docs/img/concorde_def.png +0 -0
- package/docs/img/concorde_seuil.png.webp +0 -0
- package/docs/img/concorde_seuil_invert.png +0 -0
- package/docs/img/paul_metrand.jpg +0 -0
- package/docs/img/paul_metrand_xs.jpg +0 -0
- package/docs/index.html +0 -93
- package/docs/src/core/components/functional/date/date.md +0 -290
- package/docs/src/core/components/functional/fetch/fetch.md +0 -117
- package/docs/src/core/components/functional/if/if.md +0 -16
- package/docs/src/core/components/functional/list/list.md +0 -199
- package/docs/src/core/components/functional/mix/mix.md +0 -41
- package/docs/src/core/components/functional/queue/queue.md +0 -87
- package/docs/src/core/components/functional/router/router.md +0 -108
- package/docs/src/core/components/functional/sdui/default-library.json +0 -108
- package/docs/src/core/components/functional/sdui/example.json +0 -99
- package/docs/src/core/components/functional/sdui/sdui.md +0 -356
- package/docs/src/core/components/functional/states/states.md +0 -87
- package/docs/src/core/components/functional/submit/submit.md +0 -83
- package/docs/src/core/components/functional/subscriber/subscriber.md +0 -91
- package/docs/src/core/components/functional/value/value.md +0 -35
- package/docs/src/core/components/ui/alert/alert.md +0 -121
- package/docs/src/core/components/ui/alert-messages/alert-messages.md +0 -0
- package/docs/src/core/components/ui/badge/badge.md +0 -127
- package/docs/src/core/components/ui/button/button.md +0 -182
- package/docs/src/core/components/ui/captcha/captcha.md +0 -12
- package/docs/src/core/components/ui/card/card.md +0 -97
- package/docs/src/core/components/ui/divider/divider.md +0 -35
- package/docs/src/core/components/ui/form/checkbox/checkbox.md +0 -94
- package/docs/src/core/components/ui/form/fieldset/fieldset.md +0 -129
- package/docs/src/core/components/ui/form/form-actions/form-actions.md +0 -77
- package/docs/src/core/components/ui/form/form-layout/form-layout.md +0 -44
- package/docs/src/core/components/ui/form/input/input.md +0 -167
- package/docs/src/core/components/ui/form/input-autocomplete/input-autocomplete.md +0 -130
- package/docs/src/core/components/ui/form/radio/radio.md +0 -84
- package/docs/src/core/components/ui/form/select/select.md +0 -97
- package/docs/src/core/components/ui/form/switch/switch.md +0 -84
- package/docs/src/core/components/ui/form/textarea/textarea.md +0 -65
- package/docs/src/core/components/ui/group/group.md +0 -75
- package/docs/src/core/components/ui/icon/icon.md +0 -125
- package/docs/src/core/components/ui/icon/icons.json +0 -1
- package/docs/src/core/components/ui/image/image.md +0 -107
- package/docs/src/core/components/ui/link/link.md +0 -43
- package/docs/src/core/components/ui/loader/loader.md +0 -67
- package/docs/src/core/components/ui/menu/menu.md +0 -288
- package/docs/src/core/components/ui/modal/modal.md +0 -123
- package/docs/src/core/components/ui/pop/pop.md +0 -79
- package/docs/src/core/components/ui/progress/progress.md +0 -63
- package/docs/src/core/components/ui/table/table.md +0 -455
- package/docs/src/core/components/ui/tooltip/tooltip.md +0 -82
- package/docs/src/docs/_core-concept/overview.md +0 -57
- package/docs/src/docs/_core-concept/subscriber.md +0 -76
- package/docs/src/docs/_getting-started/concorde-outside.md +0 -143
- package/docs/src/docs/_getting-started/create-a-component.md +0 -137
- package/docs/src/docs/_getting-started/my-first-subscriber.md +0 -174
- package/docs/src/docs/_getting-started/pubsub.md +0 -150
- package/docs/src/docs/_getting-started/start.md +0 -39
- package/docs/src/docs/_getting-started/theming.md +0 -91
- package/docs/src/docs/search/docs-search.json +0 -3902
- package/docs/src/tag-list.json +0 -1
- package/docs/src/tsconfig-model.json +0 -23
- package/docs/src/tsconfig.json +0 -835
- package/docs/svg/regular/plane.svg +0 -1
- package/docs/svg/solid/plane.svg +0 -1
- package/php/get-challenge.php +0 -34
- package/php/some-service.php +0 -42
|
@@ -37,7 +37,7 @@ const tagName = "sonic-list";
|
|
|
37
37
|
* *
|
|
38
38
|
*/
|
|
39
39
|
export type ListItemMetadata = {
|
|
40
|
-
key?: string;
|
|
40
|
+
key?: string | number;
|
|
41
41
|
even?: boolean;
|
|
42
42
|
odd?: boolean;
|
|
43
43
|
onlyChild?: boolean;
|
|
@@ -45,6 +45,12 @@ export type ListItemMetadata = {
|
|
|
45
45
|
lastChild?: boolean;
|
|
46
46
|
};
|
|
47
47
|
|
|
48
|
+
// Simplifier le type ListItems pour n'être qu'une fonction
|
|
49
|
+
export type ListItems = (
|
|
50
|
+
item: any,
|
|
51
|
+
metadata: ListItemMetadata
|
|
52
|
+
) => DirectiveResult;
|
|
53
|
+
|
|
48
54
|
@customElement(tagName)
|
|
49
55
|
export class List extends Fetcher(Subscriber(TemplatesContainer(LitElement))) {
|
|
50
56
|
@property({ type: Object }) itemPropertyMap?: object;
|
|
@@ -63,6 +69,10 @@ export class List extends Fetcher(Subscriber(TemplatesContainer(LitElement))) {
|
|
|
63
69
|
@property() limit = Number.POSITIVE_INFINITY;
|
|
64
70
|
@property() offset = 0;
|
|
65
71
|
|
|
72
|
+
@property({ type: Object }) items?: ListItems;
|
|
73
|
+
@property({ type: Object }) noItems?: () => DirectiveResult;
|
|
74
|
+
@property({ type: Object }) skeleton?: () => DirectiveResult;
|
|
75
|
+
|
|
66
76
|
connectedCallback() {
|
|
67
77
|
this.noShadowDom = "";
|
|
68
78
|
this.defferedDebug = this.hasAttribute("debug") || null;
|
|
@@ -84,6 +94,9 @@ export class List extends Fetcher(Subscriber(TemplatesContainer(LitElement))) {
|
|
|
84
94
|
return html`<sonic-loader mode=${loader}></sonic-loader>`;
|
|
85
95
|
}
|
|
86
96
|
renderSkeleton() {
|
|
97
|
+
if (this.skeleton) {
|
|
98
|
+
return this.skeleton();
|
|
99
|
+
}
|
|
87
100
|
const template = this.templateParts["skeleton"];
|
|
88
101
|
if (!(this.isLoading && template)) return nothing;
|
|
89
102
|
return templateContent(template) as DirectiveResult;
|
|
@@ -207,6 +220,23 @@ export class List extends Fetcher(Subscriber(TemplatesContainer(LitElement))) {
|
|
|
207
220
|
`;
|
|
208
221
|
}
|
|
209
222
|
|
|
223
|
+
private handleProgrammaticTemplates(
|
|
224
|
+
item: any,
|
|
225
|
+
metadata: ListItemMetadata,
|
|
226
|
+
key: string | number
|
|
227
|
+
): DirectiveResult | null {
|
|
228
|
+
if (!this.items) return null;
|
|
229
|
+
|
|
230
|
+
return html`<sonic-subscriber
|
|
231
|
+
?debug=${this.defferedDebug === true}
|
|
232
|
+
.bindPublisher=${() => this.publisher[key]}
|
|
233
|
+
.propertyMap?=${this.itemPropertyMap}
|
|
234
|
+
dataProvider="${this.dataProvider}/list-item/${key}"
|
|
235
|
+
>
|
|
236
|
+
${this.items(item, metadata)}
|
|
237
|
+
</sonic-subscriber>`;
|
|
238
|
+
}
|
|
239
|
+
|
|
210
240
|
renderContent() {
|
|
211
241
|
/**
|
|
212
242
|
* Loading
|
|
@@ -231,11 +261,19 @@ export class List extends Fetcher(Subscriber(TemplatesContainer(LitElement))) {
|
|
|
231
261
|
|
|
232
262
|
const props = this.formatProps();
|
|
233
263
|
/**
|
|
234
|
-
*
|
|
264
|
+
* On peut définir un template spécifique si le résultat est un tableau vide
|
|
235
265
|
*/
|
|
236
|
-
if ((props?.length || 0) == 0
|
|
237
|
-
|
|
266
|
+
if ((props?.length || 0) == 0) {
|
|
267
|
+
if (this.noItems) {
|
|
268
|
+
return this.noItems();
|
|
269
|
+
}
|
|
270
|
+
this.templateParts["no-items"] =
|
|
271
|
+
this.templateParts["no-items"] || this.templateParts["no-item"];
|
|
272
|
+
if (this.templateParts["no-items"]) {
|
|
273
|
+
return templateContent(this.templateParts["no-items"]);
|
|
274
|
+
}
|
|
238
275
|
}
|
|
276
|
+
|
|
239
277
|
/**
|
|
240
278
|
* Rendu des lignes
|
|
241
279
|
* */
|
|
@@ -250,29 +288,25 @@ export class List extends Fetcher(Subscriber(TemplatesContainer(LitElement))) {
|
|
|
250
288
|
return html`
|
|
251
289
|
${items?.map((item, index: number) => {
|
|
252
290
|
if (item == null) return nothing;
|
|
253
|
-
let templatePart: HTMLTemplateElement | null = null;
|
|
254
291
|
let key: number | string = index;
|
|
292
|
+
let templatePart: HTMLTemplateElement | null = null;
|
|
255
293
|
|
|
256
294
|
if (typeof item == "object" && !Array.isArray(item)) {
|
|
295
|
+
if (extractValues) key = item?.["key"] as number | string;
|
|
296
|
+
// Récupérer le template par son nom si présent
|
|
257
297
|
const templatePartName = item[this.templateKey];
|
|
258
298
|
if (templatePartName && typeof templatePartName == "string") {
|
|
259
299
|
templatePart = this.templateParts[templatePartName];
|
|
260
300
|
}
|
|
261
|
-
if (extractValues) key = item?.["key"] as number | string;
|
|
262
301
|
}
|
|
263
302
|
if (key == "_sonic_http_response_") return nothing;
|
|
264
303
|
if (typeof key != "string" && typeof key != "number") return nothing;
|
|
304
|
+
|
|
265
305
|
const isLastChild = index >= length - 1;
|
|
266
306
|
const indexMod2 = index % 2;
|
|
267
307
|
const childPublisher = this.publisher[key];
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
*/
|
|
271
|
-
//La prop key est gardée pour le moment pour compatibilité
|
|
272
|
-
//TODO : supprimer la prop key cquand c'est ok côté covoit.
|
|
273
|
-
childPublisher._key_ = key + "";
|
|
274
|
-
childPublisher._metadata_ = {
|
|
275
|
-
...childPublisher._metadata_.get(), //Si il y a d'autres données.
|
|
308
|
+
|
|
309
|
+
const metadata: ListItemMetadata = {
|
|
276
310
|
key: key,
|
|
277
311
|
even: indexMod2 == 0,
|
|
278
312
|
odd: indexMod2 == 1,
|
|
@@ -280,26 +314,43 @@ export class List extends Fetcher(Subscriber(TemplatesContainer(LitElement))) {
|
|
|
280
314
|
firstChild: index == 0,
|
|
281
315
|
lastChild: isLastChild,
|
|
282
316
|
};
|
|
317
|
+
|
|
318
|
+
childPublisher._key_ = key + "";
|
|
319
|
+
childPublisher._metadata_ = {
|
|
320
|
+
...childPublisher._metadata_.get(),
|
|
321
|
+
...metadata,
|
|
322
|
+
};
|
|
323
|
+
|
|
324
|
+
// Essayer d'utiliser les templates programmatiques
|
|
325
|
+
const programmaticTemplate = this.handleProgrammaticTemplates(
|
|
326
|
+
item,
|
|
327
|
+
metadata,
|
|
328
|
+
key
|
|
329
|
+
);
|
|
330
|
+
if (programmaticTemplate) {
|
|
331
|
+
return html`${programmaticTemplate}${separator && !isLastChild
|
|
332
|
+
? templateContent(separator)
|
|
333
|
+
: nothing}`;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
// Sinon, utiliser le système de template existant
|
|
283
337
|
counter++;
|
|
284
338
|
if (templatePart) counter = -1;
|
|
285
|
-
return
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
${separator && !isLastChild ? templateContent(separator) : nothing}
|
|
301
|
-
`
|
|
302
|
-
);
|
|
339
|
+
return html`
|
|
340
|
+
<sonic-subscriber
|
|
341
|
+
?debug=${this.defferedDebug === true}
|
|
342
|
+
.bindPublisher=${function () {
|
|
343
|
+
return childPublisher;
|
|
344
|
+
}}
|
|
345
|
+
.propertyMap?=${this.itemPropertyMap}
|
|
346
|
+
dataProvider="${this.dataProvider}/list-item/${key}"
|
|
347
|
+
>
|
|
348
|
+
${templatePart
|
|
349
|
+
? templateContent(templatePart)
|
|
350
|
+
: templateContent(this.templateList[counter % templateCount])}
|
|
351
|
+
</sonic-subscriber>
|
|
352
|
+
${separator && !isLastChild ? templateContent(separator) : nothing}
|
|
353
|
+
`;
|
|
303
354
|
})}
|
|
304
355
|
`;
|
|
305
356
|
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { LitElement } from "lit";
|
|
2
|
+
import { html } from "lit";
|
|
3
|
+
import { customElement } from "lit/decorators.js";
|
|
4
|
+
import "./queue";
|
|
5
|
+
import { tailwind } from "../../../../docs/tailwind";
|
|
6
|
+
|
|
7
|
+
@customElement("sonic-queue-demo")
|
|
8
|
+
export class QueueDemo extends LitElement {
|
|
9
|
+
static styles = [tailwind];
|
|
10
|
+
|
|
11
|
+
private items = (item: any) => html`
|
|
12
|
+
<div class="bg-neutral-100 p-2 rounded-md">
|
|
13
|
+
<div class="font-medium">${item.nom}</div>
|
|
14
|
+
<div class="text-sm text-gray-600">Code: ${item.code}</div>
|
|
15
|
+
</div>
|
|
16
|
+
`;
|
|
17
|
+
private noItems = () => html`
|
|
18
|
+
<div class="flex flex-col items-center justify-center p-4 text-gray-500">
|
|
19
|
+
<p>Aucune commune trouvée</p>
|
|
20
|
+
</div>
|
|
21
|
+
`;
|
|
22
|
+
|
|
23
|
+
render() {
|
|
24
|
+
return html`
|
|
25
|
+
<div class="p-4">
|
|
26
|
+
<h2 class="text-xl font-medium mb-4">Liste des communes</h2>
|
|
27
|
+
<sonic-queue
|
|
28
|
+
class="grid grid-cols-3 gap-3"
|
|
29
|
+
serviceurl="https://geo.api.gouv.fr/"
|
|
30
|
+
dataproviderexpression="communes?limit=$limit"
|
|
31
|
+
limit="30"
|
|
32
|
+
.items=${this.items}
|
|
33
|
+
.noItems=${this.noItems}
|
|
34
|
+
></sonic-queue>
|
|
35
|
+
</div>
|
|
36
|
+
`;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -6,6 +6,7 @@ import { PublisherManager } from "@supersoniks/concorde/core/utils/PublisherProx
|
|
|
6
6
|
import "@supersoniks/concorde/core/components/functional/list/list";
|
|
7
7
|
import { PublisherProxy } from "@supersoniks/concorde/core/utils/PublisherProxy";
|
|
8
8
|
import { HTML } from "@supersoniks/concorde/utils";
|
|
9
|
+
import { ListItems } from "@supersoniks/concorde/core/components/functional/list/list";
|
|
9
10
|
|
|
10
11
|
type QueueItem = {
|
|
11
12
|
id: string;
|
|
@@ -32,6 +33,9 @@ const tagName = "sonic-queue";
|
|
|
32
33
|
export default class Queue extends Subscriber(LitElement, {} as QueueProps) {
|
|
33
34
|
@property({ type: Array }) templates: Array<HTMLTemplateElement> | null =
|
|
34
35
|
null;
|
|
36
|
+
@property({ type: Object }) items: ListItems | null = null;
|
|
37
|
+
@property({ type: Object }) noItems: ListItems | null = null;
|
|
38
|
+
@property({ type: Object }) skeleton: ListItems | null = null;
|
|
35
39
|
lastRequestTime = 0;
|
|
36
40
|
key = "";
|
|
37
41
|
|
|
@@ -363,6 +367,9 @@ export default class Queue extends Subscriber(LitElement, {} as QueueProps) {
|
|
|
363
367
|
endPoint="${item.endPoint}"
|
|
364
368
|
idKey=${this.idKey}
|
|
365
369
|
.templates=${templates}
|
|
370
|
+
.items=${this.items}
|
|
371
|
+
.noItems=${this.noItems}
|
|
372
|
+
.skeleton=${this.skeleton}
|
|
366
373
|
>
|
|
367
374
|
</sonic-list>
|
|
368
375
|
`;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { html, LitElement } from "lit";
|
|
2
|
+
import { customElement, state } from "lit/decorators.js";
|
|
3
|
+
import "./router";
|
|
4
|
+
import { Routes } from "@supersoniks/concorde/core/utils/route";
|
|
5
|
+
|
|
6
|
+
import { tailwind } from "../../../../docs/tailwind";
|
|
7
|
+
const defaultRoute = {
|
|
8
|
+
user: "#user/:id/:slug",
|
|
9
|
+
};
|
|
10
|
+
export type AppRoutes = typeof defaultRoute;
|
|
11
|
+
|
|
12
|
+
Routes.register<AppRoutes>(defaultRoute);
|
|
13
|
+
|
|
14
|
+
@customElement("sonic-router-demo")
|
|
15
|
+
export class RouterDemo extends LitElement {
|
|
16
|
+
static styles = [tailwind];
|
|
17
|
+
|
|
18
|
+
@state()
|
|
19
|
+
private routes = {
|
|
20
|
+
"#home": () => html`
|
|
21
|
+
<div class="p-4 border border-gray-200 rounded-md">
|
|
22
|
+
<h1 class="text-xl font-medium mb-2">Accueil</h1>
|
|
23
|
+
<p class="text-gray-600">Bienvenue sur la démo du router</p>
|
|
24
|
+
</div>
|
|
25
|
+
`,
|
|
26
|
+
[defaultRoute.user]: ({ slug, id }: { id: string; slug: string }) => html`
|
|
27
|
+
<div class="p-4 border border-gray-200 rounded-md">
|
|
28
|
+
<h1 class="text-xl font-medium mb-2">Profil Utilisateur ${id}</h1>
|
|
29
|
+
<p class="text-gray-600">Slug: ${slug}</p>
|
|
30
|
+
</div>
|
|
31
|
+
`,
|
|
32
|
+
"#products/(\\d+)/(\\w+)": ([id, slug]: [string, string]) => html`
|
|
33
|
+
<div class="p-4 border border-gray-200 rounded-md">
|
|
34
|
+
<h1 class="text-xl font-medium mb-2">Produit ${id}</h1>
|
|
35
|
+
<p class="text-gray-600">Slug: ${slug}</p>
|
|
36
|
+
</div>
|
|
37
|
+
`,
|
|
38
|
+
fallback: () => html`
|
|
39
|
+
<div class="p-4 border border-red-200 bg-red-50 rounded-md">
|
|
40
|
+
<h1 class="text-xl font-medium text-red-800 mb-2">404</h1>
|
|
41
|
+
<p class="text-red-600">Page non trouvée</p>
|
|
42
|
+
</div>
|
|
43
|
+
`,
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
render() {
|
|
47
|
+
return html`
|
|
48
|
+
<div class="p-4">
|
|
49
|
+
<h2 class="text-2xl font-medium mb-6">Démo du router</h2>
|
|
50
|
+
|
|
51
|
+
<div class="flex gap-4 mb-6">
|
|
52
|
+
<sonic-button href="#home"> Accueil </sonic-button>
|
|
53
|
+
<sonic-button href="#user/123/mySlug"> Utilisateur 123 </sonic-button>
|
|
54
|
+
<sonic-button href="#products/456/mySlug"> Produit 456 </sonic-button>
|
|
55
|
+
<sonic-button href="#invalid"> 404 </sonic-button>
|
|
56
|
+
</div>
|
|
57
|
+
|
|
58
|
+
<sonic-router .routes=${this.routes}></sonic-router>
|
|
59
|
+
</div>
|
|
60
|
+
`;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -105,4 +105,25 @@ We are then redirected to the url *#data-is-set* which does nothing in itself.
|
|
|
105
105
|
</template>
|
|
106
106
|
</sonic-code>
|
|
107
107
|
|
|
108
|
-
Example of use : use with a router and a submit to manage the steps of login/logout, display of user info.
|
|
108
|
+
Example of use : use with a router and a submit to manage the steps of login/logout, display of user info.
|
|
109
|
+
|
|
110
|
+
## Fallback
|
|
111
|
+
|
|
112
|
+
The fallback route is rendered when no other route matches the current location.
|
|
113
|
+
|
|
114
|
+
<sonic-code>
|
|
115
|
+
<sonic-router>
|
|
116
|
+
<template data-route="#home">
|
|
117
|
+
<div>Home</div>
|
|
118
|
+
</template>
|
|
119
|
+
<template data-route="#fallback">
|
|
120
|
+
<div>Fallback</div>
|
|
121
|
+
</template>
|
|
122
|
+
</sonic-router>
|
|
123
|
+
</sonic-code>
|
|
124
|
+
|
|
125
|
+
## Programmatic routes
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import { expect } from "vitest";
|
|
2
|
+
import TestUtils from "@supersoniks/concorde/test-utils/TestUtils";
|
|
3
|
+
import "./router";
|
|
4
|
+
import { html } from "lit";
|
|
5
|
+
import { Routes } from "@supersoniks/concorde/core/utils/route";
|
|
6
|
+
|
|
7
|
+
function create(template = "", addToDocument = true) {
|
|
8
|
+
return TestUtils.bootstrap(
|
|
9
|
+
`
|
|
10
|
+
<sonic-router>
|
|
11
|
+
${template}
|
|
12
|
+
</sonic-router>
|
|
13
|
+
`,
|
|
14
|
+
addToDocument
|
|
15
|
+
)[0];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
describe("SonicRouter", () => {
|
|
19
|
+
it("devrait afficher le contenu du template avec une route regexp", async () => {
|
|
20
|
+
const elt: any = create(`
|
|
21
|
+
<template data-route="/utilisateur/\\d+">
|
|
22
|
+
<div>Page Utilisateur</div>
|
|
23
|
+
</template>
|
|
24
|
+
`);
|
|
25
|
+
elt.location = "/utilisateur/123";
|
|
26
|
+
await elt.updated();
|
|
27
|
+
expect(elt.textContent.trim()).toBe("Page Utilisateur");
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it("devrait afficher le contenu avec dataProvider quand spécifié", async () => {
|
|
31
|
+
const elt: any = create(`
|
|
32
|
+
<template data-route="/utilisateur/(\\d+)" dataProviderExpression="/api/user/$1">
|
|
33
|
+
<div>Page Utilisateur</div>
|
|
34
|
+
</template>
|
|
35
|
+
`);
|
|
36
|
+
elt.location = "/utilisateur/123";
|
|
37
|
+
await elt.updated();
|
|
38
|
+
const divWrapper = elt.querySelector("div[dataProvider]");
|
|
39
|
+
expect(divWrapper.getAttribute("dataProvider")).toBe("/api/user/123");
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it("devrait afficher le contenu du template avec url-pattern", async () => {
|
|
43
|
+
const elt: any = create(`
|
|
44
|
+
<template data-route="utilisateur/:id">
|
|
45
|
+
<div>Page Utilisateur Pattern</div>
|
|
46
|
+
</template>
|
|
47
|
+
`);
|
|
48
|
+
elt.location = "/utilisateur/123";
|
|
49
|
+
await elt.updated();
|
|
50
|
+
expect(elt.textContent.trim()).toBe("Page Utilisateur Pattern");
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it("devrait afficher le fallback quand aucune route ne correspond", async () => {
|
|
54
|
+
const elt: any = create(`
|
|
55
|
+
<template data-route="/utilisateur/\\d+">
|
|
56
|
+
<div>Page Utilisateur</div>
|
|
57
|
+
</template>
|
|
58
|
+
<template data-fallback>
|
|
59
|
+
<div>Page 404</div>
|
|
60
|
+
</template>
|
|
61
|
+
`);
|
|
62
|
+
elt.location = "/page-inexistante";
|
|
63
|
+
await elt.updated();
|
|
64
|
+
expect(elt.textContent.trim()).toBe("Page 404");
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it("devrait mettre à jour le titre de la page quand spécifié", async () => {
|
|
68
|
+
const elt: any = create(`
|
|
69
|
+
<template data-route="/accueil" title="Page d'accueil">
|
|
70
|
+
<div>Accueil</div>
|
|
71
|
+
</template>
|
|
72
|
+
`);
|
|
73
|
+
elt.location = "/accueil";
|
|
74
|
+
await elt.updated();
|
|
75
|
+
expect(document.title).toBe("Page d'accueil");
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it("devrait gérer plusieurs templates correspondants", async () => {
|
|
79
|
+
const elt: any = create(`
|
|
80
|
+
<template data-route="/utilisateur">
|
|
81
|
+
<div>Base Utilisateur</div>
|
|
82
|
+
</template>
|
|
83
|
+
<template data-route="/utilisateur/(\\d+)">
|
|
84
|
+
<div>Détail Utilisateur</div>
|
|
85
|
+
</template>
|
|
86
|
+
`);
|
|
87
|
+
elt.location = "/utilisateur/123";
|
|
88
|
+
await elt.updated();
|
|
89
|
+
expect(elt.textContent.trim().replace(/\s+/gm, " ")).toBe(
|
|
90
|
+
"Base Utilisateur Détail Utilisateur"
|
|
91
|
+
);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it("devrait rediriger vers fallBackRoute si défini et aucune route ne correspond", async () => {
|
|
95
|
+
const elt: any = create(`
|
|
96
|
+
<template data-route="/utilisateur">
|
|
97
|
+
<div>Page Utilisateur</div>
|
|
98
|
+
</template>
|
|
99
|
+
`);
|
|
100
|
+
elt.fallBackRoute = "#/404";
|
|
101
|
+
document.location.href = "#/page-inexistante";
|
|
102
|
+
await elt.updated();
|
|
103
|
+
// On ne peut pas tester document.location.href directement à cause de jsdom
|
|
104
|
+
// Mais on peut vérifier que la propriété est bien définie
|
|
105
|
+
expect(document.location.href.replace(document.location.origin, "")).toBe(
|
|
106
|
+
"/#/404"
|
|
107
|
+
);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it("devrait gérer les templates fournis via l'attribut templates", async () => {
|
|
111
|
+
const elt: any = create("", false);
|
|
112
|
+
const template = document.createElement("template");
|
|
113
|
+
template.setAttribute("data-route", "/test");
|
|
114
|
+
template.innerHTML = "<div>Test Template</div>";
|
|
115
|
+
elt.templates = [template];
|
|
116
|
+
document.body.appendChild(elt);
|
|
117
|
+
elt.location = "/test";
|
|
118
|
+
await elt.updated();
|
|
119
|
+
expect(elt.textContent.trim()).toBe("Test Template");
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it("devrait gérer le dataProvider avec url-pattern", async () => {
|
|
123
|
+
const elt: any = create(`
|
|
124
|
+
<template data-route="utilisateur/:id/profil/:section" dataProviderExpression="/api/user/:id/:section">
|
|
125
|
+
<div>Profil Utilisateur</div>
|
|
126
|
+
</template>
|
|
127
|
+
`);
|
|
128
|
+
elt.location = "/utilisateur/123/profil/preferences";
|
|
129
|
+
await elt.updated();
|
|
130
|
+
const divWrapper = elt.querySelector("div[dataProvider]");
|
|
131
|
+
expect(divWrapper.getAttribute("dataProvider")).toBe(
|
|
132
|
+
"/api/user/123/preferences"
|
|
133
|
+
);
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
describe("SonicRouter Programmatic", () => {
|
|
138
|
+
it("devrait supporter les routes programmées simples", async () => {
|
|
139
|
+
const elt: any = create();
|
|
140
|
+
const routes = {
|
|
141
|
+
home: () => html`<div>Accueil</div>`,
|
|
142
|
+
about: () => html`<div>À propos</div>`,
|
|
143
|
+
fallback: () => html`<div>404</div>`,
|
|
144
|
+
} satisfies Routes;
|
|
145
|
+
|
|
146
|
+
elt.routes = routes;
|
|
147
|
+
elt.location = "/home";
|
|
148
|
+
await elt.updated();
|
|
149
|
+
expect(elt.textContent.trim()).toBe("Accueil");
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
it("devrait supporter les paramètres avec url-pattern", async () => {
|
|
153
|
+
const elt: any = create("", false);
|
|
154
|
+
const routes = {
|
|
155
|
+
"user/:id/profile/:section": ({
|
|
156
|
+
id,
|
|
157
|
+
section,
|
|
158
|
+
}: {
|
|
159
|
+
id: number;
|
|
160
|
+
section: string;
|
|
161
|
+
}) => html` <div>Utilisateur ${id} - Section ${section}</div> `,
|
|
162
|
+
} satisfies Routes;
|
|
163
|
+
|
|
164
|
+
elt.routes = routes;
|
|
165
|
+
document.body.appendChild(elt);
|
|
166
|
+
elt.location = "/user/123/profile/settings";
|
|
167
|
+
|
|
168
|
+
await elt.updated();
|
|
169
|
+
expect(elt.textContent.trim()).toBe("Utilisateur 123 - Section settings");
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
it("devrait supporter les expressions régulières", async () => {
|
|
173
|
+
const elt: any = create();
|
|
174
|
+
const routes = {
|
|
175
|
+
"user/(\\d+)/post/(\\d+)": ([userId, postId]: number[]) =>
|
|
176
|
+
html` <div>User ${userId} Post ${postId}</div> `,
|
|
177
|
+
} satisfies Routes;
|
|
178
|
+
|
|
179
|
+
elt.routes = routes;
|
|
180
|
+
elt.location = "/user/123/post/456";
|
|
181
|
+
await elt.updated();
|
|
182
|
+
expect(elt.textContent.trim()).toBe("User 123 Post 456");
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
it("devrait utiliser le fallback quand aucune route ne correspond", async () => {
|
|
186
|
+
const elt: any = create();
|
|
187
|
+
const routes = {
|
|
188
|
+
home: () => html`<div>Accueil</div>`,
|
|
189
|
+
fallback: () => html`<div>Page Non Trouvée</div>`,
|
|
190
|
+
} satisfies Routes;
|
|
191
|
+
|
|
192
|
+
elt.routes = routes;
|
|
193
|
+
elt.location = "/invalid";
|
|
194
|
+
await elt.updated();
|
|
195
|
+
expect(elt.textContent.trim()).toBe("Page Non Trouvée");
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
it("devrait prioriser les routes programmées sur les templates HTML", async () => {
|
|
199
|
+
const elt: any = create(`
|
|
200
|
+
<template data-route="home">
|
|
201
|
+
<div>Accueil HTML</div>
|
|
202
|
+
</template>
|
|
203
|
+
`);
|
|
204
|
+
|
|
205
|
+
const routes = {
|
|
206
|
+
home: () => html`<div>Accueil Programmé</div>`,
|
|
207
|
+
} satisfies Routes;
|
|
208
|
+
|
|
209
|
+
elt.routes = routes;
|
|
210
|
+
elt.location = "/home";
|
|
211
|
+
await elt.updated();
|
|
212
|
+
expect(elt.textContent.trim()).toBe("Accueil Programmé");
|
|
213
|
+
});
|
|
214
|
+
});
|