@stencil/store 2.2.1 → 2.2.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.
package/dist/index.cjs CHANGED
@@ -1,14 +1,34 @@
1
1
  'use strict';
2
2
 
3
- var core = require('@stencil/core');
3
+ var StencilCore = require('@stencil/core');
4
+
5
+ function _interopNamespaceDefault(e) {
6
+ var n = Object.create(null);
7
+ if (e) {
8
+ Object.keys(e).forEach(function (k) {
9
+ if (k !== 'default') {
10
+ var d = Object.getOwnPropertyDescriptor(e, k);
11
+ Object.defineProperty(n, k, d.get ? d : {
12
+ enumerable: true,
13
+ get: function () { return e[k]; }
14
+ });
15
+ }
16
+ });
17
+ }
18
+ n.default = e;
19
+ return Object.freeze(n);
20
+ }
21
+
22
+ var StencilCore__namespace = /*#__PURE__*/_interopNamespaceDefault(StencilCore);
4
23
 
5
24
  const appendToMap = (map, propName, value) => {
6
- const items = map.get(propName);
7
- if (!items) {
8
- map.set(propName, [value]);
25
+ let refs = map.get(propName);
26
+ if (!refs) {
27
+ refs = [];
28
+ map.set(propName, refs);
9
29
  }
10
- else if (!items.includes(value)) {
11
- items.push(value);
30
+ if (!refs.some((ref) => ref.deref() === value)) {
31
+ refs.push(new WeakRef(value));
12
32
  }
13
33
  };
14
34
  const debounce = (fn, ms) => {
@@ -36,33 +56,54 @@ const debounce = (fn, ms) => {
36
56
  const isConnected = (maybeElement) => !('isConnected' in maybeElement) || maybeElement.isConnected;
37
57
  const cleanupElements = debounce((map) => {
38
58
  for (let key of map.keys()) {
39
- map.set(key, map.get(key).filter(isConnected));
59
+ const refs = map.get(key).filter((ref) => {
60
+ const elm = ref.deref();
61
+ return elm && isConnected(elm);
62
+ });
63
+ map.set(key, refs);
40
64
  }
41
65
  }, 2_000);
66
+ const core = StencilCore__namespace;
67
+ const forceUpdate = core.forceUpdate;
68
+ const getRenderingRef = core.getRenderingRef;
42
69
  const stencilSubscription = () => {
43
- if (typeof core.getRenderingRef !== 'function') {
70
+ if (typeof getRenderingRef !== 'function' || typeof forceUpdate !== 'function') {
44
71
  // If we are not in a stencil project, we do nothing.
45
72
  // This function is not really exported by @stencil/core.
46
73
  return {};
47
74
  }
75
+ const ensureForceUpdate = forceUpdate;
76
+ const ensureGetRenderingRef = getRenderingRef;
48
77
  const elmsToUpdate = new Map();
49
78
  return {
50
79
  dispose: () => elmsToUpdate.clear(),
51
80
  get: (propName) => {
52
- const elm = core.getRenderingRef();
81
+ const elm = ensureGetRenderingRef();
53
82
  if (elm) {
54
83
  appendToMap(elmsToUpdate, propName, elm);
55
84
  }
56
85
  },
57
86
  set: (propName) => {
58
- const elements = elmsToUpdate.get(propName);
59
- if (elements) {
60
- elmsToUpdate.set(propName, elements.filter(core.forceUpdate));
87
+ const refs = elmsToUpdate.get(propName);
88
+ if (refs) {
89
+ const nextRefs = refs.filter((ref) => {
90
+ const elm = ref.deref();
91
+ if (!elm)
92
+ return false;
93
+ return ensureForceUpdate(elm);
94
+ });
95
+ elmsToUpdate.set(propName, nextRefs);
61
96
  }
62
97
  cleanupElements(elmsToUpdate);
63
98
  },
64
99
  reset: () => {
65
- elmsToUpdate.forEach((elms) => elms.forEach(core.forceUpdate));
100
+ elmsToUpdate.forEach((refs) => {
101
+ refs.forEach((ref) => {
102
+ const elm = ref.deref();
103
+ if (elm)
104
+ ensureForceUpdate(elm);
105
+ });
106
+ });
66
107
  cleanupElements(elmsToUpdate);
67
108
  },
68
109
  };
@@ -70,8 +111,11 @@ const stencilSubscription = () => {
70
111
 
71
112
  const unwrap = (val) => (typeof val === 'function' ? val() : val);
72
113
  const createObservableMap = (defaultState, shouldUpdate = (a, b) => a !== b) => {
73
- const unwrappedState = unwrap(defaultState);
74
- let states = new Map(Object.entries(unwrappedState ?? {}));
114
+ const resolveDefaultState = () => (unwrap(defaultState) ?? {});
115
+ const initialState = resolveDefaultState();
116
+ let states = new Map(Object.entries(initialState));
117
+ const proxyAvailable = typeof Proxy !== 'undefined';
118
+ const plainState = proxyAvailable ? null : {};
75
119
  const handlers = {
76
120
  dispose: [],
77
121
  get: [],
@@ -83,7 +127,10 @@ const createObservableMap = (defaultState, shouldUpdate = (a, b) => a !== b) =>
83
127
  const reset = () => {
84
128
  // When resetting the state, the default state may be a function - unwrap it to invoke it.
85
129
  // otherwise, the state won't be properly reset
86
- states = new Map(Object.entries(unwrap(defaultState) ?? {}));
130
+ states = new Map(Object.entries(resolveDefaultState()));
131
+ if (!proxyAvailable) {
132
+ syncPlainStateKeys();
133
+ }
87
134
  handlers.reset.forEach((cb) => cb());
88
135
  };
89
136
  const dispose = () => {
@@ -100,12 +147,14 @@ const createObservableMap = (defaultState, shouldUpdate = (a, b) => a !== b) =>
100
147
  const oldValue = states.get(propName);
101
148
  if (shouldUpdate(value, oldValue, propName)) {
102
149
  states.set(propName, value);
150
+ if (!proxyAvailable) {
151
+ ensurePlainProperty(propName);
152
+ }
103
153
  handlers.set.forEach((cb) => cb(propName, value, oldValue));
104
154
  }
105
155
  };
106
- const state = (typeof Proxy === 'undefined'
107
- ? {}
108
- : new Proxy(unwrappedState, {
156
+ const state = (proxyAvailable
157
+ ? new Proxy(initialState, {
109
158
  get(_, propName) {
110
159
  return get(propName);
111
160
  },
@@ -125,7 +174,11 @@ const createObservableMap = (defaultState, shouldUpdate = (a, b) => a !== b) =>
125
174
  set(propName, value);
126
175
  return true;
127
176
  },
128
- }));
177
+ })
178
+ : (() => {
179
+ syncPlainStateKeys();
180
+ return plainState;
181
+ })());
129
182
  const on = (eventName, callback) => {
130
183
  handlers[eventName].push(callback);
131
184
  return () => {
@@ -138,7 +191,10 @@ const createObservableMap = (defaultState, shouldUpdate = (a, b) => a !== b) =>
138
191
  cb(newValue);
139
192
  }
140
193
  };
141
- const resetHandler = () => cb(unwrap(defaultState)[propName]);
194
+ const resetHandler = () => {
195
+ const snapshot = resolveDefaultState();
196
+ cb(snapshot[propName]);
197
+ };
142
198
  // Register the handlers
143
199
  const unSet = on('set', setHandler);
144
200
  const unReset = on('reset', resetHandler);
@@ -181,6 +237,38 @@ const createObservableMap = (defaultState, shouldUpdate = (a, b) => a !== b) =>
181
237
  changeListeners.delete(listener);
182
238
  }
183
239
  };
240
+ function ensurePlainProperty(key) {
241
+ if (proxyAvailable || !plainState) {
242
+ return;
243
+ }
244
+ if (Object.prototype.hasOwnProperty.call(plainState, key)) {
245
+ return;
246
+ }
247
+ Object.defineProperty(plainState, key, {
248
+ configurable: true,
249
+ enumerable: true,
250
+ get() {
251
+ return get(key);
252
+ },
253
+ set(value) {
254
+ set(key, value);
255
+ },
256
+ });
257
+ }
258
+ function syncPlainStateKeys() {
259
+ if (proxyAvailable || !plainState) {
260
+ return;
261
+ }
262
+ const knownKeys = new Set(states.keys());
263
+ for (const key of Object.keys(plainState)) {
264
+ if (!knownKeys.has(key)) {
265
+ delete plainState[key];
266
+ }
267
+ }
268
+ for (const key of knownKeys) {
269
+ ensurePlainProperty(key);
270
+ }
271
+ }
184
272
  return {
185
273
  state,
186
274
  get,
package/dist/index.js CHANGED
@@ -1,12 +1,13 @@
1
- import { getRenderingRef, forceUpdate } from '@stencil/core';
1
+ import * as StencilCore from '@stencil/core';
2
2
 
3
3
  const appendToMap = (map, propName, value) => {
4
- const items = map.get(propName);
5
- if (!items) {
6
- map.set(propName, [value]);
4
+ let refs = map.get(propName);
5
+ if (!refs) {
6
+ refs = [];
7
+ map.set(propName, refs);
7
8
  }
8
- else if (!items.includes(value)) {
9
- items.push(value);
9
+ if (!refs.some((ref) => ref.deref() === value)) {
10
+ refs.push(new WeakRef(value));
10
11
  }
11
12
  };
12
13
  const debounce = (fn, ms) => {
@@ -34,33 +35,54 @@ const debounce = (fn, ms) => {
34
35
  const isConnected = (maybeElement) => !('isConnected' in maybeElement) || maybeElement.isConnected;
35
36
  const cleanupElements = debounce((map) => {
36
37
  for (let key of map.keys()) {
37
- map.set(key, map.get(key).filter(isConnected));
38
+ const refs = map.get(key).filter((ref) => {
39
+ const elm = ref.deref();
40
+ return elm && isConnected(elm);
41
+ });
42
+ map.set(key, refs);
38
43
  }
39
44
  }, 2_000);
45
+ const core = StencilCore;
46
+ const forceUpdate = core.forceUpdate;
47
+ const getRenderingRef = core.getRenderingRef;
40
48
  const stencilSubscription = () => {
41
- if (typeof getRenderingRef !== 'function') {
49
+ if (typeof getRenderingRef !== 'function' || typeof forceUpdate !== 'function') {
42
50
  // If we are not in a stencil project, we do nothing.
43
51
  // This function is not really exported by @stencil/core.
44
52
  return {};
45
53
  }
54
+ const ensureForceUpdate = forceUpdate;
55
+ const ensureGetRenderingRef = getRenderingRef;
46
56
  const elmsToUpdate = new Map();
47
57
  return {
48
58
  dispose: () => elmsToUpdate.clear(),
49
59
  get: (propName) => {
50
- const elm = getRenderingRef();
60
+ const elm = ensureGetRenderingRef();
51
61
  if (elm) {
52
62
  appendToMap(elmsToUpdate, propName, elm);
53
63
  }
54
64
  },
55
65
  set: (propName) => {
56
- const elements = elmsToUpdate.get(propName);
57
- if (elements) {
58
- elmsToUpdate.set(propName, elements.filter(forceUpdate));
66
+ const refs = elmsToUpdate.get(propName);
67
+ if (refs) {
68
+ const nextRefs = refs.filter((ref) => {
69
+ const elm = ref.deref();
70
+ if (!elm)
71
+ return false;
72
+ return ensureForceUpdate(elm);
73
+ });
74
+ elmsToUpdate.set(propName, nextRefs);
59
75
  }
60
76
  cleanupElements(elmsToUpdate);
61
77
  },
62
78
  reset: () => {
63
- elmsToUpdate.forEach((elms) => elms.forEach(forceUpdate));
79
+ elmsToUpdate.forEach((refs) => {
80
+ refs.forEach((ref) => {
81
+ const elm = ref.deref();
82
+ if (elm)
83
+ ensureForceUpdate(elm);
84
+ });
85
+ });
64
86
  cleanupElements(elmsToUpdate);
65
87
  },
66
88
  };
@@ -68,8 +90,11 @@ const stencilSubscription = () => {
68
90
 
69
91
  const unwrap = (val) => (typeof val === 'function' ? val() : val);
70
92
  const createObservableMap = (defaultState, shouldUpdate = (a, b) => a !== b) => {
71
- const unwrappedState = unwrap(defaultState);
72
- let states = new Map(Object.entries(unwrappedState ?? {}));
93
+ const resolveDefaultState = () => (unwrap(defaultState) ?? {});
94
+ const initialState = resolveDefaultState();
95
+ let states = new Map(Object.entries(initialState));
96
+ const proxyAvailable = typeof Proxy !== 'undefined';
97
+ const plainState = proxyAvailable ? null : {};
73
98
  const handlers = {
74
99
  dispose: [],
75
100
  get: [],
@@ -81,7 +106,10 @@ const createObservableMap = (defaultState, shouldUpdate = (a, b) => a !== b) =>
81
106
  const reset = () => {
82
107
  // When resetting the state, the default state may be a function - unwrap it to invoke it.
83
108
  // otherwise, the state won't be properly reset
84
- states = new Map(Object.entries(unwrap(defaultState) ?? {}));
109
+ states = new Map(Object.entries(resolveDefaultState()));
110
+ if (!proxyAvailable) {
111
+ syncPlainStateKeys();
112
+ }
85
113
  handlers.reset.forEach((cb) => cb());
86
114
  };
87
115
  const dispose = () => {
@@ -98,12 +126,14 @@ const createObservableMap = (defaultState, shouldUpdate = (a, b) => a !== b) =>
98
126
  const oldValue = states.get(propName);
99
127
  if (shouldUpdate(value, oldValue, propName)) {
100
128
  states.set(propName, value);
129
+ if (!proxyAvailable) {
130
+ ensurePlainProperty(propName);
131
+ }
101
132
  handlers.set.forEach((cb) => cb(propName, value, oldValue));
102
133
  }
103
134
  };
104
- const state = (typeof Proxy === 'undefined'
105
- ? {}
106
- : new Proxy(unwrappedState, {
135
+ const state = (proxyAvailable
136
+ ? new Proxy(initialState, {
107
137
  get(_, propName) {
108
138
  return get(propName);
109
139
  },
@@ -123,7 +153,11 @@ const createObservableMap = (defaultState, shouldUpdate = (a, b) => a !== b) =>
123
153
  set(propName, value);
124
154
  return true;
125
155
  },
126
- }));
156
+ })
157
+ : (() => {
158
+ syncPlainStateKeys();
159
+ return plainState;
160
+ })());
127
161
  const on = (eventName, callback) => {
128
162
  handlers[eventName].push(callback);
129
163
  return () => {
@@ -136,7 +170,10 @@ const createObservableMap = (defaultState, shouldUpdate = (a, b) => a !== b) =>
136
170
  cb(newValue);
137
171
  }
138
172
  };
139
- const resetHandler = () => cb(unwrap(defaultState)[propName]);
173
+ const resetHandler = () => {
174
+ const snapshot = resolveDefaultState();
175
+ cb(snapshot[propName]);
176
+ };
140
177
  // Register the handlers
141
178
  const unSet = on('set', setHandler);
142
179
  const unReset = on('reset', resetHandler);
@@ -179,6 +216,38 @@ const createObservableMap = (defaultState, shouldUpdate = (a, b) => a !== b) =>
179
216
  changeListeners.delete(listener);
180
217
  }
181
218
  };
219
+ function ensurePlainProperty(key) {
220
+ if (proxyAvailable || !plainState) {
221
+ return;
222
+ }
223
+ if (Object.prototype.hasOwnProperty.call(plainState, key)) {
224
+ return;
225
+ }
226
+ Object.defineProperty(plainState, key, {
227
+ configurable: true,
228
+ enumerable: true,
229
+ get() {
230
+ return get(key);
231
+ },
232
+ set(value) {
233
+ set(key, value);
234
+ },
235
+ });
236
+ }
237
+ function syncPlainStateKeys() {
238
+ if (proxyAvailable || !plainState) {
239
+ return;
240
+ }
241
+ const knownKeys = new Set(states.keys());
242
+ for (const key of Object.keys(plainState)) {
243
+ if (!knownKeys.has(key)) {
244
+ delete plainState[key];
245
+ }
246
+ }
247
+ for (const key of knownKeys) {
248
+ ensurePlainProperty(key);
249
+ }
250
+ }
182
251
  return {
183
252
  state,
184
253
  get,
package/dist/utils.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export declare const appendToMap: <K, V>(map: Map<K, V[]>, propName: K, value: V) => void;
1
+ export declare const appendToMap: <K, V extends Object>(map: Map<K, WeakRef<V>[]>, propName: K, value: V) => void;
2
2
  export declare const debounce: <T extends (...args: any[]) => any>(fn: T, ms: number) => ((...args: Parameters<T>) => void);
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@stencil/store",
3
3
  "author": "StencilJS Team",
4
- "version": "2.2.1",
4
+ "version": "2.2.2",
5
5
  "description": "Store is a lightweight shared state library by the StencilJS core team. Implements a simple key/value map that efficiently re-renders components when necessary.",
6
6
  "license": "MIT",
7
7
  "homepage": "https://stenciljs.com/docs/stencil-store",
@@ -33,11 +33,11 @@
33
33
  "npm": ">=6.0.0"
34
34
  },
35
35
  "scripts": {
36
- "build": "run-s build.*",
37
- "build.clean": "rm -rf dist",
36
+ "build": "run-s build.clean build.rollup",
37
+ "build.clean": "rimraf dist",
38
38
  "build.rollup": "rollup -c rollup.config.js",
39
39
  "prettier": "npm run prettier.base -- --write",
40
- "prettier.base": "prettier --cache 'src/**/*.ts'",
40
+ "prettier.base": "prettier --cache \"src/**/*.ts\"",
41
41
  "prettier.dry-run": "npm run prettier.base -- --list-different",
42
42
  "release": "np",
43
43
  "test": "run-s test.*",
@@ -53,16 +53,17 @@
53
53
  },
54
54
  "devDependencies": {
55
55
  "@ionic/prettier-config": "^4.0.0",
56
- "@rollup/plugin-typescript": "^12.1.2",
57
- "@stencil/core": "^4.27.1",
58
- "@types/node": "^24.0.3",
59
- "@vitest/coverage-v8": "^3.0.7",
56
+ "@rollup/plugin-typescript": "^12.3.0",
57
+ "@stencil/core": "^4.38.2",
58
+ "@types/node": "^24.9.2",
59
+ "@vitest/coverage-v8": "^4.0.5",
60
60
  "np": "^10.2.0",
61
- "npm-run-all2": "^8.0.1",
62
- "prettier": "^3.5.2",
63
- "rollup": "^4.34.8",
64
- "typescript": "~5.9.2",
65
- "vitest": "^3.0.7"
61
+ "npm-run-all2": "^8.0.4",
62
+ "prettier": "^3.6.2",
63
+ "rimraf": "^6.0.1",
64
+ "rollup": "^4.52.5",
65
+ "typescript": "~5.9.3",
66
+ "vitest": "^4.0.5"
66
67
  },
67
68
  "prettier": "@ionic/prettier-config"
68
69
  }