Skip to content

Commit 764e3cb

Browse files
committed
Add Yalc'd react-concurrent-store with TS fixes
1 parent fadb4c7 commit 764e3cb

File tree

11 files changed

+956
-5
lines changed

11 files changed

+956
-5
lines changed
Lines changed: 315 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,315 @@
1+
"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } }var __defProp = Object.defineProperty;
2+
var __export = (target, all) => {
3+
for (var name in all)
4+
__defProp(target, name, { get: all[name], enumerable: true });
5+
};
6+
7+
// src/experimental/index.ts
8+
var experimental_exports = {};
9+
__export(experimental_exports, {
10+
Store: () => Store,
11+
StoreProvider: () => StoreProvider,
12+
createStore: () => createStore,
13+
createStoreFromSource: () => createStoreFromSource,
14+
useStore: () => useStore,
15+
useStoreSelector: () => useStoreSelector
16+
});
17+
18+
// src/experimental/useStore.tsx
19+
20+
21+
22+
23+
24+
25+
26+
27+
28+
var _react = require('react'); var React = _interopRequireWildcard(_react);
29+
30+
// src/experimental/Store.ts
31+
32+
33+
34+
// src/experimental/Emitter.ts
35+
var Emitter = class {
36+
constructor() {
37+
this._listeners = [];
38+
}
39+
subscribe(cb) {
40+
const wrapped = (...value) => cb(...value);
41+
this._listeners.push(wrapped);
42+
return () => {
43+
this._listeners = this._listeners.filter((s) => s !== wrapped);
44+
};
45+
}
46+
notify(...value) {
47+
this._listeners.forEach((cb) => {
48+
cb(...value);
49+
});
50+
}
51+
};
52+
53+
// src/experimental/Store.ts
54+
var sharedReactInternals = React.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE;
55+
function reactTransitionIsActive() {
56+
return !!sharedReactInternals.T;
57+
}
58+
var Store = class extends Emitter {
59+
constructor(source) {
60+
super();
61+
this.source = source;
62+
this.state = source.getState();
63+
this.committedState = source.getState();
64+
}
65+
commit(state) {
66+
this.committedState = state;
67+
}
68+
getCommittedState() {
69+
return this.committedState;
70+
}
71+
getState() {
72+
return this.state;
73+
}
74+
handleUpdate(action) {
75+
const noPendingTransitions = this.committedState === this.state;
76+
this.state = this.source.getState();
77+
if (reactTransitionIsActive()) {
78+
this.notify();
79+
} else {
80+
if (noPendingTransitions) {
81+
this.committedState = this.state;
82+
this.notify();
83+
} else {
84+
const newState = this.state;
85+
this.committedState = this.source.reducer(this.committedState, action);
86+
this.state = this.committedState;
87+
this.notify();
88+
this.state = newState;
89+
_react.startTransition.call(void 0, () => {
90+
this.notify();
91+
});
92+
}
93+
}
94+
}
95+
};
96+
97+
// src/experimental/StoreManager.ts
98+
var StoreManager = class extends Emitter {
99+
constructor() {
100+
super(...arguments);
101+
this._storeRefCounts = /* @__PURE__ */ new Map();
102+
}
103+
getAllCommittedStates() {
104+
return new Map(
105+
Array.from(this._storeRefCounts.keys()).map((store) => [
106+
store,
107+
store.getCommittedState()
108+
])
109+
);
110+
}
111+
getAllStates() {
112+
return new Map(
113+
Array.from(this._storeRefCounts.keys()).map((store) => [
114+
store,
115+
store.getState()
116+
])
117+
);
118+
}
119+
addStore(store) {
120+
const prev = this._storeRefCounts.get(store);
121+
if (prev == null) {
122+
this._storeRefCounts.set(store, {
123+
unsubscribe: store.subscribe(() => {
124+
this.notify();
125+
}),
126+
count: 1
127+
});
128+
} else {
129+
this._storeRefCounts.set(store, { ...prev, count: prev.count + 1 });
130+
}
131+
}
132+
commitAllStates(state) {
133+
for (const [store, committedState] of state) {
134+
store.commit(committedState);
135+
}
136+
this.sweep();
137+
}
138+
removeStore(store) {
139+
const prev = this._storeRefCounts.get(store);
140+
if (prev == null) {
141+
throw new Error(
142+
"Imblance in concurrent-safe store reference counting. This is a bug in react-use-store, please report it."
143+
);
144+
}
145+
this._storeRefCounts.set(store, {
146+
unsubscribe: prev.unsubscribe,
147+
count: prev.count - 1
148+
});
149+
}
150+
sweep() {
151+
for (const [store, refs] of this._storeRefCounts) {
152+
if (refs.count < 1) {
153+
refs.unsubscribe();
154+
this._storeRefCounts.delete(store);
155+
}
156+
}
157+
}
158+
};
159+
160+
// src/experimental/useStore.tsx
161+
var _jsxruntime = require('react/jsx-runtime');
162+
function createStore(reducer, initialState) {
163+
let state = initialState;
164+
const store = new Store({
165+
getState: () => state,
166+
reducer
167+
});
168+
store.dispatch = (action) => {
169+
state = reducer(state, action);
170+
store.handleUpdate(action);
171+
};
172+
return store;
173+
}
174+
function createStoreFromSource(source) {
175+
return new Store(source);
176+
}
177+
var storeManagerContext = _react.createContext.call(void 0, null);
178+
var CommitTracker = _react.memo.call(void 0,
179+
({ storeManager }) => {
180+
const [allStates, setAllStates] = _react.useState.call(void 0,
181+
storeManager.getAllCommittedStates()
182+
);
183+
_react.useEffect.call(void 0, () => {
184+
const unsubscribe = storeManager.subscribe(() => {
185+
const allStates2 = storeManager.getAllStates();
186+
setAllStates(allStates2);
187+
});
188+
return () => {
189+
unsubscribe();
190+
storeManager.sweep();
191+
};
192+
}, [storeManager]);
193+
_react.useLayoutEffect.call(void 0, () => {
194+
storeManager.commitAllStates(allStates);
195+
}, [storeManager, allStates]);
196+
return null;
197+
}
198+
);
199+
function StoreProvider({ children }) {
200+
const [storeManager] = _react.useState.call(void 0, () => new StoreManager());
201+
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, storeManagerContext.Provider, { value: storeManager, children: [
202+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, CommitTracker, { storeManager }),
203+
children
204+
] });
205+
}
206+
function useStoreSelector(store, selector) {
207+
const storeManager = _react.useContext.call(void 0, storeManagerContext);
208+
if (storeManager == null) {
209+
throw new Error(
210+
"Expected useStoreSelector to be rendered within a StoreProvider."
211+
);
212+
}
213+
const previousStoreRef = _react.useRef.call(void 0, store);
214+
if (store !== previousStoreRef.current) {
215+
throw new Error(
216+
"useStoreSelector does not currently support dynamic stores"
217+
);
218+
}
219+
const previousSelectorRef = _react.useRef.call(void 0, selector);
220+
if (selector !== previousSelectorRef.current) {
221+
throw new Error(
222+
"useStoreSelector does not currently support dynamic selectors"
223+
);
224+
}
225+
const [state, setState] = _react.useState.call(void 0, () => selector(store.getState()));
226+
_react.useLayoutEffect.call(void 0, () => {
227+
storeManager.addStore(store);
228+
const mountState = selector(store.getState());
229+
const mountCommittedState = selector(store.getCommittedState());
230+
if (state !== mountCommittedState) {
231+
setState(mountCommittedState);
232+
}
233+
if (mountState !== mountCommittedState) {
234+
_react.startTransition.call(void 0, () => {
235+
setState(mountState);
236+
});
237+
}
238+
const unsubscribe = store.subscribe(() => {
239+
const state2 = store.getState();
240+
setState(selector(state2));
241+
});
242+
return () => {
243+
unsubscribe();
244+
storeManager.removeStore(store);
245+
};
246+
}, []);
247+
return state;
248+
}
249+
function identity(x) {
250+
return x;
251+
}
252+
function useStore(store) {
253+
return useStoreSelector(store, identity);
254+
}
255+
256+
// src/useStore.ts
257+
258+
259+
// src/types.ts
260+
var REACT_STORE_TYPE = Symbol.for("react.store");
261+
262+
// src/useStore.ts
263+
var isStore = (value) => {
264+
return value && "$$typeof" in value && value.$$typeof === REACT_STORE_TYPE;
265+
};
266+
function createStore2(initialValue, reducer) {
267+
const store = {
268+
$$typeof: REACT_STORE_TYPE,
269+
_listeners: /* @__PURE__ */ new Set(),
270+
_current: initialValue,
271+
_sync: initialValue,
272+
_transition: initialValue,
273+
refresh: () => {
274+
store._listeners.forEach((listener) => listener());
275+
},
276+
subscribe: (listener) => {
277+
store._listeners.add(listener);
278+
return () => {
279+
store._listeners.delete(listener);
280+
};
281+
},
282+
update: (action) => {
283+
store._transition = reducer ? reducer(store._transition, action) : action;
284+
store.refresh();
285+
}
286+
};
287+
return store;
288+
}
289+
function useStore2(store) {
290+
if (!isStore(store)) {
291+
throw new Error(
292+
"Invalid store type. Ensure you are using a valid React store."
293+
);
294+
}
295+
const [cache, setCache] = _react.useState.call(void 0, () => store._current);
296+
const [_, startTransition3] = _react.useTransition.call(void 0, );
297+
_react.useEffect.call(void 0, () => {
298+
return store.subscribe(() => {
299+
store._sync = store._transition;
300+
startTransition3(() => {
301+
setCache(store._current = store._sync);
302+
});
303+
});
304+
}, [store]);
305+
return cache;
306+
}
307+
308+
// src/index.ts
309+
var experimental = experimental_exports;
310+
311+
312+
313+
314+
exports.createStore = createStore2; exports.experimental = experimental; exports.useStore = useStore2;
315+
//# sourceMappingURL=index.cjs.map

.yalc/react-concurrent-store/dist/index.cjs.map

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)