anu-verzum 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 +43 -40
- package/dist/core/components/AnulyticsProvider.js +1 -3
- package/dist/core/components/Connector.js +1 -3
- package/dist/core/components/Context.d.ts +8 -5
- package/dist/core/components/Context.js +2 -6
- package/dist/core/components/Fragment.js +1 -3
- package/dist/core/components/Intl.d.ts +2 -2
- package/dist/core/components/Intl.js +2 -2
- package/dist/core/elements.d.ts +2 -1
- package/dist/index.d.ts +7 -7
- package/dist/store/store.d.ts +8 -1
- package/package.json +3 -2
- package/dist/core/components/AnulyticsProvider.ts +0 -271
- package/dist/core/components/Component.ts +0 -39
- package/dist/core/components/Connector.ts +0 -190
- package/dist/core/components/Context.ts +0 -106
- package/dist/core/components/Feature.ts +0 -34
- package/dist/core/components/Fragment.ts +0 -20
- package/dist/core/components/History.ts +0 -208
- package/dist/core/components/Intl.ts +0 -214
- package/dist/core/domUtils.ts +0 -196
- package/dist/core/elements.ts +0 -44
- package/dist/core/reconciler.ts +0 -500
- package/dist/index.ts +0 -86
- package/dist/misc/utils.ts +0 -28
- package/dist/server-api/server-api.ts +0 -142
- package/dist/store/store.ts +0 -236
package/README.md
CHANGED
|
@@ -47,8 +47,12 @@ Anu.render(<App />, document.getElementById('root'));
|
|
|
47
47
|
<h3>TypeScript setup</h3>
|
|
48
48
|
|
|
49
49
|
The library is written in TypeScript and ships with declaration files (`.d.ts`) out of the box —
|
|
50
|
-
no extra `@types` package is needed.
|
|
51
|
-
|
|
50
|
+
no extra `@types` package is needed. The `dist/` directory contains only compiled `.js` files and
|
|
51
|
+
`.d.ts` declarations, so the package works correctly under all standard TypeScript `moduleResolution`
|
|
52
|
+
modes including `"node"`, `"node16"`, and `"bundler"`.
|
|
53
|
+
|
|
54
|
+
If your project uses TypeScript, add the following to your `tsconfig.json` so the compiler
|
|
55
|
+
understands JSX produced by ANUVerzum:
|
|
52
56
|
|
|
53
57
|
```json
|
|
54
58
|
{
|
|
@@ -116,11 +120,14 @@ The following types are exported from `anu-verzum` for use in consumer projects:
|
|
|
116
120
|
| Type | Description |
|
|
117
121
|
|------|-------------|
|
|
118
122
|
| `AnuElement` | The virtual-DOM element descriptor (return type of `createElement`) |
|
|
123
|
+
| `AnuChild` | Union of all valid JSX child types: `AnuElement \| string \| number \| boolean \| null \| undefined` |
|
|
119
124
|
| `Props` | Base props type — all component prop objects should extend this |
|
|
120
125
|
| `Ref<T>` | Reference object created by `Anu.createRef<T>()` |
|
|
121
126
|
| `Component<P, S>` | Abstract base class for class components |
|
|
122
127
|
| `FunctionComponent<P>` | Function component signature |
|
|
123
128
|
| `ElementType` | String tag, function component, or class component constructor |
|
|
129
|
+
| `ContextValue<T>` | Context value passed to a `Consumer` render-prop: `{ value: Partial<T>; defaultContext: { value: T } }` |
|
|
130
|
+
| `ConsumerProps<T>` | Props for a typed context `Consumer` — `children` is the render-prop `(ctx: ContextValue<T>) => AnuElement \| null` |
|
|
124
131
|
| `Store<S, A>` | Store instance returned by `Anu.store.createStore` |
|
|
125
132
|
| `Reducer<S, A>` | Reducer function signature |
|
|
126
133
|
| `Middleware<S, A>` | Middleware function signature |
|
|
@@ -128,6 +135,7 @@ The following types are exported from `anu-verzum` for use in consumer projects:
|
|
|
128
135
|
| `Action` | Base action type `{ type: string; [key: string]: any }` |
|
|
129
136
|
| `ThunkAction<S>` | Thunk action `(dispatch, getState) => any` |
|
|
130
137
|
| `SelectorFn<TInput, TOutput>` | Selector function signature for `createSelector` |
|
|
138
|
+
| `CreateSelectorFn` | Overloaded interface for `Anu.store.createSelector` — enables full type inference on transformation parameters |
|
|
131
139
|
| `ApiSuccessResponse<T>` | Successful HTTP response `{ status: number; response: T \| null }` |
|
|
132
140
|
| `ApiErrorResponse` | Error HTTP response `{ status: number; response: null }` |
|
|
133
141
|
|
|
@@ -136,7 +144,8 @@ The following types are exported from `anu-verzum` for use in consumer projects:
|
|
|
136
144
|
These scripts are available when working on the library itself:
|
|
137
145
|
|
|
138
146
|
```bash
|
|
139
|
-
npm run
|
|
147
|
+
npm run clean # Delete dist/ entirely
|
|
148
|
+
npm run build # Clean, compile TypeScript sources to dist/, and emit .d.ts files
|
|
140
149
|
npm run typecheck # Type-check without emitting any output
|
|
141
150
|
npm run lint # Run ESLint on all source files
|
|
142
151
|
npm run format # Format all source files with Prettier
|
|
@@ -1625,45 +1634,37 @@ It takes a <code>context</code> argument which can be reached later as <code>con
|
|
|
1625
1634
|
|
|
1626
1635
|
<h3 id="usage-of-context-provider-and-consumers">Usage of the context provider and its consumer(s)</h3>
|
|
1627
1636
|
|
|
1628
|
-
- Context props defined on <code><ThemedContext.
|
|
1637
|
+
- Context props defined on <code><ThemedContext.Provider /></code> can be accessed from within the function child of the <code><ThemedContext.Consumer /></code> as <code>context.value</code>.
|
|
1629
1638
|
- Context providers can have multiple context consumer descendents.
|
|
1630
1639
|
- Context consumers can have one function-as-a-child (which takes the <code>context</code> as argument) which must return a valid HTML, inline-SVG element, component (either class-based or function) or <code>null</code>.
|
|
1631
1640
|
- You can have as many elements between the context provider and consumer(s), as you want.<br>
|
|
1632
1641
|
No need to pass the <code>context</code> all the way down within the "props flow"; the function child of the context consumer will have access to it by default.<br>
|
|
1633
1642
|
It allows you to create your "intermediate" components without depending from the <code>context</code> (they don't need to be aware of it if they have nothing to do with it...).
|
|
1643
|
+
- In TypeScript projects use <code>Provider</code> / <code>Consumer</code> — the callback argument type is inferred from the `createContext<T>()` type parameter, so no manual annotation is needed.
|
|
1644
|
+
- **Avoid** <code>ContextProvider</code> / <code>ContextConsumer</code> in TypeScript projects. These aliases exist for internal use (e.g. by `Intl` and `Feature` modules) but carry looser types: the consumer callback argument is typed as `Props` instead of `ContextValue<T>`, so you lose type inference on `context.value` and `context.defaultContext`.
|
|
1634
1645
|
|
|
1635
1646
|
```typescript
|
|
1636
|
-
import Anu, { AnuElement
|
|
1647
|
+
import Anu, { AnuElement } from 'anu-verzum';
|
|
1637
1648
|
|
|
1638
1649
|
const ComponentWithContext = (): AnuElement => {
|
|
1639
1650
|
const theme2 = 'Theme-2';
|
|
1640
1651
|
return (
|
|
1641
|
-
<ThemedContext.
|
|
1652
|
+
<ThemedContext.Provider theme={theme2}>
|
|
1642
1653
|
<MyComponent1>
|
|
1643
1654
|
<MyComponentN>
|
|
1644
|
-
<ThemedContext.
|
|
1645
|
-
{(
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
}
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
}
|
|
1655
|
-
} = context;
|
|
1656
|
-
return (
|
|
1657
|
-
<Anu.Fragment>
|
|
1658
|
-
<span>{theme}</span>
|
|
1659
|
-
<span>{defaultTheme}</span>
|
|
1660
|
-
</Anu.Fragment>
|
|
1661
|
-
);
|
|
1662
|
-
}}
|
|
1663
|
-
</ThemedContext.ContextConsumer>
|
|
1655
|
+
<ThemedContext.Consumer>
|
|
1656
|
+
{({ value: { theme }, defaultContext: { value: { theme: defaultTheme } } }) => (
|
|
1657
|
+
// context type is inferred as ContextValue<ThemeContextValue>
|
|
1658
|
+
// theme → "Theme-2", defaultTheme → "Theme-1"
|
|
1659
|
+
<Anu.Fragment>
|
|
1660
|
+
<span>{theme}</span>
|
|
1661
|
+
<span>{defaultTheme}</span>
|
|
1662
|
+
</Anu.Fragment>
|
|
1663
|
+
)}
|
|
1664
|
+
</ThemedContext.Consumer>
|
|
1664
1665
|
</MyComponentN>
|
|
1665
1666
|
</MyComponent1>
|
|
1666
|
-
</ThemedContext.
|
|
1667
|
+
</ThemedContext.Provider>
|
|
1667
1668
|
);
|
|
1668
1669
|
};
|
|
1669
1670
|
```
|
|
@@ -1820,10 +1821,11 @@ it should return that part, with the updated desired values:
|
|
|
1820
1821
|
|
|
1821
1822
|
- Selectors are memoized functions which come handy if you need to do expensive calculations or conversions on the global state.
|
|
1822
1823
|
- To create selector, use the <code>Anu.store.createSelector()</code> (it comes handy in <code>mapStateToProps()</code> - see <a href="#connector-api">Connecting components to the global state - The Connector API</a> section):
|
|
1823
|
-
- Its first argument is an array of "getter" functions
|
|
1824
|
+
- Its first argument is either a single "getter" function or an array of up to four "getter" functions, each returning a desired slice of the global state object.
|
|
1824
1825
|
These functions must always return something.
|
|
1825
|
-
- The second argument is a "handler" function which
|
|
1826
|
-
Their number and order is the same as of the "getters" within the first
|
|
1826
|
+
- The second argument is a "handler" function which takes as many arguments as "getter" functions you defined; these arguments are the return values of the "getter" functions.
|
|
1827
|
+
Their number and order is the same as of the "getters" within the first argument of the <code>Anu.store.createSelector()</code>.
|
|
1828
|
+
- In TypeScript, when you pass the getter array inline, the handler's parameter types are inferred automatically — no manual annotations needed.
|
|
1827
1829
|
|
|
1828
1830
|
```typescript
|
|
1829
1831
|
import Anu, { SelectorFn } from 'anu-verzum';
|
|
@@ -1837,17 +1839,18 @@ it should return that part, with the updated desired values:
|
|
|
1837
1839
|
const getStatePart1: SelectorFn<MyGlobalState, string> = state => state.myStatePart1;
|
|
1838
1840
|
const getStatePart2: SelectorFn<MyGlobalState, number[]> = state => state.myStatePart2;
|
|
1839
1841
|
|
|
1840
|
-
//
|
|
1841
|
-
const
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
// Do something with the state-parts and return the result:
|
|
1846
|
-
return `${part1}: ${part2.join(', ')}`;
|
|
1847
|
-
};
|
|
1842
|
+
// Single getter — transformation receives the getter's return type directly:
|
|
1843
|
+
const mySimpleSelector = Anu.store.createSelector(
|
|
1844
|
+
getStatePart1,
|
|
1845
|
+
(part1) => part1.toUpperCase() // part1 inferred as string
|
|
1846
|
+
);
|
|
1848
1847
|
|
|
1849
|
-
//
|
|
1850
|
-
const mySelector
|
|
1848
|
+
// Multiple getters — pass the array inline so TypeScript can infer a tuple:
|
|
1849
|
+
const mySelector = Anu.store.createSelector(
|
|
1850
|
+
[getStatePart1, getStatePart2],
|
|
1851
|
+
(part1, part2) => `${part1}: ${part2.join(', ')}`
|
|
1852
|
+
// part1 inferred as string, part2 as number[]
|
|
1853
|
+
);
|
|
1851
1854
|
```
|
|
1852
1855
|
|
|
1853
1856
|
<h3 id="combining-reducers">Combining reducers</h3>
|
|
@@ -206,9 +206,7 @@ class AnulyticsProvider extends _Component.Component {
|
|
|
206
206
|
}
|
|
207
207
|
}
|
|
208
208
|
render() {
|
|
209
|
-
const
|
|
210
|
-
children
|
|
211
|
-
} = this.props;
|
|
209
|
+
const children = this.props.children;
|
|
212
210
|
try {
|
|
213
211
|
if (!children || children.length !== 1) {
|
|
214
212
|
throw new Error('Provider must have one child element!');
|
|
@@ -32,9 +32,7 @@ class Provider extends _Component.Component {
|
|
|
32
32
|
});
|
|
33
33
|
}
|
|
34
34
|
render() {
|
|
35
|
-
const
|
|
36
|
-
children
|
|
37
|
-
} = this.props;
|
|
35
|
+
const children = this.props.children;
|
|
38
36
|
try {
|
|
39
37
|
if (!children || children.length !== 1) {
|
|
40
38
|
throw new Error('Provider must have one child element!');
|
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
import { Component } from './Component';
|
|
2
|
-
import { Props } from '../elements';
|
|
2
|
+
import { AnuElement, Props } from '../elements';
|
|
3
3
|
export type ContextValue<T> = {
|
|
4
4
|
value: Partial<T>;
|
|
5
5
|
defaultContext: {
|
|
6
6
|
value: T;
|
|
7
7
|
};
|
|
8
8
|
};
|
|
9
|
-
export type
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
export type ConsumerProps<T> = {
|
|
10
|
+
children: (ctx: ContextValue<T>) => AnuElement | null;
|
|
11
|
+
};
|
|
12
|
+
export type Context<T extends Record<string, any> = Record<string, any>> = {
|
|
13
|
+
Provider: new (props: Props & Partial<T>) => Component;
|
|
14
|
+
Consumer: new (props: ConsumerProps<T>) => Component;
|
|
12
15
|
ContextProvider: new (props: Props) => Component;
|
|
13
16
|
ContextConsumer: new (props: Props) => Component;
|
|
14
17
|
};
|
|
15
|
-
export declare const createContext: <T extends Record<string, any> = Record<string, any>>(context: T) => Context
|
|
18
|
+
export declare const createContext: <T extends Record<string, any> = Record<string, any>>(context: T) => Context<T>;
|
|
@@ -40,9 +40,7 @@ const createContext = context => {
|
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
42
|
render() {
|
|
43
|
-
const
|
|
44
|
-
children
|
|
45
|
-
} = this.props;
|
|
43
|
+
const children = this.props.children;
|
|
46
44
|
try {
|
|
47
45
|
if (!children || children.length !== 1) {
|
|
48
46
|
throw new Error('Context Component must have exactly one child element!');
|
|
@@ -62,9 +60,7 @@ const createContext = context => {
|
|
|
62
60
|
}
|
|
63
61
|
}
|
|
64
62
|
render() {
|
|
65
|
-
const
|
|
66
|
-
children
|
|
67
|
-
} = this.props;
|
|
63
|
+
const children = this.props.children;
|
|
68
64
|
const {
|
|
69
65
|
value,
|
|
70
66
|
defaultContext
|
|
@@ -7,9 +7,7 @@ exports.Fragment = void 0;
|
|
|
7
7
|
var _Component = require("./Component");
|
|
8
8
|
class Fragment extends _Component.Component {
|
|
9
9
|
render() {
|
|
10
|
-
const
|
|
11
|
-
children
|
|
12
|
-
} = this.props;
|
|
10
|
+
const children = this.props.children;
|
|
13
11
|
try {
|
|
14
12
|
if (!children || !children.length) {
|
|
15
13
|
throw new Error('Fragment must have at least one child element!');
|
|
@@ -17,8 +17,8 @@ export interface AbbreviateNumberOptions {
|
|
|
17
17
|
}
|
|
18
18
|
declare const Intl: {
|
|
19
19
|
abbreviateNumber: (value: number, options?: AbbreviateNumberOptions) => string | number;
|
|
20
|
-
FormattedMessage: ({ id, values, defaultMessage }: FormattedMessageProps) => AnuElement
|
|
20
|
+
FormattedMessage: ({ id, values, defaultMessage }: FormattedMessageProps) => AnuElement;
|
|
21
21
|
formatMessage: (id: string, values?: Record<string, string | number>, defaultMessage?: string) => string;
|
|
22
|
-
Provider: ({ locale, messages, defaultLocale, children }: IntlProviderProps) => AnuElement |
|
|
22
|
+
Provider: ({ locale, messages, defaultLocale, children }: IntlProviderProps) => AnuElement | null;
|
|
23
23
|
};
|
|
24
24
|
export default Intl;
|
|
@@ -46,7 +46,7 @@ const IntlProvider = ({
|
|
|
46
46
|
}
|
|
47
47
|
} catch (err) {
|
|
48
48
|
console.error(err);
|
|
49
|
-
return
|
|
49
|
+
return null;
|
|
50
50
|
}
|
|
51
51
|
};
|
|
52
52
|
const interpolateValues = (text, values) => {
|
|
@@ -89,7 +89,7 @@ const FormattedMessage = ({
|
|
|
89
89
|
}
|
|
90
90
|
} catch (err) {
|
|
91
91
|
console.error(err);
|
|
92
|
-
return
|
|
92
|
+
return null;
|
|
93
93
|
}
|
|
94
94
|
});
|
|
95
95
|
const formatMessage = (id, values, defaultMessage) => {
|
package/dist/core/elements.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export declare const TEXT_ELEMENT: "TEXT_ELEMENT";
|
|
2
|
+
export type AnuChild = AnuElement | string | number | boolean | null | undefined;
|
|
2
3
|
export type Props = {
|
|
3
|
-
children?:
|
|
4
|
+
children?: AnuChild | AnuChild[];
|
|
4
5
|
ref?: Ref<any>;
|
|
5
6
|
key?: string | number;
|
|
6
7
|
style?: Partial<CSSStyleDeclaration & Record<string, string>>;
|
package/dist/index.d.ts
CHANGED
|
@@ -27,7 +27,7 @@ declare const Anu: {
|
|
|
27
27
|
};
|
|
28
28
|
}, props?: unknown) => void;
|
|
29
29
|
};
|
|
30
|
-
createContext: <T extends Record<string, any> = Record<string, any>>(context: T) => import("./core/components/Context").Context
|
|
30
|
+
createContext: <T extends Record<string, any> = Record<string, any>>(context: T) => import("./core/components/Context").Context<T>;
|
|
31
31
|
createElement: (type: import(".").ElementType, config: Props | null, ...args: any[]) => AnuElement;
|
|
32
32
|
createRef: <T = any>() => import("./core/reconciler").Ref<T>;
|
|
33
33
|
Component: typeof Component;
|
|
@@ -88,9 +88,9 @@ declare const Anu: {
|
|
|
88
88
|
};
|
|
89
89
|
Intl: {
|
|
90
90
|
abbreviateNumber: (value: number, options?: import(".").AbbreviateNumberOptions) => string | number;
|
|
91
|
-
FormattedMessage: ({ id, values, defaultMessage }: import("./core/components/Intl").FormattedMessageProps) => AnuElement
|
|
91
|
+
FormattedMessage: ({ id, values, defaultMessage }: import("./core/components/Intl").FormattedMessageProps) => AnuElement;
|
|
92
92
|
formatMessage: (id: string, values?: Record<string, string | number>, defaultMessage?: string) => string;
|
|
93
|
-
Provider: ({ locale, messages, defaultLocale, children }: import("./core/components/Intl").IntlProviderProps) => AnuElement |
|
|
93
|
+
Provider: ({ locale, messages, defaultLocale, children }: import("./core/components/Intl").IntlProviderProps) => AnuElement | null;
|
|
94
94
|
};
|
|
95
95
|
Connector: {
|
|
96
96
|
connect: <TState = any, TOwnProps extends Props = Props, TStateProps extends Props = Props, TDispatchProps extends Props = Props>(mapStateToProps?: ((state: TState, ownProps: TOwnProps) => TStateProps) | null, mapDispatchToProps?: ((dispatch: any, ownProps: TOwnProps) => TDispatchProps) | null) => (WrappedComponent: import("./core/elements").ComponentConstructor<TStateProps & TDispatchProps & TOwnProps>) => import("./core/elements").ComponentConstructor;
|
|
@@ -124,7 +124,7 @@ declare const Anu: {
|
|
|
124
124
|
};
|
|
125
125
|
store: {
|
|
126
126
|
combineReducers: <S extends Record<string, any> = Record<string, any>>(reducers: { [K in keyof S]: import(".").Reducer<S[K]>; }) => import(".").Reducer<S>;
|
|
127
|
-
createSelector:
|
|
127
|
+
createSelector: import(".").CreateSelectorFn;
|
|
128
128
|
createStore: <S = any, A extends import(".").Action = import(".").Action>(reducer: import(".").Reducer<S, A>, initialState: S, middleware?: import(".").Middleware<S, A>) => import(".").Store<S, A>;
|
|
129
129
|
middleware: {
|
|
130
130
|
applyMiddleware: <S = any, A extends import(".").Action = import(".").Action>(...middlewares: Array<import(".").Middleware<S, A>>) => (store: import(".").MiddlewareAPI<S, A>) => ((next: import(".").Dispatch<A>) => import(".").Dispatch<A>);
|
|
@@ -136,9 +136,9 @@ declare const Anu: {
|
|
|
136
136
|
deepEqual: (object1: Record<string, any>, object2: Record<string, any>) => boolean;
|
|
137
137
|
};
|
|
138
138
|
};
|
|
139
|
-
export type { AnuElement, Props, Ref, FunctionComponent, ElementType } from './core/elements';
|
|
140
|
-
export type { ContextValue } from './core/components/Context';
|
|
141
|
-
export type { Action, ThunkAction, Dispatch, Reducer, MiddlewareAPI, Middleware, Store, SelectorFn } from './store/store';
|
|
139
|
+
export type { AnuElement, AnuChild, Props, Ref, FunctionComponent, ElementType } from './core/elements';
|
|
140
|
+
export type { ContextValue, ConsumerProps } from './core/components/Context';
|
|
141
|
+
export type { Action, ThunkAction, Dispatch, Reducer, MiddlewareAPI, Middleware, Store, SelectorFn, CreateSelectorFn } from './store/store';
|
|
142
142
|
export type { ApiSuccessResponse, ApiErrorResponse } from './server-api/server-api';
|
|
143
143
|
export { Component, Fragment, createElement, createRef, createContext, render, goTo };
|
|
144
144
|
export { AnulyticsProvider, trackEvent };
|
package/dist/store/store.d.ts
CHANGED
|
@@ -17,9 +17,16 @@ export type Store<S = any, A extends Action = Action> = {
|
|
|
17
17
|
unsubscribe: (listener: () => void) => void;
|
|
18
18
|
};
|
|
19
19
|
export type SelectorFn<TInput = any, TOutput = any> = (input: TInput) => TOutput;
|
|
20
|
+
export interface CreateSelectorFn {
|
|
21
|
+
<TInput, TI, TOutput>(dep: SelectorFn<TInput, TI>, fn: (r: TI) => TOutput): SelectorFn<TInput, TOutput>;
|
|
22
|
+
<TInput, T1, TOutput>(deps: [SelectorFn<TInput, T1>], fn: (r1: T1) => TOutput): SelectorFn<TInput, TOutput>;
|
|
23
|
+
<TInput, T1, T2, TOutput>(deps: [SelectorFn<TInput, T1>, SelectorFn<TInput, T2>], fn: (r1: T1, r2: T2) => TOutput): SelectorFn<TInput, TOutput>;
|
|
24
|
+
<TInput, T1, T2, T3, TOutput>(deps: [SelectorFn<TInput, T1>, SelectorFn<TInput, T2>, SelectorFn<TInput, T3>], fn: (r1: T1, r2: T2, r3: T3) => TOutput): SelectorFn<TInput, TOutput>;
|
|
25
|
+
<TInput, T1, T2, T3, T4, TOutput>(deps: [SelectorFn<TInput, T1>, SelectorFn<TInput, T2>, SelectorFn<TInput, T3>, SelectorFn<TInput, T4>], fn: (r1: T1, r2: T2, r3: T3, r4: T4) => TOutput): SelectorFn<TInput, TOutput>;
|
|
26
|
+
}
|
|
20
27
|
declare const store: {
|
|
21
28
|
combineReducers: <S extends Record<string, any> = Record<string, any>>(reducers: { [K in keyof S]: Reducer<S[K]>; }) => Reducer<S>;
|
|
22
|
-
createSelector:
|
|
29
|
+
createSelector: CreateSelectorFn;
|
|
23
30
|
createStore: <S = any, A extends Action = Action>(reducer: Reducer<S, A>, initialState: S, middleware?: Middleware<S, A>) => Store<S, A>;
|
|
24
31
|
middleware: {
|
|
25
32
|
applyMiddleware: <S = any, A extends Action = Action>(...middlewares: Array<Middleware<S, A>>) => (store: MiddlewareAPI<S, A>) => ((next: Dispatch<A>) => Dispatch<A>);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "anu-verzum",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.9.0",
|
|
4
4
|
"description": "A \"React-like\" UI library that supports JSX syntax, Redux-like state management, array-rendering, i18n, routing and many more.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"anu-verzum",
|
|
@@ -29,7 +29,8 @@
|
|
|
29
29
|
"main": "dist/index.js",
|
|
30
30
|
"types": "dist/index.d.ts",
|
|
31
31
|
"scripts": {
|
|
32
|
-
"
|
|
32
|
+
"clean": "node -e \"require('fs').rmSync('dist', {recursive:true, force:true})\"",
|
|
33
|
+
"build": "npm run clean && babel src --out-dir dist --extensions \".ts\" && tsc --emitDeclarationOnly",
|
|
33
34
|
"typecheck": "tsc --noEmit",
|
|
34
35
|
"lint": "eslint src",
|
|
35
36
|
"format": "prettier --write src",
|
|
@@ -1,271 +0,0 @@
|
|
|
1
|
-
import { Component } from './Component';
|
|
2
|
-
import { AnuElement, Props } from '../elements';
|
|
3
|
-
import ServerAPI from '../../server-api/server-api';
|
|
4
|
-
|
|
5
|
-
const EventTypes = {
|
|
6
|
-
INITIALIZATION: 'initialization',
|
|
7
|
-
USER_ACTION: 'userAction',
|
|
8
|
-
STATE_CHANGE: 'stateChange',
|
|
9
|
-
NAVIGATION: 'navigation',
|
|
10
|
-
PAGE_LEAVE: 'pageLeave'
|
|
11
|
-
} as const;
|
|
12
|
-
|
|
13
|
-
type AnulyticsData = {
|
|
14
|
-
startDate: number;
|
|
15
|
-
events: Array<Record<string, any>>;
|
|
16
|
-
user: Record<string, any>;
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
type UserActionEvent = {
|
|
20
|
-
type: string;
|
|
21
|
-
keyCode?: number | null;
|
|
22
|
-
pageX?: number;
|
|
23
|
-
pageY?: number;
|
|
24
|
-
target?: {
|
|
25
|
-
id?: string;
|
|
26
|
-
name?: string;
|
|
27
|
-
nodeName?: string;
|
|
28
|
-
value?: string;
|
|
29
|
-
};
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
const AnulyticsState = (() => {
|
|
33
|
-
const initStart = new Date().getTime();
|
|
34
|
-
let _anulyticsInstanceExist = false;
|
|
35
|
-
|
|
36
|
-
const setAnulyticsInstanceExist = (instanceExist: boolean): void => {
|
|
37
|
-
_anulyticsInstanceExist = instanceExist;
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
const getAnulyticsInstanceExist = (): boolean => _anulyticsInstanceExist;
|
|
41
|
-
|
|
42
|
-
const _anulytics: AnulyticsData = {
|
|
43
|
-
startDate: initStart,
|
|
44
|
-
events: [
|
|
45
|
-
{
|
|
46
|
-
[EventTypes.INITIALIZATION]: {
|
|
47
|
-
eventType: window.location.pathname,
|
|
48
|
-
timestamp: initStart,
|
|
49
|
-
properties: {}
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
],
|
|
53
|
-
user: {}
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
return {
|
|
57
|
-
getAnulyticsInstanceExist,
|
|
58
|
-
setAnulyticsInstanceExist,
|
|
59
|
-
addEvent: (key: string, val: Record<string, any>): void => {
|
|
60
|
-
_anulytics.events.push({ [key]: val });
|
|
61
|
-
},
|
|
62
|
-
trackEvent: (
|
|
63
|
-
{
|
|
64
|
-
type,
|
|
65
|
-
keyCode = null,
|
|
66
|
-
pageX = 0,
|
|
67
|
-
pageY = 0,
|
|
68
|
-
target: { id = '', name = '', nodeName = '', value = '' } = {}
|
|
69
|
-
}: UserActionEvent,
|
|
70
|
-
rawProps: unknown
|
|
71
|
-
): void => {
|
|
72
|
-
const scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
|
|
73
|
-
const scrollLeft = document.body.scrollLeft || document.documentElement.scrollLeft;
|
|
74
|
-
const props =
|
|
75
|
-
typeof rawProps === 'object' && !Array.isArray(rawProps) && rawProps !== null
|
|
76
|
-
? (rawProps as Record<string, any>)
|
|
77
|
-
: null;
|
|
78
|
-
|
|
79
|
-
const event = {
|
|
80
|
-
[EventTypes.USER_ACTION]: {
|
|
81
|
-
eventType: type,
|
|
82
|
-
timestamp: new Date().getTime(),
|
|
83
|
-
properties: {
|
|
84
|
-
id,
|
|
85
|
-
keyCode,
|
|
86
|
-
name,
|
|
87
|
-
nodeName,
|
|
88
|
-
value,
|
|
89
|
-
pageX,
|
|
90
|
-
pageY,
|
|
91
|
-
scrollTop,
|
|
92
|
-
scrollLeft,
|
|
93
|
-
url: window.location.pathname,
|
|
94
|
-
props
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
};
|
|
98
|
-
|
|
99
|
-
_anulytics.events.push(event);
|
|
100
|
-
},
|
|
101
|
-
trackStateChange: (
|
|
102
|
-
prevState: Record<string, any>,
|
|
103
|
-
action: Record<string, any>,
|
|
104
|
-
nextState: Record<string, any>
|
|
105
|
-
): void => {
|
|
106
|
-
const event = {
|
|
107
|
-
[EventTypes.STATE_CHANGE]: {
|
|
108
|
-
eventType: action['type'],
|
|
109
|
-
timestamp: new Date().getTime(),
|
|
110
|
-
properties: {
|
|
111
|
-
url: window.location.pathname,
|
|
112
|
-
prevState,
|
|
113
|
-
action,
|
|
114
|
-
nextState
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
};
|
|
118
|
-
|
|
119
|
-
_anulytics.events.push(event);
|
|
120
|
-
},
|
|
121
|
-
setUser: (user: Record<string, any> | null | undefined): void => {
|
|
122
|
-
_anulytics.user = user || {};
|
|
123
|
-
},
|
|
124
|
-
getAnulyticsData: (): AnulyticsData => _anulytics
|
|
125
|
-
};
|
|
126
|
-
})();
|
|
127
|
-
|
|
128
|
-
const _isBot: boolean = !!(
|
|
129
|
-
(window as any).phantom ||
|
|
130
|
-
(window as any)._phantom ||
|
|
131
|
-
(window as any).__nightmare ||
|
|
132
|
-
window.navigator.webdriver ||
|
|
133
|
-
(window as any).Cypress
|
|
134
|
-
);
|
|
135
|
-
|
|
136
|
-
const _isInstalled = (): boolean => {
|
|
137
|
-
if ((window.navigator as any).standalone) {
|
|
138
|
-
return true;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
if (window.matchMedia('(display-mode: standalone)').matches) {
|
|
142
|
-
return true;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
return false;
|
|
146
|
-
};
|
|
147
|
-
|
|
148
|
-
export const trackEvent = (event: UserActionEvent, props?: unknown): void => {
|
|
149
|
-
if (AnulyticsState.getAnulyticsInstanceExist()) {
|
|
150
|
-
AnulyticsState.trackEvent(event, props);
|
|
151
|
-
}
|
|
152
|
-
};
|
|
153
|
-
|
|
154
|
-
export const trackStateChange = (
|
|
155
|
-
prevState: Record<string, any>,
|
|
156
|
-
action: Record<string, any>,
|
|
157
|
-
nextState: Record<string, any>
|
|
158
|
-
): void => {
|
|
159
|
-
if (AnulyticsState.getAnulyticsInstanceExist()) {
|
|
160
|
-
AnulyticsState.trackStateChange(prevState, action, nextState);
|
|
161
|
-
}
|
|
162
|
-
};
|
|
163
|
-
|
|
164
|
-
export const trackRouteChange = (path?: string): void => {
|
|
165
|
-
if (AnulyticsState.getAnulyticsInstanceExist()) {
|
|
166
|
-
const url = path || window.location.pathname;
|
|
167
|
-
const event = {
|
|
168
|
-
eventType: url,
|
|
169
|
-
timestamp: new Date().getTime(),
|
|
170
|
-
properties: {}
|
|
171
|
-
};
|
|
172
|
-
|
|
173
|
-
AnulyticsState.addEvent(EventTypes.NAVIGATION, event);
|
|
174
|
-
}
|
|
175
|
-
};
|
|
176
|
-
|
|
177
|
-
export interface AnulyticsProviderProps extends Props {
|
|
178
|
-
analyticsUrl: string;
|
|
179
|
-
userData?: Record<string, any>;
|
|
180
|
-
onSuccess: (response: any) => void;
|
|
181
|
-
onFail: (status: number) => void;
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
class AnulyticsProvider extends Component<AnulyticsProviderProps> {
|
|
185
|
-
constructor(props: AnulyticsProviderProps) {
|
|
186
|
-
super(props);
|
|
187
|
-
AnulyticsState.setAnulyticsInstanceExist(true);
|
|
188
|
-
this.handleVisibilityChange = this.handleVisibilityChange.bind(this);
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
componentDidMount(): void {
|
|
192
|
-
const { userData } = this.props;
|
|
193
|
-
AnulyticsState.setUser(userData || null);
|
|
194
|
-
|
|
195
|
-
document.addEventListener('visibilitychange', this.handleVisibilityChange, {
|
|
196
|
-
passive: true
|
|
197
|
-
});
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
componentWillUnmount(): void {
|
|
201
|
-
document.removeEventListener('visibilitychange', this.handleVisibilityChange as EventListener);
|
|
202
|
-
AnulyticsState.setAnulyticsInstanceExist(false);
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
handleVisibilityChange(): void {
|
|
206
|
-
const { analyticsUrl, onSuccess, onFail } = this.props;
|
|
207
|
-
|
|
208
|
-
if (_isBot) {
|
|
209
|
-
return;
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
if (document.visibilityState === 'hidden') {
|
|
213
|
-
const url = window.location.pathname;
|
|
214
|
-
const event = {
|
|
215
|
-
eventType: url,
|
|
216
|
-
timestamp: new Date().getTime(),
|
|
217
|
-
properties: {}
|
|
218
|
-
};
|
|
219
|
-
let ua: { userAgent: any; mobile: boolean; platform: string };
|
|
220
|
-
|
|
221
|
-
AnulyticsState.addEvent(EventTypes.PAGE_LEAVE, event);
|
|
222
|
-
|
|
223
|
-
if ((window.navigator as any).userAgentData) {
|
|
224
|
-
const { brands, mobile, platform } = (window.navigator as any).userAgentData;
|
|
225
|
-
|
|
226
|
-
ua = { userAgent: brands, mobile, platform };
|
|
227
|
-
} else {
|
|
228
|
-
ua = {
|
|
229
|
-
userAgent: window.navigator.userAgent,
|
|
230
|
-
mobile: false,
|
|
231
|
-
platform: ''
|
|
232
|
-
};
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
const data = {
|
|
236
|
-
...AnulyticsState.getAnulyticsData(),
|
|
237
|
-
endDate: new Date().getTime(),
|
|
238
|
-
system: {
|
|
239
|
-
referrer: document.referrer || null,
|
|
240
|
-
innerWidth: window.innerWidth,
|
|
241
|
-
isMobileAppInstalled: _isInstalled(),
|
|
242
|
-
userAgentData: ua
|
|
243
|
-
}
|
|
244
|
-
};
|
|
245
|
-
|
|
246
|
-
ServerAPI.post(analyticsUrl, data)
|
|
247
|
-
.then(({ response }) => onSuccess(response))
|
|
248
|
-
.catch(({ status }) => onFail(status));
|
|
249
|
-
} else {
|
|
250
|
-
this.setState();
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
render(): AnuElement | AnuElement[] | null {
|
|
255
|
-
const { children } = this.props;
|
|
256
|
-
|
|
257
|
-
try {
|
|
258
|
-
if (!children || children.length !== 1) {
|
|
259
|
-
throw new Error('Provider must have one child element!');
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
return children;
|
|
263
|
-
} catch (err) {
|
|
264
|
-
console.error(err);
|
|
265
|
-
|
|
266
|
-
return null;
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
export default AnulyticsProvider;
|