@veams/status-quo 1.5.1 → 1.7.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/.turbo/turbo-build.log +12 -0
- package/.turbo/turbo-check$colon$types.log +4 -0
- package/.turbo/turbo-docs$colon$build.log +14 -0
- package/.turbo/turbo-lint.log +8 -0
- package/.turbo/turbo-test.log +15 -0
- package/CHANGELOG.md +24 -3
- package/README.md +217 -41
- package/dist/config/status-quo-config.d.ts +13 -0
- package/dist/config/status-quo-config.js +14 -0
- package/dist/config/status-quo-config.js.map +1 -1
- package/dist/hooks/__tests__/state-provider.spec.d.ts +4 -0
- package/dist/hooks/__tests__/state-provider.spec.js +179 -0
- package/dist/hooks/__tests__/state-provider.spec.js.map +1 -0
- package/dist/hooks/__tests__/state-selector.spec.js +11 -12
- package/dist/hooks/__tests__/state-selector.spec.js.map +1 -1
- package/dist/hooks/__tests__/state-singleton.spec.js +10 -11
- package/dist/hooks/__tests__/state-singleton.spec.js.map +1 -1
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/index.js +1 -0
- package/dist/hooks/index.js.map +1 -1
- package/dist/hooks/state-factory.js.map +1 -1
- package/dist/hooks/state-provider.d.ts +14 -0
- package/dist/hooks/state-provider.js +24 -0
- package/dist/hooks/state-provider.js.map +1 -0
- package/dist/hooks/state-subscription-selector.js +6 -2
- package/dist/hooks/state-subscription-selector.js.map +1 -1
- package/dist/hooks/state-subscription.js +1 -1
- package/dist/hooks/state-subscription.js.map +1 -1
- package/dist/index.d.ts +4 -5
- package/dist/index.js +2 -3
- package/dist/index.js.map +1 -1
- package/dist/react/hooks/__tests__/state-provider.spec.d.ts +4 -0
- package/dist/react/hooks/__tests__/state-provider.spec.js +179 -0
- package/dist/react/hooks/__tests__/state-provider.spec.js.map +1 -0
- package/dist/react/hooks/__tests__/state-selector.spec.d.ts +4 -0
- package/dist/react/hooks/__tests__/state-selector.spec.js +547 -0
- package/dist/react/hooks/__tests__/state-selector.spec.js.map +1 -0
- package/dist/react/hooks/__tests__/state-singleton.spec.d.ts +4 -0
- package/dist/react/hooks/__tests__/state-singleton.spec.js +96 -0
- package/dist/react/hooks/__tests__/state-singleton.spec.js.map +1 -0
- package/{src/hooks/index.ts → dist/react/hooks/index.d.ts} +1 -0
- package/dist/react/hooks/index.js +7 -0
- package/dist/react/hooks/index.js.map +1 -0
- package/dist/react/hooks/state-actions.d.ts +2 -0
- package/dist/react/hooks/state-actions.js +5 -0
- package/dist/react/hooks/state-actions.js.map +1 -0
- package/dist/react/hooks/state-factory.d.ts +7 -0
- package/dist/react/hooks/state-factory.js +13 -0
- package/dist/react/hooks/state-factory.js.map +1 -0
- package/dist/react/hooks/state-handler.d.ts +2 -0
- package/dist/react/hooks/state-handler.js +9 -0
- package/dist/react/hooks/state-handler.js.map +1 -0
- package/dist/react/hooks/state-provider.d.ts +14 -0
- package/dist/react/hooks/state-provider.js +24 -0
- package/dist/react/hooks/state-provider.js.map +1 -0
- package/dist/react/hooks/state-singleton.d.ts +6 -0
- package/dist/react/hooks/state-singleton.js +7 -0
- package/dist/react/hooks/state-singleton.js.map +1 -0
- package/dist/react/hooks/state-subscription-selector.d.ts +3 -0
- package/dist/react/hooks/state-subscription-selector.js +114 -0
- package/dist/react/hooks/state-subscription-selector.js.map +1 -0
- package/dist/react/hooks/state-subscription.d.ts +9 -0
- package/dist/react/hooks/state-subscription.js +53 -0
- package/dist/react/hooks/state-subscription.js.map +1 -0
- package/dist/react/index.d.ts +1 -0
- package/dist/react/index.js +2 -0
- package/dist/react/index.js.map +1 -0
- package/dist/store/__tests__/observable-state-handler.spec.js +66 -11
- package/dist/store/__tests__/observable-state-handler.spec.js.map +1 -1
- package/dist/store/__tests__/signal-state-handler.spec.js.map +1 -1
- package/dist/store/base-state-handler.d.ts +3 -5
- package/dist/store/base-state-handler.js +10 -9
- package/dist/store/base-state-handler.js.map +1 -1
- package/dist/store/dev-tools.js +0 -3
- package/dist/store/dev-tools.js.map +1 -1
- package/dist/store/observable-state-handler.d.ts +4 -10
- package/dist/store/observable-state-handler.js +4 -11
- package/dist/store/observable-state-handler.js.map +1 -1
- package/dist/store/signal-state-handler.d.ts +2 -5
- package/dist/store/signal-state-handler.js +3 -2
- package/dist/store/signal-state-handler.js.map +1 -1
- package/dist/store/state-singleton.js +1 -1
- package/dist/store/state-singleton.js.map +1 -1
- package/eslint.config.mjs +75 -0
- package/package.json +18 -18
- package/src/config/status-quo-config.ts +31 -1
- package/src/index.ts +11 -15
- package/src/react/hooks/__tests__/state-provider.spec.tsx +286 -0
- package/src/{hooks → react/hooks}/__tests__/state-selector.spec.tsx +118 -44
- package/src/{hooks → react/hooks}/__tests__/state-singleton.spec.tsx +21 -20
- package/src/react/hooks/index.ts +11 -0
- package/src/{hooks → react/hooks}/state-actions.tsx +1 -1
- package/src/{hooks → react/hooks}/state-factory.tsx +2 -2
- package/src/{hooks → react/hooks}/state-handler.tsx +1 -1
- package/src/react/hooks/state-provider.tsx +56 -0
- package/src/{hooks → react/hooks}/state-singleton.tsx +1 -1
- package/src/react/hooks/state-subscription-selector.tsx +190 -0
- package/src/{hooks → react/hooks}/state-subscription.tsx +5 -9
- package/src/react/index.ts +1 -0
- package/src/store/__tests__/observable-state-handler.spec.ts +92 -13
- package/src/store/__tests__/signal-state-handler.spec.ts +5 -1
- package/src/store/base-state-handler.ts +17 -22
- package/src/store/dev-tools.ts +3 -3
- package/src/store/observable-state-handler.ts +12 -22
- package/src/store/signal-state-handler.ts +11 -8
- package/src/store/state-singleton.ts +1 -1
- package/tsconfig.json +2 -3
- package/.eslintrc.cjs +0 -132
- package/.github/workflows/pages.yml +0 -46
- package/.github/workflows/release.yml +0 -33
- package/.nvmrc +0 -1
- package/.prettierrc +0 -7
- package/docs/assets/index-BBmpszOW.css +0 -1
- package/docs/assets/index-Cf8El_RO.js +0 -194
- package/docs/assets/statusquo-logo-8GVRbxpc.png +0 -0
- package/docs/index.html +0 -13
- package/playground/index.html +0 -12
- package/playground/src/App.tsx +0 -699
- package/playground/src/assets/philosophy-agnostic.svg +0 -18
- package/playground/src/assets/philosophy-separation.svg +0 -13
- package/playground/src/assets/philosophy-swap.svg +0 -17
- package/playground/src/assets/statusquo-logo.png +0 -0
- package/playground/src/main.tsx +0 -19
- package/playground/src/styles.css +0 -534
- package/playground/tsconfig.json +0 -12
- package/playground/vite.config.ts +0 -18
- package/src/hooks/state-subscription-selector.tsx +0 -111
|
@@ -1,22 +1,17 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { resolveDevToolsOptions } from '../config/status-quo-config.js';
|
|
2
2
|
import { createSelectorCache, selectWithCache } from '../utils/selector-cache.js';
|
|
3
|
+
import { withDevTools } from './dev-tools.js';
|
|
3
4
|
|
|
4
5
|
import type { StateSubscriptionHandler } from '../types/types.js';
|
|
5
|
-
import type { DevTools, MessagePayload } from './dev-tools.js';
|
|
6
6
|
import type { EqualityFn, Selector } from '../utils/selector-cache.js';
|
|
7
|
-
|
|
8
|
-
type DevToolsOptions
|
|
9
|
-
enabled?: boolean;
|
|
10
|
-
namespace: string;
|
|
11
|
-
};
|
|
7
|
+
import type { DevTools, MessagePayload } from './dev-tools.js';
|
|
8
|
+
import type { DevToolsOptions } from '../config/status-quo-config.js';
|
|
12
9
|
|
|
13
10
|
type Subscribable<T> = {
|
|
14
11
|
subscribe: (listener: (value: T) => void) => () => void;
|
|
15
12
|
getSnapshot?: () => T;
|
|
16
13
|
};
|
|
17
14
|
|
|
18
|
-
const defaultDevToolsOptions = { enabled: false, namespace: 'Store' };
|
|
19
|
-
|
|
20
15
|
const devToolsFeatures = {
|
|
21
16
|
pause: true,
|
|
22
17
|
lock: true,
|
|
@@ -41,19 +36,18 @@ export abstract class BaseStateHandler<S, A> implements StateSubscriptionHandler
|
|
|
41
36
|
}
|
|
42
37
|
|
|
43
38
|
protected initDevTools(devToolsOptions?: DevToolsOptions) {
|
|
44
|
-
const
|
|
45
|
-
...defaultDevToolsOptions,
|
|
46
|
-
...devToolsOptions,
|
|
47
|
-
};
|
|
39
|
+
const resolvedOptions = resolveDevToolsOptions(devToolsOptions);
|
|
48
40
|
|
|
49
|
-
if (!
|
|
41
|
+
if (!resolvedOptions.enabled) {
|
|
50
42
|
this.devTools = null;
|
|
51
43
|
return;
|
|
52
44
|
}
|
|
53
45
|
|
|
46
|
+
const namespace = devToolsOptions?.namespace ?? this.getDevToolsNamespace();
|
|
47
|
+
|
|
54
48
|
this.devTools = withDevTools(this.initialState, {
|
|
55
|
-
name:
|
|
56
|
-
instanceId:
|
|
49
|
+
name: namespace,
|
|
50
|
+
instanceId: namespace.toLowerCase().replaceAll(' ', '-'),
|
|
57
51
|
actionCreators: this.getActions(),
|
|
58
52
|
features: devToolsFeatures,
|
|
59
53
|
});
|
|
@@ -86,23 +80,24 @@ export abstract class BaseStateHandler<S, A> implements StateSubscriptionHandler
|
|
|
86
80
|
protected abstract getStateValue(): S;
|
|
87
81
|
protected abstract setStateValue(nextState: S): void;
|
|
88
82
|
|
|
83
|
+
protected getDevToolsNamespace() {
|
|
84
|
+
return this.constructor.name || 'Store';
|
|
85
|
+
}
|
|
86
|
+
|
|
89
87
|
protected bindSubscribable<T, Sel>(
|
|
90
88
|
service: Subscribable<T>,
|
|
91
89
|
onChange: (value: Sel) => void,
|
|
92
90
|
selector: Selector<T, Sel>,
|
|
93
91
|
isEqual?: EqualityFn<Sel>
|
|
94
92
|
): void;
|
|
95
|
-
protected bindSubscribable<T>(
|
|
96
|
-
service: Subscribable<T>,
|
|
97
|
-
onChange: (value: T) => void
|
|
98
|
-
): void;
|
|
93
|
+
protected bindSubscribable<T>(service: Subscribable<T>, onChange: (value: T) => void): void;
|
|
99
94
|
protected bindSubscribable<T, Sel = T>(
|
|
100
95
|
service: Subscribable<T>,
|
|
101
96
|
onChange: (value: Sel) => void,
|
|
102
97
|
selector?: Selector<T, Sel>,
|
|
103
98
|
isEqual: EqualityFn<Sel> = Object.is
|
|
104
99
|
) {
|
|
105
|
-
const selectorFn = (selector ?? ((value: T) => value as unknown as Sel))
|
|
100
|
+
const selectorFn = (selector ?? ((value: T) => value as unknown as Sel));
|
|
106
101
|
const selectorCache = createSelectorCache<Sel>();
|
|
107
102
|
let receivedSyncValue = false;
|
|
108
103
|
|
|
@@ -150,7 +145,7 @@ export abstract class BaseStateHandler<S, A> implements StateSubscriptionHandler
|
|
|
150
145
|
|
|
151
146
|
case 'JUMP_TO_STATE':
|
|
152
147
|
case 'JUMP_TO_ACTION':
|
|
153
|
-
this.setStateValue(JSON.parse(message.state));
|
|
148
|
+
this.setStateValue(JSON.parse(message.state) as S);
|
|
154
149
|
break;
|
|
155
150
|
|
|
156
151
|
default:
|
package/src/store/dev-tools.ts
CHANGED
|
@@ -28,17 +28,17 @@ export function withDevTools<S>(initialState: S, options = {}): DevTools | null
|
|
|
28
28
|
return null;
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
|
|
32
32
|
if (!window.__REDUX_DEVTOOLS_EXTENSION__) {
|
|
33
33
|
console.error('Status Quo :: Devtools Extension is not installed!');
|
|
34
34
|
return null;
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
|
|
37
|
+
|
|
38
38
|
const devTools = window.__REDUX_DEVTOOLS_EXTENSION__.connect(options);
|
|
39
39
|
|
|
40
40
|
devTools.init(initialState);
|
|
41
41
|
|
|
42
|
-
|
|
42
|
+
|
|
43
43
|
return devTools;
|
|
44
44
|
}
|
|
@@ -1,18 +1,15 @@
|
|
|
1
1
|
import { BehaviorSubject, distinctUntilChanged, distinctUntilKeyChanged, map } from 'rxjs';
|
|
2
2
|
|
|
3
|
-
import { BaseStateHandler } from './base-state-handler.js';
|
|
4
3
|
import { resolveDistinctOptions } from '../config/status-quo-config.js';
|
|
4
|
+
import { BaseStateHandler } from './base-state-handler.js';
|
|
5
5
|
|
|
6
|
+
import type { DevToolsOptions, DistinctOptions } from '../config/status-quo-config.js';
|
|
6
7
|
import type { Observable } from 'rxjs';
|
|
7
|
-
import type { DistinctOptions } from '../config/status-quo-config.js';
|
|
8
8
|
|
|
9
9
|
type ObservableStateHandlerProps<S> = {
|
|
10
10
|
initialState: S;
|
|
11
11
|
options?: {
|
|
12
|
-
devTools?:
|
|
13
|
-
enabled?: boolean;
|
|
14
|
-
namespace: string;
|
|
15
|
-
};
|
|
12
|
+
devTools?: DevToolsOptions;
|
|
16
13
|
distinct?: DistinctOptions<S>;
|
|
17
14
|
useDistinctUntilChanged?: boolean;
|
|
18
15
|
};
|
|
@@ -27,7 +24,10 @@ export abstract class ObservableStateHandler<S, A> extends BaseStateHandler<S, A
|
|
|
27
24
|
protected constructor({ initialState, options }: ObservableStateHandlerProps<S>) {
|
|
28
25
|
super(initialState);
|
|
29
26
|
this.state$ = new BehaviorSubject<S>(initialState);
|
|
30
|
-
this.distinctOptions = resolveDistinctOptions(
|
|
27
|
+
this.distinctOptions = resolveDistinctOptions(
|
|
28
|
+
options?.distinct,
|
|
29
|
+
options?.useDistinctUntilChanged
|
|
30
|
+
);
|
|
31
31
|
this.initDevTools(options?.devTools);
|
|
32
32
|
}
|
|
33
33
|
|
|
@@ -39,16 +39,15 @@ export abstract class ObservableStateHandler<S, A> extends BaseStateHandler<S, A
|
|
|
39
39
|
this.state$.next(nextState);
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
|
|
42
|
+
getObservableItem<K extends keyof S>(key: K): Observable<S[K]> {
|
|
43
43
|
return this.state$.pipe(
|
|
44
44
|
distinctUntilKeyChanged(key),
|
|
45
45
|
map((state) => state[key])
|
|
46
46
|
);
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
|
|
50
|
-
const useDistinctUntilChanged =
|
|
51
|
-
options.useDistinctUntilChanged ?? this.distinctOptions.enabled;
|
|
49
|
+
getObservable(options: StateObservableOptions = {}): Observable<S> {
|
|
50
|
+
const useDistinctUntilChanged = options.useDistinctUntilChanged ?? this.distinctOptions.enabled;
|
|
52
51
|
|
|
53
52
|
if (!useDistinctUntilChanged) {
|
|
54
53
|
return this.state$;
|
|
@@ -58,22 +57,13 @@ export abstract class ObservableStateHandler<S, A> extends BaseStateHandler<S, A
|
|
|
58
57
|
distinctUntilChanged((previous, next) => {
|
|
59
58
|
return this.distinctOptions.comparator(previous, next);
|
|
60
59
|
})
|
|
61
|
-
)
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
getObservable(key: keyof S) {
|
|
65
|
-
return this.getStateItemAsObservable(key);
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/** @deprecated Use getObservable instead. */
|
|
69
|
-
getObservableItem(key: keyof S) {
|
|
70
|
-
return this.getObservable(key);
|
|
60
|
+
);
|
|
71
61
|
}
|
|
72
62
|
|
|
73
63
|
subscribe(listener: () => void): () => void;
|
|
74
64
|
subscribe(listener: (value: S) => void): () => void;
|
|
75
65
|
subscribe(listener: (value: S) => void) {
|
|
76
|
-
const subscription = this.
|
|
66
|
+
const subscription = this.getObservable().subscribe((nextState) => {
|
|
77
67
|
listener(nextState);
|
|
78
68
|
});
|
|
79
69
|
return () => subscription.unsubscribe();
|
|
@@ -1,18 +1,15 @@
|
|
|
1
1
|
import { signal } from '@preact/signals-core';
|
|
2
2
|
|
|
3
|
-
import { BaseStateHandler } from './base-state-handler.js';
|
|
4
3
|
import { resolveDistinctOptions } from '../config/status-quo-config.js';
|
|
4
|
+
import { BaseStateHandler } from './base-state-handler.js';
|
|
5
5
|
|
|
6
|
+
import type { DevToolsOptions, DistinctOptions } from '../config/status-quo-config.js';
|
|
6
7
|
import type { Signal } from '@preact/signals-core';
|
|
7
|
-
import type { DistinctOptions } from '../config/status-quo-config.js';
|
|
8
8
|
|
|
9
9
|
type SignalStateHandlerProps<S> = {
|
|
10
10
|
initialState: S;
|
|
11
11
|
options?: {
|
|
12
|
-
devTools?:
|
|
13
|
-
enabled?: boolean;
|
|
14
|
-
namespace: string;
|
|
15
|
-
};
|
|
12
|
+
devTools?: DevToolsOptions;
|
|
16
13
|
distinct?: DistinctOptions<S>;
|
|
17
14
|
useDistinctUntilChanged?: boolean;
|
|
18
15
|
};
|
|
@@ -26,7 +23,10 @@ export abstract class SignalStateHandler<S, A> extends BaseStateHandler<S, A> {
|
|
|
26
23
|
super(initialState);
|
|
27
24
|
|
|
28
25
|
this.state = signal<S>(initialState);
|
|
29
|
-
this.distinctOptions = resolveDistinctOptions(
|
|
26
|
+
this.distinctOptions = resolveDistinctOptions(
|
|
27
|
+
options?.distinct,
|
|
28
|
+
options?.useDistinctUntilChanged
|
|
29
|
+
);
|
|
30
30
|
this.initDevTools(options?.devTools);
|
|
31
31
|
}
|
|
32
32
|
|
|
@@ -48,7 +48,10 @@ export abstract class SignalStateHandler<S, A> extends BaseStateHandler<S, A> {
|
|
|
48
48
|
return;
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
-
if (
|
|
51
|
+
if (
|
|
52
|
+
this.distinctOptions.enabled &&
|
|
53
|
+
this.distinctOptions.comparator(previousSnapshot, nextState)
|
|
54
|
+
) {
|
|
52
55
|
previousSnapshot = nextState;
|
|
53
56
|
return;
|
|
54
57
|
}
|
|
@@ -10,7 +10,7 @@ export interface StateSingletonOptions {
|
|
|
10
10
|
|
|
11
11
|
export function makeStateSingleton<S, A>(
|
|
12
12
|
stateHandlerFactory: () => StateSubscriptionHandler<S, A>,
|
|
13
|
-
{ destroyOnNoConsumers =
|
|
13
|
+
{ destroyOnNoConsumers = false }: StateSingletonOptions = {}
|
|
14
14
|
): StateSingleton<S, A> {
|
|
15
15
|
let instance: StateSubscriptionHandler<S, A> | null = null;
|
|
16
16
|
const singleton: StateSingleton<S, A> & {
|
package/tsconfig.json
CHANGED
|
@@ -24,9 +24,8 @@
|
|
|
24
24
|
"declarationDir": "dist",
|
|
25
25
|
"outDir": "dist",
|
|
26
26
|
"typeRoots": [
|
|
27
|
-
"
|
|
28
|
-
"node_modules/@
|
|
29
|
-
"node_modules/@redux-devtools/extension"
|
|
27
|
+
"../../node_modules/@types",
|
|
28
|
+
"../../node_modules/@redux-devtools/extension"
|
|
30
29
|
],
|
|
31
30
|
"jsx": "react"
|
|
32
31
|
},
|
package/.eslintrc.cjs
DELETED
|
@@ -1,132 +0,0 @@
|
|
|
1
|
-
module.exports = {
|
|
2
|
-
root: true,
|
|
3
|
-
parser: '@typescript-eslint/parser', // Specifies the ESLint parser
|
|
4
|
-
plugins: ['react', '@typescript-eslint', 'simple-import-sort'],
|
|
5
|
-
ignorePatterns: [
|
|
6
|
-
'.eslintrc.js',
|
|
7
|
-
'*.config.js',
|
|
8
|
-
'setupTests.js',
|
|
9
|
-
'setupTests.ts',
|
|
10
|
-
'env.js',
|
|
11
|
-
'env.local.js',
|
|
12
|
-
],
|
|
13
|
-
extends: [
|
|
14
|
-
'plugin:@typescript-eslint/recommended', // Uses the recommended rules from @typescript-eslint/eslint-plugin
|
|
15
|
-
'airbnb-base',
|
|
16
|
-
'airbnb-typescript/base',
|
|
17
|
-
'plugin:prettier/recommended', // Enables eslint-plugin-prettier and displays prettier errors as ESLint errors. Make sure this is always the last configuration in the extends array.
|
|
18
|
-
'plugin:react/recommended',
|
|
19
|
-
'airbnb',
|
|
20
|
-
'airbnb/hooks',
|
|
21
|
-
'airbnb-typescript',
|
|
22
|
-
// Enables eslint-plugin-prettier and displays prettier errors as ESLint errors.
|
|
23
|
-
// Make sure this is always the last configuration in the extends array.
|
|
24
|
-
'plugin:prettier/recommended',
|
|
25
|
-
],
|
|
26
|
-
parserOptions: {
|
|
27
|
-
project: './tsconfig.json',
|
|
28
|
-
ecmaVersion: 2020, // Allows for the parsing of modern ECMAScript features
|
|
29
|
-
sourceType: 'module', // Allows for the use of imports
|
|
30
|
-
ecmaFeatures: {
|
|
31
|
-
jsx: true, // Allows for the parsing of JSX
|
|
32
|
-
},
|
|
33
|
-
},
|
|
34
|
-
settings: {
|
|
35
|
-
react: {
|
|
36
|
-
version: 'detect', // React version. "detect" automatically picks the version you have installed.
|
|
37
|
-
},
|
|
38
|
-
},
|
|
39
|
-
// Place to specify ESLint rules. Can be used to overwrite rules specified from the extended configs
|
|
40
|
-
rules: {
|
|
41
|
-
'max-classes-per-file': ['error', 2],
|
|
42
|
-
'no-console': 'off',
|
|
43
|
-
'@typescript-eslint/consistent-type-imports': 'error',
|
|
44
|
-
'no-param-reassign': ['error', {props: false}], // for reducer and simple reference changes
|
|
45
|
-
'import/order': 'off', // Is handled by simple-import-sort
|
|
46
|
-
'import/prefer-default-export': 'off', // This is not really useful, because named exports are easier to import (IDE)
|
|
47
|
-
'import/no-default-export': 'error', // Prefer named exports over default exports since they are easier to find and refactor
|
|
48
|
-
'import/extensions': [
|
|
49
|
-
'error',
|
|
50
|
-
'always',
|
|
51
|
-
{
|
|
52
|
-
ignorePackages: true,
|
|
53
|
-
js: 'always',
|
|
54
|
-
},
|
|
55
|
-
],
|
|
56
|
-
'simple-import-sort/exports': 'error',
|
|
57
|
-
'simple-import-sort/imports': [
|
|
58
|
-
'error',
|
|
59
|
-
{
|
|
60
|
-
/**
|
|
61
|
-
* The default grouping, but with type imports last as a separate group.
|
|
62
|
-
* From https://github.com/lydell/eslint-plugin-simple-import-sort/blob/37f9448cdfed85dacf27e34c515653ff96f0377a/examples/.eslintrc.js.
|
|
63
|
-
*/
|
|
64
|
-
groups: [['^\\u0000'], ['^@?\\w'], ['^'], ['^\\.'], ['^.+\\u0000$']],
|
|
65
|
-
},
|
|
66
|
-
],
|
|
67
|
-
'@typescript-eslint/no-use-before-define': ['error', {functions: false}], // function declarations are always
|
|
68
|
-
// hoisted so it's safe
|
|
69
|
-
'@typescript-eslint/lines-between-class-members': [
|
|
70
|
-
'error',
|
|
71
|
-
'always',
|
|
72
|
-
{exceptAfterSingleLine: true},
|
|
73
|
-
], // Avoid blowing up classes
|
|
74
|
-
|
|
75
|
-
// Forbid the use of extraneous packages
|
|
76
|
-
// https://github.com/benmosher/eslint-plugin-import/blob/master/docs/rules/no-extraneous-dependencies.md
|
|
77
|
-
// paths are treated both as absolute paths, and relative to process.cwd()
|
|
78
|
-
'import/no-extraneous-dependencies': [
|
|
79
|
-
'error',
|
|
80
|
-
{
|
|
81
|
-
devDependencies: [
|
|
82
|
-
'**/setupTests.{js,ts}', // test setup files
|
|
83
|
-
'test/**', // tape, common npm pattern
|
|
84
|
-
'tests/**', // also common npm pattern
|
|
85
|
-
'spec/**', // mocha, rspec-like pattern
|
|
86
|
-
'**/__tests__/**', // jest pattern
|
|
87
|
-
'**/__mocks__/**', // jest pattern
|
|
88
|
-
'test.{js,jsx}', // repos with a single test file
|
|
89
|
-
'test-*.{js,jsx}', // repos with multiple top-level test files
|
|
90
|
-
'**/*{.,_}{test,spec}.{js,jsx}', // tests where the extension or filename suffix denotes that it is a test
|
|
91
|
-
'**/jest.config.js', // jest config
|
|
92
|
-
'**/jest.setup.js', // jest setup
|
|
93
|
-
'**/vue.config.js', // vue-cli config
|
|
94
|
-
'**/webpack.config.js', // webpack config
|
|
95
|
-
'**/webpack.config.*.js', // webpack config
|
|
96
|
-
'**/rollup.config.js', // rollup config
|
|
97
|
-
'**/rollup.config.*.js', // rollup config
|
|
98
|
-
'**/gulpfile.js', // gulp config
|
|
99
|
-
'**/gulpfile.*.js', // gulp config
|
|
100
|
-
'**/Gruntfile{,.js}', // grunt config
|
|
101
|
-
'**/protractor.conf.js', // protractor config
|
|
102
|
-
'**/protractor.conf.*.js', // protractor config
|
|
103
|
-
'**/karma.conf.js', // karma config
|
|
104
|
-
'**/.eslintrc.js', // eslint config
|
|
105
|
-
],
|
|
106
|
-
optionalDependencies: false,
|
|
107
|
-
},
|
|
108
|
-
],
|
|
109
|
-
'react/prop-types': 'off', // Since we do not use prop-types
|
|
110
|
-
'react/require-default-props': 'off', // Since we do not use prop-types
|
|
111
|
-
// Many of our loops are server side rendered, so we can rely on the index in general
|
|
112
|
-
'react/no-array-index-key': 0,
|
|
113
|
-
// To support hydration of components, a string is necessary so that the minification of bundles
|
|
114
|
-
// do not affect our markup generation on the server.
|
|
115
|
-
'react/display-name': [2, {ignoreTranspilerName: true}],
|
|
116
|
-
// aria roles ignored (0) instead of warning (1) / errors (2).
|
|
117
|
-
'jsx-a11y/role-supports-aria-props': 0,
|
|
118
|
-
'react/function-component-definition': [2, {namedComponents: 'arrow-function'}],
|
|
119
|
-
// Conditional spreads are easier to do so we can deactivate this rule
|
|
120
|
-
'react/jsx-props-no-spreading': 0,
|
|
121
|
-
// Enforce the definition of Fragment instead of shorthand syntax.
|
|
122
|
-
// The thing is, that keys can only be applied to the long version. So we should stick to one version.
|
|
123
|
-
'react/jsx-fragments': [2, 'element'],
|
|
124
|
-
// We need to use setDangerouslyInnerHtml for article and server side rendered markup prepared by external helpers.
|
|
125
|
-
// So it makes no sense to have this rule in place.
|
|
126
|
-
'react/no-danger': 0,
|
|
127
|
-
// strict null-checking is not necessary.
|
|
128
|
-
// The syntax itself should be avoided for sure but in some cases where we know we get the data,
|
|
129
|
-
// we can use this functionality
|
|
130
|
-
'@typescript-eslint/no-non-null-assertion': 0,
|
|
131
|
-
},
|
|
132
|
-
};
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
name: Deploy Docs
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
branches: [master]
|
|
6
|
-
workflow_dispatch:
|
|
7
|
-
|
|
8
|
-
permissions:
|
|
9
|
-
contents: read
|
|
10
|
-
pages: write
|
|
11
|
-
id-token: write
|
|
12
|
-
|
|
13
|
-
concurrency:
|
|
14
|
-
group: pages
|
|
15
|
-
cancel-in-progress: true
|
|
16
|
-
|
|
17
|
-
jobs:
|
|
18
|
-
build:
|
|
19
|
-
runs-on: ubuntu-latest
|
|
20
|
-
steps:
|
|
21
|
-
- name: Checkout
|
|
22
|
-
uses: actions/checkout@v4
|
|
23
|
-
- name: Setup Node
|
|
24
|
-
uses: actions/setup-node@v4
|
|
25
|
-
with:
|
|
26
|
-
node-version: 20
|
|
27
|
-
cache: npm
|
|
28
|
-
- name: Install dependencies
|
|
29
|
-
run: npm ci
|
|
30
|
-
- name: Build docs
|
|
31
|
-
run: npm run docs:build
|
|
32
|
-
- name: Upload artifact
|
|
33
|
-
uses: actions/upload-pages-artifact@v3
|
|
34
|
-
with:
|
|
35
|
-
path: ./docs
|
|
36
|
-
|
|
37
|
-
deploy:
|
|
38
|
-
runs-on: ubuntu-latest
|
|
39
|
-
needs: build
|
|
40
|
-
environment:
|
|
41
|
-
name: github-pages
|
|
42
|
-
url: ${{ steps.deployment.outputs.page_url }}
|
|
43
|
-
steps:
|
|
44
|
-
- name: Deploy
|
|
45
|
-
id: deployment
|
|
46
|
-
uses: actions/deploy-pages@v4
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
name: Release
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
tags:
|
|
6
|
-
- 'v*'
|
|
7
|
-
|
|
8
|
-
permissions:
|
|
9
|
-
contents: write
|
|
10
|
-
|
|
11
|
-
jobs:
|
|
12
|
-
release:
|
|
13
|
-
runs-on: ubuntu-latest
|
|
14
|
-
steps:
|
|
15
|
-
- name: Checkout
|
|
16
|
-
uses: actions/checkout@v4
|
|
17
|
-
- name: Setup Node
|
|
18
|
-
uses: actions/setup-node@v4
|
|
19
|
-
with:
|
|
20
|
-
node-version: 20
|
|
21
|
-
cache: npm
|
|
22
|
-
- name: Install dependencies
|
|
23
|
-
run: npm ci
|
|
24
|
-
- name: Build dist
|
|
25
|
-
run: npm run build
|
|
26
|
-
- name: Package dist
|
|
27
|
-
run: |
|
|
28
|
-
zip -r "dist-${{ github.ref_name }}.zip" dist
|
|
29
|
-
- name: Create GitHub release
|
|
30
|
-
uses: softprops/action-gh-release@v2
|
|
31
|
-
with:
|
|
32
|
-
files: dist-${{ github.ref_name }}.zip
|
|
33
|
-
generate_release_notes: true
|
package/.nvmrc
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
v22
|
package/.prettierrc
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
@import"https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;600;700&family=IBM+Plex+Mono:wght@400;500&display=swap";code[class*=language-],pre[class*=language-]{color:#ccc;background:none;font-family:Consolas,Monaco,Andale Mono,Ubuntu Mono,monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto}:not(pre)>code[class*=language-],pre[class*=language-]{background:#2d2d2d}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.token.comment,.token.block-comment,.token.prolog,.token.doctype,.token.cdata{color:#999}.token.punctuation{color:#ccc}.token.tag,.token.attr-name,.token.namespace,.token.deleted{color:#e2777a}.token.function-name{color:#6196cc}.token.boolean,.token.number,.token.function{color:#f08d49}.token.property,.token.class-name,.token.constant,.token.symbol{color:#f8c555}.token.selector,.token.important,.token.atrule,.token.keyword,.token.builtin{color:#cc99cd}.token.string,.token.char,.token.attr-value,.token.regex,.token.variable{color:#7ec699}.token.operator,.token.entity,.token.url{color:#67cdcc}.token.important,.token.bold{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help}.token.inserted{color:green}:root{color-scheme:light;--bg: #f3f2ee;--bg-strong: #e6e1d8;--card: #ffffff;--ink: #1b1b1f;--muted: #5c5c66;--accent: #2f6bff;--accent-soft: #c9d8ff;--accent-2: #ff9f1c;--shadow: 0 18px 45px -30px rgba(0, 0, 0, .45);--radius-lg: 28px;--radius-md: 18px;--radius-sm: 12px;--panel-dark: #0e1116;font-family:Space Grotesk,system-ui,-apple-system,sans-serif}*{box-sizing:border-box}body{margin:0;min-height:100vh;color:var(--ink);background:radial-gradient(circle at 20% 20%,rgba(47,107,255,.18),transparent 55%),radial-gradient(circle at 80% 0%,rgba(255,159,28,.2),transparent 50%),linear-gradient(160deg,var(--bg),var(--bg-strong))}#root{min-height:100vh}.app{max-width:1100px;margin:0 auto;padding:56px 28px 72px;display:flex;flex-direction:column;gap:40px}.brand-bar{display:inline-flex;align-items:center;gap:10px;font-weight:600;justify-content:center;width:100%}.brand-logo{width:260px;height:auto;display:block}.nav{display:flex;align-items:center;justify-content:center;flex-direction:column;padding:10px 6px;width:100%}.nav-toggle{display:none;border:1px solid rgba(27,27,31,.18);background:#ffffffd9;color:var(--ink);border-radius:999px;padding:8px 14px;font:inherit;font-weight:600;cursor:pointer;box-shadow:var(--shadow)}.nav-links{display:inline-flex;align-items:center;justify-content:center;gap:10px;flex-wrap:wrap;padding:6px 12px;width:min(100%,980px);background:#ffffffb3;border-radius:999px;border:1px solid rgba(27,27,31,.1);box-shadow:var(--shadow)}.nav-links a{text-decoration:none;color:var(--ink);font-weight:500;padding:6px 12px;border-radius:999px;transition:background .2s ease,color .2s ease}.nav-links a:hover{background:#2f6bff1f;color:var(--accent)}.hero{display:grid;gap:16px;padding:32px 34px;background:#ffffffbf;border-radius:var(--radius-lg);box-shadow:var(--shadow);border:1px solid rgba(27,27,31,.08);-webkit-backdrop-filter:blur(14px);backdrop-filter:blur(14px);animation:fade-up .6s ease both}.hero.intro{gap:18px}h1{font-size:clamp(2rem,1.6vw + 1.4rem,2.8rem);line-height:1.15;margin:0}h2{margin:0;font-size:1.4rem}h3{margin:0 0 8px}p{margin:0;color:var(--muted);line-height:1.6}p span{font-family:monospace;font-weight:700;font-size:.9rem}.muted{color:var(--muted)}.eyebrow{font-family:IBM Plex Mono,ui-monospace,SFMono-Regular,monospace;text-transform:uppercase;letter-spacing:.18em;font-size:.7rem;color:var(--muted);margin-bottom:10px}.subtext{max-width:600px}.hero .subtext{margin-top:12px}.hero .subtext+.subtext{margin-top:10px}.grid{display:grid;gap:24px;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));align-items:stretch}.doc-section{display:grid;gap:18px;padding:28px;border-radius:var(--radius-md);background:#ffffffd9;border:1px solid rgba(27,27,31,.08);box-shadow:var(--shadow)}.doc-copy{display:grid;gap:10px}.doc-snippets{display:grid;gap:12px}.singleton-grid{display:grid;gap:20px;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));align-items:stretch}.singleton-card{background:#fff;border-radius:var(--radius-md);padding:22px;border:1px solid rgba(27,27,31,.08);box-shadow:var(--shadow);display:grid;gap:14px;align-content:start;height:100%}.singleton-count{font-size:2.4rem;font-weight:700;color:var(--ink);background:var(--bg-strong);border-radius:var(--radius-sm);padding:10px 16px;width:fit-content}.singleton-count.highlight{background:#2f6bff29;color:var(--accent)}.singleton-hint{font-size:.85rem;color:var(--muted)}.guide{display:grid;gap:20px;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));align-items:stretch}.api-flow{display:grid;gap:30px}.api-group{display:grid;gap:18px}.api-grid{display:grid;gap:18px;grid-template-columns:repeat(2,minmax(0,1fr));align-items:stretch}.api-composition-card{padding:2px 0 18px;border-bottom:1px solid rgba(27,27,31,.16);display:grid;gap:10px;align-content:start}.api-composition-card h3{margin:0;font-size:1rem}.api-composition-punch{margin-top:8px;font-weight:600;color:var(--ink);background:linear-gradient(120deg,#2f6bff24,#ff9f1c24);border:1px solid rgba(47,107,255,.2);border-radius:var(--radius-sm);padding:10px 12px}.api-card{background:#fff;border-radius:var(--radius-sm);padding:18px;border:1px solid rgba(27,27,31,.08);box-shadow:var(--shadow);display:grid;gap:10px;align-content:start;height:100%}.api-card h3{margin:0;font-size:1rem}.api-card-wide{grid-column:1 / -1}.philosophy-grid{display:grid;gap:20px;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));align-items:stretch}.philosophy-card{background:#fff;border-radius:var(--radius-md);border:1px solid rgba(27,27,31,.08);box-shadow:var(--shadow);overflow:hidden;display:grid;gap:16px;align-content:start;height:100%}.philosophy-card img{width:100%;height:190px;object-fit:cover;background:var(--panel-dark)}.philosophy-card div{padding:0 20px 22px;display:grid;gap:8px}.guide-card{background:#ffffffd9;border-radius:var(--radius-md);padding:22px;border:1px solid rgba(27,27,31,.08);box-shadow:var(--shadow);display:grid;gap:16px;align-content:start;height:100%}.guide-highlight{margin-top:4px;font-weight:600;color:var(--ink);background:linear-gradient(120deg,#2f6bff29,#ff9f1c29);border:1px solid rgba(47,107,255,.2);border-radius:var(--radius-sm);padding:10px 12px}.code-block.compact{font-size:.75rem;padding:12px 14px}.card{background:var(--card);border-radius:var(--radius-md);padding:24px;box-shadow:var(--shadow);border:1px solid rgba(27,27,31,.08);display:flex;flex-direction:column;gap:20px;animation:fade-up .6s ease both;height:100%}.card:nth-child(2){animation-delay:.1s}.card-header{display:flex;align-items:center;justify-content:space-between;gap:12px}.count-chip{background:var(--accent-soft);color:var(--accent);border-radius:999px;padding:6px 14px;font-weight:600;font-size:1rem}.count-display{display:grid;gap:8px;padding:16px;border-radius:var(--radius-sm);background:linear-gradient(120deg,#2f6bff1a,#ff9f1c14)}.code-block{margin:0;padding:16px 18px;border-radius:var(--radius-sm);background:#12131a;color:#f0f2ff;font-family:IBM Plex Mono,ui-monospace,SFMono-Regular,monospace;font-size:.8rem;line-height:1.5;overflow-x:auto;box-shadow:inset 0 0 0 1px #ffffff14}.code-block code{font-family:inherit}.count-label{font-size:.85rem;color:var(--muted)}.count-value{font-size:2.6rem;font-weight:700}.actions{display:grid;grid-template-columns:repeat(auto-fit,minmax(110px,1fr));gap:10px}.btn{border:1px solid rgba(27,27,31,.18);border-radius:999px;padding:10px 14px;font:inherit;background:#fff;cursor:pointer;transition:transform .2s ease,box-shadow .2s ease,border .2s ease}.btn:hover{transform:translateY(-1px);box-shadow:0 10px 20px -14px #1b1b1f66}.btn.primary{background:var(--accent);color:#fff;border-color:transparent}.btn.ghost{background:transparent;color:var(--ink)}@keyframes fade-up{0%{opacity:0;transform:translateY(12px)}to{opacity:1;transform:translateY(0)}}@media (max-width: 720px){.app{padding:40px 20px 60px}.nav{padding:0}.nav-toggle{display:inline-flex;align-items:center;justify-content:center;margin-bottom:10px}.nav-links{display:none;width:100%;border-radius:var(--radius-md);padding:10px;gap:8px}.nav-links.is-open{display:grid;grid-template-columns:repeat(2,minmax(0,1fr))}.nav-links a{text-align:center}.doc-section{padding:22px}.api-grid{grid-template-columns:1fr}.hero{padding:26px}.footer-card{flex-direction:column;align-items:flex-start}}
|