@bemedev/app-reactjs 1.7.0 → 1.9.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
@@ -32,10 +32,10 @@ service.start();
32
32
 
33
33
  function MyComponent() {
34
34
  // 1. Select a specific slice of context
35
- const count = useService(service, s => s.context.count);
35
+ const count = useService(service, { selector: s => s.context.count });
36
36
 
37
37
  // 2. Or track the active state value
38
- const stateValue = useService(service, s => s.value);
38
+ const stateValue = useService(service, { selector: s => s.value });
39
39
 
40
40
  // 3. Or track the whole state object
41
41
  const state = useService(service);
@@ -53,15 +53,15 @@ function MyComponent() {
53
53
 
54
54
  ## API Reference
55
55
 
56
- ### `useService(service, selector?)`
56
+ ### `useService(service, options?)`
57
57
 
58
58
  Creates a React state hook that updates whenever the interpreter
59
59
  transitions, using deep comparison to prevent unnecessary renders.
60
60
 
61
- | Parameter | Type | Description |
62
- | ---------- | ----------------------- | ---------------------------------------------------------------------- |
63
- | `service` | `Interpreter` | The `@bemedev/app` interpreter service instance. |
64
- | `selector` | `(state: State) => any` | Optional selector function to slice and track specific parts of state. |
61
+ | Parameter | Type | Description |
62
+ | --------- | ------------------- | ----------------------------------------------------------------------------------- |
63
+ | `service` | `Interpreter` | The `@bemedev/app` interpreter service instance. |
64
+ | `options` | `UseServiceOptions` | Optional object containing `selector` and/or custom `equality` comparison function. |
65
65
 
66
66
  Returns the selected state or slice.
67
67
 
@@ -1,20 +1,23 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- let _bemedev_app_utils = require("@bemedev/app/utils");
2
+ let _bemedev_app = require("@bemedev/app");
3
3
  let react = require("react");
4
4
  //#region src/useService.ts
5
5
  /**
6
6
  * A hook that creates a React state from a service with a subscribe function.
7
7
  *
8
8
  * @param service - The service containing the state and subscribe method.
9
- * @param selector - A function to select the desired slice of state.
9
+ * @param options - Optional configuration options for selection and equality comparison.
10
10
  * @returns The selected state.
11
11
  */
12
- function useService(service, selector = (s) => s) {
12
+ function useService(service, options) {
13
+ const { selector = (s) => s, equality = (first, next) => (0, _bemedev_app.deepEqual)(first, next) } = options ?? {};
13
14
  const [state, setState] = (0, react.useState)(() => selector(service.state));
14
15
  const sub = service.subscribe((nextState) => setState(selector(nextState)), { equals: (first, next) => {
15
- return (0, _bemedev_app_utils.deepEqual)(selector(first), selector(next));
16
+ const _first = selector(first);
17
+ const _next = selector(next);
18
+ return equality(_first, _next);
16
19
  } });
17
- (0, react.useEffect)(() => sub.unsubscribe, [service, selector]);
20
+ (0, react.useEffect)(() => sub.unsubscribe, []);
18
21
  return state;
19
22
  }
20
23
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"useService.cjs","names":[],"sources":["../src/useService.ts"],"sourcesContent":["import type {\n AddSubscriber_F,\n EventObject,\n PrimitiveObject,\n State,\n} from '@bemedev/app/types';\nimport { deepEqual } from '@bemedev/app/utils';\nimport { useEffect, useState } from 'react';\n\n/**\n * A hook that creates a React state from a service with a subscribe function.\n *\n * @param service - The service containing the state and subscribe method.\n * @param selector - A function to select the desired slice of state.\n * @returns The selected state.\n */\nexport function useService<\n Tc extends PrimitiveObject,\n Ta extends string,\n Eo extends EventObject,\n T = State<Eo, Tc, Ta>,\n>(\n service: {\n subscribe: AddSubscriber_F<Tc, Ta, Eo>;\n state: State<Eo, Tc, Ta>;\n },\n selector: (state: State<Eo, Tc, Ta>) => T = (s: State<Eo, Tc, Ta>) =>\n s as unknown as T,\n): T {\n const [state, setState] = useState<T>(() => selector(service.state));\n\n const sub = service.subscribe(\n nextState => setState(selector(nextState)),\n {\n equals: (first, next) => {\n const _first = selector(first);\n const _next = selector(next);\n return deepEqual(_first, _next);\n },\n },\n );\n\n useEffect(() => sub.unsubscribe, [service, selector]);\n return state;\n}\n"],"mappings":";;;;;;;;;;;AAgBA,SAAgB,WAMd,SAIA,YAA6C,MAC3C,GACC;CACH,MAAM,CAAC,OAAO,aAAA,GAAA,MAAA,SAAA,OAA8B,SAAS,QAAQ,KAAK,CAAC;CAEnE,MAAM,MAAM,QAAQ,WAClB,cAAa,SAAS,SAAS,SAAS,CAAC,GACzC,EACE,SAAS,OAAO,SAAS;EAGvB,QAAA,GAAA,mBAAA,UAAA,CAFe,SAAS,KAEF,GADR,SAAS,IACM,CAAC;CAChC,EACF,CACF;CAEA,CAAA,GAAA,MAAA,UAAA,OAAgB,IAAI,aAAa,CAAC,SAAS,QAAQ,CAAC;CACpD,OAAO;AACT"}
1
+ {"version":3,"file":"useService.cjs","names":["deepEqual","useState"],"sources":["../src/useService.ts"],"sourcesContent":["import type {\n AddSubscriber_F,\n EventObject,\n PrimitiveObject,\n State,\n} from '@bemedev/app';\nimport { deepEqual } from '@bemedev/app';\nimport { useEffect, useState } from 'react';\n\nexport type UseServiceOptions<\n Tc extends PrimitiveObject,\n Ta extends string,\n Eo extends EventObject,\n T = State<Eo, Tc, Ta>,\n> = {\n selector?: (state: State<Eo, Tc, Ta>) => T;\n equality?: (first: T, next: T) => boolean;\n};\n\n/**\n * A hook that creates a React state from a service with a subscribe function.\n *\n * @param service - The service containing the state and subscribe method.\n * @param options - Optional configuration options for selection and equality comparison.\n * @returns The selected state.\n */\nexport function useService<\n Tc extends PrimitiveObject,\n Ta extends string,\n Eo extends EventObject,\n T = State<Eo, Tc, Ta>,\n>(\n service: {\n subscribe: AddSubscriber_F<Tc, Ta, Eo>;\n state: State<Eo, Tc, Ta>;\n },\n options?: UseServiceOptions<Tc, Ta, Eo, T>,\n): T {\n const {\n selector = (s: State<Eo, Tc, Ta>) => s as T,\n equality = (first: T, next: T) => deepEqual(first, next),\n } = options ?? {};\n\n const [state, setState] = useState<T>(() => selector(service.state));\n\n const sub = service.subscribe(\n nextState => setState(selector(nextState)),\n {\n equals: (first, next) => {\n const _first = selector(first);\n const _next = selector(next);\n return equality(_first, _next);\n },\n },\n );\n\n useEffect(() => sub.unsubscribe, []);\n return state;\n}\n"],"mappings":";;;;;;;;;;;AA0BA,SAAgB,WAMd,SAIA,SACG;CACH,MAAM,EACJ,YAAY,MAAyB,GACrC,YAAY,OAAU,UAAA,GAAYA,aAAAA,UAAAA,CAAU,OAAO,IAAI,MACrD,WAAW,CAAC;CAEhB,MAAM,CAAC,OAAO,aAAA,GAAYC,MAAAA,SAAAA,OAAkB,SAAS,QAAQ,KAAK,CAAC;CAEnE,MAAM,MAAM,QAAQ,WAClB,cAAa,SAAS,SAAS,SAAS,CAAC,GACzC,EACE,SAAS,OAAO,SAAS;EACvB,MAAM,SAAS,SAAS,KAAK;EAC7B,MAAM,QAAQ,SAAS,IAAI;EAC3B,OAAO,SAAS,QAAQ,KAAK;CAC/B,EACF,CACF;CAEA,CAAA,GAAA,MAAA,UAAA,OAAgB,IAAI,aAAa,CAAC,CAAC;CACnC,OAAO;AACT"}
@@ -1,13 +1,17 @@
1
- import type { AddSubscriber_F, EventObject, PrimitiveObject, State } from '@bemedev/app/types';
1
+ import type { AddSubscriber_F, EventObject, PrimitiveObject, State } from '@bemedev/app';
2
+ export type UseServiceOptions<Tc extends PrimitiveObject, Ta extends string, Eo extends EventObject, T = State<Eo, Tc, Ta>> = {
3
+ selector?: (state: State<Eo, Tc, Ta>) => T;
4
+ equality?: (first: T, next: T) => boolean;
5
+ };
2
6
  /**
3
7
  * A hook that creates a React state from a service with a subscribe function.
4
8
  *
5
9
  * @param service - The service containing the state and subscribe method.
6
- * @param selector - A function to select the desired slice of state.
10
+ * @param options - Optional configuration options for selection and equality comparison.
7
11
  * @returns The selected state.
8
12
  */
9
13
  export declare function useService<Tc extends PrimitiveObject, Ta extends string, Eo extends EventObject, T = State<Eo, Tc, Ta>>(service: {
10
14
  subscribe: AddSubscriber_F<Tc, Ta, Eo>;
11
15
  state: State<Eo, Tc, Ta>;
12
- }, selector?: (state: State<Eo, Tc, Ta>) => T): T;
16
+ }, options?: UseServiceOptions<Tc, Ta, Eo, T>): T;
13
17
  //# sourceMappingURL=useService.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useService.d.ts","sourceRoot":"","sources":["../src/useService.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EACf,WAAW,EACX,eAAe,EACf,KAAK,EACN,MAAM,oBAAoB,CAAC;AAI5B;;;;;;GAMG;AACH,wBAAgB,UAAU,CACxB,EAAE,SAAS,eAAe,EAC1B,EAAE,SAAS,MAAM,EACjB,EAAE,SAAS,WAAW,EACtB,CAAC,GAAG,KAAK,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,EAErB,OAAO,EAAE;IACP,SAAS,EAAE,eAAe,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;IACvC,KAAK,EAAE,KAAK,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;CAC1B,EACD,QAAQ,GAAE,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,KAAK,CACrB,GAClB,CAAC,CAgBH"}
