@tramvai/state 2.108.1 → 2.109.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.
@@ -1,5 +1,6 @@
1
1
  export * from './useConsumerContext';
2
2
  export * from './useActions';
3
+ export * from './useEvents';
3
4
  export * from './useStore';
4
5
  export * from './useSelector';
5
6
  export * from './useStoreSelector';
@@ -0,0 +1,7 @@
1
+ import type { Event, EventCreatorN } from '@tramvai/types-actions-state-context';
2
+ type ConvertEventToDispatch<Ev extends EventCreatorN<any>> = Ev extends (...args: infer T) => Event<infer P> ? (...args: T) => P : never;
3
+ export declare function useEvents<Ev extends EventCreatorN<any>>(event: Ev): ConvertEventToDispatch<Ev>;
4
+ export declare function useEvents<Ev extends Readonly<EventCreatorN<any>[]>>(events: Ev): {
5
+ [key in keyof Ev]: ConvertEventToDispatch<Ev[key]>;
6
+ };
7
+ export {};
@@ -0,0 +1,25 @@
1
+ import isArray from '@tinkoff/utils/is/array';
2
+ import { useMemo } from 'react';
3
+ import { useShallowEqual } from '@tinkoff/react-hooks';
4
+ import { useConsumerContext } from './useConsumerContext.es.js';
5
+
6
+ function useEvents(events) {
7
+ const context = useConsumerContext();
8
+ const eventsRef = useShallowEqual(events);
9
+ return useMemo(() => {
10
+ if (isArray(eventsRef)) {
11
+ return eventsRef.map((event) => (...args) => {
12
+ const ev = event(...args);
13
+ context.dispatch(ev);
14
+ return ev.payload;
15
+ });
16
+ }
17
+ return (...args) => {
18
+ const ev = eventsRef(...args);
19
+ context.dispatch(ev);
20
+ return ev.payload;
21
+ };
22
+ }, [eventsRef, context]);
23
+ }
24
+
25
+ export { useEvents };
@@ -0,0 +1,33 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var isArray = require('@tinkoff/utils/is/array');
6
+ var React = require('react');
7
+ var reactHooks = require('@tinkoff/react-hooks');
8
+ var useConsumerContext = require('./useConsumerContext.js');
9
+
10
+ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
11
+
12
+ var isArray__default = /*#__PURE__*/_interopDefaultLegacy(isArray);
13
+
14
+ function useEvents(events) {
15
+ const context = useConsumerContext.useConsumerContext();
16
+ const eventsRef = reactHooks.useShallowEqual(events);
17
+ return React.useMemo(() => {
18
+ if (isArray__default["default"](eventsRef)) {
19
+ return eventsRef.map((event) => (...args) => {
20
+ const ev = event(...args);
21
+ context.dispatch(ev);
22
+ return ev.payload;
23
+ });
24
+ }
25
+ return (...args) => {
26
+ const ev = eventsRef(...args);
27
+ context.dispatch(ev);
28
+ return ev.payload;
29
+ };
30
+ }, [eventsRef, context]);
31
+ }
32
+
33
+ exports.useEvents = useEvents;
@@ -0,0 +1 @@
1
+ export {};
@@ -38,7 +38,7 @@ function useSelector(storesOrStore, selector, equalityFn = shallowEqual) {
38
38
  selectedState = useSyncExternalStoreWithSelector(subscribe, context.getState, serverState ? () => serverState : context.getState, selector, equalityFn);
39
39
  }
