Skip to content

Commit a264145

Browse files
committed
feat: add change to localStorage plugin
1 parent 11b80f4 commit a264145

File tree

5 files changed

+48
-9
lines changed

5 files changed

+48
-9
lines changed

src/core/keat.ts

+13
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,15 @@ import { mutable } from "./utils";
1313

1414
export type ExtractFeatures<K> = K extends KeatApi<infer K> ? keyof K : never;
1515

16+
export type Listener = () => void;
17+
export type Unsubscribe = () => void;
18+
1619
export function keatCore<TFeatures extends AnyFeatures>({
1720
features,
1821
display = "swap",
1922
plugins = [],
2023
}: KeatInit<TFeatures>): KeatApi<TFeatures> {
24+
let listeners: Listener[] = [];
2125
let defaultDisplay = display;
2226
let defaultUser: User | undefined = undefined;
2327
let configId = 0;
@@ -33,6 +37,9 @@ export function keatCore<TFeatures extends AnyFeatures>({
3337
configId += 1;
3438
config = newConfig;
3539
},
40+
onChange: () => {
41+
listeners.forEach((l) => l());
42+
},
3643
}
3744
)
3845
)
@@ -98,6 +105,12 @@ export function keatCore<TFeatures extends AnyFeatures>({
98105
const useLatest = loader.useLatest(display);
99106
return evaluate(feature as string, user, useLatest ? configId : 0);
100107
},
108+
onChange: (listener: Listener): Unsubscribe => {
109+
listeners.push(listener);
110+
return () => {
111+
listeners = listeners.filter((l) => l === listener);
112+
};
113+
},
101114
};
102115
}
103116

src/core/plugin.ts

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ export type OnPluginInitCtx = {
2525

2626
export type OnPluginInitApi = {
2727
setConfig: (newConfig: Config) => void;
28+
onChange: () => void;
2829
};
2930

3031
export type OnEvalHook = (

src/core/types.ts

+2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { Listener, Unsubscribe } from "./keat";
12
import type { Plugin } from "./plugin";
23

34
/**
@@ -64,6 +65,7 @@ export type KeatApi<TFeatures extends AnyFeatures> = {
6465
? TFeatures[TFeature]["variates"][number]
6566
: boolean
6667
: boolean;
68+
onChange(listener: Listener): Unsubscribe;
6769
};
6870

6971
/* * * * * * * * * * * * *

src/plugins/localStorage.ts

+25-8
Original file line numberDiff line numberDiff line change
@@ -16,32 +16,49 @@ type Options = {
1616
value?: string;
1717

1818
/**
19-
* Whether the local storage item should only
20-
* retried at initialisation.
19+
* Whether the local storage is polled for updated.
2120
*
22-
* @default false
21+
* The default polling time every 2 seconds.
22+
* You can change it by setting a number (in ms).
2323
*/
24-
once?: boolean;
24+
poll?: boolean | number;
2525
};
2626

2727
export const localStorage = (
2828
name: string,
29-
{ key, value, once = false }: Options = {}
29+
{ key, value, poll = false }: Options = {}
3030
): Plugin => {
31-
const item = once ?? window.localStorage.getItem(key ?? name);
31+
const k = key ?? name;
32+
let item = window.localStorage.getItem(k);
33+
3234
return {
35+
onPluginInit(_, { onChange }) {
36+
const pollInterval =
37+
poll === true ? 2000 : typeof poll === "number" && poll > 0 ? poll : 0;
38+
if (hasSetInterval() && pollInterval > 0) {
39+
setInterval(() => {
40+
const newItem = window.localStorage.getItem(k);
41+
const hasChanged = item !== newItem;
42+
item = newItem;
43+
if (hasChanged) onChange();
44+
}, pollInterval);
45+
}
46+
},
3347
onEval({ variates, rules }, { setResult }) {
3448
if (typeof window === "undefined") return;
3549

3650
const index = rules.findIndex((rule) =>
3751
takeStrings(rule).some((r) => {
3852
if (r !== name) return false;
39-
const i = once ? item : window.localStorage.getItem(key ?? name);
40-
return value ? i === value : Boolean(i);
53+
return value ? item === value : Boolean(item);
4154
})
4255
);
4356

4457
if (index !== -1) setResult(variates[index]);
4558
},
4659
};
4760
};
61+
62+
function hasSetInterval() {
63+
return typeof window !== "undefined" && window.setInterval;
64+
}

src/react/KeatReact.tsx

+7-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { ReactNode, useEffect } from "react";
1+
import React, { ReactNode, useEffect, useReducer } from "react";
22
import { AnyFeatures, Display, KeatApi, keatCore, KeatInit } from "../core";
33

44
type KeatReactApi<TFeatures extends AnyFeatures> = KeatApi<TFeatures> & {
@@ -48,11 +48,17 @@ export function keatReact<TFeatures extends AnyFeatures>(
4848
children,
4949
}) {
5050
const [loading, setLoading] = React.useState(true);
51+
const [_, forceUpdate] = useReducer((x) => x + 1, 0);
5152

5253
useEffect(() => {
5354
keatInstance.ready(display).then(() => setLoading(false));
5455
}, [setLoading]);
5556

57+
useEffect(() => {
58+
const unsubscribe = keatInstance.onChange(forceUpdate);
59+
return () => unsubscribe();
60+
}, []);
61+
5662
if (loading) {
5763
return <>{invisible}</>;
5864
}

0 commit comments

Comments
 (0)