@blackbirdjs/component 0.1.0 → 0.1.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 (2) hide show
  1. package/package.json +2 -2
  2. package/src/component.js +23 -6
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blackbirdjs/component",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Template-first fine-grained Web Component layer for BlackbirdJS",
5
5
  "type": "module",
6
6
  "main": "./src/index.js",
@@ -8,7 +8,7 @@
8
8
  ".": "./src/index.js"
9
9
  },
10
10
  "dependencies": {
11
- "@blackbirdjs/store": "^0.1.0"
11
+ "@blackbirdjs/store": "^0.2.0"
12
12
  },
13
13
  "license": "Apache-2.0",
14
14
  "publishConfig": {
package/src/component.js CHANGED
@@ -7,6 +7,9 @@ export function setGlobalStore(store) {
7
7
  }
8
8
 
9
9
  export class BlackbirdComponent extends HTMLElement {
10
+ // Add an internal register array to capture cleanup tokens safely
11
+ #unsubscribers = [];
12
+
10
13
  constructor() {
11
14
  super();
12
15
  this.attachShadow({ mode: 'open' });
@@ -32,17 +35,25 @@ export class BlackbirdComponent extends HTMLElement {
32
35
  return;
33
36
  }
34
37
 
35
- const clone = template.contentEditable.cloneNode(true);
38
+ // Changed contentEditable to template.content
39
+ const clone = template.content.cloneNode(true);
36
40
  this.shadowRoot.appendChild(clone);
37
41
 
38
42
  this._hydrateInitialAttributes();
39
43
  this._compileDOM();
40
44
  }
41
45
 
46
+ // Automatically clean up memory when the component leaves the screen
47
+ disconnectedCallback() {
48
+ this.#unsubscribers.forEach(unsubscribe => unsubscribe());
49
+ this.#unsubscribers = [];
50
+ }
51
+
42
52
  _hydrateInitialAttributes() {
43
53
  Array.from(this.attributes).forEach(attr => {
44
54
  if (attr.name.startsWith('data-')) {
45
- const cleanKey = attr.name.replace(/^data-/, '').replace(/-(a-z)/g, g => g.toLocaleUpperCase());
55
+ // FIX 3: Fixed broken regex format from /-(a-z)/g to /-([a-z])/g
56
+ const cleanKey = attr.name.replace(/^data-/, '').replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());
46
57
  this.localStore.set(cleanKey, attr.value);
47
58
  }
48
59
  });
@@ -50,23 +61,29 @@ export class BlackbirdComponent extends HTMLElement {
50
61
 
51
62
  _compileDOM() {
52
63
  // Map Text Bindings
53
- const boundElements = this.shadowRoot.querySelector('[data-bind]');
64
+ // Changed querySelector to querySelectorAll so .forEach runs successfully
65
+ const boundElements = this.shadowRoot.querySelectorAll('[data-bind]');
66
+
54
67
  boundElements.forEach(element => {
55
68
  const bindingExpression = element.getAttribute('data-bind').trim();
56
69
 
57
70
  if (bindingExpression.startsWith('global.')) {
58
71
  const key = bindingExpression.replace('global.', '');
59
72
  if (globalStoreInstance) {
60
- globalStoreInstance.subscribe(key, (val) => {
73
+ // Push the returned unsubscribe token to the cleanup tracking list
74
+ const sub = globalStoreInstance.subscribe(key, (val) => {
61
75
  element.textContent = val;
62
76
  });
77
+ this.#unsubscribers.push(sub.unsubscribe);
63
78
  } else {
64
- console.warn(`[Blackbird] Global Variable "${key}" requested but no global store.configured.`);
79
+ console.warn(`[Blackbird] Global Variable "${key}" requested but no global store configured.`);
65
80
  }
66
81
  } else {
67
- this.localStore.subscribe(bindingExpression, (val) => {
82
+ // Capture local store unsubscriptions as well
83
+ const sub = this.localStore.subscribe(bindingExpression, (val) => {
68
84
  element.textContent = val;
69
85
  });
86
+ this.#unsubscribers.push(sub.unsubscribe);
70
87
  }
71
88
  });
72
89