40
40
  catch (err) {
41
- let errorMessage = `An error occured while selecting the store state: ${err.message}.`;
41
+ let errorMessage = `An error occurred while selecting the store state: ${err.message}.`;
42
42
  if (latestSubscriptionCallbackError.current) {
43
43
  errorMessage += `\nThe error may be correlated with this previous error:\n${latestSubscriptionCallbackError.current.stack}\n\nOriginal stack trace:`;
44
44
  }
@@ -48,7 +48,7 @@ function useSelector(storesOrStore, selector, equalityFn = shallowEqual__default
48
48
  selectedState = withSelector.useSyncExternalStoreWithSelector(subscribe, context$1.getState, serverState ? () => serverState : context$1.getState, selector, equalityFn);
49
49
  }
50
50
  catch (err) {
51
- let errorMessage = `An error occured while selecting the store state: ${err.message}.`;
51
+ let errorMessage = `An error occurred while selecting the store state: ${err.message}.`;
52
52
  if (latestSubscriptionCallbackError.current) {
53
53
  errorMessage += `\nThe error may be correlated with this previous error:\n${latestSubscriptionCallbackError.current.stack}\n\nOriginal stack trace:`;
54
54
  }
@@ -1,2 +1,2 @@
1
1
  import type { Reducer } from '../..';
2
- export declare const useStoreSelector: <TState, TPayload>(store: Reducer<TState, string>, selector: (state: TState) => TPayload) => TPayload;
2
+ export declare const useStoreSelector: <TState, TPayload>(store: Reducer<TState, string, any>, selector: (state: TState) => TPayload) => TPayload;
@@ -1,4 +1,4 @@
1
- import type { EmptyEventCreator, EventCreator0, EventCreator1, EventCreator2, EventCreator3, EventCreatorN, PayloadTransformer0, PayloadTransformer1, PayloadTransformer2, PayloadTransformer3, PayloadTransformerN } from './createEvent.h';
1
+ import type { AnyEventCreator, EmptyEventCreator, EventCreator0, EventCreator1, EventCreator2, EventCreator3, EventCreatorN, PayloadTransformer0, PayloadTransformer1, PayloadTransformer2, PayloadTransformer3, PayloadTransformerN } from './createEvent.h';
2
2
  export declare function createEvent(description: string): EmptyEventCreator;
3
3
  export declare function createEvent<A1>(description: string): EventCreator1<A1>;
4
4
  /**
@@ -41,3 +41,4 @@ export declare function createEvent<A1, A2, Payload>(description: string, payloa
41
41
  */
42
42
  export declare function createEvent<A1, A2, A3, Payload>(description: string, payloadCreator: PayloadTransformer3<A1, A2, A3, Payload>): EventCreator3<A1, A2, A3, Payload>;
43
43
  export declare function createEvent<Payload>(description: string, payloadCreator: PayloadTransformerN<Payload>): EventCreatorN<Payload>;
44
+ export declare const isEventCreator: (eventCreator: any) => eventCreator is AnyEventCreator<any>;
@@ -12,11 +12,15 @@ function createEvent(eventName, payloadCreator = identity) {
12
12
  return {
13
13
  type,
14
14
  payload: payloadCreator(...args),
15
+ store: eventCreator.store,
15
16
  };
16
17
  };
17
18
  eventCreator.getType = () => type;
18
19
  eventCreator.toString = () => type;
19
20
  return eventCreator;
20
21
  }
22
+ const isEventCreator = (eventCreator) => {
23
+ return typeof eventCreator === 'function' && 'getType' in eventCreator;
24
+ };
21
25
 
22
- export { createEvent };
26
+ export { createEvent, isEventCreator };
@@ -21,11 +21,16 @@ function createEvent(eventName, payloadCreator = identity__default["default"]) {
21
21
  return {
22
22
  type,
23
23
  payload: payloadCreator(...args),
24
+ store: eventCreator.store,
24
25
  };
25
26
  };
26
27
  eventCreator.getType = () => type;
27
28
  eventCreator.toString = () => type;
28
29
  return eventCreator;
29
30
  }
31
+ const isEventCreator = (eventCreator) => {
32
+ return typeof eventCreator === 'function' && 'getType' in eventCreator;
33
+ };
30
34
 
31
35
  exports.createEvent = createEvent;
36
+ exports.isEventCreator = isEventCreator;
@@ -1,2 +1,10 @@
1
- import type { Reducer } from './createReducer.h';
2
- export declare function createReducer<State = {}, Name extends string = string>(name: Name, initialState: State): Reducer<State, Name>;
1
+ import type { EventHandlersToEventCreators } from '@tramvai/types-actions-state-context';
2
+ import type { EventHandler, Reducer } from './createReducer.h';
3
+ interface Options<Name extends string, State, Events extends Record<string, EventHandler<State, any>>> {
4
+ name: Name;
5
+ initialState: State;
6
+ events?: Events;
7
+ }
8
+ export declare function createReducer<State, Name extends string, Events extends Record<string, EventHandler<State, any>> = Record<string, EventHandler<State, any>>>(options: Options<Name, State, Events>): Reducer<State, Name, EventHandlersToEventCreators<State, Events>>;
9
+ export declare function createReducer<State = {}, Name extends string = string>(name: Name, initialState: State): Reducer<State, Name, never>;
10
+ export {};
@@ -1,60 +1,70 @@
1
- import { createEvent } from '../createEvent/createEvent.es.js';
1
+ import { createEvent, isEventCreator } from '../createEvent/createEvent.es.js';
2
2
  import { SimpleEmitter } from '../stores/SimpleEmitter.es.js';
3
3
 
