@supersoniks/concorde 3.2.6 → 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 (52) hide show
  1. package/build-infos.json +1 -1
  2. package/concorde-core.bundle.js +249 -249
  3. package/concorde-core.es.js +2251 -1886
  4. package/dist/concorde-core.bundle.js +249 -249
  5. package/dist/concorde-core.es.js +2251 -1886
  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 +47 -22
  24. package/src/core/components/ui/form/input-autocomplete/input-autocomplete.ts +9 -1
  25. package/src/core/components/ui/tooltip/tooltip.ts +67 -2
  26. package/src/core/decorators/Subscriber.ts +5 -187
  27. package/src/core/decorators/subscriber/ancestorAttribute.ts +17 -0
  28. package/src/core/decorators/subscriber/autoFill.ts +28 -0
  29. package/src/core/decorators/subscriber/autoSubscribe.ts +54 -0
  30. package/src/core/decorators/subscriber/bind.ts +305 -0
  31. package/src/core/decorators/subscriber/common.ts +50 -0
  32. package/src/core/decorators/subscriber/onAssign.ts +318 -0
  33. package/src/core/mixins/Fetcher.ts +17 -8
  34. package/src/core/utils/HTML.ts +2 -0
  35. package/src/core/utils/PublisherProxy.ts +1 -1
  36. package/src/core/utils/api.ts +7 -0
  37. package/src/decorators.ts +9 -2
  38. package/src/docs/_misc/ancestor-attribute.md +94 -0
  39. package/src/docs/_misc/auto-subscribe.md +199 -0
  40. package/src/docs/_misc/bind.md +362 -0
  41. package/src/docs/_misc/on-assign.md +336 -0
  42. package/src/docs/_misc/templates-demo.md +19 -0
  43. package/src/docs/example/decorators-demo.ts +658 -0
  44. package/src/docs/navigation/navigation.ts +22 -3
  45. package/src/docs/search/docs-search.json +415 -0
  46. package/src/docs.ts +4 -0
  47. package/src/tsconfig-model.json +1 -1
  48. package/src/tsconfig.json +22 -2
  49. package/src/tsconfig.tsbuildinfo +1 -1
  50. package/vite.config.mts +0 -2
  51. package/docs/assets/index-Dgl1lJQo.js +0 -4861
  52. package/templates-test.html +0 -32
