@flagdown/react 0.0.3 → 0.0.4
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 +36 -25
- package/dist/index.d.ts +10 -17
- package/dist/index.js +20 -17
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,32 +1,50 @@
|
|
|
1
1
|
# @flagdown/react
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Use the `Feature` component to switch between new UI and a fallback in React 18+.
|
|
4
4
|
|
|
5
|
-
```
|
|
6
|
-
|
|
5
|
+
```sh
|
|
6
|
+
npm install @flagdown/react@0.0.4
|
|
7
|
+
```
|
|
7
8
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
```tsx
|
|
10
|
+
import { Feature } from '@flagdown/react';
|
|
11
|
+
|
|
12
|
+
export function Checkout() {
|
|
13
|
+
return (
|
|
14
|
+
<Feature
|
|
15
|
+
flag="new-checkout"
|
|
16
|
+
fallback={<OldCheckout />}
|
|
17
|
+
>
|
|
18
|
+
<NewCheckout />
|
|
19
|
+
</Feature>
|
|
20
|
+
);
|
|
11
21
|
}
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
`Feature` renders its children when the named flag is on. When it is off, unknown,
|
|
25
|
+
still loading, or unavailable, it renders `fallback`. Omit `fallback` to render
|
|
26
|
+
nothing in those cases. Only the selected branch mounts; `Feature` adds no DOM
|
|
27
|
+
wrapper.
|
|
28
|
+
|
|
29
|
+
Configure the project once at your app root:
|
|
30
|
+
|
|
31
|
+
```tsx
|
|
32
|
+
import { FlagdownProvider } from '@flagdown/react';
|
|
12
33
|
|
|
13
34
|
<FlagdownProvider
|
|
14
|
-
apiUrl="https://
|
|
35
|
+
apiUrl="https://api.flagdown.dev"
|
|
15
36
|
clientToken="COPY_PUBLIC_CLIENT_TOKEN_FROM_DASHBOARD"
|
|
16
37
|
>
|
|
17
|
-
<
|
|
38
|
+
<App />
|
|
18
39
|
</FlagdownProvider>
|
|
19
40
|
```
|
|
20
41
|
|
|
21
|
-
Create a project and flag in the dashboard, then copy
|
|
22
|
-
|
|
23
|
-
includes the remote adapter; the previously published 0.0.2 build only provides
|
|
24
|
-
an injectable evaluator. This source must be released before registry installs
|
|
25
|
-
can use remote reads.
|
|
42
|
+
Create a project and flag in the dashboard, then copy its integration snippet.
|
|
43
|
+
`apiUrl` is the API base URL without `/v1`. `Feature` must be inside the provider.
|
|
26
44
|
|
|
27
45
|
Flags refresh every 10 seconds, without reloading the page. Set
|
|
28
46
|
`refreshIntervalMs` to change this (minimum 1000ms). Requests time out after 10
|
|
29
|
-
seconds. Initial values, unknown flags and refresh failures evaluate
|
|
47
|
+
seconds. Initial values, unknown flags and refresh failures evaluate off;
|
|
30
48
|
a successful later refresh restores values. An optional `onError(error)` callback
|
|
31
49
|
can report failures. Changing project configuration immediately discards the
|
|
32
50
|
previous project's values. Unmounting cancels in-flight work and future refreshes.
|
|
@@ -35,14 +53,7 @@ Client tokens are public, project-scoped read configuration. They cannot manage
|
|
|
35
53
|
flags. Replacing a token in the dashboard invalidates the previous token; update
|
|
36
54
|
apps using it. Client-side flags are not an authorization boundary.
|
|
37
55
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
<Checkout />
|
|
43
|
-
</FlagdownProvider>
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
An explicit evaluator takes precedence over remote configuration. A provider
|
|
47
|
-
without either configuration evaluates every flag off. `useFlag` must be called
|
|
48
|
-
inside a provider.
|
|
56
|
+
`Feature` is the SDK's flag consumption API. The evaluation context and evaluator
|
|
57
|
+
are internal; the package exposes no flag hooks or direct evaluation functions.
|
|
58
|
+
Use `FlagdownProvider` to configure your project. A provider without project
|
|
59
|
+
configuration renders each feature's fallback.
|
package/dist/index.d.ts
CHANGED
|
@@ -1,20 +1,15 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
|
-
import { PropsWithChildren } from 'react';
|
|
2
|
+
import { PropsWithChildren, ReactNode } from 'react';
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
* It deliberately keeps every flag disabled so applications can install the
|
|
12
|
-
* provider and hook safely before remote evaluation is available.
|
|
13
|
-
*/
|
|
14
|
-
declare const disabledFlagEvaluator: FlagEvaluator;
|
|
4
|
+
type FeatureProps = PropsWithChildren<{
|
|
5
|
+
/** Key of the flag controlling this feature. */
|
|
6
|
+
flag: string;
|
|
7
|
+
/** Rendered while the flag is off, unknown, loading, or unavailable. */
|
|
8
|
+
fallback?: ReactNode;
|
|
9
|
+
}>;
|
|
10
|
+
declare function Feature({ flag, fallback, children }: FeatureProps): react.JSX.Element;
|
|
15
11
|
|
|
16
12
|
interface FlagdownProviderProps extends PropsWithChildren {
|
|
17
|
-
evaluator?: FlagEvaluator;
|
|
18
13
|
apiUrl?: string;
|
|
19
14
|
/** Public, read-only project token copied from the dashboard. */
|
|
20
15
|
clientToken?: string;
|
|
@@ -22,8 +17,6 @@ interface FlagdownProviderProps extends PropsWithChildren {
|
|
|
22
17
|
refreshIntervalMs?: number;
|
|
23
18
|
onError?: (error: Error) => void;
|
|
24
19
|
}
|
|
25
|
-
declare function FlagdownProvider({ children,
|
|
26
|
-
|
|
27
|
-
declare function useFlag(flagKey: string): boolean;
|
|
20
|
+
declare function FlagdownProvider({ children, apiUrl, clientToken, refreshIntervalMs, onError }: FlagdownProviderProps): react.JSX.Element;
|
|
28
21
|
|
|
29
|
-
export { type
|
|
22
|
+
export { Feature, type FeatureProps, FlagdownProvider, type FlagdownProviderProps };
|
package/dist/index.js
CHANGED
|
@@ -1,17 +1,21 @@
|
|
|
1
|
-
// src/
|
|
2
|
-
import {
|
|
1
|
+
// src/Feature.tsx
|
|
2
|
+
import { useContext } from "react";
|
|
3
3
|
|
|
4
4
|
// src/FlagdownContext.tsx
|
|
5
|
-
import { createContext
|
|
5
|
+
import { createContext } from "react";
|
|
6
6
|
var FlagdownContext = createContext(void 0);
|
|
7
|
-
|
|
7
|
+
|
|
8
|
+
// src/Feature.tsx
|
|
9
|
+
import { Fragment, jsx } from "react/jsx-runtime";
|
|
10
|
+
function Feature({ flag, fallback = null, children }) {
|
|
8
11
|
const evaluator = useContext(FlagdownContext);
|
|
9
|
-
if (!evaluator)
|
|
10
|
-
|
|
11
|
-
}
|
|
12
|
-
return evaluator.isEnabled(flagKey);
|
|
12
|
+
if (!evaluator) throw new Error("Feature must be used within a FlagdownProvider");
|
|
13
|
+
return /* @__PURE__ */ jsx(Fragment, { children: evaluator.isEnabled(flag) ? children : fallback });
|
|
13
14
|
}
|
|
14
15
|
|
|
16
|
+
// src/FlagdownProvider.tsx
|
|
17
|
+
import { useEffect, useMemo, useState, useRef } from "react";
|
|
18
|
+
|
|
15
19
|
// src/flags.ts
|
|
16
20
|
var disabledFlagEvaluator = {
|
|
17
21
|
isEnabled: () => false
|
|
@@ -33,15 +37,15 @@ async function fetchFlagState(apiUrl, clientToken, signal) {
|
|
|
33
37
|
}
|
|
34
38
|
|
|
35
39
|
// src/FlagdownProvider.tsx
|
|
36
|
-
import { jsx } from "react/jsx-runtime";
|
|
37
|
-
function FlagdownProvider({ children,
|
|
40
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
41
|
+
function FlagdownProvider({ children, apiUrl, clientToken, refreshIntervalMs = 1e4, onError }) {
|
|
38
42
|
const errorHandler = useRef(onError);
|
|
39
43
|
useEffect(() => {
|
|
40
44
|
errorHandler.current = onError;
|
|
41
45
|
}, [onError]);
|
|
42
46
|
const [snapshot, setSnapshot] = useState();
|
|
43
47
|
useEffect(() => {
|
|
44
|
-
if (
|
|
48
|
+
if (!apiUrl || !clientToken) return;
|
|
45
49
|
let active = true;
|
|
46
50
|
let timer;
|
|
47
51
|
let controller;
|
|
@@ -70,12 +74,11 @@ function FlagdownProvider({ children, evaluator, apiUrl, clientToken, refreshInt
|
|
|
70
74
|
clearTimeout(timer);
|
|
71
75
|
controller?.abort();
|
|
72
76
|
};
|
|
73
|
-
}, [apiUrl, clientToken,
|
|
74
|
-
const value = useMemo(() =>
|
|
75
|
-
return /* @__PURE__ */
|
|
77
|
+
}, [apiUrl, clientToken, refreshIntervalMs]);
|
|
78
|
+
const value = useMemo(() => snapshot && snapshot.apiUrl === apiUrl && snapshot.clientToken === clientToken ? { isEnabled: (key) => Object.hasOwn(snapshot.flags, key) && snapshot.flags[key] === true } : disabledFlagEvaluator, [snapshot, apiUrl, clientToken]);
|
|
79
|
+
return /* @__PURE__ */ jsx2(FlagdownContext.Provider, { value, children });
|
|
76
80
|
}
|
|
77
81
|
export {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
useFlag
|
|
82
|
+
Feature,
|
|
83
|
+
FlagdownProvider
|
|
81
84
|
};
|