@supersoniks/concorde 3.2.8 → 3.3.2

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.
Files changed (50) hide show
  1. package/build-infos.json +1 -1
  2. package/concorde-core.bundle.js +229 -229
  3. package/concorde-core.es.js +2166 -1831
  4. package/dist/concorde-core.bundle.js +229 -229
  5. package/dist/concorde-core.es.js +2166 -1831
  6. package/docs/assets/{index-C0K6xugr.css → index-B669R8JF.css} +1 -1
  7. package/docs/assets/index-BTo6ly4d.js +4820 -0
  8. package/docs/index.html +2 -2
  9. package/docs/src/core/components/functional/fetch/fetch.md +6 -0
  10. package/docs/src/core/components/ui/menu/menu.md +46 -5
  11. package/docs/src/core/components/ui/modal/modal.md +0 -4
  12. package/docs/src/core/components/ui/toast/toast.md +166 -0
  13. package/docs/src/docs/_misc/ancestor-attribute.md +94 -0
  14. package/docs/src/docs/_misc/auto-subscribe.md +199 -0
  15. package/docs/src/docs/_misc/bind.md +362 -0
  16. package/docs/src/docs/_misc/on-assign.md +336 -0
  17. package/docs/src/docs/_misc/templates-demo.md +19 -0
  18. package/docs/src/docs/search/docs-search.json +550 -0
  19. package/docs/src/tsconfig-model.json +1 -1
  20. package/docs/src/tsconfig.json +28 -8
  21. package/package.json +8 -1
  22. package/src/core/components/functional/queue/queue.demo.ts +8 -11
  23. package/src/core/components/functional/sdui/sdui.ts +0 -0
  24. package/src/core/decorators/Subscriber.ts +5 -187
  25. package/src/core/decorators/subscriber/ancestorAttribute.ts +17 -0
  26. package/src/core/decorators/subscriber/autoFill.ts +28 -0
  27. package/src/core/decorators/subscriber/autoSubscribe.ts +54 -0
  28. package/src/core/decorators/subscriber/bind.ts +305 -0
  29. package/src/core/decorators/subscriber/common.ts +50 -0
  30. package/src/core/decorators/subscriber/onAssign.ts +318 -0
  31. package/src/core/mixins/Fetcher.ts +0 -0
  32. package/src/core/utils/HTML.ts +0 -0
  33. package/src/core/utils/PublisherProxy.ts +1 -1
  34. package/src/core/utils/api.ts +0 -0
  35. package/src/decorators.ts +9 -2
  36. package/src/docs/_misc/ancestor-attribute.md +94 -0
  37. package/src/docs/_misc/auto-subscribe.md +199 -0
  38. package/src/docs/_misc/bind.md +362 -0
  39. package/src/docs/_misc/on-assign.md +336 -0
  40. package/src/docs/_misc/templates-demo.md +19 -0
  41. package/src/docs/example/decorators-demo.ts +658 -0
  42. package/src/docs/navigation/navigation.ts +22 -3
  43. package/src/docs/search/docs-search.json +415 -0
  44. package/src/docs.ts +4 -0
  45. package/src/tsconfig-model.json +1 -1
  46. package/src/tsconfig.json +22 -2
  47. package/src/tsconfig.tsbuildinfo +1 -1
  48. package/vite.config.mts +0 -2
  49. package/docs/assets/index-Dgl1lJQo.js +0 -4861
  50. package/templates-test.html +0 -32
