@supersoniks/concorde 3.3.2 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/build-infos.json +1 -1
  2. package/concorde-core.bundle.js +154 -154
  3. package/concorde-core.es.js +2366 -2356
  4. package/dist/concorde-core.bundle.js +154 -154
  5. package/dist/concorde-core.es.js +2366 -2356
  6. package/package.json +1 -4
  7. package/src/core/_types/types.ts +1 -1
  8. package/src/core/components/functional/queue/queue.ts +3 -4
  9. package/src/core/components/functional/states/states.demo.ts +5 -2
  10. package/src/core/components/functional/states/states.spec.ts +14 -13
  11. package/src/core/components/functional/submit/submit.ts +2 -2
  12. package/src/core/components/ui/captcha/captcha.ts +16 -12
  13. package/src/core/components/ui/form/input-autocomplete/input-autocomplete.ts +41 -7
  14. package/src/core/components/ui/pop/pop.ts +6 -6
  15. package/src/core/components/ui/theme/theme.ts +3 -3
  16. package/src/core/decorators/subscriber/bind.ts +2 -2
  17. package/src/core/decorators/subscriber/onAssign.ts +6 -4
  18. package/src/core/directives/DataProvider.ts +47 -60
  19. package/src/core/directives/Wording.ts +4 -4
  20. package/src/core/mixins/FormCheckable.ts +12 -12
  21. package/src/core/mixins/FormElement.ts +1 -1
  22. package/src/core/utils/PublisherProxy.ts +260 -178
  23. package/src/core/utils/Utils.ts +3 -0
  24. package/src/core/utils/api.ts +4 -6
  25. package/src/dataprovider.ts +1 -0
  26. package/src/directives.ts +27 -13
  27. package/src/docs/_misc/on-assign.md +5 -5
  28. package/src/docs/search/docs-search.json +70 -0
  29. package/src/tsconfig.json +0 -9
  30. package/src/tsconfig.tsbuildinfo +1 -1
  31. package/src/utils.ts +2 -4
  32. package/mcp-server/COMPARISON-MCP.md +0 -176
  33. package/mcp-server/README-MCP-NODEJS.md +0 -284
  34. package/mcp-server/README-MCP.md +0 -114
  35. package/mcp-server/README.md +0 -127
  36. package/mcp-server/TECHNICAL-DOCS.md +0 -269
  37. package/mcp-server/concorde-mcp-server.js +0 -859
  38. package/mcp-server/concorde-mcp-server.py +0 -801
  39. package/mcp-server/cursor-mcp-config-advanced.json +0 -68
  40. package/mcp-server/cursor-mcp-config-nodejs.json +0 -74
  41. package/mcp-server/cursor-mcp-config.json +0 -11
  42. package/mcp-server/install-mcp-nodejs.sh +0 -104
  43. package/mcp-server/install-mcp.sh +0 -62
  44. package/mcp-server/package-lock.json +0 -147
  45. package/mcp-server/package-mcp.json +0 -40
  46. package/mcp-server/package.json +0 -40
  47. package/mcp-server/test-mcp.js +0 -107
  48. package/mcp-server/test-mcp.py +0 -73
  49. package/src/core/components/ui/toast/message-subscriber.stories.ts +0 -43
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@supersoniks/concorde",
3
- "version": "3.3.2",
3
+ "version": "4.0.0",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "",
@@ -260,9 +260,6 @@
260
260
  "./ui/theme/light": "./src/core/components/ui/theme/theme-collection/light.ts",
261
261
  "./theme": "./src/core/components/ui/theme/theme.ts",
262
262
  "./ui/theme": "./src/core/components/ui/theme/theme.ts",
263
- "./message-subscriber.stories": "./src/core/components/ui/toast/message-subscriber.stories.ts",
264
- "./ui/message-subscriber.stories": "./src/core/components/ui/toast/message-subscriber.stories.ts",
265
- "./ui/toast/message-subscriber.stories": "./src/core/components/ui/toast/message-subscriber.stories.ts",
266
263
  "./message-subscriber": "./src/core/components/ui/toast/message-subscriber.ts",
267
264
  "./ui/message-subscriber": "./src/core/components/ui/toast/message-subscriber.ts",
268
265
  "./ui/toast/message-subscriber": "./src/core/components/ui/toast/message-subscriber.ts",
@@ -1,7 +1,7 @@
1
1
  /* eslint-disable @typescript-eslint/no-explicit-any*/
