@createstore/createstore 0.0.0 → 1.1.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.
package/README.md CHANGED
@@ -24,6 +24,28 @@ function Counter() {
24
24
  Every component that reads `'count'` re-renders when any of them changes it. Outside React, use
25
25
  `store.getState('count')` and `store.setState('count', 2)`.
26
26
 
27
+ ### Share state between components
28
+
29
+ Take `useGlobalState` out of the store, and any component can read or change the same list. No provider, no props
30
+ passed down:
31
+
32
+ ```tsx
33
+ const { useGlobalState } = createStore({ todos: [] as { text: string }[] });
34
+
35
+ function TodoCount() {
36
+ const [todos] = useGlobalState('todos');
37
+ return <p>{todos.length} todos</p>;
38
+ }
39
+
40
+ function AddTodo() {
41
+ const [todos, setTodos] = useGlobalState('todos');
42
+ const add = (text: string) => setTodos([...todos, { text }]);
43
+ return <Form onAdd={add} />;
44
+ }
45
+ ```
46
+
47
+ `<Form>` stands for your own form component. When `AddTodo` adds a todo, `TodoCount` updates by itself.
48
+
27
49
  Everything else stays off until you use it: computed values, server data with `query()`, persistence, offline
28
50
  support, undo/redo, tab sync, events and server rendering.
29
51
 
@@ -33,6 +55,14 @@ support, undo/redo, tab sync, events and server rendering.
33
55
  - Published with [npm provenance](https://docs.npmjs.com/generating-provenance-statements).
34
56
  - Versioned with [semantic versioning](https://semver.org); see [CHANGELOG.md](./CHANGELOG.md) once a release exists.
35
57
 
58
+ ## Links
59
+
60
+ - [GitHub repository](https://github.com/Gauravasawa/createstore): source code, issues and releases
61
+ - [npm package](https://www.npmjs.com/package/@createstore/createstore)
62
+ - [Documentation](https://createstore-docs.pages.dev)
63
+ - [Report a bug or request a feature](https://github.com/Gauravasawa/createstore/issues/new/choose)
64
+ - [Security policy](https://github.com/Gauravasawa/createstore/security/policy)
65
+
36
66
  ## License
37
67
 
38
68
  [MIT](./LICENSE)
@@ -29,6 +29,15 @@ __export(createStore_exports, {
29
29
  module.exports = __toCommonJS(createStore_exports);
30
30
  var import_react_bindings = require("./react-bindings.cjs");
31
31
  const __SnapshotContext = import_react_bindings.RSC ? null : (0, import_react_bindings.createContext)(null);
32
+ let leavingPage = false;
33
+ if (typeof window !== "undefined" && typeof window.addEventListener === "function") {
34
+ window.addEventListener("pagehide", () => {
35
+ leavingPage = true;
36
+ });
37
+ window.addEventListener("pageshow", () => {
38
+ leavingPage = false;
39
+ });
40
+ }
32
41
  const storesByName = /* @__PURE__ */ new Map();
33
42
  const MERGE = /* @__PURE__ */ Symbol("createStore.merge");
34
43
  const QUIET = /* @__PURE__ */ Symbol("createStore.quiet");
@@ -163,12 +172,48 @@ function defineEvents() {
163
172
  return void 0;
164
173
  }
165
174
  function createStore(initialState, options = {}) {
175
+ checkStoreOptions(options);
166
176
  if ("queries" in options)
167
177
  throw new Error(
168
178
  `[${options.name ?? "store"}] the queries option was replaced: declare each query in the state with query(fetch, options), e.g. { product: query((id, signal) => api.product(id, signal)) }, and read it with useGlobalState('product', id).`
169
179
  );
170
180
  return withScopes(initialState, options, makeBase(initialState, options));
171
181
  }
182
+ const STORE_OPTIONS = /* @__PURE__ */ new Set([
183
+ "name",
184
+ "persist",
185
+ "syncTabs",
186
+ "history",
187
+ "devtools",
188
+ "shared",
189
+ "ssr",
190
+ "logger",
191
+ "onChange",
192
+ "offline",
193
+ "validate",
194
+ "events",
195
+ "computed",
196
+ "keyActions",
197
+ "actions",
198
+ "queries"
199
+ ]);
200
+ const warnedOptions = /* @__PURE__ */ new Set();
201
+ function checkStoreOptions(opts) {
202
+ const options = opts;
203
+ const warn = (message) => {
204
+ if (warnedOptions.has(message)) return;
205
+ warnedOptions.add(message);
206
+ console.warn(message);
207
+ };
208
+ const id = options.name ?? "store";
209
+ for (const k of Object.keys(options))
210
+ if (!STORE_OPTIONS.has(k))
211
+ warn(`[${id}] createStore() has no option "${k}", so it is ignored. Options: ${[...STORE_OPTIONS].filter((o) => o !== "queries").join(", ")}.`);
212
+ if (!options.name && (options.persist || options.syncTabs || options.offline || options.shared))
213
+ warn(
214
+ `[store] persist, syncTabs, offline and shared use the store's name to tell stores apart. Without { name: '...' }, every unnamed store uses "store", so two of them would overwrite each other's saved data and mix up their tabs. Give this one a name.`
215
+ );
216
+ }
172
217
  const warnedSharedOnServer = /* @__PURE__ */ new Set();
173
218
  const warnedShape = /* @__PURE__ */ new Set();
174
219
  const SHAPE = /* @__PURE__ */ Symbol("createStore.shape");
@@ -1263,6 +1308,7 @@ function build(initialState, options, sharedDefinition) {
1263
1308
  updateHistoryInfo();
1264
1309
  }
1265
1310
  function batch(fn) {
1311
+ if (typeof fn !== "function") throw new Error(`[${name}] batch() takes a function that makes the changes: store.batch(() => { store.setState('a', 1); store.setState('b', 2); }).`);
1266
1312
  batchDepth++;
1267
1313
  if (batchDepth === 1 && historyLimit) batchChanges = /* @__PURE__ */ Object.create(null);
1268
1314
  let result;
@@ -1590,15 +1636,6 @@ function build(initialState, options, sharedDefinition) {
1590
1636
  ownPromises.add(promise);
1591
1637
  return promise;
1592
1638
  }
1593
- let leavingPage = false;
1594
- if (isBrowser && typeof window.addEventListener === "function") {
1595
- window.addEventListener("pagehide", () => {
1596
- leavingPage = true;
1597
- });
1598
- window.addEventListener("pageshow", () => {
1599
- leavingPage = false;
1600
- });
1601
- }
1602
1639
  const SERVER_LOADING = Object.freeze({
1603
1640
  state: "loading",
1604
1641
  loading: true,
@@ -2242,6 +2279,8 @@ function build(initialState, options, sharedDefinition) {
2242
2279
  };
2243
2280
  const api = Object.assign(Object.create(setterProtoOf(def, API_NAMES, "apiProto")), apiMembers);
2244
2281
  Object.defineProperty(api, SETTER_OF, { value: (k) => setterFor(k) });
2282
+ if (options.actions != null && typeof options.actions !== "function")
2283
+ throw new Error(`[${name}] actions must be a function that receives the store's api and returns your actions: createStore(state, { actions: (api) => ({ add(x) { api.setState('items', (i) => [...i, x]); } }) }).`);
2245
2284
  const actions = options.actions?.(api) ?? {};
2246
2285
  const keyActionDefs = options.keyActions ?? {};
2247
2286
  const ssrCfg = options.ssr;