4
- function createReducer(name, initialState) {
5
- var _a;
4
+ function createReducer(nameOrOptions, initialStateArg) {
5
+ const { name, initialState } = typeof nameOrOptions === 'object'
6
+ ? nameOrOptions
7
+ : { name: nameOrOptions, initialState: initialStateArg };
6
8
  const reducers = {};
7
- return _a = class ReducerStore extends SimpleEmitter {
8
- constructor() {
9
- super();
10
- this.state = initialState;
11
- }
12
- static createEvents(model) {
13
- const eventNames = Object.keys(model);
14
- const events = {};
15
- eventNames.forEach((eventName) => {
16
- const handler = model[eventName];
17
- const eventCreator = createEvent(`${eventName}`);
18
- events[eventName] = eventCreator;
19
- ReducerStore.on(eventCreator, handler);
20
- });
21
- return events;
22
- }
23
- static on(eventOrType, reducer) {
24
- if (Array.isArray(eventOrType)) {
25
- eventOrType.forEach((event) => ReducerStore.on(event, reducer));
26
- return ReducerStore;
27
- }
28
- const type = eventOrType.toString();
29
- ReducerStore.handlers[type] = 'handle';
30
- reducers[type] = reducer;
9
+ class ReducerStore extends SimpleEmitter {
10
+ constructor() {
11
+ super();
12
+ this.state = initialState;
13
+ }
14
+ static createEvents(model) {
15
+ const eventNames = Object.keys(model);
16
+ const events = {};
17
+ eventNames.forEach((eventName) => {
18
+ const handler = model[eventName];
19
+ const eventCreator = createEvent(`${this.storeName}_${eventName}`);
20
+ events[eventName] = eventCreator;
21
+ ReducerStore.on(eventCreator, handler);
22
+ });
23
+ return events;
24
+ }
25
+ static on(eventOrType, reducer) {
26
+ if (Array.isArray(eventOrType)) {
27
+ eventOrType.forEach((event) => ReducerStore.on(event, reducer));
31
28
  return ReducerStore;
32
29
  }
33
- getState() {
34
- return this.state;
30
+ if (isEventCreator(eventOrType) && !eventOrType.store) {
31
+ // eslint-disable-next-line no-param-reassign
32
+ eventOrType.store = ReducerStore;
35
33
  }
36
- setState(state) {
37
- this.state = state;
38
- // обновление необходимо, иначе state-manager не пересчитает состояние
34
+ const type = eventOrType.toString();
35
+ ReducerStore.handlers[type] = 'handle';
36
+ reducers[type] = reducer;
37
+ return ReducerStore;
38
+ }
39
+ getState() {
40
+ return this.state;
41
+ }
42
+ setState(state) {
43
+ this.state = state;
44
+ // обновление необходимо, иначе state-manager не пересчитает состояние
45
+ this.emit('change');
46
+ }
47
+ dehydrate() {
48
+ return this.state;
49
+ }
50
+ rehydrate(state) {
51
+ this.state = state;
52
+ }
53
+ handle(payload, eventName) {
54
+ const reducer = reducers[eventName];
55
+ if (reducer) {
56
+ this.state = reducer(this.state, payload);
39
57
  this.emit('change');
40
58
  }
41
- dehydrate() {
42
- return this.state;
43
- }
44
- rehydrate(state) {
45
- this.state = state;
46
- }
47
- handle(payload, eventName) {
48
- const reducer = reducers[eventName];
49
- if (reducer) {
50
- this.state = reducer(this.state, payload);
51
- this.emit('change');
52
- }
53
- }
54
- },
55
- _a.storeName = name,
56
- _a.handlers = {},
57
- _a;
59
+ }
60
+ }
61
+ ReducerStore.storeName = name;
62
+ ReducerStore.events = undefined;
63
+ ReducerStore.handlers = {};
64
+ if (typeof nameOrOptions === 'object' && nameOrOptions.events) {
65
+ ReducerStore.events = ReducerStore.createEvents(nameOrOptions.events);
66
+ }
67
+ return ReducerStore;
58
68
  }
59
69
 
60
70
  export { createReducer };
@@ -5,60 +5,70 @@ Object.defineProperty(exports, '__esModule', { value: true });
5
5
  var createEvent = require('../createEvent/createEvent.js');
6
6
  var SimpleEmitter = require('../stores/SimpleEmitter.js');
7
7
 
8
- function createReducer(name, initialState) {
9
- var _a;
8
+ function createReducer(nameOrOptions, initialStateArg) {
9
+ const { name, initialState } = typeof nameOrOptions === 'object'
10
+ ? nameOrOptions
11
+ : { name: nameOrOptions, initialState: initialStateArg };
10
12
  const reducers = {};
11
- return _a = class ReducerStore extends SimpleEmitter.SimpleEmitter {
12
- constructor() {
13
- super();
14
- this.state = initialState;
15
- }
16
- static createEvents(model) {
17
- const eventNames = Object.keys(model);
18
- const events = {};
19
- eventNames.forEach((eventName) => {
20
- const handler = model[eventName];
21
- const eventCreator = createEvent.createEvent(`${eventName}`);
22
- events[eventName] = eventCreator;
23
- ReducerStore.on(eventCreator, handler);
24
- });
25
- return events;
26
- }
27
- static on(eventOrType, reducer) {
28
- if (Array.isArray(eventOrType)) {
29
- eventOrType.forEach((event) => ReducerStore.on(event, reducer));
30
- return ReducerStore;
31
- }
32
- const type = eventOrType.toString();
33
- ReducerStore.handlers[type] = 'handle';
34
- reducers[type] = reducer;
13
+ class ReducerStore extends SimpleEmitter.SimpleEmitter {
14
+ constructor() {
15
+ super();
16
+ this.state = initialState;
17
+ }
18
+ static createEvents(model) {
19
+ const eventNames = Object.keys(model);
20
+ const events = {};
21
+ eventNames.forEach((eventName) => {
22
+ const handler = model[eventName];
23
+ const eventCreator = createEvent.createEvent(`${this.storeName}_${eventName}`);
24
+ events[eventName] = eventCreator;
25
+ ReducerStore.on(eventCreator, handler);
26
+ });
27
+ return events;
28
+ }
29
+ static on(eventOrType, reducer) {
30
+ if (Array.isArray(eventOrType)) {
31
+ eventOrType.forEach((event) => ReducerStore.on(event, reducer));
35
32
  return ReducerStore;
36
33
  }
37
- getState() {
38
- return this.state;
34
+ if (createEvent.isEventCreator(eventOrType) && !eventOrType.store) {
35
+ // eslint-disable-next-line no-param-reassign
36
+ eventOrType.store = ReducerStore;
39
37
  }
40
- setState(state) {
41
- this.state = state;
42
- // обновление необходимо, иначе state-manager не пересчитает состояние
38
+ const type = eventOrType.toString();
39
+ ReducerStore.handlers[type] = 'handle';
40
+ reducers[type] = reducer;
41
+ return ReducerStore;
42
+ }
43
+ getState() {
44
+ return this.state;
45
+ }
46
+ setState(state) {
47
+ this.state = state;
48
+ // обновление необходимо, иначе state-manager не пересчитает состояние
49
+ this.emit('change');
50
+ }
51
+ dehydrate() {
52
+ return this.state;
53
+ }
54
+ rehydrate(state) {
55
+ this.state = state;
56
+ }
57
+ handle(payload, eventName) {
58
+ const reducer = reducers[eventName];
59
+ if (reducer) {
60
+ this.state = reducer(this.state, payload);
43
61
  this.emit('change');
44
62
  }
45
- dehydrate() {
46
- return this.state;
47
- }
48
- rehydrate(state) {
49
- this.state = state;
50
- }
51
- handle(payload, eventName) {
52
- const reducer = reducers[eventName];
53
- if (reducer) {
54
- this.state = reducer(this.state, payload);
55
- this.emit('change');
56
- }
57
- }
58
- },
59
- _a.storeName = name,
60
- _a.handlers = {},
61
- _a;
63
+ }
64
+ }
65
+ ReducerStore.storeName = name;
66
+ ReducerStore.events = undefined;
67
+ ReducerStore.handlers = {};
68
+ if (typeof nameOrOptions === 'object' && nameOrOptions.events) {
69
+ ReducerStore.events = ReducerStore.createEvents(nameOrOptions.events);
70
+ }
71
+ return ReducerStore;
62
72
  }
63
73
 
64
74
  exports.createReducer = createReducer;
@@ -0,0 +1 @@
1
+ export {};
@@ -32,15 +32,22 @@ class DispatcherContext extends SimpleEmitter {
32
32
  constructor(dispatcher, context, initialState, middlewares) {
33
33
  super();
34
34
  this.applyDispatch = (event) => {
35
- const eventHandlers = this.dispatcher.handlers[event.type] || [];
35
+ let eventHandlers = this.dispatcher.handlers[event.type] || [];
36
36
  if (!eventHandlers.length) {
37
- if (process.env.NODE_ENV === 'development') {
38
- console.warn(`
37
+ if (event.store) {
38
+ this.registerStore(event.store);
39
+ eventHandlers = this.dispatcher.handlers[event.type] || [];
40
+ }
41
+ else {
42
+ if (process.env.NODE_ENV === 'development') {
43
+ // fallback to previous versions of createEvent
44
+ console.warn(`
39
45
  The event "${event.type}" has been dispatched, but no reducers for this event were registered.
40
46
  Have you forgot to register reducer or add event handler in existing reducer?
41
47
  `);
48
+ }
49
+ return event.payload;
42
50
  }
43
- return event.payload;
44
51
  }
45
52
  this.applyHandlers(event, eventHandlers);
46
53
  return event.payload;
@@ -40,15 +40,22 @@ class DispatcherContext extends SimpleEmitter.SimpleEmitter {
40
40
  constructor(dispatcher, context, initialState, middlewares) {
41
41
  super();
42
42
  this.applyDispatch = (event) => {
43
- const eventHandlers = this.dispatcher.handlers[event.type] || [];
43
+ let eventHandlers = this.dispatcher.handlers[event.type] || [];
44
44
  if (!eventHandlers.length) {
45
- if (process.env.NODE_ENV === 'development') {
46
- console.warn(`
45
+ if (event.store) {
46
+ this.registerStore(event.store);
47
+ eventHandlers = this.dispatcher.handlers[event.type] || [];
48
+ }
49
+ else {
50
+ if (process.env.NODE_ENV === 'development') {
51
+ // fallback to previous versions of createEvent
52
+ console.warn(`
47
53
  The event "${event.type}" has been dispatched, but no reducers for this event were registered.
48
54
  Have you forgot to register reducer or add event handler in existing reducer?
49
55
  `);
56
+ }
57
+ return event.payload;
50
58
  }
51
- return event.payload;
52
59
  }
53
60
  this.applyHandlers(event, eventHandlers);
54
61
  return event.payload;
package/lib/index.es.js CHANGED
@@ -12,6 +12,7 @@ export { scheduling } from './connect/scheduling.es.js';
12
12
  export { Provider } from './connect/Provider.es.js';
13
13
  export { useConsumerContext } from './connect/hooks/useConsumerContext.es.js';
14
14
  export { useActions } from './connect/hooks/useActions.es.js';
15
+ export { useEvents } from './connect/hooks/useEvents.es.js';
15
16
  export { useStore } from './connect/hooks/useStore.es.js';
16
17
  export { useSelector } from './connect/hooks/useSelector.es.js';
17
18
  export { useStoreSelector } from './connect/hooks/useStoreSelector.es.js';
package/lib/index.js CHANGED
@@ -15,6 +15,7 @@ var scheduling = require('./connect/scheduling.js');
15
15
  var Provider = require('./connect/Provider.js');
16
16
  var useConsumerContext = require('./connect/hooks/useConsumerContext.js');
17
17
  var useActions = require('./connect/hooks/useActions.js');
18
+ var useEvents = require('./connect/hooks/useEvents.js');
18
19
  var useStore = require('./connect/hooks/useStore.js');
19
20
  var useSelector = require('./connect/hooks/useSelector.js');
20
21
  var useStoreSelector = require('./connect/hooks/useStoreSelector.js');
@@ -39,6 +40,7 @@ exports.scheduling = scheduling.scheduling;
39
40
  exports.Provider = Provider.Provider;
40
41
  exports.useConsumerContext = useConsumerContext.useConsumerContext;
41
42
  exports.useActions = useActions.useActions;
43
+ exports.useEvents = useEvents.useEvents;
42
44
  exports.useStore = useStore.useStore;
43
45
  exports.useSelector = useSelector.useSelector;
44
46
  exports.useStoreSelector = useStoreSelector.useStoreSelector;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tramvai/state",
3
- "version": "2.108.1",
3
+ "version": "2.109.0",
4
4
  "description": "",
5
5
  "main": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
@@ -19,7 +19,7 @@
19
19
  "dependencies": {
20
20
  "@tinkoff/react-hooks": "0.1.6",
21
21
  "@tinkoff/utils": "^2.1.2",
22
- "@tramvai/types-actions-state-context": "2.108.1",
22
+ "@tramvai/types-actions-state-context": "2.109.0",
23
23
  "@types/hoist-non-react-statics": "^3.3.1",
24
24
  "invariant": "^2.2.4",
25
25
  "react-is": ">=17",
@@ -34,7 +34,7 @@
34
34
  },
35
35
  "devDependencies": {
36
36
  "@reatom/core": "^1.1.5",
37
- "@tramvai/core": "2.108.1",
37
+ "@tramvai/core": "2.109.0",
38
38
  "@types/invariant": "^2.2.31",
39
39
  "@types/react-is": "^17.0.0",
40
40
  "@types/use-sync-external-store": "^0.0.3",