@supersoniks/concorde 4.2.1 → 4.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/README.md +163 -0
  2. package/build-infos.json +1 -1
  3. package/concorde-core.bundle.js +175 -171
  4. package/concorde-core.es.js +2490 -2246
  5. package/dist/concorde-core.bundle.js +175 -171
  6. package/dist/concorde-core.es.js +2490 -2246
  7. package/package.json +22 -1
  8. package/php/get-challenge.php +34 -0
  9. package/php/some-service.php +42 -0
  10. package/scripts/pre-build.mjs +4 -0
  11. package/src/core/_types/endpoint.ts +4 -0
  12. package/src/core/_types/key.ts +1 -0
  13. package/src/core/components/functional/example/example.ts +38 -6
  14. package/src/core/decorators/Subscriber.ts +2 -0
  15. package/src/core/decorators/api.spec.ts +150 -0
  16. package/src/core/decorators/api.ts +244 -0
  17. package/src/core/decorators/subscriber/bind.ts +57 -145
  18. package/src/core/decorators/subscriber/dynamicPath.ts +77 -0
  19. package/src/core/decorators/subscriber/dynamicPropertyWatch.ts +105 -0
  20. package/src/core/decorators/subscriber/onAssign.ts +11 -147
  21. package/src/core/decorators/subscriber/publish.spec.ts +21 -0
  22. package/src/core/decorators/subscriber/publish.ts +148 -0
  23. package/src/core/decorators/subscriber/publisherPath.ts +13 -0
  24. package/src/core/decorators/subscriber/subscribe.spec.ts +21 -0
  25. package/src/core/decorators/subscriber/subscribe.ts +32 -0
  26. package/src/core/decorators/subscriber/subscribe.type-test.ts +32 -0
  27. package/src/core/utils/api.ts +83 -15
  28. package/src/core/utils/dataProviderKey.spec.ts +34 -0
  29. package/src/core/utils/dataProviderKey.ts +86 -0
  30. package/src/core/utils/endpoint.spec.ts +41 -0
  31. package/src/core/utils/endpoint.ts +87 -0
  32. package/src/decorators.ts +14 -0
  33. package/src/docs/{_misc → _decorators}/ancestor-attribute.md +15 -31
  34. package/src/docs/_decorators/bind.md +164 -0
  35. package/src/docs/_decorators/get.md +65 -0
  36. package/src/docs/_decorators/publish.md +54 -0
  37. package/src/docs/_decorators/subscribe.md +36 -0
  38. package/src/docs/_misc/dataProviderKey.md +135 -0
  39. package/src/docs/_misc/endpoint.md +42 -0
  40. package/src/docs/example/decorators-demo-bind-demos.ts +210 -0
  41. package/src/docs/example/decorators-demo-geo.ts +45 -0
  42. package/src/docs/example/decorators-demo-init.ts +228 -0
  43. package/src/docs/example/decorators-demo-subscribe-publish-get-demos.ts +324 -0
  44. package/src/docs/example/decorators-demo.ts +12 -459
  45. package/src/docs/navigation/navigation.ts +27 -10
  46. package/src/docs/search/docs-search.json +1059 -609
  47. package/src/tsconfig-model.json +1 -1
  48. package/src/tsconfig.json +65 -1
  49. package/src/tsconfig.tsbuildinfo +1 -1
  50. package/src/utils.ts +8 -1
  51. package/vite.config.mts +11 -0
  52. package/src/docs/_misc/bind.md +0 -362
  53. /package/src/docs/{_misc → _decorators}/auto-subscribe.md +0 -0
  54. /package/src/docs/{_misc → _decorators}/on-assign.md +0 -0
  55. /package/src/docs/{_misc → _decorators}/wait-for-ancestors.md +0 -0