1
+ {"version":3,"file":"useService.d.ts","sourceRoot":"","sources":["../src/useService.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EACf,WAAW,EACX,eAAe,EACf,KAAK,EACN,MAAM,cAAc,CAAC;AAItB,MAAM,MAAM,iBAAiB,CAC3B,EAAE,SAAS,eAAe,EAC1B,EAAE,SAAS,MAAM,EACjB,EAAE,SAAS,WAAW,EACtB,CAAC,GAAG,KAAK,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,IACnB;IACF,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC;IAC3C,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC;CAC3C,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,UAAU,CACxB,EAAE,SAAS,eAAe,EAC1B,EAAE,SAAS,MAAM,EACjB,EAAE,SAAS,WAAW,EACtB,CAAC,GAAG,KAAK,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,EAErB,OAAO,EAAE;IACP,SAAS,EAAE,eAAe,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;IACvC,KAAK,EAAE,KAAK,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;CAC1B,EACD,OAAO,CAAC,EAAE,iBAAiB,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,GACzC,CAAC,CAqBH"}
package/lib/useService.js CHANGED
@@ -1,19 +1,22 @@
1
- import { deepEqual } from "@bemedev/app/utils";
1
+ import { deepEqual } from "@bemedev/app";
2
2
  import { useEffect, useState } from "react";
3
3
  //#region src/useService.ts
4
4
  /**
5
5
  * A hook that creates a React state from a service with a subscribe function.
6
6
  *
7
7
  * @param service - The service containing the state and subscribe method.
8
- * @param selector - A function to select the desired slice of state.
8
+ * @param options - Optional configuration options for selection and equality comparison.
9
9
  * @returns The selected state.
10
10
  */
11
- function useService(service, selector = (s) => s) {
11
+ function useService(service, options) {
12
+ const { selector = (s) => s, equality = (first, next) => deepEqual(first, next) } = options ?? {};
12
13
  const [state, setState] = useState(() => selector(service.state));
13
14
  const sub = service.subscribe((nextState) => setState(selector(nextState)), { equals: (first, next) => {
14
- return deepEqual(selector(first), selector(next));
15
+ const _first = selector(first);
16
+ const _next = selector(next);
17
+ return equality(_first, _next);
15
18
  } });
16
- useEffect(() => sub.unsubscribe, [service, selector]);
19
+ useEffect(() => sub.unsubscribe, []);
17
20
  return state;
18
21
  }
19
22
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"useService.js","names":[],"sources":["../src/useService.ts"],"sourcesContent":["import type {\n AddSubscriber_F,\n EventObject,\n PrimitiveObject,\n State,\n} from '@bemedev/app/types';\nimport { deepEqual } from '@bemedev/app/utils';\nimport { useEffect, useState } from 'react';\n\n/**\n * A hook that creates a React state from a service with a subscribe function.\n *\n * @param service - The service containing the state and subscribe method.\n * @param selector - A function to select the desired slice of state.\n * @returns The selected state.\n */\nexport function useService<\n Tc extends PrimitiveObject,\n Ta extends string,\n Eo extends EventObject,\n T = State<Eo, Tc, Ta>,\n>(\n service: {\n subscribe: AddSubscriber_F<Tc, Ta, Eo>;\n state: State<Eo, Tc, Ta>;\n },\n selector: (state: State<Eo, Tc, Ta>) => T = (s: State<Eo, Tc, Ta>) =>\n s as unknown as T,\n): T {\n const [state, setState] = useState<T>(() => selector(service.state));\n\n const sub = service.subscribe(\n nextState => setState(selector(nextState)),\n {\n equals: (first, next) => {\n const _first = selector(first);\n const _next = selector(next);\n return deepEqual(_first, _next);\n },\n },\n );\n\n useEffect(() => sub.unsubscribe, [service, selector]);\n return state;\n}\n"],"mappings":";;;;;;;;;;AAgBA,SAAgB,WAMd,SAIA,YAA6C,MAC3C,GACC;CACH,MAAM,CAAC,OAAO,YAAY,eAAkB,SAAS,QAAQ,KAAK,CAAC;CAEnE,MAAM,MAAM,QAAQ,WAClB,cAAa,SAAS,SAAS,SAAS,CAAC,GACzC,EACE,SAAS,OAAO,SAAS;EAGvB,OAAO,UAFQ,SAAS,KAEF,GADR,SAAS,IACM,CAAC;CAChC,EACF,CACF;CAEA,gBAAgB,IAAI,aAAa,CAAC,SAAS,QAAQ,CAAC;CACpD,OAAO;AACT"}
1
+ {"version":3,"file":"useService.js","names":[],"sources":["../src/useService.ts"],"sourcesContent":["import type {\n AddSubscriber_F,\n EventObject,\n PrimitiveObject,\n State,\n} from '@bemedev/app';\nimport { deepEqual } from '@bemedev/app';\nimport { useEffect, useState } from 'react';\n\nexport type UseServiceOptions<\n Tc extends PrimitiveObject,\n Ta extends string,\n Eo extends EventObject,\n T = State<Eo, Tc, Ta>,\n> = {\n selector?: (state: State<Eo, Tc, Ta>) => T;\n equality?: (first: T, next: T) => boolean;\n};\n\n/**\n * A hook that creates a React state from a service with a subscribe function.\n *\n * @param service - The service containing the state and subscribe method.\n * @param options - Optional configuration options for selection and equality comparison.\n * @returns The selected state.\n */\nexport function useService<\n Tc extends PrimitiveObject,\n Ta extends string,\n Eo extends EventObject,\n T = State<Eo, Tc, Ta>,\n>(\n service: {\n subscribe: AddSubscriber_F<Tc, Ta, Eo>;\n state: State<Eo, Tc, Ta>;\n },\n options?: UseServiceOptions<Tc, Ta, Eo, T>,\n): T {\n const {\n selector = (s: State<Eo, Tc, Ta>) => s as T,\n equality = (first: T, next: T) => deepEqual(first, next),\n } = options ?? {};\n\n const [state, setState] = useState<T>(() => selector(service.state));\n\n const sub = service.subscribe(\n nextState => setState(selector(nextState)),\n {\n equals: (first, next) => {\n const _first = selector(first);\n const _next = selector(next);\n return equality(_first, _next);\n },\n },\n );\n\n useEffect(() => sub.unsubscribe, []);\n return state;\n}\n"],"mappings":";;;;;;;;;;AA0BA,SAAgB,WAMd,SAIA,SACG;CACH,MAAM,EACJ,YAAY,MAAyB,GACrC,YAAY,OAAU,SAAY,UAAU,OAAO,IAAI,MACrD,WAAW,CAAC;CAEhB,MAAM,CAAC,OAAO,YAAY,eAAkB,SAAS,QAAQ,KAAK,CAAC;CAEnE,MAAM,MAAM,QAAQ,WAClB,cAAa,SAAS,SAAS,SAAS,CAAC,GACzC,EACE,SAAS,OAAO,SAAS;EACvB,MAAM,SAAS,SAAS,KAAK;EAC7B,MAAM,QAAQ,SAAS,IAAI;EAC3B,OAAO,SAAS,QAAQ,KAAK;CAC/B,EACF,CACF;CAEA,gBAAgB,IAAI,aAAa,CAAC,CAAC;CACnC,OAAO;AACT"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bemedev/app-reactjs",
3
- "version": "1.7.0",
3
+ "version": "1.9.0",
4
4
  "description": "Middleware between @bemedev/app and reactjs",
5
5
  "keywords": [
6
6
  "app",
@@ -44,43 +44,42 @@
44
44
  "module": "lib/index.js",
45
45
  "types": "lib/index.d.ts",
46
46
  "devDependencies": {
47
- "@bemedev/decompose": "2.2.0",
48
- "@bemedev/dev-utils": "^0.8.3",
47
+ "@bemedev/decompose": "2.3.0",
48
+ "@bemedev/dev-utils": "^1.1.1",
49
49
  "@bemedev/sleep": "^0.2.2",
50
- "@size-limit/file": "^12.1.0",
51
- "@testing-library/jest-dom": "^6.9.1",
52
- "@testing-library/react": "^16.2.0",
50
+ "@size-limit/file": "^13.0.2",
51
+ "@testing-library/jest-dom": "^7.0.0",
52
+ "@testing-library/react": "^16.3.2",
53
53
  "@testing-library/user-event": "^14.6.1",
54
- "@types/node": "^26.1.0",
55
- "@types/react": "^19.0.0",
56
- "@types/react-dom": "^19.0.0",
57
- "@vitest/coverage-v8": "^4.1.9",
58
- "@vitest/ui": "4.1.9",
54
+ "@types/node": "^26.1.2",
55
+ "@types/react": "^19.2.17",
56
+ "@types/react-dom": "^19.2.3",
57
+ "@vitest/coverage-v8": "^4.1.10",
58
+ "@vitest/ui": "4.1.10",
59
59
  "glob": "^13.0.6",
60
- "globals": "^17.7.0",
60
+ "globals": "^17.8.0",
61
61
  "husky": "^9.1.7",
62
- "jsdom": "^29.1.1",
62
+ "jsdom": "^30.0.1",
63
63
  "onchange": "^7.1.0",
64
- "oxfmt": "^0.57.0",
65
- "oxlint": "^1.72.0",
66
- "prettier": "^3.9.4",
64
+ "oxfmt": "^0.61.0",
65
+ "oxlint": "^1.76.0",
66
+ "prettier": "^3.9.6",
67
67
  "pretty-quick": "^4.2.2",
68
- "react": "^19.0.0",
69
- "react-dom": "^19.0.0",
70
- "rolldown": "1.1.4",
71
- "rolldown-plugin-dts": "^0.26.0",
72
- "size-limit": "^12.1.0",
68
+ "react": "^19.2.8",
69
+ "react-dom": "^19.2.8",
70
+ "rolldown": "1.2.1",
71
+ "rolldown-plugin-dts": "^0.27.14",
72
+ "size-limit": "^13.0.2",
73
73
  "tslib": "^2.8.1",
74
- "tsx": "^4.22.4",
74
+ "tsx": "^4.23.1",
75
75
  "typescript": "^6.0.3",
76
- "vitest": "^4.1.9",
77
- "@bemedev/app-vitest": "^1.7.0",
78
- "@bemedev/app": "^1.7.0"
76
+ "vitest": "^4.1.10",
77
+ "@bemedev/app": "^1.9.0",
78
+ "@bemedev/app-vitest": "^1.9.0"
79
79
  },
80
80
  "peerDependencies": {
81
- "@bemedev/decompose": "2.2.0",
82
- "react": "^18.0.0 || ^19.0.0",
83
- "@bemedev/app": "^1.7.0"
81
+ "react": "^19.2.8",
82
+ "@bemedev/app": "^1.9.0"
84
83
  },
85
84
  "size-limit": [
86
85
  {