Skip to content

Commit

Permalink
feat: add change to localStorage plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
WitoDelnat committed Nov 23, 2022
1 parent 11b80f4 commit a264145
Show file tree
Hide file tree
Showing 5 changed files with 48 additions and 9 deletions.
13 changes: 13 additions & 0 deletions src/core/keat.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,15 @@ import { mutable } from "./utils";

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

export type Listener = () => void;
export type Unsubscribe = () => void;

export function keatCore<TFeatures extends AnyFeatures>({
features,
display = "swap",
plugins = [],
}: KeatInit<TFeatures>): KeatApi<TFeatures> {
let listeners: Listener[] = [];
let defaultDisplay = display;
let defaultUser: User | undefined = undefined;
let configId = 0;
Expand All @@ -33,6 +37,9 @@ export function keatCore<TFeatures extends AnyFeatures>({
configId += 1;
config = newConfig;
},
onChange: () => {
listeners.forEach((l) => l());
},
}
)
)
Expand Down Expand Up @@ -98,6 +105,12 @@ export function keatCore<TFeatures extends AnyFeatures>({
const useLatest = loader.useLatest(display);
return evaluate(feature as string, user, useLatest ? configId : 0);
},
onChange: (listener: Listener): Unsubscribe => {
listeners.push(listener);
return () => {
listeners = listeners.filter((l) => l === listener);
};
},
};
}

Expand Down
1 change: 1 addition & 0 deletions src/core/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export type OnPluginInitCtx = {

export type OnPluginInitApi = {
setConfig: (newConfig: Config) => void;
onChange: () => void;
};

export type OnEvalHook = (
Expand Down
2 changes: 2 additions & 0 deletions src/core/types.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { Listener, Unsubscribe } from "./keat";
import type { Plugin } from "./plugin";

/**
Expand Down Expand Up @@ -64,6 +65,7 @@ export type KeatApi<TFeatures extends AnyFeatures> = {
? TFeatures[TFeature]["variates"][number]
: boolean
: boolean;
onChange(listener: Listener): Unsubscribe;
};

/* * * * * * * * * * * * *
Expand Down
33 changes: 25 additions & 8 deletions src/plugins/localStorage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,32 +16,49 @@ type Options = {
value?: string;

/**
* Whether the local storage item should only
* retried at initialisation.
* Whether the local storage is polled for updated.
*
* @default false
* The default polling time every 2 seconds.
* You can change it by setting a number (in ms).
*/
once?: boolean;
poll?: boolean | number;
};

export const localStorage = (
name: string,
{ key, value, once = false }: Options = {}
{ key, value, poll = false }: Options = {}
): Plugin => {
const item = once ?? window.localStorage.getItem(key ?? name);
const k = key ?? name;
let item = window.localStorage.getItem(k);

return {
onPluginInit(_, { onChange }) {
const pollInterval =
poll === true ? 2000 : typeof poll === "number" && poll > 0 ? poll : 0;
if (hasSetInterval() && pollInterval > 0) {
setInterval(() => {
const newItem = window.localStorage.getItem(k);
const hasChanged = item !== newItem;
item = newItem;
if (hasChanged) onChange();
}, pollInterval);
}
},
onEval({ variates, rules }, { setResult }) {
if (typeof window === "undefined") return;

const index = rules.findIndex((rule) =>
takeStrings(rule).some((r) => {
if (r !== name) return false;
const i = once ? item : window.localStorage.getItem(key ?? name);
return value ? i === value : Boolean(i);
return value ? item === value : Boolean(item);
})
);

if (index !== -1) setResult(variates[index]);
},
};
};

function hasSetInterval() {
return typeof window !== "undefined" && window.setInterval;
}
8 changes: 7 additions & 1 deletion src/react/KeatReact.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { ReactNode, useEffect } from "react";
import React, { ReactNode, useEffect, useReducer } from "react";
import { AnyFeatures, Display, KeatApi, keatCore, KeatInit } from "../core";

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

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

useEffect(() => {
const unsubscribe = keatInstance.onChange(forceUpdate);
return () => unsubscribe();
}, []);

if (loading) {
return <>{invisible}</>;
}
Expand Down

0 comments on commit a264145

Please sign in to comment.