@@ -0,0 +1,210 @@
1
+ import { html, LitElement } from "lit";
2
+ import { customElement, property, state } from "lit/decorators.js";
3
+ import { bind } from "@supersoniks/concorde/decorators";
4
+ import { DataProviderKey } from "@supersoniks/concorde/core/utils/dataProviderKey";
5
+ import { sub } from "@supersoniks/concorde/directives";
6
+ import {
7
+ PublisherManager,
8
+ PublisherProxy,
9
+ } from "@supersoniks/concorde/core/utils/PublisherProxy";
10
+ import { Objects } from "@supersoniks/concorde/utils";
11
+ import { tailwind } from "../tailwind";
12
+ import "./decorators-demo-init";
13
+
14
+ @customElement("demo-bind")
15
+ export class DemoBind extends LitElement {
16
+ static styles = [tailwind];
17
+
18
+ @bind("demoData.firstName")
19
+ @state()
20
+ firstName = "";
21
+
22
+ @bind("demoData.lastName")
23
+ @state()
24
+ lastName: string = "";
25
+
26
+ @bind("demoData.count")
27
+ @state()
28
+ count: number = 0;
29
+
30
+ render() {
31
+ return html`
32
+ <div>
33
+ <sonic-button @click=${this.updateData}>Update Data</sonic-button>
34
+ </div>
35
+ <div class="p-3">
36
+ <p>Title: <strong>${this.firstName || "Not set"}</strong></p>
37
+ <p>User Name: <strong>${this.lastName || "Not set"}</strong></p>
38
+ <p>Number of updates: <strong>${this.count}</strong></p>
39
+ </div>
40
+ `;
41
+ }
42
+
43
+ updateData() {
44
+ const demoData = PublisherManager.get("demoData");
45
+ const demoUsers = PublisherManager.get("demoUsers");
46
+ const randomIndex = Math.floor(Math.random() * demoUsers.get().length);
47
+ const randomUser = demoUsers.get()[randomIndex];
48
+ demoData.set({
49
+ firstName: randomUser.firstName,
50
+ lastName: randomUser.lastName,
51
+ count: (demoData.count.get() || 0) + 1,
52
+ });
53
+ }
54
+ }
55
+
56
+ @customElement("demo-bind-reflect")
57
+ export class DemoBindReflect extends LitElement {
58
+ static styles = [tailwind];
59
+
60
+ @bind("bindReflectDemo.count", { reflect: true })
61
+ @state()
62
+ withReflect: number = 0;
63
+
64
+ @bind("bindReflectDemo.count")
65
+ @state()
66
+ withoutReflect: number = 0;
67
+
68
+ connectedCallback() {
69
+ super.connectedCallback();
70
+ this.resetData();
71
+ }
72
+
73
+ resetData() {
74
+ PublisherManager.get("bindReflectDemo").set({ count: 0 });
75
+ }
76
+ render() {
77
+ return html`
78
+ <div class="mb-3">
79
+ from publisher : ${sub("bindReflectDemo.count")} <br />
80
+ from component with reflect : ${this.withReflect} <br />
81
+ from component without reflect : ${this.withoutReflect}
82
+ </div>
83
+ <sonic-button @click=${() => this.withReflect++}
84
+ >Increment with reflect</sonic-button
85
+ >
86
+ <sonic-button @click=${() => this.withoutReflect++}
87
+ >Increment without reflect</sonic-button
88
+ >
89
+ <sonic-button @click=${this.resetData}>Reset publisher data</sonic-button>
90
+ `;
91
+ }
92
+ }
93
+
94
+ type BindReflectDemoData = { count: number };
95
+ const bindReflectDemoKey = new DataProviderKey<BindReflectDemoData>("bindReflectDemo");
96
+
97
+ @customElement("demo-bind-key")
98
+ export class DemoBindKey extends LitElement {
99
+ static styles = [tailwind];
100
+
101
+ @bind(bindReflectDemoKey.count, { reflect: true })
102
+ @state()
103
+ count: number = 0;
104
+
105
+ connectedCallback() {
106
+ super.connectedCallback();
107
+ PublisherManager.get("bindReflectDemo").set({ count: 0 });
108
+ }
109
+
110
+ render() {
111
+ return html`
112
+ <div class="mb-3">
113
+ <p>@bind with DataProviderKey&lt;number&gt; (type-safe): ${this.count}</p>
114
+ </div>
115
+ <sonic-button @click=${() => this.count++}>Increment</sonic-button>
116
+ `;
117
+ }
118
+ }
119
+
120
+ @customElement("demo-bind-dynamic")
121
+ export class DemoBindDynamic extends LitElement {
122
+ static styles = [tailwind];
123
+
124
+ @property({ type: String })
125
+ dataProvider: "demoUsers" | "demoUsersAlt" = "demoUsers";
126
+
127
+ @property({ type: Number })
128
+ userIndex: number = 1;
129
+
130
+ @bind("${dataProvider}.${userIndex}")
131
+ @state()
132
+ user: any = {};
133
+
134
+ updateUserIndex(e: Event) {
135
+ this.userIndex = parseInt((e.target as HTMLInputElement).value);
136
+ }
137
+
138
+ updateDataProvider(e: Event) {
139
+ this.dataProvider = (e.target as HTMLSelectElement).value as
140
+ | "demoUsers"
141
+ | "demoUsersAlt";
142
+ }
143
+
144
+ updateCurrentUserData() {
145
+ const usersPublisher = PublisherManager.get(this.dataProvider);
146
+ const userPublisher = Objects.traverse(usersPublisher, [
147
+ String(this.userIndex),
148
+ ]) as PublisherProxy;
149
+
150
+ if (userPublisher) {
151
+ const randomNames = [
152
+ { firstName: "Alice", lastName: "Wonder" },
153
+ { firstName: "Bob", lastName: "Builder" },
154
+ { firstName: "Charlie", lastName: "Chaplin" },
155
+ { firstName: "Diana", lastName: "Prince" },
156
+ { firstName: "Eve", lastName: "Adams" },
157
+ ];
158
+
159
+ const randomName =
160
+ randomNames[Math.floor(Math.random() * randomNames.length)];
161
+ const randomEmail = `${randomName.firstName.toLowerCase()}.${randomName.lastName.toLowerCase()}@example.com`;
162
+
163
+ const currentUser = userPublisher.get() || {};
164
+ userPublisher.set({
165
+ ...currentUser,
166
+ firstName: randomName.firstName,
167
+ lastName: randomName.lastName,
168
+ email: randomEmail,
169
+ });
170
+ }
171
+ }
172
+
173
+ render() {
174
+ return html`
175
+ <div class="flex flex-col gap-2">
176
+ <sonic-select
177
+ .value=${this.dataProvider}
178
+ label="Users set"
179
+ @change=${this.updateDataProvider}
180
+ >
181
+ <option value="demoUsers">First set of users</option>
182
+ <option value="demoUsersAlt">Second set of users</option>
183
+ </sonic-select>
184
+ <sonic-input
185
+ type="number"
186
+ .value=${this.userIndex}
187
+ @input=${this.updateUserIndex}
188
+ min="0"
189
+ max="9"
190
+ label="Index"
191
+ class="block"
192
+ >
193
+ </sonic-input>
194
+ <sonic-button @click=${this.updateCurrentUserData}
195
+ >Update current user data</sonic-button
196
+ >
197
+ <div class="flex flex-col gap-2 border p-2">
198
+ <div>
199
+ <sonic-icon name="user" library="heroicons"></sonic-icon>
200
+ ${this.user?.firstName} ${this.user?.lastName}
201
+ </div>
202
+ <div>
203
+ <sonic-icon name="envelope" library="heroicons"></sonic-icon>
204
+ ${this.user?.email}
205
+ </div>
206
+ </div>
207
+ </div>
208
+ `;
209
+ }
210
+ }
@@ -0,0 +1,45 @@
1
+ import type { APIConfiguration } from "@supersoniks/concorde/core/utils/api";
2
+ import type { ApiGetResult } from "@supersoniks/concorde/core/utils/api";
3
+ import { Endpoint } from "@supersoniks/concorde/core/utils/endpoint";
4
+ import { DataProviderKey } from "@supersoniks/concorde/core/utils/dataProviderKey";
5
+ import { PublisherManager } from "@supersoniks/concorde/core/utils/PublisherProxy";
6
+ import "./decorators-demo-init";
7
+
8
+ export type GeoCommuneRow = { nom: string; code: string };
9
+
10
+ export const geoApiDemoConfiguration: APIConfiguration = {
11
+ serviceURL: "https://geo.api.gouv.fr/",
12
+ token: null,
13
+ userName: null,
14
+ password: null,
15
+ authToken: null,
16
+ tokenProvider: null,
17
+ };
18
+
19
+ const docsDemoGeoApiConfigurationId = "docsDemoGeoApiConfiguration";
20
+ PublisherManager.get(docsDemoGeoApiConfigurationId).set(geoApiDemoConfiguration);
21
+
22
+ export const docsDemoGeoApiConfigurationKey = new DataProviderKey<APIConfiguration>(
23
+ docsDemoGeoApiConfigurationId,
24
+ );
25
+
26
+ export const geoCommunesApiGetEndpoint = new Endpoint<GeoCommuneRow[]>(
27
+ "communes?limit=5&fields=nom,code",
28
+ );
29
+
30
+ export const docsDemoDynApiConfKeyTemplate = new DataProviderKey<APIConfiguration>(
31
+ "docsDemoDynApiConf${configSlot}",
32
+ );
33
+
34
+ PublisherManager.get("docsDemoDynApiConfA").set(geoApiDemoConfiguration);
35
+ PublisherManager.get("docsDemoDynApiConfB").set({
36
+ ...geoApiDemoConfiguration,
37
+ serviceURL: "https://geo.api.gouv.fr/",
38
+ });
39
+
40
+ export const geoCommunesApiGetEndpointDynamic = new Endpoint<GeoCommuneRow[]>(
41
+ "communes?limit=${communeLimit}&fields=nom,code",
42
+ );
43
+
44
+ export const geoCommunesApiGetPublishKey =
45
+ new DataProviderKey<ApiGetResult<GeoCommuneRow[]>>(geoCommunesApiGetEndpoint.path);
@@ -0,0 +1,228 @@
1
+ import { PublisherManager } from "@supersoniks/concorde/core/utils/PublisherProxy";
2
+
3
+ export const ensurePublisherValue = <T>(
4
+ publisherId: string,
5
+ defaultValue: T,
6
+ ): void => {
7
+ const publisher = PublisherManager.get(publisherId);
8
+ const currentValue =
9
+ typeof publisher.get === "function" ? publisher.get() : undefined;
10
+
11
+ const isUnset =
12
+ currentValue === undefined ||
13
+ currentValue === null ||
14
+ (typeof currentValue === "object" &&
15
+ !Array.isArray(currentValue) &&
16
+ Object.keys(currentValue).length === 0);
17
+
18
+ if (isUnset) {
19
+ publisher.set(defaultValue as T);
20
+ }
21
+ };
22
+
23
+ export const initializeDecoratorsDemoData = () => {
24
+ ensurePublisherValue("demoData", {
25
+ title: "Initial Title",
26
+ user: { name: "Initial User" },
27
+ count: 0,
28
+ });
29
+
30
+ ensurePublisherValue("demoUser", {
31
+ name: "Demo User",
32
+ email: "demo@example.com",
33
+ });
34
+
35
+ ensurePublisherValue("demoSettings", {
36
+ theme: "light",
37
+ language: "en",
38
+ });
39
+
40
+ ensurePublisherValue("demoUserSettings", {
41
+ theme: "light",
42
+ language: "en",
43
+ });
44
+
45
+ ensurePublisherValue("autoValue1", 10);
46
+ ensurePublisherValue("autoValue2", 20);
47
+ ensurePublisherValue("waitAncestorDemo", {
48
+ message: "Context from ancestor",
49
+ });
50
+
51
+ ensurePublisherValue("combinedData", { title: "Combined Title" });
52
+ ensurePublisherValue("combinedUser", { name: "Combined User" });
53
+ ensurePublisherValue("combinedSettings", { theme: "dark" });
54
+
55
+ ensurePublisherValue("reflectData", {
56
+ title: "Initial Reflected Title",
57
+ count: 0,
58
+ });
59
+
60
+ ensurePublisherValue("publishDemo", {
61
+ email: "",
62
+ message: "",
63
+ });
64
+
65
+ ensurePublisherValue("dynamicProfiles", {
66
+ alpha: { info: { title: "Profil Alpha" } },
67
+ beta: { info: { title: "Profil Beta" } },
68
+ });
69
+
70
+ ensurePublisherValue("dynamicProfilesAlt", {
71
+ alpha: { info: { title: "Profil Alpha (Alt)" } },
72
+ beta: { info: { title: "Profil Beta (Alt)" } },
73
+ });
74
+
75
+ ensurePublisherValue("demoUsers", [
76
+ {
77
+ id: 1,
78
+ firstName: "Alice",
79
+ lastName: "Smith",
80
+ email: "alice.smith@example.com",
81
+ },
82
+ {
83
+ id: 2,
84
+ firstName: "Bob",
85
+ lastName: "Johnson",
86
+ email: "bob.johnson@example.com",
87
+ },
88
+ {
89
+ id: 3,
90
+ firstName: "Carol",
91
+ lastName: "Williams",
92
+ email: "carol.williams@example.com",
93
+ },
94
+ {
95
+ id: 4,
96
+ firstName: "David",
97
+ lastName: "Brown",
98
+ email: "david.brown@example.com",
99
+ },
100
+ {
101
+ id: 5,
102
+ firstName: "Eve",
103
+ lastName: "Jones",
104
+ email: "eve.jones@example.com",
105
+ },
106
+ {
107
+ id: 6,
108
+ firstName: "Frank",
109
+ lastName: "Garcia",
110
+ email: "frank.garcia@example.com",
111
+ },
112
+ {
113
+ id: 7,
114
+ firstName: "Grace",
115
+ lastName: "Miller",
116
+ email: "grace.miller@example.com",
117
+ },
118
+ {
119
+ id: 8,
120
+ firstName: "Henry",
121
+ lastName: "Davis",
122
+ email: "henry.davis@example.com",
123
+ },
124
+ {
125
+ id: 9,
126
+ firstName: "Ivy",
127
+ lastName: "Martinez",
128
+ email: "ivy.martinez@example.com",
129
+ },
130
+ {
131
+ id: 10,
132
+ firstName: "Jack",
133
+ lastName: "Taylor",
134
+ email: "jack.taylor@example.com",
135
+ },
136
+ ]);
137
+
138
+ ensurePublisherValue("demoUsersAlt", [
139
+ {
140
+ id: 11,
141
+ firstName: "Sophie",
142
+ lastName: "Lindquist",
143
+ email: "sophie.lindquist@example.com",
144
+ },
145
+ {
146
+ id: 12,
147
+ firstName: "Mateo",
148
+ lastName: "Ortega",
149
+ email: "mateo.ortega@example.com",
150
+ },
151
+ {
152
+ id: 13,
153
+ firstName: "Jin",
154
+ lastName: "Park",
155
+ email: "jin.park@example.com",
156
+ },
157
+ {
158
+ id: 14,
159
+ firstName: "Fatima",
160
+ lastName: "El-Sayed",
161
+ email: "fatima.el-sayed@example.com",
162
+ },
163
+ {
164
+ id: 15,
165
+ firstName: "Lars",
166
+ lastName: "Johansson",
167
+ email: "lars.johansson@example.com",
168
+ },
169
+ {
170
+ id: 16,
171
+ firstName: "Amara",
172
+ lastName: "Singh",
173
+ email: "amara.singh@example.com",
174
+ },
175
+ {
176
+ id: 17,
177
+ firstName: "Zuri",
178
+ lastName: "Okafor",
179
+ email: "zuri.okafor@example.com",
180
+ },
181
+ {
182
+ id: 18,
183
+ firstName: "Luca",
184
+ lastName: "Rossi",
185
+ email: "luca.rossi@example.com",
186
+ },
187
+ {
188
+ id: 19,
189
+ firstName: "Ava",
190
+ lastName: "Murphy",
191
+ email: "ava.murphy@example.com",
192
+ },
193
+ {
194
+ id: 20,
195
+ firstName: "Noah",
196
+ lastName: "Keller",
197
+ email: "noah.keller@example.com",
198
+ },
199
+ ]);
200
+
201
+ ensurePublisherValue("demoUsersSettings", [
202
+ { theme: "light", language: "en" },
203
+ { theme: "dark", language: "fr" },
204
+ { theme: "auto", language: "es" },
205
+ { theme: "light", language: "en" },
206
+ { theme: "dark", language: "fr" },
207
+ { theme: "auto", language: "es" },
208
+ { theme: "light", language: "en" },
209
+ { theme: "dark", language: "fr" },
210
+ { theme: "auto", language: "es" },
211
+ { theme: "light", language: "en" },
212
+ ]);
213
+
214
+ ensurePublisherValue("demoUsersAltSettings", [
215
+ { theme: "dark", language: "de" },
216
+ { theme: "light", language: "it" },
217
+ { theme: "auto", language: "ja" },
218
+ { theme: "dark", language: "pt" },
219
+ { theme: "light", language: "ru" },
220
+ { theme: "auto", language: "zh" },
221
+ { theme: "dark", language: "ar" },
222
+ { theme: "light", language: "sv" },
223
+ { theme: "auto", language: "nl" },
224
+ { theme: "dark", language: "pl" },
225
+ ]);
226
+ };
227
+
228
+ initializeDecoratorsDemoData();