@@ -22,17 +22,14 @@ export class QueueDemo extends LitElement {
22
22
 
23
23
  render() {
24
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>
25
+ <sonic-queue
26
+ class="grid grid-cols-3 gap-3"
27
+ serviceurl="https://geo.api.gouv.fr/"
28
+ dataproviderexpression="communes?limit=$limit"
29
+ limit="30"
30
+ .items=${this.items}
31
+ .noItems=${this.noItems}
32
+ ></sonic-queue>
36
33
  `;
37
34
  }
38
35
  }
@@ -5,11 +5,11 @@ import {
5
5
  SDUINode,
6
6
  SDUITransformDescription,
7
7
  } from "@supersoniks/concorde/core/components/functional/sdui/types";
8
- import {Fetcher, Subscriber} from "@supersoniks/concorde/mixins";
8
+ import { Fetcher, Subscriber } from "@supersoniks/concorde/mixins";
9
9
 
10
- import {HTML, Objects} from "@supersoniks/concorde/utils";
11
- import {LitElement, PropertyValues} from "lit";
12
- import {customElement, property} from "lit/decorators.js";
10
+ import { HTML, Objects } from "@supersoniks/concorde/utils";
11
+ import { LitElement, PropertyValues } from "lit";
12
+ import { customElement, property } from "lit/decorators.js";
13
13
  const tagName = "sonic-sdui"; // For Astro.build
14
14
  /**
15
15
  * ### sonic-sdui (Server Driven User Interface) est un fetcher chargant un JSON décrivant une interface utilisateur
@@ -75,7 +75,9 @@ export class SonicSDUI extends Fetcher(Subscriber(LitElement)) {
75
75
  * Suppressiond du contenu du composant avant le génération de la nouvelle ui
76
76
  */
77
77
  private removeChildren() {
78
- while ([...this.children].filter((elt) => elt.nodeName != "SLOT").length > 0) {
78
+ while (
79
+ [...this.children].filter((elt) => elt.nodeName != "SLOT").length > 0
80
+ ) {
79
81
  this.removeChild(this.children[0]);
80
82
  }
81
83
  }
@@ -118,9 +120,12 @@ export class SonicSDUI extends Fetcher(Subscriber(LitElement)) {
118
120
  if (!this.sduiDescriptor) return;
119
121
  let nodes = this.sduiDescriptor.nodes;
120
122
  if (!nodes) nodes = [];
121
- const messageProvider = {tagName: "sonic-toast-message-subscriber", attributes: {}};
123
+ const messageProvider = {
124
+ tagName: "sonic-toast-message-subscriber",
125
+ attributes: {},
126
+ };
122
127
  if (this.messagesKey) {
123
- messageProvider.attributes = {subDataProvider: this.messagesKey};
128
+ messageProvider.attributes = { subDataProvider: this.messagesKey };
124
129
  }
125
130
  nodes.push(messageProvider);
126
131
  nodes.forEach((node) => this.appendChild(this.parseChild(node)));
@@ -130,7 +135,7 @@ export class SonicSDUI extends Fetcher(Subscriber(LitElement)) {
130
135
  */
131
136
  private parseChild(node: SDUINode) {
132
137
  const tagName = node.tagName || "div";
133
- let {element, contentElement} = this.handleLibrary(node, tagName);
138
+ let { element, contentElement } = this.handleLibrary(node, tagName);
134
139
  this.handleAttributes(node, element);
135
140
  element = this.handleMarkup(node, element);
136
141
  if (!contentElement) contentElement = element;
@@ -148,7 +153,8 @@ export class SonicSDUI extends Fetcher(Subscriber(LitElement)) {
148
153
  */
149
154
  private handlePrefixSuffix(node: SDUINode, element: HTMLElement) {
150
155
  const container = document.createElement("div");
151
- container.innerHTML = (node.prefix || "") + element.outerHTML + (node.suffix || "");
156
+ container.innerHTML =
157
+ (node.prefix || "") + element.outerHTML + (node.suffix || "");
152
158
  container.style.display = "contents";
153
159
  return container;
154
160
  }
@@ -156,18 +162,26 @@ export class SonicSDUI extends Fetcher(Subscriber(LitElement)) {
156
162
  * Création des enfants du noeud courant
157
163
  * Si l'enfant à un attribut parentElementSelector, il est ajouté dans le noeud correspondant au sélecteur css associé et non pas dans l'élément directement.
158
164
  */
159
- private handleChildNodes(node: SDUINode, contentElement: HTMLElement, element: HTMLElement) {
165
+ private handleChildNodes(
166
+ node: SDUINode,
167
+ contentElement: HTMLElement,
168
+ element: HTMLElement
169
+ ) {
160
170
  if (node.nodes) {
161
171
  const children: Array<SDUINode> = node.nodes;
162
172
  for (const child of children) {
163
173
  const childElement = this.parseChild(child);
164
174
  let nodeToAppendOn = contentElement;
165
175
  if (child.parentElementSelector) {
166
- nodeToAppendOn = element.querySelector(child.parentElementSelector) || contentElement;
176
+ nodeToAppendOn =
177
+ element.querySelector(child.parentElementSelector) ||
178
+ contentElement;
167
179
  }
168
- if (nodeToAppendOn.shadowRoot) nodeToAppendOn.shadowRoot.appendChild(childElement);
180
+ if (nodeToAppendOn.shadowRoot)
181
+ nodeToAppendOn.shadowRoot.appendChild(childElement);
169
182
  else if (nodeToAppendOn.tagName.toLocaleLowerCase() == "template") {
170
- const template: HTMLTemplateElement = nodeToAppendOn as HTMLTemplateElement;
183
+ const template: HTMLTemplateElement =
184
+ nodeToAppendOn as HTMLTemplateElement;
171
185
  template.content.appendChild(childElement);
172
186
  } else nodeToAppendOn.appendChild(childElement);
173
187
  }
@@ -184,11 +198,15 @@ export class SonicSDUI extends Fetcher(Subscriber(LitElement)) {
184
198
  let element: HTMLElement;
185
199
  let contentElement: HTMLElement | undefined;
186
200
  if (node.libraryKey && this.sduiDescriptor.library) {
187
- element = this.parseChild(this.sduiDescriptor.library[node.libraryKey] || {tagName: "div"});
188
- const selector = (this.sduiDescriptor.library[node.libraryKey] || {}).contentElementSelector;
189
- if (selector) contentElement = element.querySelector(selector) as HTMLElement;
201
+ element = this.parseChild(
202
+ this.sduiDescriptor.library[node.libraryKey] || { tagName: "div" }
203
+ );
204
+ const selector = (this.sduiDescriptor.library[node.libraryKey] || {})
205
+ .contentElementSelector;
206
+ if (selector)
207
+ contentElement = element.querySelector(selector) as HTMLElement;
190
208
  } else element = document.createElement(tagName) as HTMLElement;
191
- return {element, contentElement};
209
+ return { element, contentElement };
192
210
  }
193
211
  /**
194
212
  * Remplissage des attributs html avec les attributs fournis dans le noeud
@@ -197,7 +215,9 @@ export class SonicSDUI extends Fetcher(Subscriber(LitElement)) {
197
215
  const attributes = node.attributes;
198
216
  for (const k in attributes) {
199
217
  const attrData: object | string = attributes[k];
200
- const attr: string = Objects.isObject(attrData) ? JSON.stringify(attrData) : attrData;
218
+ const attr: string = Objects.isObject(attrData)
219
+ ? JSON.stringify(attrData)
220
+ : attrData;
201
221
  element.setAttribute(k, attr);
202
222
  }
203
223
  }
@@ -216,13 +236,18 @@ export class SonicSDUI extends Fetcher(Subscriber(LitElement)) {
216
236
  /**
217
237
  * si le noeud à une propriété innerHTML, on l'ajout ay innerHTML de l'élément html en cours de création
218
238
  */
219
- private handleInnerHTML(node: SDUINode, contentElement: HTMLElement | undefined) {
239
+ private handleInnerHTML(
240
+ node: SDUINode,
241
+ contentElement: HTMLElement | undefined
242
+ ) {
220
243
  if (!node.innerHTML) return;
221
244
  if (node.innerHTML.indexOf("wording_") != -1) {
222
245
  const wordingProvider = this.getAncestorAttributeValue("wordingProvider");
223
- this.api?.post(wordingProvider, {labels: [node.innerHTML.substring(8)]}).then((value) => {
224
- if (contentElement) contentElement.innerHTML += value;
225
- });
246
+ this.api
247
+ ?.post(wordingProvider, { labels: [node.innerHTML.substring(8)] })
248
+ .then((value) => {
249
+ if (contentElement) contentElement.innerHTML += value;
250
+ });
226
251
  } else if (contentElement) {
227
252
  contentElement.innerHTML += node.innerHTML;
228
253
  }
@@ -4,6 +4,7 @@ import {
4
4
  property,
5
5
  queryAssignedNodes,
6
6
  state,
7
+ query,
7
8
  } from "lit/decorators.js";
8
9
  import {
9
10
  FormInput,
@@ -23,6 +24,7 @@ import { Input } from "@supersoniks/concorde/core/components/ui/form/input/input
23
24
  import { customScroll } from "@supersoniks/concorde/core/components/ui/_css/scroll";
24
25
  import { ResizeController } from "@lit-labs/observers/resize-controller.js";
25
26
  import { traverseDotNotation } from "@supersoniks/concorde/core/utils/Objects";
27
+ import { Pop } from "../../pop/pop";
26
28
 
27
29
  type ListItem = Record<string, string>;
28
30
 
@@ -82,6 +84,7 @@ export class InputAutocomplete extends TemplatesContainer(
82
84
  slotInputPrefixNodes!: Array<Node>;
83
85
 
84
86
  @state() hasInputPrefix = false;
87
+ @query("sonic-pop") popElement!: Pop;
85
88
  _resizeController = new ResizeController(this, {});
86
89
 
87
90
  @state() isPopVisible = false;
@@ -324,9 +327,13 @@ export class InputAutocomplete extends TemplatesContainer(
324
327
  return this.searchPublisher?.get();
325
328
  }
326
329
 
330
+ handleFocus(): void {
331
+ this.popElement.show();
332
+ }
333
+
327
334
  render() {
328
335
  return html`
329
- <sonic-pop noToggle style="display:block;" @hide=${this.handleHide}>
336
+ <sonic-pop manual style="display:block;" @hide=${this.handleHide}>
330
337
  <sonic-input
331
338
  class="form-element"
332
339
  dataProvider="${this.initSearchDataProvider + Math.random()}"
@@ -344,6 +351,7 @@ export class InputAutocomplete extends TemplatesContainer(
344
351
  clearable
345
352
  inlineContent
346
353
  size=${this.size}
354
+ @focus=${this.handleFocus}
347
355
  value=${ifDefined(this.getInputValue())}
348
356
  >
349
357
  <slot
@@ -36,9 +36,8 @@ export class Tooltip extends LitElement {
36
36
  will-change: opacity, transform;
37
37
  }
38
38
 
39
- /* désactive au focus-within cause persistance du tooltip au clic */
40
- /* :host(:focus-within) .tooltip:before, */
41
39
  :host(:focus-visible) .tooltip:before,
40
+ :host(.keyboard-focus) .tooltip:before,
42
41
  .tooltip:hover:before {
43
42
  opacity: 1;
44
43
  scale: 1;
@@ -132,12 +131,78 @@ export class Tooltip extends LitElement {
132
131
  @property({ type: Boolean }) disabled = false;
133
132
  @property({ type: Boolean }) focusable = false;
134
133
 
134
+ private lastKeyWasTab = false;
135
+ private boundHandleKeyDown: (e: KeyboardEvent) => void;
136
+ private boundHandleMouseDown: () => void;
137
+
138
+ constructor() {
139
+ super();
140
+ this.boundHandleKeyDown = this.handleKeyDown.bind(this);
141
+ this.boundHandleMouseDown = this.handleMouseDown.bind(this);
142
+ }
143
+
144
+ private handleKeyDown = (e: KeyboardEvent) => {
145
+ // Détecter si Tab ou Shift+Tab a été pressé
146
+ if (e.key === "Tab") {
147
+ this.lastKeyWasTab = true;
148
+ }
149
+ };
150
+
151
+ private handleMouseDown = () => {
152
+ // Réinitialiser le flag si la souris est utilisée
153
+ this.lastKeyWasTab = false;
154
+ // Retirer la classe si elle existe (au cas où)
155
+ this.classList.remove("keyboard-focus");
156
+ };
157
+
158
+ private handleFocusIn = () => {
159
+ // Ajouter la classe seulement si le focus est venu du clavier (Tab)
160
+ if (this.lastKeyWasTab) {
161
+ this.classList.add("keyboard-focus");
162
+ }
163
+ this.lastKeyWasTab = false;
164
+ };
165
+
166
+ private handleFocusOut = () => {
167
+ this.classList.remove("keyboard-focus");
168
+ this.lastKeyWasTab = false;
169
+ };
170
+
171
+ connectedCallback() {
172
+ super.connectedCallback();
173
+ this.addEventListener("focusin", this.handleFocusIn);
174
+ this.addEventListener("focusout", this.handleFocusOut);
175
+ // Écouter les événements au niveau du document avec capture pour détecter Tab
176
+ document.addEventListener("keydown", this.boundHandleKeyDown, true);
177
+ document.addEventListener("mousedown", this.boundHandleMouseDown, true);
178
+ }
179
+
180
+ disconnectedCallback() {
181
+ super.disconnectedCallback();
182
+ this.removeEventListener("focusin", this.handleFocusIn);
183
+ this.removeEventListener("focusout", this.handleFocusOut);
184
+ document.removeEventListener("keydown", this.boundHandleKeyDown, true);
185
+ document.removeEventListener("mousedown", this.boundHandleMouseDown, true);
186
+ }
187
+
135
188
  protected willUpdate(_changedProperties: PropertyValues): void {
136
189
  if (_changedProperties.has("disabled")) {
137
190
  const wasDisabledBefore = _changedProperties.get("disabled") === true;
138
191
  if (this.disabled) {
139
192
  this.setAttribute("tabindex", "-1");
193
+ this.classList.remove("keyboard-focus");
140
194
  } else if (!this.disabled && wasDisabledBefore) {
195
+ if (this.focusable) {
196
+ this.setAttribute("tabindex", "0");
197
+ } else {
198
+ this.removeAttribute("tabindex");
199
+ }
200
+ }
201
+ }
202
+ if (_changedProperties.has("focusable")) {
203
+ if (this.focusable && !this.disabled) {
204
+ this.setAttribute("tabindex", "0");
205
+ } else if (!this.focusable && !this.disabled) {
141
206
  this.removeAttribute("tabindex");
142
207
  }
143
208
  }
@@ -1,187 +1,5 @@
1
- import {Objects} from "@supersoniks/concorde/utils";
2
- import {PublisherProxy, PublisherManager} from "../utils/PublisherProxy";
3
-
4
- type Callback = (...values: unknown[]) => void;
5
- type ConnectedComponent = Record<string, unknown> & {
6
- __onConnected__: (callback: (component: ConnectedComponent) => void) => void;
7
- __onDisconnected__: (callback: (component: ConnectedComponent) => void) => void;
8
- __connectedCallbackCalls__?: Set<(component: ConnectedComponent) => void>;
9
- __disconnectedCallbackCalls__?: Set<(component: ConnectedComponent) => void>;
10
- };
11
- type Configuration = {
12
- callbacks: Set<Callback>;
13
- publisher: PublisherProxy;
14
- onAssign: (value: unknown) => void;
15
- };
16
-
17
- function onConnected(this: ConnectedComponent, callback: (component: ConnectedComponent) => void) {
18
- if (!this.__connectedCallbackCalls__) this.__connectedCallbackCalls__ = new Set();
19
- this.__connectedCallbackCalls__.add(callback);
20
- }
21
- function __onDisconnected__(this: ConnectedComponent, callback: (component: ConnectedComponent) => void) {
22
- if (!this.__disconnectedCallbackCalls__) this.__disconnectedCallbackCalls__ = new Set();
23
- this.__disconnectedCallbackCalls__.add(callback);
24
- }
25
-
26
- function setSubscribable(target: any) {
27
- if (target.__is__setSubscribable__) return;
28
- target.__is__setSubscribable__ = true;
29
-
30
- target.__onConnected__ = onConnected;
31
- target.__onDisconnected__ = __onDisconnected__;
32
- // target.offConnected = onConnected;
33
- // target.offDisconnected = __onDisconnected__;
34
-
35
- const originalConnectedCallback = target.connectedCallback;
36
- target.connectedCallback = function (this: any) {
37
- originalConnectedCallback.call(this);
38
- if (this.__connectedCallbackCalls__) {
39
- this.__connectedCallbackCalls__.forEach((callback: (component: any) => void) => callback(this));
40
- }
41
- };
42
- const originalDisconnectedCallback = target.disconnectedCallback;
43
- target.disconnectedCallback = function (this: any) {
44
- originalDisconnectedCallback.call(this);
45
- if (this.__disconnectedCallbackCalls__) {
46
- this.__disconnectedCallbackCalls__.forEach((callback: (component: any) => void) => callback(this));
47
- }
48
- };
49
- }
50
-
51
- export function bind(path: string) {
52
- const split = path.split(".");
53
- if (split.length == 0) {
54
- return function () {
55
- //Empty def function
56
- };
57
- }
58
- const dataProvider: string = split.shift() || "";
59
- let publisher = PublisherManager.get(dataProvider);
60
- publisher = Objects.traverse(publisher, split);
61
- return function (target: unknown, propertyKey: string) {
62
- if (!target) return;
63
- let onAssign: (value: unknown) => void;
64
- setSubscribable(target);
65
-
66
- (target as ConnectedComponent).__onConnected__((component) => {
67
- onAssign = (value: unknown) => {
68
- component[propertyKey] = value;
69
- };
70
- publisher.onAssign(onAssign);
71
- });
72
-
73
- (target as ConnectedComponent).__onDisconnected__(() => {
74
- publisher.offAssign(onAssign);
75
- });
76
- };
77
- }
78
-
79
- export function onAssign(...values: Array<string>) {
80
- const onAssignValues: unknown[] = [];
81
- const confs: Configuration[] = [];
82
- for (let i = 0; i < values.length; i++) {
83
- const value = values[i];
84
- const split = value.split(".");
85
- if (split.length == 0) {
86
- continue;
87
- }
88
- const dataProvider: string = split.shift() || "";
89
-
90
- let publisher = PublisherManager.get(dataProvider);
91
-
92
- publisher = Objects.traverse(publisher, split);
93
- const callbacks: Set<Callback> = new Set();
94
- const onAssign = (value: unknown) => {
95
- onAssignValues[i] = value;
96
- if (onAssignValues.filter((v) => v !== null).length == values.length) callbacks.forEach((callback) => callback(...onAssignValues));
97
- };
98
- confs.push({publisher, onAssign, callbacks});
99
- }
100
- return function (target: unknown, _propertyKey: string, descriptor: PropertyDescriptor) {
101
- setSubscribable(target);
102
- let callback: Callback;
103
-
104
- (target as ConnectedComponent).__onConnected__((component) => {
105
- for (const conf of confs) {
106
- callback = descriptor.value.bind(component);
107
- conf.callbacks.add(callback);
108
- conf.publisher.onAssign(conf.onAssign);
109
- }
110
- });
111
-
112
- (target as ConnectedComponent).__onDisconnected__(() => {
113
- for (const conf of confs) {
114
- conf.callbacks.delete(callback);
115
- conf.publisher.offAssign(conf.onAssign);
116
- }
117
- });
118
- };
119
- }
120
-
121
- export function autoSubscribe() {
122
- return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
123
- let renderId = 0;
124
-
125
- const originalMethod = descriptor.value;
126
- const originalDC = target.constructor.prototype.disconnectedCallback;
127
- target.constructor.prototype.disconnectedCallback = function () {
128
- originalDC.apply(this);
129
- this.__removeAutoSubscribe__();
130
- };
131
- const originalConnectedCallback = target.connectedCallback;
132
- target.connectedCallback = function (this: any) {
133
- originalConnectedCallback?.call(this);
134
- this[propertyKey]();
135
- };
136
- descriptor.value = function (...args: unknown[]) {
137
- let publishers: Set<PublisherProxy> = new Set();
138
- const onAssign = () => {
139
- renderId++;
140
- const id = renderId;
141
- window.queueMicrotask(() => {
142
- if (id !== renderId) return;
143
- (this as any)[propertyKey]();
144
- });
145
- };
146
- //on désabone les publishers du rendu précédant
147
- publishers.forEach((publisher: PublisherProxy) => {
148
- publisher.offAssign(onAssign);
149
- });
150
- //on collecte les publisher modifiés pour s'abonner pour la prochaine modification
151
- PublisherManager.collectModifiedPublisher();
152
- const result = originalMethod.apply(this, args);
153
- publishers = PublisherManager.getModifiedPublishers() || new Set<PublisherProxy>();
154
- publishers.forEach((publisher: PublisherProxy) => {
155
- publisher.onAssign(onAssign, false);
156
- });
157
- (this as typeof target.constructor.prototype.disconnectedCallback).__removeAutoSubscribe__ = () => {
158
- publishers.forEach((publisher: PublisherProxy) => {
159
- publisher.offAssign(onAssign);
160
- });
161
- };
162
- return result;
163
- };
164
- };
165
- }
166
- export function autoFill(values: string[]) {
167
- return function (target: unknown) {
168
- setSubscribable(target);
169
- for (const value of values) {
170
- const split = value.split(".");
171
- if (split.length == 0) {
172
- continue;
173
- }
174
- const dataProvider: string = split.shift() || "";
175
- let publisher = PublisherManager.get(dataProvider);
176
- publisher = Objects.traverse(publisher, split);
177
- (target as ConnectedComponent).__onConnected__((component: unknown) => {
178
- publisher.startTemplateFilling(component);
179
- });
180
- (target as ConnectedComponent).__onDisconnected__(() => {
181
- (component: unknown) => {
182
- publisher.stopTemplateFilling(component);
183
- };
184
- });
185
- }
186
- };
187
- }
1
+ export { bind } from "./subscriber/bind";
2
+ export { onAssign } from "./subscriber/onAssign";
3
+ export { autoSubscribe } from "./subscriber/autoSubscribe";
4
+ export { autoFill } from "./subscriber/autoFill";
5
+ export { ancestorAttribute } from "./subscriber/ancestorAttribute";
@@ -0,0 +1,17 @@
1
+ import HTML from "../../utils/HTML";
2
+ import { ConnectedComponent, setSubscribable } from "./common";
3
+
4
+ export function ancestorAttribute(attributeName: string) {
5
+ return function (target: unknown, propertyKey: string) {
6
+ if (!target) return;
7
+ setSubscribable(target);
8
+
9
+ (target as ConnectedComponent).__onConnected__((component) => {
10
+ const value = HTML.getAncestorAttributeValue(
11
+ component as any,
12
+ attributeName
13
+ );
14
+ component[propertyKey] = value;
15
+ });
16
+ };
17
+ }
@@ -0,0 +1,28 @@
1
+ import { Objects } from "@supersoniks/concorde/utils";
2
+
3
+ import { PublisherManager } from "../../utils/PublisherProxy";
4
+ import { ConnectedComponent, setSubscribable } from "./common";
5
+
6
+ export function autoFill(values: string[]) {
7
+ return function (target: unknown) {
8
+ setSubscribable(target);
9
+ for (const value of values) {
10
+ const split = value.split(".");
11
+ if (split.length === 0) {
12
+ continue;
13
+ }
14
+ const dataProvider: string = split.shift() || "";
15
+ let publisher = PublisherManager.get(dataProvider);
16
+ publisher = Objects.traverse(publisher, split);
17
+ (target as ConnectedComponent).__onConnected__((component: unknown) => {
18
+ publisher.startTemplateFilling(component);
19
+ });
20
+ (target as ConnectedComponent).__onDisconnected__(() => {
21
+ (component: unknown) => {
22
+ publisher.stopTemplateFilling(component);
23
+ };
24
+ });
25
+ }
26
+ };
27
+ }
28
+
@@ -0,0 +1,54 @@
1
+ import { PublisherProxy, PublisherManager } from "../../utils/PublisherProxy";
2
+
3
+ export function autoSubscribe() {
4
+ return function (
5
+ target: any,
6
+ propertyKey: string,
7
+ descriptor: PropertyDescriptor
8
+ ) {
9
+ let renderId = 0;
10
+
11
+ const originalMethod = descriptor.value;
12
+ const originalDisconnectedCallback =
13
+ target.constructor.prototype.disconnectedCallback;
14
+ target.constructor.prototype.disconnectedCallback = function () {
15
+ originalDisconnectedCallback?.apply(this);
16
+ this.__removeAutoSubscribe__();
17
+ };
18
+ const originalConnectedCallback = target.connectedCallback;
19
+ target.connectedCallback = function (this: any) {
20
+ originalConnectedCallback?.call(this);
21
+ this[propertyKey]();
22
+ };
23
+ descriptor.value = function (...args: unknown[]) {
24
+ let publishers: Set<PublisherProxy> = new Set();
25
+ const onAssign = () => {
26
+ renderId++;
27
+ const id = renderId;
28
+ window.queueMicrotask(() => {
29
+ if (id !== renderId) return;
30
+ (this as any)[propertyKey]();
31
+ });
32
+ };
33
+ publishers.forEach((publisher: PublisherProxy) => {
34
+ publisher.offAssign(onAssign);
35
+ });
36
+ PublisherManager.collectModifiedPublisher();
37
+ const result = originalMethod.apply(this, args);
38
+ publishers =
39
+ PublisherManager.getModifiedPublishers() || new Set<PublisherProxy>();
40
+
41
+ publishers.forEach((publisher: PublisherProxy) => {
42
+ publisher.onAssign(onAssign, false);
43
+ });
44
+ (
45
+ this as typeof target.constructor.prototype.disconnectedCallback
46
+ ).__removeAutoSubscribe__ = () => {
47
+ publishers.forEach((publisher: PublisherProxy) => {
48
+ publisher.offAssign(onAssign);
49
+ });
50
+ };
51
+ return result;
52
+ };
53
+ };
54
+ }