2
2
 
3
3
  import DataBindObserver from "@supersoniks/concorde/core/utils/DataBindObserver";
4
- import Publisher from "../utils/PublisherProxy";
4
+ import type { Publisher } from "../utils/PublisherProxy";
5
5
  export type Message = {
6
6
  type?: string;
7
7
  content?: string;
@@ -2,9 +2,8 @@ import { html, LitElement, nothing, PropertyValues } from "lit";
2
2
  import { customElement, property } from "lit/decorators.js";
3
3
  import Subscriber from "@supersoniks/concorde/core/mixins/Subscriber";
4
4
  import { map } from "lit/directives/map.js";
5
- import { PublisherManager } from "@supersoniks/concorde/core/utils/PublisherProxy";
5
+ import DataProvider, { PublisherManager } from "@supersoniks/concorde/core/utils/PublisherProxy";
6
6
  import "@supersoniks/concorde/core/components/functional/list/list";
7
- import { PublisherProxy } from "@supersoniks/concorde/core/utils/PublisherProxy";
8
7
  import { HTML } from "@supersoniks/concorde/utils";
9
8
  import { ListItems } from "@supersoniks/concorde/core/components/functional/list/list";
10
9
 
@@ -118,7 +117,7 @@ export default class Queue extends Subscriber(LitElement, {} as QueueProps) {
118
117
  this.lastRequestTime = new Date().getTime();
119
118
  this.configFilter();
120
119
  }
121
- filterPublisher: PublisherProxy | null = null;
120
+ filterPublisher: DataProvider | null = null;
122
121
  configFilter() {
123
122
  const dataFilterProvider =
124
123
  this.getAncestorAttributeValue("dataFilterProvider");
@@ -145,7 +144,7 @@ export default class Queue extends Subscriber(LitElement, {} as QueueProps) {
145
144
  split.shift();
146
145
  const searchParams = new URLSearchParams(split.join("?"));
147
146
  const filterData: Record<string, string | string[]> =
148
- this.filterPublisher?.get();
147
+ this.filterPublisher?.get() ;
149
148
  const filteredFieldsArray = this.filteredFields.split(" ");
150
149
  for (const f in filterData) {
151
150
  let value = filterData[f];
@@ -1,9 +1,12 @@
1
1
  import { LitElement } from "lit";
2
2
  import { html } from "lit";
3
3
  import { customElement, state } from "lit/decorators.js";
4
- import { dp } from "@supersoniks/concorde/directives";
4
+ import { dp } from "@supersoniks/concorde/dataprovider";
5
5
  import "./states";
6
6
  import { tailwind } from "../../../../docs/tailwind";
7
+ type StatesDemoProvider = {
8
+ status?: string;
9
+ };
7
10
 
8
11
  @customElement("sonic-states-demo")
9
12
  export class SonicStatesDemo extends LitElement {
@@ -12,7 +15,7 @@ export class SonicStatesDemo extends LitElement {
12
15
  constructor() {
13
16
  super();
14
17
  // Initialisation du dataProvider
15
- dp("states-demo-provider").set({});
18
+ dp<StatesDemoProvider>("states-demo-provider").set({});
16
19
  }
17
20
 
18
21
  @state()
@@ -5,7 +5,7 @@ import "./states";
5
5
  import { dp } from "@supersoniks/concorde/directives";
6
6
 
7
7
  function create(template = "", addToDocument = true) {
8
- dp("state-dataprovider-test").set({});
8
+ dp<{state: string}>("state-dataprovider-test").set({state: ""});
9
9
  return TestUtils.bootstrap(
10
10
  `
11
11
  <sonic-states dataProvider="state-dataprovider-test" data-path="status">
@@ -25,8 +25,9 @@ describe("SonicStates", () => {
25
25
  <template data-value="inactive">
26
26
  <div>État Inactif</div>
27
27
  </template>
28
- `);
29
- dp("state-dataprovider-test").state = "active";
28
+ `);
29
+
30
+ dp<{state: string}>("state-dataprovider-test").set({state: "active"});
30
31
  await elt.updated();
31
32
  expect(elt.textContent.trim()).toBe("État Actif");
32
33
  });
@@ -37,7 +38,7 @@ describe("SonicStates", () => {
37
38
  <div>Nombre</div>
38
39
  </template>
39
40
  `);
40
- dp("state-dataprovider-test").status = "123";
41
+ dp<{state: string}>("state-dataprovider-test").set({state: "123"});
41
42
  await elt.updated();
42
43
  expect(elt.textContent.trim()).toBe("Nombre");
43
44
  });
@@ -48,7 +49,7 @@ describe("SonicStates", () => {
48
49
  <div>Utilisateur</div>
49
50
  </template>
50
51
  `);
51
- dp("state-dataprovider-test").status = "user/123";
52
+ dp<{state: string}>("state-dataprovider-test").set({state: "user/123"});
52
53
  await elt.updated();
53
54
  expect(elt.textContent.trim()).toBe("Utilisateur");
54
55
  });
@@ -59,7 +60,7 @@ describe("SonicStates", () => {
59
60
  <div>Utilisateur</div>
60
61
  </template>
61
62
  `);
62
- dp("state-dataprovider-test").status = "user/123";
63
+ dp<{state: string}>("state-dataprovider-test").set({state: "user/123"});
63
64
  await elt.updated();
64
65
  const divWrapper = elt.querySelector("div[dataProvider]");
65
66
  expect(divWrapper.getAttribute("dataProvider")).toBe("/api/user/123");
@@ -71,7 +72,7 @@ describe("SonicStates", () => {
71
72
  <div>Utilisateur</div>
72
73
  </template>
73
74
  `);
74
- dp("state-dataprovider-test").status = "user/123";
75
+ dp<{state: string}>("state-dataprovider-test").set({state: "user/123"});
75
76
  await elt.updated();
76
77
  const divWrapper = elt.querySelector("div[dataProvider]");
77
78
  expect(divWrapper.getAttribute("dataProvider")).toBe("/api/user/123");
@@ -82,7 +83,7 @@ describe("SonicStates", () => {
82
83
  elt.states = {
83
84
  active: () => html`<div>État Actif Programmatique</div>`,
84
85
  };
85
- dp("state-dataprovider-test").status = "active";
86
+ dp<{state: string}>("state-dataprovider-test").set({state: "active"});
86
87
  await elt.updated();
87
88
  expect(elt.textContent.trim()).toBe("État Actif Programmatique");
88
89
  });
@@ -92,7 +93,7 @@ describe("SonicStates", () => {
92
93
  elt.states = {
93
94
  "(\\d+)": (status: string) => html`<div>Nombre: ${status}</div>`,
94
95
  };
95
- dp("state-dataprovider-test").status = "123";
96
+ dp<{state: string}>("state-dataprovider-test").set({state: "123"});
96
97
  await elt.updated();
97
98
  expect(elt.textContent.trim()).toBe("Nombre: 123");
98
99
  });
@@ -104,7 +105,7 @@ describe("SonicStates", () => {
104
105
  return html`<div>Utilisateur ${id} ${slug}</div>`;
105
106
  },
106
107
  };
107
- dp("state-dataprovider-test").status = "user/123/mySlug";
108
+ dp<{state: string}>("state-dataprovider-test").set({state: "user/123/mySlug"});
108
109
  await elt.updated();
109
110
  expect(elt.textContent.trim()).toBe("Utilisateur 123 mySlug");
110
111
  });
@@ -115,7 +116,7 @@ describe("SonicStates", () => {
115
116
  active: () => html`<div>État Actif</div>`,
116
117
  fallback: () => html`<div>État Par Défaut</div>`,
117
118
  };
118
- dp("state-dataprovider-test").status = "unknown";
119
+ dp<{state: string}>("state-dataprovider-test").set({state: "unknown"});
119
120
  await elt.updated();
120
121
  expect(elt.textContent.trim()).toBe("État Par Défaut");
121
122
  });
@@ -130,11 +131,11 @@ describe("SonicStates", () => {
130
131
  prog: () => html`<div>Template Programmatique</div>`,
131
132
  };
132
133
 
133
- dp("state-dataprovider-test").status = "html";
134
+ dp<{state: string}>("state-dataprovider-test").set({state: "html"});
134
135
  await elt.updated();
135
136
  expect(elt.textContent.trim()).toBe("Template HTML");
136
137
 
137
- dp("state-dataprovider-test").status = "prog";
138
+ dp<{state: string}>("state-dataprovider-test").set({state: "prog"});
138
139
  await elt.updated();
139
140
  expect(elt.textContent.trim()).toBe("Template Programmatique");
140
141
  });
@@ -113,7 +113,7 @@ export class Submit extends Subscriber(LitElement) {
113
113
  );
114
114
  //
115
115
  // Validation du formulaire
116
- formPublisher.isFormValid = true;
116
+ formPublisher.isFormValid.set(true);
117
117
  formPublisher.invalidateForm();
118
118
  if (!formPublisher.isFormValid.get()) return;
119
119
  this.disabled = true;
@@ -258,7 +258,7 @@ export class Submit extends Subscriber(LitElement) {
258
258
  ? formPublisher
259
259
  : null;
260
260
  if (captchaPublisher) {
261
- captchaPublisher.captchaToken = "request_token";
261
+ captchaPublisher.captchaToken.set("request_token");
262
262
  const captchaAssign = (token?: string) => {
263
263
  if (token != "request_token") {
264
264
  sendData();
@@ -1,9 +1,9 @@
1
1
  import { Subscriber } from "@supersoniks/concorde/mixins";
2
- import { HTML, PublisherManager } from "@supersoniks/concorde/utils";
2
+ import { dp, HTML } from "@supersoniks/concorde/utils";
3
3
  import { css, html, LitElement, nothing } from "lit";
4
4
  import { customElement, property } from "lit/decorators.js";
5
5
  import { ConcordeWindow } from "@supersoniks/concorde/core/_types/types";
6
- import Publisher from "@supersoniks/concorde/core/utils/PublisherProxy";
6
+ import type { DataProvider, Publisher } from "@supersoniks/concorde/core/utils/PublisherProxy";
7
7
  import {
8
8
  generateKey,
9
9
  encryptToBase64,
@@ -51,15 +51,15 @@ export class Captcha extends Subscriber(LitElement) {
51
51
  @property() key = "";
52
52
  @property() action: string | null = null;
53
53
  @property({ type: Number }) zIndex = 9999;
54
- formPublisher?: {
54
+ formPublisher?: DataProvider<{
55
55
  needsCaptchaValidation: boolean;
56
56
  captchaKey: string;
57
- captchaToken: Publisher<string> | string;
58
- };
57
+ captchaToken: string;
58
+ }>;
59
59
 
60
60
  onCaptchaTokenChanged = (v: string) => {
61
61
  if (v == "request_token") {
62
- if (this.formPublisher) this.formPublisher.captchaToken = "";
62
+ if (this.formPublisher) this.formPublisher.captchaToken.set("");
63
63
  this.requestToken();
64
64
  }
65
65
  };
@@ -78,7 +78,11 @@ export class Captcha extends Subscriber(LitElement) {
78
78
  }
79
79
  this.generateEncryptedKey();
80
80
  super.connectedCallback();
81
- this.formPublisher = PublisherManager.get(
81
+ this.formPublisher = dp<{
82
+ needsCaptchaValidation: boolean;
83
+ captchaKey: string;
84
+ captchaToken: string;
85
+ }>(
82
86
  this.getAncestorAttributeValue("headersDataProvider") ??
83
87
  this.getAncestorAttributeValue("formDataProvider")
84
88
  );
@@ -87,7 +91,7 @@ export class Captcha extends Subscriber(LitElement) {
87
91
  this.formPublisher &&
88
92
  !(this.formPublisher.captchaToken as Publisher<string>).get()
89
93
  ) {
90
- this.formPublisher.needsCaptchaValidation = true;
94
+ this.formPublisher.needsCaptchaValidation.set(true);
91
95
  (this.formPublisher.captchaToken as Publisher<string>).onAssign(
92
96
  this.onCaptchaTokenChanged
93
97
  );
@@ -98,8 +102,8 @@ export class Captcha extends Subscriber(LitElement) {
98
102
  (this.formPublisher.captchaToken as Publisher<string>).offAssign(
99
103
  this.onCaptchaTokenChanged
100
104
  );
101
- this.formPublisher.captchaToken = "";
102
- this.formPublisher.needsCaptchaValidation = false;
105
+ this.formPublisher.captchaToken.set("");
106
+ this.formPublisher.needsCaptchaValidation.set(false);
103
107
  }
104
108
 
105
109
  super.disconnectedCallback();
@@ -110,8 +114,8 @@ export class Captcha extends Subscriber(LitElement) {
110
114
  const form = this.shadowRoot.querySelector("form");
111
115
  if (!form) return;
112
116
  const formData = new FormData(form);
113
- this.formPublisher.captchaKey = this.key;
114
- this.formPublisher.captchaToken = formData.get("altcha")?.toString() || "";
117
+ this.formPublisher.captchaKey.set(this.key);
118
+ this.formPublisher.captchaToken.set(formData.get("altcha")?.toString() || "");
115
119
  }
116
120
 
117
121
  async generateEncryptedKey() {
@@ -1,4 +1,4 @@
1
- import { html, LitElement, css, nothing } from "lit";
1
+ import { html, LitElement, css, nothing, PropertyValues } from "lit";
2
2
  import {
3
3
  customElement,
4
4
  property,
@@ -18,7 +18,7 @@ import "@supersoniks/concorde/core/components/functional/queue/queue";
18
18
  import "@supersoniks/concorde/core/components/ui/menu/menu-item";
19
19
  import { ifDefined } from "lit/directives/if-defined.js";
20
20
  import { PublisherManager } from "@supersoniks/concorde/utils";
21
- import { PublisherProxy } from "@supersoniks/concorde/core/utils/PublisherProxy";
21
+ import DataProvider from "@supersoniks/concorde/core/utils/PublisherProxy";
22
22
  import { Size } from "../../_css/size";
23
23
  import { Input } from "@supersoniks/concorde/core/components/ui/form/input/input";
24
24
  import { customScroll } from "@supersoniks/concorde/core/components/ui/_css/scroll";
@@ -98,10 +98,10 @@ export class InputAutocomplete extends TemplatesContainer(
98
98
  private initQueueDataProvider = "";
99
99
  @state()
100
100
  private lastValidSearch: ListItem | string = "";
101
- private searchPublisher?: PublisherProxy;
102
- private countPublisher?: PublisherProxy;
103
- private initCountPublisher?: PublisherProxy;
104
- private formValuePublisher?: PublisherProxy;
101
+ private searchPublisher?: DataProvider;
102
+ private countPublisher?: DataProvider;
103
+ private initCountPublisher?: DataProvider;
104
+ private formValuePublisher?: DataProvider;
105
105
 
106
106
  /**
107
107
  * Les fonctions de gestion
@@ -239,7 +239,7 @@ export class InputAutocomplete extends TemplatesContainer(
239
239
  * Pour récupérer la valeur de searchParameter correspondante et renseigner l'input
240
240
  **/
241
241
  if (this.value) {
242
- PublisherManager.get(this.initSearchDataProvider)[this.name] = this.value;
242
+ PublisherManager.get(this.initSearchDataProvider)[this.name].set(this.value);
243
243
  }
244
244
  this.initCountPublisher?.onAssign(this.initSearchParameter);
245
245
 
@@ -257,6 +257,12 @@ export class InputAutocomplete extends TemplatesContainer(
257
257
  this.searchPublisher?.onAssign(this.updatePopContentVisibility);
258
258
  }
259
259
 
260
+ protected firstUpdated(_changedProperties: PropertyValues): void {
261
+ super.firstUpdated(_changedProperties);
262
+ // Écouter le focusout sur le popElement pour fermer le pop quand le focus sort
263
+ this.popElement.addEventListener("focusout", this.handleFocusOut);
264
+ }
265
+
260
266
  disconnectedCallback() {
261
267
  super.disconnectedCallback();
262
268
  this.initCountPublisher?.offAssign(this.initSearchParameter);
@@ -269,6 +275,9 @@ export class InputAutocomplete extends TemplatesContainer(
269
275
  getPublisher(this.queueDataProvider).delete();
270
276
 
271
277
  this.searchPublisher?.offAssign(this.updatePopContentVisibility);
278
+
279
+ // Retirer l'écouteur de focusout
280
+ this.popElement.removeEventListener("focusout", this.handleFocusOut);
272
281
  }
273
282
 
274
283
  /**
@@ -331,6 +340,31 @@ export class InputAutocomplete extends TemplatesContainer(
331
340
  this.popElement.show();
332
341
  }
333
342
 
343
+ handleFocusOut = (_e: FocusEvent): void => {
344
+ // Utiliser setTimeout pour vérifier où va le focus après le focusout
345
+ // Cela permet de ne pas fermer le pop si le focus va vers un élément du pop
346
+ setTimeout(() => {
347
+ const activeElement = document.activeElement;
348
+ if (!activeElement) {
349
+ this.popElement.hide();
350
+ return;
351
+ }
352
+
353
+ // Vérifier si le focus est dans le popElement ou dans ce composant
354
+ const isInPop =
355
+ this.popElement.contains(activeElement) ||
356
+ this.popElement.shadowRoot?.contains(activeElement);
357
+ const isInComponent =
358
+ this.contains(activeElement) ||
359
+ this.shadowRoot?.contains(activeElement);
360
+
361
+ // Si le focus n'est ni dans le pop ni dans ce composant, fermer le pop
362
+ if (!isInPop && !isInComponent) {
363
+ this.popElement.hide();
364
+ }
365
+ }, 0);
366
+ };
367
+
334
368
  render() {
335
369
  return html`
336
370
  <sonic-pop manual style="display:block;" @hide=${this.handleHide}>
@@ -30,7 +30,7 @@ export class Pop extends LitElement {
30
30
  }
31
31
 
32
32
  slot[name="content"] {
33
- max-width: 80vw;
33
+ max-width: 100vw;
34
34
  background-color: var(--sc-base, #fff);
35
35
  position: fixed;
36
36
  z-index: 99999;
@@ -76,7 +76,7 @@ export class Pop extends LitElement {
76
76
  lastContentX = 0;
77
77
  lastContentY = 0;
78
78
  resizeObserver: ResizeObserver = new ResizeObserver(() =>
79
- this.computePosition(this.placement)
79
+ this.computePosition(this.placement),
80
80
  );
81
81
 
82
82
  @state() private triggerElement: HTMLElement | null = null;
@@ -176,7 +176,7 @@ export class Pop extends LitElement {
176
176
  Pop.pops.forEach((pop: Pop) => {
177
177
  const popContainsTarget = path.includes(pop);
178
178
  const popContentContainsTarget = path.includes(
179
- pop.querySelector('[slot="content"]') as EventTarget
179
+ pop.querySelector('[slot="content"]') as EventTarget,
180
180
  );
181
181
  const isCloseManual =
182
182
  HTML.getAncestorAttributeValue(target, "data-on-select") === "keep";
@@ -230,7 +230,7 @@ export class Pop extends LitElement {
230
230
  const thisRect = this.getBoundingClientRect();
231
231
 
232
232
  const scrollableAncestor = HTML.getScrollableAncestor(
233
- this.popContent
233
+ this.popContent,
234
234
  ) as HTMLElement;
235
235
  const scrollableAncestorRect = scrollableAncestor?.getBoundingClientRect();
236
236
  const minX = Math.max(0, scrollableAncestorRect?.left || 0) + padding;
@@ -238,12 +238,12 @@ export class Pop extends LitElement {
238
238
  const maxX =
239
239
  Math.min(
240
240
  window.innerWidth,
241
- scrollableAncestorRect?.right || window.innerWidth
241
+ scrollableAncestorRect?.right || window.innerWidth,
242
242
  ) - padding;
243
243
  const maxY =
244
244
  Math.min(
245
245
  window.innerHeight,
246
- scrollableAncestorRect?.bottom || window.innerHeight
246
+ scrollableAncestorRect?.bottom || window.innerHeight,
247
247
  ) - padding;
248
248
  const x0 = thisRect.left;
249
249
  const y0 = thisRect.top;
@@ -24,7 +24,7 @@ export class Theme extends LitElement {
24
24
  font-style: var(--sc-font-style-base, normal);
25
25
  }
26
26
  ::slotted(.sonic-pop-content) {
27
- max-width: 80vw;
27
+ max-width: 100vw;
28
28
  background-color: var(--sc-base, #fff);
29
29
  position: fixed;
30
30
  z-index: 99999;
@@ -99,8 +99,8 @@ export class Theme extends LitElement {
99
99
  type: "SonicTheme",
100
100
  ...theme,
101
101
  },
102
- "*"
103
- )
102
+ "*",
103
+ ),
104
104
  );
105
105
  }
106
106
 
@@ -1,6 +1,6 @@
1
1
  import { Objects } from "@supersoniks/concorde/utils";
2
2
 
3
- import { PublisherProxy, PublisherManager } from "../../utils/PublisherProxy";
3
+ import DataProvider, { PublisherManager } from "../../utils/PublisherProxy";
4
4
  import { ConnectedComponent, setSubscribable } from "./common";
5
5
 
6
6
  const dynamicWatcherStore = Symbol("__bindDynamicWatcherStore__");
@@ -138,7 +138,7 @@ function getPublisherFromPath(path: string) {
138
138
  let publisher = PublisherManager.get(dataProvider);
139
139
  if (!publisher) return null;
140
140
  publisher = Objects.traverse(publisher, segments);
141
- return publisher as PublisherProxy | null;
141
+ return publisher as DataProvider | null;
142
142
  }
143
143
 
144
144
  export function bind(path: string, options?: { reflect?: boolean }) {
@@ -1,6 +1,6 @@
1
1
  import { Objects } from "@supersoniks/concorde/utils";
2
2
 
3
- import { PublisherProxy, PublisherManager } from "../../utils/PublisherProxy";
3
+ import DataProvider, { PublisherManager } from "../../utils/PublisherProxy";
4
4
  import { ConnectedComponent, setSubscribable } from "./common";
5
5
 
6
6
  const dynamicWatcherStore = Symbol("__onAssignDynamicWatcherStore__");
@@ -43,12 +43,14 @@ function registerDynamicWatcher(
43
43
  function ensureWillUpdateHook(instance: any) {
44
44
  const proto = Object.getPrototypeOf(instance);
45
45
  if (!proto || proto[dynamicWillUpdateHookedStore]) return;
46
+
46
47
  const originalWillUpdate = Object.prototype.hasOwnProperty.call(
47
48
  proto,
48
49
  "willUpdate"
49
50
  )
50
51
  ? proto.willUpdate
51
52
  : Object.getPrototypeOf(proto)?.willUpdate;
53
+
52
54
  proto.willUpdate = function (changedProperties?: Map<unknown, unknown>) {
53
55
  const handlers = this[dynamicWatcherStore] as
54
56
  | Map<string, Set<() => void>>
@@ -140,7 +142,7 @@ function getPublisherFromPath(path: string) {
140
142
  let publisher = PublisherManager.get(dataProvider);
141
143
  if (!publisher) return null;
142
144
  publisher = Objects.traverse(publisher, segments);
143
- return publisher as PublisherProxy | null;
145
+ return publisher as DataProvider | null;
144
146
  }
145
147
 
146
148
  type Callback = (...values: unknown[]) => void;
@@ -152,7 +154,7 @@ type PathConfiguration = {
152
154
 
153
155
  type Configuration = {
154
156
  callbacks: Set<Callback>;
155
- publisher: PublisherProxy | null;
157
+ publisher: DataProvider | null;
156
158
  onAssign: (value: unknown) => void;
157
159
  unsubscribePublisher: (() => void) | null;
158
160
  pathConfig: PathConfiguration;
@@ -175,7 +177,7 @@ export function onAssign(...values: Array<string>) {
175
177
  descriptor: PropertyDescriptor
176
178
  ) {
177
179
  setSubscribable(target);
178
- const stateKey = `__onAssign_state__`;
180
+ const stateKey = `__onAssign_state_${_propertyKey}__`;
179
181
  let callback: Callback;
180
182
 
181
183
  (target as ConnectedComponent).__onConnected__((component) => {
@@ -1,41 +1,22 @@
1
1
  import { AsyncDirective, PartInfo } from "lit/async-directive.js";
2
2
  import { directive } from "lit/directive.js";
3
- import {
4
- PublisherManager,
5
- PublisherProxy,
6
- } from "@supersoniks/concorde/core/utils/PublisherProxy";
7
3
  import { noChange } from "lit";
8
- import Objects from "../utils/Objects";
9
4
  import { SearchableDomElement } from "../utils/HTML";
10
- import Publisher from "../utils/PublisherProxy";
11
- type Observable = PublisherProxy | string | (() => unknown);
12
- function getObservables(observable: Observable): Set<PublisherProxy> {
13
- if (typeof observable === "function") {
14
- const func = observable as () => unknown;
15
- PublisherManager.collectModifiedPublisher();
16
- func();
17
- return PublisherManager.getModifiedPublishers() || new Set();
18
- }
19
- if (typeof observable === "string") {
20
- const split = observable.split(".");
21
- const dataProvider: string = split.shift() || "";
22
- let publisher = PublisherManager.get(dataProvider);
23
- publisher = Objects.traverse(publisher, split);
24
- const set = new Set<PublisherProxy>();
25
- set.add(publisher);
26
- return set;
27
- }
28
- return new Set<PublisherProxy>([observable as Publisher]);
29
- }
5
+ import {
6
+ getObservables,
7
+ get as pubGet, set as pubSet, dataProvider as pubDataProvider ,
8
+ dp as pubDp, DataProvider
9
+ } from "../utils/PublisherProxy";
10
+
30
11
 
31
12
  class ObserveDirective extends AsyncDirective {
32
- observables: Set<PublisherProxy> = new Set();
13
+ observables: Set<DataProvider<any>> = new Set();
33
14
  unsubscribe(): void {
34
- this.observables.forEach((publisher: PublisherProxy) =>
15
+ this.observables.forEach((publisher: DataProvider<any>) =>
35
16
  publisher.offAssign(this.onAssign)
36
17
  );
37
18
  }
38
- observable?: Observable;
19
+ observable?: string;
39
20
  node?: SearchableDomElement;
40
21
 
41
22
  /* eslint-disable @typescript-eslint/no-explicit-any*/
@@ -45,7 +26,7 @@ class ObserveDirective extends AsyncDirective {
45
26
  }
46
27
  /* eslint-enable @typescript-eslint/no-explicit-any*/
47
28
 
48
- render(observable: Observable) {
29
+ render(observable: string) {
49
30
  if (this.observable !== observable) {
50
31
  this.observable = observable;
51
32
  if (this.isConnected) {
@@ -60,18 +41,12 @@ class ObserveDirective extends AsyncDirective {
60
41
  };
61
42
  // Subscribes to the observable, calling the directive's asynchronous
62
43
  // setValue API each time the value changes
63
- subscribe(observable: Observable) {
44
+ subscribe<T>(observable: string) {
64
45
  this.unsubscribe();
65
- if (typeof observable === "function") {
66
- this.onAssign = () => {
67
- this.setValue(observable());
68
- };
69
- } else {
70
- this.onAssign = (v: unknown) => {
71
- this.setValue(v);
72
- };
73
- }
74
- this.observables = getObservables(observable);
46
+ this.onAssign = (v: unknown) => {
47
+ this.setValue(v);
48
+ };
49
+ this.observables = getObservables<T>(observable);
75
50
 
76
51
  this.observables.forEach((publisher) => {
77
52
  publisher.onAssign(this.onAssign);
@@ -86,7 +61,7 @@ class ObserveDirective extends AsyncDirective {
86
61
  // re-connected, re-subscribe to make the directive operable again
87
62
  reconnected() {
88
63
  if (!this.observable) return;
89
- this.subscribe(this.observable as Observable);
64
+ this.subscribe(this.observable);
90
65
  }
91
66
  }
92
67
  const dir = directive(ObserveDirective);
@@ -95,25 +70,37 @@ const dir = directive(ObserveDirective);
95
70
  export const subscribe = dir;
96
71
  export const sub = dir;
97
72
 
98
- // get value
99
- export const get = (id: Observable) => {
100
- return getObservables(id).values().next().value?.get();
101
- };
102
73
 
103
- const deepee = (id: Observable, defaultValue?: any) => {
104
- const value = getObservables(id).values().next().value;
105
- if (defaultValue !== undefined && value) {
106
- const innerValue = value.get();
107
- if (Objects.isEmpty(innerValue)) {
108
- value.set(defaultValue);
109
- }
110
- }
111
- return value as any;
112
- };
74
+ /**
75
+ * @deprecated @see {@link "/src/core/utils/PublisherProxy.ts#get"}
76
+ * @param id Observable
77
+ * @returns value of the observable
78
+ *
79
+ */
80
+ export const get: <T = any>(id: string) => T = pubGet;
81
+
82
+
83
+
84
+ /**
85
+ * @deprecated @see {@link "/src/core/utils/PublisherProxy.ts#dataProvider"}
86
+ * @param id Observable
87
+ * @param defaultValue Optional default value
88
+ * @returns Observable
89
+ */
90
+ export const dataProvider = pubDataProvider;
113
91
 
114
- export const dataProvider = deepee;
115
- export const dp = deepee;
92
+ /**
93
+ * @deprecated @see {@link "/src/core/utils/PublisherProxy.ts#dp"}
94
+ * @param id Observable
95
+ * @param defaultValue Optional default value
96
+ * @returns Observable
97
+ */
98
+ export const dp = pubDp;
116
99
 
117
- export const set = (id: Observable, value: unknown) => {
118
- getObservables(id).values().next().value?.set(value);
119
- };
100
+ /**
101
+ * @deprecated @see {@link "/src/core/utils/PublisherProxy.ts#set"}
102
+ * @param id Observable
103
+ * @param value value to set
104
+ * @returns void
105
+ */
106
+ export const set: <T = any>(id: string, value: T) => void = pubSet;