UNPKG

flagged

Version:

Feature flags for React made easy with hooks, HOC and Render Props

56 lines (55 loc) 1.97 kB
import * as React from "react"; let FeatureFlagsContext = React.createContext({}); function transformFlags(features) { if (!Array.isArray(features)) return features; return Object.fromEntries(features.map((feature) => [feature, true])); } function mergeFeatures(a, b) { return { ...a, ...b }; } export function FlagsProvider({ features = {}, children, }) { let currentFeatures = useFeatures(); return (React.createElement(FeatureFlagsContext.Provider, { value: mergeFeatures(transformFlags(currentFeatures), transformFlags(features)) }, children)); } // Custom Hook API export function useFeatures() { return React.useContext(FeatureFlagsContext); } // Custom Hook API export function useFeature(name) { let features = useFeatures(); if (Array.isArray(features)) return features.includes(name); if (typeof features[name] === "boolean") return features[name]; let featureGroup = structuredClone(features); for (let featureName of name.split("/")) { if (typeof featureGroup === "boolean") return featureGroup; if (featureGroup[featureName] === undefined) return false; featureGroup = featureGroup[featureName]; } return featureGroup; } // Render Prop API export function Feature({ name, children, render = children, }) { let hasFeature = useFeature(name); if (typeof render === "function") return render(hasFeature); if (!hasFeature) return null; return React.createElement(React.Fragment, null, render); } // High Order Component API export function withFeature(featureName) { return (Component) => { function WithFeature(props) { return (React.createElement(Feature, { name: featureName }, React.createElement(Component, { ...props }))); } WithFeature.displayName = `WithFeature(${Component.displayName || Component.name})`; return WithFeature; }; }