@@ -0,0 +1,19 @@
1
+ # Templates Demo
2
+
3
+ Some test/demos
4
+
5
+ ## States
6
+
7
+ <sonic-states-demo></sonic-states-demo>
8
+
9
+ ## Queue
10
+
11
+
12
+ <sonic-queue-demo></sonic-queue-demo>
13
+
14
+ ## Ressources liées
15
+
16
+ - [Router](#core/components/functional/router/router.md/router)
17
+ - [States](#core/components/functional/states/states.md/states)
18
+ - [Queue](#core/components/functional/queue/queue.md/queue)
19
+
@@ -0,0 +1,658 @@
1
+ import { html, LitElement } from "lit";
2
+ import { customElement, property, state } from "lit/decorators.js";
3
+ import {
4
+ bind,
5
+ ancestorAttribute,
6
+ onAssign,
7
+ autoSubscribe,
8
+ } from "@supersoniks/concorde/decorators";
9
+ import { sub } from "@supersoniks/concorde/directives";
10
+ import {
11
+ PublisherManager,
12
+ PublisherProxy,
13
+ } from "@supersoniks/concorde/core/utils/PublisherProxy";
14
+ import { Objects } from "@supersoniks/concorde/utils";
15
+ import { tailwind } from "../tailwind";
16
+
17
+ const demoSectionClasses =
18
+ "my-6 rounded-2xl border border-neutral-200 dark:border-neutral-800 bg-neutral-0 dark:bg-neutral-900/40 px-6 py-6 md:px-8 md:py-8 space-y-4 shadow-sm";
19
+
20
+ const ensurePublisherValue = <T>(
21
+ publisherId: string,
22
+ defaultValue: T
23
+ ): void => {
24
+ const publisher = PublisherManager.get(publisherId);
25
+ const currentValue =
26
+ typeof publisher.get === "function" ? publisher.get() : undefined;
27
+
28
+ const isUnset =
29
+ currentValue === undefined ||
30
+ currentValue === null ||
31
+ (typeof currentValue === "object" &&
32
+ !Array.isArray(currentValue) &&
33
+ Object.keys(currentValue).length === 0);
34
+
35
+ if (isUnset) {
36
+ publisher.set(defaultValue as T);
37
+ }
38
+ };
39
+
40
+ const initializeDecoratorsDemoData = () => {
41
+ ensurePublisherValue("demoData", {
42
+ title: "Initial Title",
43
+ user: { name: "Initial User" },
44
+ count: 0,
45
+ });
46
+
47
+ ensurePublisherValue("demoUser", {
48
+ name: "Demo User",
49
+ email: "demo@example.com",
50
+ });
51
+
52
+ ensurePublisherValue("demoSettings", {
53
+ theme: "light",
54
+ language: "en",
55
+ });
56
+
57
+ ensurePublisherValue("autoValue1", 10);
58
+ ensurePublisherValue("autoValue2", 20);
59
+
60
+ ensurePublisherValue("combinedData", { title: "Combined Title" });
61
+ ensurePublisherValue("combinedUser", { name: "Combined User" });
62
+ ensurePublisherValue("combinedSettings", { theme: "dark" });
63
+
64
+ ensurePublisherValue("reflectData", {
65
+ title: "Initial Reflected Title",
66
+ count: 0,
67
+ });
68
+
69
+ ensurePublisherValue("dynamicProfiles", {
70
+ alpha: { info: { title: "Profil Alpha" } },
71
+ beta: { info: { title: "Profil Beta" } },
72
+ });
73
+
74
+ ensurePublisherValue("dynamicProfilesAlt", {
75
+ alpha: { info: { title: "Profil Alpha (Alt)" } },
76
+ beta: { info: { title: "Profil Beta (Alt)" } },
77
+ });
78
+
79
+ ensurePublisherValue("demoUsers", [
80
+ {
81
+ id: 1,
82
+ firstName: "Alice",
83
+ lastName: "Smith",
84
+ email: "alice.smith@example.com",
85
+ },
86
+ {
87
+ id: 2,
88
+ firstName: "Bob",
89
+ lastName: "Johnson",
90
+ email: "bob.johnson@example.com",
91
+ },
92
+ {
93
+ id: 3,
94
+ firstName: "Carol",
95
+ lastName: "Williams",
96
+ email: "carol.williams@example.com",
97
+ },
98
+ {
99
+ id: 4,
100
+ firstName: "David",
101
+ lastName: "Brown",
102
+ email: "david.brown@example.com",
103
+ },
104
+ {
105
+ id: 5,
106
+ firstName: "Eve",
107
+ lastName: "Jones",
108
+ email: "eve.jones@example.com",
109
+ },
110
+ {
111
+ id: 6,
112
+ firstName: "Frank",
113
+ lastName: "Garcia",
114
+ email: "frank.garcia@example.com",
115
+ },
116
+ {
117
+ id: 7,
118
+ firstName: "Grace",
119
+ lastName: "Miller",
120
+ email: "grace.miller@example.com",
121
+ },
122
+ {
123
+ id: 8,
124
+ firstName: "Henry",
125
+ lastName: "Davis",
126
+ email: "henry.davis@example.com",
127
+ },
128
+ {
129
+ id: 9,
130
+ firstName: "Ivy",
131
+ lastName: "Martinez",
132
+ email: "ivy.martinez@example.com",
133
+ },
134
+ {
135
+ id: 10,
136
+ firstName: "Jack",
137
+ lastName: "Taylor",
138
+ email: "jack.taylor@example.com",
139
+ },
140
+ ]);
141
+
142
+ ensurePublisherValue("demoUsersAlt", [
143
+ {
144
+ id: 11,
145
+ firstName: "Sophie",
146
+ lastName: "Lindquist",
147
+ email: "sophie.lindquist@example.com",
148
+ },
149
+ {
150
+ id: 12,
151
+ firstName: "Mateo",
152
+ lastName: "Ortega",
153
+ email: "mateo.ortega@example.com",
154
+ },
155
+ {
156
+ id: 13,
157
+ firstName: "Jin",
158
+ lastName: "Park",
159
+ email: "jin.park@example.com",
160
+ },
161
+ {
162
+ id: 14,
163
+ firstName: "Fatima",
164
+ lastName: "El-Sayed",
165
+ email: "fatima.el-sayed@example.com",
166
+ },
167
+ {
168
+ id: 15,
169
+ firstName: "Lars",
170
+ lastName: "Johansson",
171
+ email: "lars.johansson@example.com",
172
+ },
173
+ {
174
+ id: 16,
175
+ firstName: "Amara",
176
+ lastName: "Singh",
177
+ email: "amara.singh@example.com",
178
+ },
179
+ {
180
+ id: 17,
181
+ firstName: "Zuri",
182
+ lastName: "Okafor",
183
+ email: "zuri.okafor@example.com",
184
+ },
185
+ {
186
+ id: 18,
187
+ firstName: "Luca",
188
+ lastName: "Rossi",
189
+ email: "luca.rossi@example.com",
190
+ },
191
+ {
192
+ id: 19,
193
+ firstName: "Ava",
194
+ lastName: "Murphy",
195
+ email: "ava.murphy@example.com",
196
+ },
197
+ {
198
+ id: 20,
199
+ firstName: "Noah",
200
+ lastName: "Keller",
201
+ email: "noah.keller@example.com",
202
+ },
203
+ ]);
204
+
205
+ ensurePublisherValue("demoUsersSettings", [
206
+ { theme: "light", language: "en" },
207
+ { theme: "dark", language: "fr" },
208
+ { theme: "auto", language: "es" },
209
+ { theme: "light", language: "en" },
210
+ { theme: "dark", language: "fr" },
211
+ { theme: "auto", language: "es" },
212
+ { theme: "light", language: "en" },
213
+ { theme: "dark", language: "fr" },
214
+ { theme: "auto", language: "es" },
215
+ { theme: "light", language: "en" },
216
+ ]);
217
+
218
+ ensurePublisherValue("demoUsersAltSettings", [
219
+ { theme: "dark", language: "de" },
220
+ { theme: "light", language: "it" },
221
+ { theme: "auto", language: "ja" },
222
+ { theme: "dark", language: "pt" },
223
+ { theme: "light", language: "ru" },
224
+ { theme: "auto", language: "zh" },
225
+ { theme: "dark", language: "ar" },
226
+ { theme: "light", language: "sv" },
227
+ { theme: "auto", language: "nl" },
228
+ { theme: "dark", language: "pl" },
229
+ ]);
230
+ };
231
+
232
+ initializeDecoratorsDemoData();
233
+
234
+ /**
235
+ * Demo component showcasing @ancestorAttribute decorator
236
+ */
237
+ @customElement("demo-ancestor-attribute")
238
+ export class DemoAncestorAttribute extends LitElement {
239
+ @ancestorAttribute("dataProvider")
240
+ dataProvider: string | null = null;
241
+
242
+ @ancestorAttribute("testAttribute")
243
+ testAttribute: string | null = null;
244
+
245
+ render() {
246
+ return html`
247
+ <section>
248
+ <p>
249
+ DataProvider property initialized from ancestor:
250
+ <strong>${this.dataProvider || "null"}</strong>
251
+ </p>
252
+ <p>
253
+ TestAttribute property initialized from ancestor:
254
+ <strong>${this.testAttribute || "null"}</strong>
255
+ </p>
256
+ </section>
257
+ `;
258
+ }
259
+ }
260
+
261
+ /**
262
+ * Demo component showcasing @bind decorator
263
+ */
264
+ @customElement("demo-bind")
265
+ export class DemoBind extends LitElement {
266
+ static styles = [tailwind];
267
+
268
+ @bind("demoData.firstName")
269
+ @state()
270
+ firstName = "";
271
+
272
+ @bind("demoData.lastName")
273
+ @state()
274
+ lastName: string = "";
275
+
276
+ @bind("demoData.count")
277
+ @state()
278
+ count: number = 0;
279
+
280
+ render() {
281
+ return html`
282
+ <div>
283
+ <sonic-button @click=${this.updateData}>Update Data</sonic-button>
284
+ </div>
285
+ <div class="p-3">
286
+ <p>Title: <strong>${this.firstName || "Not set"}</strong></p>
287
+ <p>User Name: <strong>${this.lastName || "Not set"}</strong></p>
288
+ <p>Number of updates: <strong>${this.count}</strong></p>
289
+ </div>
290
+ `;
291
+ }
292
+
293
+ updateData() {
294
+ const demoData = PublisherManager.get("demoData");
295
+ const demoUsers = PublisherManager.get("demoUsers");
296
+ const randomIndex = Math.floor(Math.random() * demoUsers.get().length);
297
+ const randomUser = demoUsers.get()[randomIndex];
298
+ demoData.set({
299
+ firstName: randomUser.firstName,
300
+ lastName: randomUser.lastName,
301
+ count: (demoData.count.get() || 0) + 1,
302
+ });
303
+ }
304
+ }
305
+
306
+ /**
307
+ * Demo component showcasing @bind decorator with reflect option
308
+ */
309
+ @customElement("demo-bind-reflect")
310
+ export class DemoBindReflect extends LitElement {
311
+ static styles = [tailwind];
312
+
313
+ @bind("bindReflectDemo.count", { reflect: true })
314
+ @state()
315
+ withReflect: number = 0;
316
+
317
+ @bind("bindReflectDemo.count")
318
+ @state()
319
+ withoutReflect: number = 0;
320
+ // initialize the publisher data
321
+ connectedCallback() {
322
+ super.connectedCallback();
323
+ this.resetData();
324
+ }
325
+
326
+ resetData() {
327
+ PublisherManager.get("bindReflectDemo").set({ count: 0 });
328
+ }
329
+ render() {
330
+ return html`
331
+ <div class="mb-3">
332
+ from publisher : ${sub("bindReflectDemo.count")} <br />
333
+ from component with reflect : ${this.withReflect} <br />
334
+ from component without reflect : ${this.withoutReflect}
335
+ </div>
336
+ <sonic-button @click=${() => this.withReflect++}
337
+ >Increment with reflect</sonic-button
338
+ >
339
+ <sonic-button @click=${() => this.withoutReflect++}
340
+ >Increment without reflect</sonic-button
341
+ >
342
+ <sonic-button @click=${this.resetData}>Reset publisher data</sonic-button>
343
+ `;
344
+ }
345
+ }
346
+
347
+ /**
348
+ * Demo component showcasing @bind decorator with dynamic dataProvider/id
349
+ */
350
+ @customElement("demo-bind-dynamic")
351
+ export class DemoBindDynamic extends LitElement {
352
+ static styles = [tailwind];
353
+
354
+ @property({ type: String })
355
+ dataProvider: "demoUsers" | "demoUsersAlt" = "demoUsers";
356
+
357
+ @property({ type: Number })
358
+ userIndex: number = 1;
359
+
360
+ @bind("${dataProvider}.${userIndex}")
361
+ @state()
362
+ user: any = {};
363
+
364
+ updateUserIndex(e: Event) {
365
+ this.userIndex = parseInt((e.target as HTMLInputElement).value);
366
+ }
367
+
368
+ updateDataProvider(e: Event) {
369
+ this.dataProvider = (e.target as HTMLSelectElement).value as
370
+ | "demoUsers"
371
+ | "demoUsersAlt";
372
+ }
373
+
374
+ updateCurrentUserData() {
375
+ const usersPublisher = PublisherManager.get(this.dataProvider);
376
+ const userPublisher = Objects.traverse(usersPublisher, [
377
+ String(this.userIndex),
378
+ ]) as PublisherProxy;
379
+
380
+ if (userPublisher) {
381
+ // Générer de nouvelles données aléatoires
382
+ const randomNames = [
383
+ { firstName: "Alice", lastName: "Wonder" },
384
+ { firstName: "Bob", lastName: "Builder" },
385
+ { firstName: "Charlie", lastName: "Chaplin" },
386
+ { firstName: "Diana", lastName: "Prince" },
387
+ { firstName: "Eve", lastName: "Adams" },
388
+ ];
389
+
390
+ const randomName =
391
+ randomNames[Math.floor(Math.random() * randomNames.length)];
392
+ const randomEmail = `${randomName.firstName.toLowerCase()}.${randomName.lastName.toLowerCase()}@example.com`;
393
+
394
+ // Mettre à jour l'utilisateur directement
395
+ const currentUser = userPublisher.get() || {};
396
+ userPublisher.set({
397
+ ...currentUser,
398
+ firstName: randomName.firstName,
399
+ lastName: randomName.lastName,
400
+ email: randomEmail,
401
+ });
402
+ }
403
+ }
404
+
405
+ render() {
406
+ return html`
407
+ <div class="flex flex-col gap-2">
408
+ <sonic-select
409
+ .value=${this.dataProvider}
410
+ label="Users set"
411
+ @change=${this.updateDataProvider}
412
+ >
413
+ <option value="demoUsers">First set of users</option>
414
+ <option value="demoUsersAlt">Second set of users</option>
415
+ </sonic-select>
416
+ <sonic-input
417
+ type="number"
418
+ .value=${this.userIndex}
419
+ @input=${this.updateUserIndex}
420
+ min="0"
421
+ max="9"
422
+ label="Index"
423
+ class="block"
424
+ >
425
+ </sonic-input>
426
+ <sonic-button @click=${this.updateCurrentUserData}
427
+ >Update current user data</sonic-button
428
+ >
429
+ <div class="flex flex-col gap-2 border p-2">
430
+ <div>
431
+ <sonic-icon name="user" library="heroicons"></sonic-icon>
432
+ ${this.user?.firstName} ${this.user?.lastName}
433
+ </div>
434
+ <div>
435
+ <sonic-icon name="envelope" library="heroicons"></sonic-icon>
436
+ ${this.user?.email}
437
+ </div>
438
+ </div>
439
+ </div>
440
+ `;
441
+ }
442
+ }
443
+
444
+ /**
445
+ * Demo component showcasing @onAssign decorator
446
+ */
447
+ @customElement("demo-on-assign")
448
+ export class DemoOnAssign extends LitElement {
449
+ static styles = [tailwind];
450
+
451
+ @state() userWithSettings: any = null;
452
+ @state() isReady: boolean = false;
453
+ @state() lastUpdate: string = "";
454
+
455
+ @onAssign("demoUser", "demoUserSettings")
456
+ handleDataReady(user: any, settings: any) {
457
+ this.isReady =
458
+ Object.keys(user).length > 0 && Object.keys(settings).length > 0;
459
+ this.userWithSettings = { ...user, ...settings };
460
+ this.lastUpdate = new Date().toLocaleTimeString();
461
+ this.requestUpdate();
462
+ }
463
+
464
+ render() {
465
+ const { name, email, theme, language } = this.userWithSettings;
466
+ return html`
467
+ <div class="mt-2">
468
+ <sonic-button @click=${this.updateData}>Update Data</sonic-button>
469
+ </div>
470
+ <div class="p-3">
471
+ ${this.isReady === false
472
+ ? html`<p>No settings yet...</p>`
473
+ : html`<p>${name || "N/A"}</p>
474
+ <p>${email || "N/A"}</p>
475
+ <p>${theme || "N/A"}</p>
476
+ <p>${language || "N/A"}</p>
477
+ <p><small>Last updated: ${this.lastUpdate}</small></p> `}
478
+ </div>
479
+ `;
480
+ }
481
+
482
+ updateData() {
483
+ const user = PublisherManager.get("demoUser");
484
+ const userSettings = PublisherManager.get("demoUserSettings");
485
+ const userNumber = Math.floor(Math.random() * 100);
486
+ user.set({
487
+ name: `User n°${userNumber}`,
488
+ email: `user-${userNumber}@example.com`,
489
+ });
490
+
491
+ userSettings.set({
492
+ theme: ["light", "dark", "auto"][Math.floor(Math.random() * 3)],
493
+ language: ["en", "fr", "es"][Math.floor(Math.random() * 3)],
494
+ });
495
+ }
496
+ }
497
+
498
+ /**
499
+ * Demo component showcasing @onAssign decorator with dynamic paths
500
+ */
501
+ @customElement("demo-on-assign-dynamic")
502
+ export class DemoOnAssignDynamic extends LitElement {
503
+ static styles = [tailwind];
504
+
505
+ @property({ type: String })
506
+ dataProvider: "demoUsers" | "demoUsersAlt" = "demoUsers";
507
+
508
+ @property({ type: Number })
509
+ userIndex: number = 0;
510
+
511
+ @state() user: any = null;
512
+ @state() userSettings: any = null;
513
+
514
+ @onAssign(
515
+ "${dataProvider}.${userIndex}",
516
+ "${dataProvider}Settings.${userIndex}"
517
+ )
518
+ handleUserDataReady(user: any, settings: any) {
519
+ this.user = user;
520
+ this.userSettings = settings;
521
+ }
522
+
523
+ updateUserIndex(e: Event) {
524
+ this.userIndex = parseInt((e.target as HTMLInputElement).value);
525
+ }
526
+
527
+ updateDataProvider(e: Event) {
528
+ this.dataProvider = (e.target as HTMLSelectElement).value as
529
+ | "demoUsers"
530
+ | "demoUsersAlt";
531
+ }
532
+
533
+ updateCurrentUserData() {
534
+ const usersPublisher = PublisherManager.get(this.dataProvider);
535
+ const settingsPublisher = PublisherManager.get(
536
+ `${this.dataProvider}Settings`
537
+ );
538
+ const userPublisher = Objects.traverse(usersPublisher, [
539
+ String(this.userIndex),
540
+ ]) as PublisherProxy;
541
+ const settingPublisher = Objects.traverse(settingsPublisher, [
542
+ String(this.userIndex),
543
+ ]) as PublisherProxy;
544
+
545
+ if (userPublisher && settingPublisher) {
546
+ // Générer de nouvelles données aléatoires
547
+ const randomNames = [
548
+ { firstName: "Alice", lastName: "Wonder" },
549
+ { firstName: "Bob", lastName: "Builder" },
550
+ { firstName: "Charlie", lastName: "Chaplin" },
551
+ { firstName: "Diana", lastName: "Prince" },
552
+ { firstName: "Eve", lastName: "Adams" },
553
+ ];
554
+ const randomThemes = ["light", "dark", "auto"];
555
+ const randomLanguages = ["en", "fr", "es", "de", "it"];
556
+
557
+ const randomName =
558
+ randomNames[Math.floor(Math.random() * randomNames.length)];
559
+ const randomEmail = `${randomName.firstName.toLowerCase()}.${randomName.lastName.toLowerCase()}@example.com`;
560
+ const randomTheme =
561
+ randomThemes[Math.floor(Math.random() * randomThemes.length)];
562
+ const randomLanguage =
563
+ randomLanguages[Math.floor(Math.random() * randomLanguages.length)];
564
+
565
+ // Mettre à jour l'utilisateur directement
566
+ const currentUser = userPublisher.get() || {};
567
+ userPublisher.set({
568
+ ...currentUser,
569
+ firstName: randomName.firstName,
570
+ lastName: randomName.lastName,
571
+ email: randomEmail,
572
+ });
573
+
574
+ // Mettre à jour les settings directement
575
+ settingPublisher.set({
576
+ theme: randomTheme,
577
+ language: randomLanguage,
578
+ });
579
+ }
580
+ }
581
+
582
+ render() {
583
+ return html`
584
+ <div class="flex flex-col gap-2">
585
+ <sonic-select label="Users set" @change=${this.updateDataProvider}>
586
+ <option value="demoUsers">First set of users</option>
587
+ <option value="demoUsersAlt">Second set of users</option>
588
+ </sonic-select>
589
+ <sonic-input
590
+ type="number"
591
+ .value=${this.userIndex}
592
+ @input=${this.updateUserIndex}
593
+ min="0"
594
+ max="9"
595
+ label="Index"
596
+ class="block"
597
+ >
598
+ </sonic-input>
599
+ <sonic-button @click=${this.updateCurrentUserData}
600
+ >Update current user data</sonic-button
601
+ >
602
+ <div class="flex flex-col gap-2 border p-2">
603
+ <div>
604
+ <sonic-icon name="user" library="heroicons"></sonic-icon>
605
+ ${this.user?.firstName} ${this.user?.lastName}
606
+ </div>
607
+ <div>
608
+ <sonic-icon name="envelope" library="heroicons"></sonic-icon>
609
+ ${this.user?.email}
610
+ </div>
611
+ <div>
612
+ Theme: ${this.userSettings?.theme} | Language:
613
+ ${this.userSettings?.language}
614
+ </div>
615
+ </div>
616
+ </div>
617
+ `;
618
+ }
619
+ }
620
+
621
+ /**
622
+ * Demo component showcasing @autoSubscribe decorator
623
+ */
624
+ @customElement("demo-auto-subscribe")
625
+ export class DemoAutoSubscribe extends LitElement {
626
+ static styles = [tailwind];
627
+
628
+ @state() displayText: string = "";
629
+ @state() computedValue: number = 0;
630
+
631
+ @autoSubscribe()
632
+ updateDisplay() {
633
+ const value1 = PublisherManager.get("autoValue1").get() || 0;
634
+ const value2 = PublisherManager.get("autoValue2").get() || 0;
635
+
636
+ this.computedValue = value1 + value2;
637
+ this.displayText = `${value1} + ${value2} = ${this.computedValue}`;
638
+ }
639
+
640
+ render() {
641
+ return html`
642
+ <p><strong>${this.displayText}</strong></p>
643
+ <div>
644
+ <sonic-button @click=${() => this.randomizeValue("autoValue1")}>
645
+ Randomize Value 1
646
+ </sonic-button>
647
+ <sonic-button @click=${() => this.randomizeValue("autoValue2")}>
648
+ Randomize Value 2
649
+ </sonic-button>
650
+ </div>
651
+ `;
652
+ }
653
+
654
+ randomizeValue(publisherId: string) {
655
+ const value = PublisherManager.get(publisherId);
656
+ value.set(Math.floor(Math.random() * 100));
657
+ }
658
+ }
@@ -28,9 +28,6 @@ export class DocsNavigation extends LitElement {
28
28
  label: "The subscriber mixin",
29
29
  href: "#docs/_core-concept/subscriber.md/subscriber",
30
30
  },
31
- // "Standalone attributes",
32
- // {label: "Data-bind", href: "#"},
33
- // {label: "FormDataProvider", href: "#"},
34
31
  "Functionnal components",
35
32
  { label: "Date", href: "#core/components/functional/date/date.md/date" },
36
33
  {
@@ -132,6 +129,28 @@ export class DocsNavigation extends LitElement {
132
129
  label: "Tooltip",
133
130
  href: "#core/components/ui/tooltip/tooltip.md/tooltip",
134
131
  },
132
+ "Misc",
133
+ {
134
+ label: "@ancestorAttribute",
135
+ href: "#docs/_misc/ancestor-attribute.md/ancestor-attribute",
136
+ },
137
+ {
138
+ label: "@bind",
139
+ href: "#docs/_misc/bind.md/bind",
140
+ },
141
+ {
142
+ label: "@onAssign",
143
+ href: "#docs/_misc/on-assign.md/on-assign",
144
+ },
145
+ {
146
+ label: "@autoSubscribe",
147
+ href: "#docs/_misc/auto-subscribe.md/auto-subscribe",
148
+ },
149
+
150
+ {
151
+ label: "Templates Demo",
152
+ href: "#docs/_misc/templates-demo.md/templates-demo",
153
+ },
135
154
  ];
136
155
 
137
156
  /**