@localflag/react 0.0.1 → 0.0.3
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 +47 -7
- package/dist/index.d.ts +71 -4
- package/dist/index.js +495 -148
- package/dist/index.js.map +1 -1
- package/package.json +21 -1
package/README.md
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# @localflag/react
|
|
2
2
|
|
|
3
|
-
Type-safe feature flags for React with built-in
|
|
3
|
+
Type-safe feature flags for React with built-in LocalFlagDevTools.
|
|
4
|
+
|
|
5
|
+
[Website](https://localflag.io) · [Documentation](https://docs.localflag.io) · [Demo](https://demo.localflag.io) · [GitHub](https://github.com/localflag/localflag)
|
|
4
6
|
|
|
5
7
|
## Installation
|
|
6
8
|
|
|
@@ -11,7 +13,7 @@ npm install @localflag/react
|
|
|
11
13
|
## Quick Start
|
|
12
14
|
|
|
13
15
|
```tsx
|
|
14
|
-
import { FeatureFlagProvider, useFeatureFlag,
|
|
16
|
+
import { FeatureFlagProvider, useFeatureFlag, LocalFlagDevTools } from '@localflag/react';
|
|
15
17
|
|
|
16
18
|
// 1. Define your flags
|
|
17
19
|
const defaultFlags = {
|
|
@@ -28,7 +30,7 @@ function App() {
|
|
|
28
30
|
return (
|
|
29
31
|
<FeatureFlagProvider<AppFlags> defaultFlags={defaultFlags}>
|
|
30
32
|
<MyApp />
|
|
31
|
-
<
|
|
33
|
+
<LocalFlagDevTools /> {/* Optional: adds a floating panel to toggle flags */}
|
|
32
34
|
</FeatureFlagProvider>
|
|
33
35
|
);
|
|
34
36
|
}
|
|
@@ -119,14 +121,14 @@ import { FeatureFlag } from '@localflag/react';
|
|
|
119
121
|
</FeatureFlag>
|
|
120
122
|
```
|
|
121
123
|
|
|
122
|
-
#### `
|
|
124
|
+
#### `LocalFlagDevTools`
|
|
123
125
|
|
|
124
126
|
A floating panel for toggling flags during development.
|
|
125
127
|
|
|
126
128
|
```tsx
|
|
127
|
-
import {
|
|
129
|
+
import { LocalFlagDevTools } from '@localflag/react';
|
|
128
130
|
|
|
129
|
-
<
|
|
131
|
+
<LocalFlagDevTools
|
|
130
132
|
position="bottom-right" // 'bottom-right' | 'bottom-left' | 'top-right' | 'top-left'
|
|
131
133
|
defaultOpen={false} // Start expanded or collapsed
|
|
132
134
|
/>
|
|
@@ -151,11 +153,49 @@ const version = useFeatureFlagValue<AppFlags>('apiVersion');
|
|
|
151
153
|
// TypeScript knows this is 'v2' (string literal type)
|
|
152
154
|
```
|
|
153
155
|
|
|
156
|
+
### Config File Pattern
|
|
157
|
+
|
|
158
|
+
For larger projects, you can use `defineFlags` to create a centralized config file:
|
|
159
|
+
|
|
160
|
+
```ts
|
|
161
|
+
// flags.config.ts
|
|
162
|
+
import { defineFlags } from '@localflag/react';
|
|
163
|
+
|
|
164
|
+
export const flags = defineFlags({
|
|
165
|
+
darkMode: false,
|
|
166
|
+
newCheckout: true,
|
|
167
|
+
maxRetries: 3,
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
export type AppFlags = typeof flags;
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
Then import it in your app:
|
|
174
|
+
|
|
175
|
+
```tsx
|
|
176
|
+
// App.tsx
|
|
177
|
+
import { flags, AppFlags } from './flags.config';
|
|
178
|
+
import { FeatureFlagProvider, useFeatureFlag } from '@localflag/react';
|
|
179
|
+
|
|
180
|
+
function App() {
|
|
181
|
+
return (
|
|
182
|
+
<FeatureFlagProvider<AppFlags> defaultFlags={flags}>
|
|
183
|
+
<MyApp />
|
|
184
|
+
</FeatureFlagProvider>
|
|
185
|
+
);
|
|
186
|
+
}
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
Benefits:
|
|
190
|
+
- All flags managed in one place
|
|
191
|
+
- Easy to export and share types across your app
|
|
192
|
+
- Enables future tooling integration
|
|
193
|
+
|
|
154
194
|
## Persistence
|
|
155
195
|
|
|
156
196
|
By default, flag overrides are persisted to `localStorage`. This means:
|
|
157
197
|
|
|
158
|
-
- Flags you toggle in
|
|
198
|
+
- Flags you toggle in LocalFlagDevTools persist across page reloads
|
|
159
199
|
- Each user can have their own overrides for testing
|
|
160
200
|
- Call `resetFlags()` to clear all overrides and return to defaults
|
|
161
201
|
|
package/dist/index.d.ts
CHANGED
|
@@ -4,6 +4,9 @@ type FlagValue = boolean | string | number;
|
|
|
4
4
|
interface FeatureFlags {
|
|
5
5
|
[key: string]: FlagValue;
|
|
6
6
|
}
|
|
7
|
+
interface FlagDescriptions {
|
|
8
|
+
[key: string]: string;
|
|
9
|
+
}
|
|
7
10
|
interface FeatureFlagContextValue<T extends FeatureFlags = FeatureFlags> {
|
|
8
11
|
flags: T;
|
|
9
12
|
isEnabled: (flagName: keyof T) => boolean;
|
|
@@ -14,11 +17,12 @@ interface FeatureFlagContextValue<T extends FeatureFlags = FeatureFlags> {
|
|
|
14
17
|
interface FeatureFlagProviderProps<T extends FeatureFlags = FeatureFlags> {
|
|
15
18
|
children: React.ReactNode;
|
|
16
19
|
defaultFlags: T;
|
|
20
|
+
descriptions?: Partial<Record<keyof T, string>>;
|
|
17
21
|
storageKey?: string;
|
|
18
22
|
persistOverrides?: boolean;
|
|
19
23
|
}
|
|
20
24
|
|
|
21
|
-
declare function FeatureFlagProvider<T extends FeatureFlags>({ children, defaultFlags, storageKey, persistOverrides, }: FeatureFlagProviderProps<T>): react_jsx_runtime.JSX.Element;
|
|
25
|
+
declare function FeatureFlagProvider<T extends FeatureFlags>({ children, defaultFlags, descriptions, storageKey, persistOverrides, }: FeatureFlagProviderProps<T>): react_jsx_runtime.JSX.Element;
|
|
22
26
|
declare function useFeatureFlagContext<T extends FeatureFlags = FeatureFlags>(): FeatureFlagContextValue<T>;
|
|
23
27
|
|
|
24
28
|
/**
|
|
@@ -49,10 +53,73 @@ declare function FeatureFlag<T extends FeatureFlags = FeatureFlags>({ flag, chil
|
|
|
49
53
|
fallback?: React.ReactNode;
|
|
50
54
|
}): React.ReactNode;
|
|
51
55
|
|
|
56
|
+
type Position = "bottom-right" | "bottom-left" | "top-right" | "top-left";
|
|
52
57
|
interface DevToolsProps {
|
|
53
|
-
position?:
|
|
58
|
+
position?: Position;
|
|
54
59
|
defaultOpen?: boolean;
|
|
60
|
+
/**
|
|
61
|
+
* Keyboard shortcut to toggle the DevTools panel.
|
|
62
|
+
* Set to `false` to disable the shortcut.
|
|
63
|
+
* @default "mod+shift+f" (Cmd+Shift+F on Mac, Ctrl+Shift+F on Windows/Linux)
|
|
64
|
+
*/
|
|
65
|
+
shortcut?: string | false;
|
|
55
66
|
}
|
|
56
|
-
declare function
|
|
67
|
+
declare function LocalFlagDevTools({ position, defaultOpen, shortcut, }: DevToolsProps): react_jsx_runtime.JSX.Element | null;
|
|
68
|
+
/** @deprecated Use `LocalFlagDevTools` instead */
|
|
69
|
+
declare const DevTools: typeof LocalFlagDevTools;
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Helper function to define feature flags with type safety.
|
|
73
|
+
* This is a type-only helper with no runtime logic - it simply returns the flags as-is.
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* ```ts
|
|
77
|
+
* // flags.config.ts
|
|
78
|
+
* import { defineFlags } from '@localflag/react';
|
|
79
|
+
*
|
|
80
|
+
* export const flags = defineFlags({
|
|
81
|
+
* darkMode: false,
|
|
82
|
+
* newCheckout: true,
|
|
83
|
+
* maxRetries: 3,
|
|
84
|
+
* });
|
|
85
|
+
*
|
|
86
|
+
* export type AppFlags = typeof flags;
|
|
87
|
+
* ```
|
|
88
|
+
*/
|
|
89
|
+
declare function defineFlags<T extends Record<string, FlagValue>>(flags: T): T;
|
|
90
|
+
/**
|
|
91
|
+
* Flag configuration with value and optional description.
|
|
92
|
+
*/
|
|
93
|
+
interface FlagConfig<T extends FlagValue = FlagValue> {
|
|
94
|
+
value: T;
|
|
95
|
+
description?: string;
|
|
96
|
+
}
|
|
97
|
+
type FlagInput<T extends FlagValue = FlagValue> = T | FlagConfig<T>;
|
|
98
|
+
type ExtractFlagValue<T> = T extends FlagConfig<infer V> ? V : T;
|
|
99
|
+
type ExtractFlags<T extends Record<string, FlagInput>> = {
|
|
100
|
+
[K in keyof T]: ExtractFlagValue<T[K]>;
|
|
101
|
+
};
|
|
102
|
+
/**
|
|
103
|
+
* Helper function to define feature flags with descriptions.
|
|
104
|
+
* Returns both the flags object and a descriptions object.
|
|
105
|
+
*
|
|
106
|
+
* @example
|
|
107
|
+
* ```ts
|
|
108
|
+
* // flags.config.ts
|
|
109
|
+
* import { createFlags } from '@localflag/react';
|
|
110
|
+
*
|
|
111
|
+
* export const { flags, descriptions } = createFlags({
|
|
112
|
+
* darkMode: { value: false, description: "Enable dark theme" },
|
|
113
|
+
* newCheckout: { value: true, description: "Use new checkout flow" },
|
|
114
|
+
* maxRetries: 3, // Simple value without description
|
|
115
|
+
* });
|
|
116
|
+
*
|
|
117
|
+
* export type AppFlags = typeof flags;
|
|
118
|
+
* ```
|
|
119
|
+
*/
|
|
120
|
+
declare function createFlags<T extends Record<string, FlagInput>>(config: T): {
|
|
121
|
+
flags: ExtractFlags<T>;
|
|
122
|
+
descriptions: Partial<Record<keyof T, string>>;
|
|
123
|
+
};
|
|
57
124
|
|
|
58
|
-
export { DevTools, FeatureFlag, type FeatureFlagContextValue, FeatureFlagProvider, type FeatureFlagProviderProps, type FeatureFlags, type FlagValue, useFeatureFlag, useFeatureFlagContext, useFeatureFlagControls, useFeatureFlagValue, useFeatureFlags };
|
|
125
|
+
export { DevTools, FeatureFlag, type FeatureFlagContextValue, FeatureFlagProvider, type FeatureFlagProviderProps, type FeatureFlags, type FlagConfig, type FlagDescriptions, type FlagValue, LocalFlagDevTools, createFlags, defineFlags, useFeatureFlag, useFeatureFlagContext, useFeatureFlagControls, useFeatureFlagValue, useFeatureFlags };
|
package/dist/index.js
CHANGED
|
@@ -46,6 +46,7 @@ function notifyListeners() {
|
|
|
46
46
|
function FeatureFlagProvider({
|
|
47
47
|
children,
|
|
48
48
|
defaultFlags,
|
|
49
|
+
descriptions = {},
|
|
49
50
|
storageKey = STORAGE_KEY_DEFAULT,
|
|
50
51
|
persistOverrides = true
|
|
51
52
|
}) {
|
|
@@ -57,9 +58,13 @@ function FeatureFlagProvider({
|
|
|
57
58
|
[defaultFlags, overrides]
|
|
58
59
|
);
|
|
59
60
|
useEffect(() => {
|
|
60
|
-
currentState = {
|
|
61
|
+
currentState = {
|
|
62
|
+
flags,
|
|
63
|
+
defaultFlags,
|
|
64
|
+
descriptions
|
|
65
|
+
};
|
|
61
66
|
notifyListeners();
|
|
62
|
-
}, [flags, defaultFlags]);
|
|
67
|
+
}, [flags, defaultFlags, descriptions]);
|
|
63
68
|
useEffect(() => {
|
|
64
69
|
if (persistOverrides) {
|
|
65
70
|
setStoredOverrides(storageKey, overrides);
|
|
@@ -141,174 +146,271 @@ function FeatureFlag({
|
|
|
141
146
|
}
|
|
142
147
|
|
|
143
148
|
// src/devtools.tsx
|
|
144
|
-
import { useState as useState2 } from "react";
|
|
145
|
-
import { jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
149
|
+
import { useState as useState2, useEffect as useEffect2 } from "react";
|
|
150
|
+
import { Fragment, jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
151
|
+
var POSITION_STORAGE_KEY = "localflag:position";
|
|
146
152
|
var positionStyles = {
|
|
147
|
-
"bottom-right": { bottom:
|
|
148
|
-
"bottom-left": { bottom:
|
|
149
|
-
"top-right": { top:
|
|
150
|
-
"top-left": { top:
|
|
153
|
+
"bottom-right": { bottom: 12, right: 12 },
|
|
154
|
+
"bottom-left": { bottom: 12, left: 12 },
|
|
155
|
+
"top-right": { top: 12, right: 12 },
|
|
156
|
+
"top-left": { top: 12, left: 12 }
|
|
151
157
|
};
|
|
152
158
|
var baseStyles = {
|
|
153
159
|
position: "fixed",
|
|
154
160
|
zIndex: 99999,
|
|
155
|
-
fontFamily: 'ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace',
|
|
156
|
-
fontSize:
|
|
161
|
+
fontFamily: 'ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace',
|
|
162
|
+
fontSize: 12,
|
|
163
|
+
lineHeight: 1.5,
|
|
164
|
+
WebkitFontSmoothing: "antialiased"
|
|
157
165
|
};
|
|
158
166
|
var panelStyles = {
|
|
159
|
-
backgroundColor: "#
|
|
160
|
-
border: "1px solid
|
|
161
|
-
borderRadius:
|
|
162
|
-
boxShadow: "0
|
|
167
|
+
backgroundColor: "#0a0a0a",
|
|
168
|
+
border: "1px solid rgba(255, 255, 255, 0.08)",
|
|
169
|
+
borderRadius: 10,
|
|
170
|
+
boxShadow: "0 0 0 1px rgba(0, 0, 0, 0.5), 0 16px 70px rgba(0, 0, 0, 0.6)",
|
|
163
171
|
overflow: "hidden",
|
|
164
|
-
minWidth:
|
|
165
|
-
maxWidth:
|
|
166
|
-
maxHeight: "
|
|
172
|
+
minWidth: 260,
|
|
173
|
+
maxWidth: 320,
|
|
174
|
+
maxHeight: "60vh"
|
|
167
175
|
};
|
|
168
176
|
var headerStyles = {
|
|
169
177
|
display: "flex",
|
|
170
178
|
alignItems: "center",
|
|
171
179
|
justifyContent: "space-between",
|
|
172
180
|
padding: "10px 12px",
|
|
173
|
-
|
|
174
|
-
borderBottom: "1px solid #2d2d44",
|
|
181
|
+
borderBottom: "1px solid rgba(255, 255, 255, 0.06)",
|
|
175
182
|
cursor: "pointer",
|
|
176
183
|
userSelect: "none"
|
|
177
184
|
};
|
|
178
185
|
var titleStyles = {
|
|
179
|
-
color: "
|
|
180
|
-
fontWeight:
|
|
181
|
-
fontSize:
|
|
182
|
-
|
|
183
|
-
letterSpacing: "0.5px",
|
|
186
|
+
color: "rgba(255, 255, 255, 0.9)",
|
|
187
|
+
fontWeight: 500,
|
|
188
|
+
fontSize: 11,
|
|
189
|
+
letterSpacing: "0.01em",
|
|
184
190
|
display: "flex",
|
|
185
191
|
alignItems: "center",
|
|
186
|
-
gap:
|
|
192
|
+
gap: 8
|
|
193
|
+
};
|
|
194
|
+
var tabBarStyles = {
|
|
195
|
+
display: "flex",
|
|
196
|
+
borderBottom: "1px solid rgba(255, 255, 255, 0.06)",
|
|
197
|
+
padding: "0 12px",
|
|
198
|
+
gap: 4
|
|
199
|
+
};
|
|
200
|
+
var tabStyles = {
|
|
201
|
+
padding: "8px 10px",
|
|
202
|
+
fontSize: 11,
|
|
203
|
+
fontWeight: 500,
|
|
204
|
+
color: "rgba(255, 255, 255, 0.5)",
|
|
205
|
+
backgroundColor: "transparent",
|
|
206
|
+
border: "none",
|
|
207
|
+
borderBottom: "2px solid transparent",
|
|
208
|
+
cursor: "pointer",
|
|
209
|
+
transition: "color 0.15s ease",
|
|
210
|
+
fontFamily: "inherit",
|
|
211
|
+
marginBottom: -1
|
|
212
|
+
};
|
|
213
|
+
var tabActiveStyles = {
|
|
214
|
+
...tabStyles,
|
|
215
|
+
color: "rgba(255, 255, 255, 0.9)",
|
|
216
|
+
borderBottomColor: "#fff"
|
|
187
217
|
};
|
|
188
218
|
var contentStyles = {
|
|
189
219
|
padding: 0,
|
|
190
220
|
overflowY: "auto",
|
|
191
|
-
maxHeight: "calc(
|
|
221
|
+
maxHeight: "calc(60vh - 84px)"
|
|
192
222
|
};
|
|
193
223
|
var flagRowStyles = {
|
|
194
224
|
display: "flex",
|
|
195
225
|
alignItems: "center",
|
|
196
226
|
justifyContent: "space-between",
|
|
197
|
-
padding: "
|
|
198
|
-
borderBottom: "1px solid
|
|
199
|
-
transition: "background-color 0.15s"
|
|
227
|
+
padding: "8px 12px",
|
|
228
|
+
borderBottom: "1px solid rgba(255, 255, 255, 0.04)",
|
|
229
|
+
transition: "background-color 0.15s ease",
|
|
230
|
+
gap: 12
|
|
200
231
|
};
|
|
201
|
-
var
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
232
|
+
var flagRowHoverStyles = {
|
|
233
|
+
backgroundColor: "rgba(255, 255, 255, 0.03)"
|
|
234
|
+
};
|
|
235
|
+
var flagNameContainerStyles = {
|
|
205
236
|
flex: 1,
|
|
206
237
|
overflow: "hidden",
|
|
238
|
+
display: "flex",
|
|
239
|
+
flexDirection: "column",
|
|
240
|
+
gap: 2,
|
|
241
|
+
minWidth: 0
|
|
242
|
+
};
|
|
243
|
+
var flagNameStyles = {
|
|
244
|
+
color: "rgba(255, 255, 255, 0.7)",
|
|
245
|
+
fontSize: 12,
|
|
246
|
+
fontWeight: 400,
|
|
247
|
+
overflow: "hidden",
|
|
248
|
+
textOverflow: "ellipsis",
|
|
249
|
+
whiteSpace: "nowrap",
|
|
250
|
+
display: "flex",
|
|
251
|
+
alignItems: "center",
|
|
252
|
+
gap: 6
|
|
253
|
+
};
|
|
254
|
+
var flagDescriptionStyles = {
|
|
255
|
+
color: "rgba(255, 255, 255, 0.4)",
|
|
256
|
+
fontSize: 10,
|
|
257
|
+
fontWeight: 400,
|
|
258
|
+
overflow: "hidden",
|
|
207
259
|
textOverflow: "ellipsis",
|
|
208
260
|
whiteSpace: "nowrap"
|
|
209
261
|
};
|
|
210
262
|
var toggleStyles = {
|
|
211
263
|
position: "relative",
|
|
212
|
-
width:
|
|
213
|
-
height:
|
|
214
|
-
backgroundColor: "
|
|
215
|
-
borderRadius:
|
|
264
|
+
width: 28,
|
|
265
|
+
height: 16,
|
|
266
|
+
backgroundColor: "rgba(255, 255, 255, 0.1)",
|
|
267
|
+
borderRadius: 8,
|
|
216
268
|
cursor: "pointer",
|
|
217
|
-
transition: "background-color 0.
|
|
269
|
+
transition: "background-color 0.15s ease",
|
|
218
270
|
flexShrink: 0,
|
|
219
271
|
border: "none",
|
|
220
272
|
padding: 0
|
|
221
273
|
};
|
|
222
274
|
var toggleActiveStyles = {
|
|
223
275
|
...toggleStyles,
|
|
224
|
-
backgroundColor: "#
|
|
276
|
+
backgroundColor: "#fff"
|
|
225
277
|
};
|
|
226
278
|
var toggleKnobStyles = {
|
|
227
279
|
position: "absolute",
|
|
228
280
|
top: 2,
|
|
229
281
|
left: 2,
|
|
230
|
-
width:
|
|
231
|
-
height:
|
|
232
|
-
backgroundColor: "
|
|
282
|
+
width: 12,
|
|
283
|
+
height: 12,
|
|
284
|
+
backgroundColor: "rgba(255, 255, 255, 0.5)",
|
|
233
285
|
borderRadius: "50%",
|
|
234
|
-
transition: "transform 0.
|
|
235
|
-
boxShadow: "0 1px 3px rgba(0, 0, 0, 0.3)"
|
|
286
|
+
transition: "transform 0.15s ease, background-color 0.15s ease"
|
|
236
287
|
};
|
|
237
288
|
var toggleKnobActiveStyles = {
|
|
238
289
|
...toggleKnobStyles,
|
|
239
|
-
transform: "translateX(
|
|
290
|
+
transform: "translateX(12px)",
|
|
291
|
+
backgroundColor: "#0a0a0a"
|
|
240
292
|
};
|
|
241
293
|
var inputStyles = {
|
|
242
|
-
backgroundColor: "
|
|
243
|
-
border: "1px solid
|
|
244
|
-
borderRadius:
|
|
245
|
-
color: "
|
|
246
|
-
padding: "
|
|
247
|
-
fontSize:
|
|
248
|
-
width:
|
|
249
|
-
outline: "none"
|
|
250
|
-
|
|
251
|
-
var badgeStyles = {
|
|
252
|
-
backgroundColor: "#4ade80",
|
|
253
|
-
color: "#1a1a2e",
|
|
254
|
-
fontSize: 10,
|
|
255
|
-
fontWeight: 700,
|
|
256
|
-
padding: "2px 6px",
|
|
257
|
-
borderRadius: 4,
|
|
258
|
-
marginLeft: 6
|
|
294
|
+
backgroundColor: "rgba(255, 255, 255, 0.05)",
|
|
295
|
+
border: "1px solid rgba(255, 255, 255, 0.1)",
|
|
296
|
+
borderRadius: 5,
|
|
297
|
+
color: "rgba(255, 255, 255, 0.9)",
|
|
298
|
+
padding: "3px 8px",
|
|
299
|
+
fontSize: 11,
|
|
300
|
+
width: 72,
|
|
301
|
+
outline: "none",
|
|
302
|
+
transition: "border-color 0.15s ease, background-color 0.15s ease"
|
|
259
303
|
};
|
|
260
|
-
var
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
borderRadius: 3,
|
|
267
|
-
marginLeft: 6
|
|
304
|
+
var overrideDotStyles = {
|
|
305
|
+
width: 5,
|
|
306
|
+
height: 5,
|
|
307
|
+
borderRadius: "50%",
|
|
308
|
+
backgroundColor: "#3b82f6",
|
|
309
|
+
flexShrink: 0
|
|
268
310
|
};
|
|
269
311
|
var buttonStyles = {
|
|
270
312
|
backgroundColor: "transparent",
|
|
271
313
|
border: "none",
|
|
272
|
-
color: "
|
|
314
|
+
color: "rgba(255, 255, 255, 0.4)",
|
|
273
315
|
cursor: "pointer",
|
|
274
316
|
padding: 4,
|
|
275
317
|
borderRadius: 4,
|
|
276
318
|
display: "flex",
|
|
277
319
|
alignItems: "center",
|
|
278
320
|
justifyContent: "center",
|
|
279
|
-
transition: "color 0.15s
|
|
321
|
+
transition: "color 0.15s ease"
|
|
280
322
|
};
|
|
281
323
|
var resetButtonStyles = {
|
|
282
|
-
backgroundColor: "
|
|
283
|
-
border: "1px solid
|
|
284
|
-
borderRadius:
|
|
285
|
-
color: "
|
|
286
|
-
padding: "6px
|
|
324
|
+
backgroundColor: "rgba(255, 255, 255, 0.05)",
|
|
325
|
+
border: "1px solid rgba(255, 255, 255, 0.08)",
|
|
326
|
+
borderRadius: 6,
|
|
327
|
+
color: "rgba(255, 255, 255, 0.6)",
|
|
328
|
+
padding: "6px 10px",
|
|
287
329
|
fontSize: 11,
|
|
330
|
+
fontWeight: 500,
|
|
288
331
|
cursor: "pointer",
|
|
289
|
-
margin: "8px 12px
|
|
332
|
+
margin: "8px 12px 10px",
|
|
290
333
|
width: "calc(100% - 24px)",
|
|
291
|
-
transition: "background-color 0.15s"
|
|
334
|
+
transition: "background-color 0.15s ease, color 0.15s ease",
|
|
335
|
+
fontFamily: "inherit"
|
|
292
336
|
};
|
|
293
337
|
var fabStyles = {
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
338
|
+
height: 32,
|
|
339
|
+
paddingLeft: 10,
|
|
340
|
+
paddingRight: 10,
|
|
341
|
+
borderRadius: 8,
|
|
342
|
+
backgroundColor: "#0a0a0a",
|
|
343
|
+
border: "1px solid rgba(255, 255, 255, 0.1)",
|
|
344
|
+
cursor: "pointer",
|
|
345
|
+
display: "flex",
|
|
346
|
+
alignItems: "center",
|
|
347
|
+
justifyContent: "center",
|
|
348
|
+
gap: 6,
|
|
349
|
+
boxShadow: "0 0 0 1px rgba(0, 0, 0, 0.5), 0 4px 16px rgba(0, 0, 0, 0.4)",
|
|
350
|
+
transition: "background-color 0.15s ease, border-color 0.15s ease",
|
|
351
|
+
fontFamily: "inherit",
|
|
352
|
+
fontSize: 11,
|
|
353
|
+
fontWeight: 500,
|
|
354
|
+
color: "rgba(255, 255, 255, 0.8)"
|
|
355
|
+
};
|
|
356
|
+
var badgeStyles = {
|
|
357
|
+
backgroundColor: "#3b82f6",
|
|
358
|
+
color: "#fff",
|
|
359
|
+
fontSize: 9,
|
|
360
|
+
fontWeight: 600,
|
|
361
|
+
minWidth: 14,
|
|
362
|
+
height: 14,
|
|
363
|
+
padding: "0 4px",
|
|
364
|
+
borderRadius: 7,
|
|
365
|
+
display: "inline-flex",
|
|
366
|
+
alignItems: "center",
|
|
367
|
+
justifyContent: "center"
|
|
368
|
+
};
|
|
369
|
+
var optionsSectionStyles = {
|
|
370
|
+
padding: "12px"
|
|
371
|
+
};
|
|
372
|
+
var optionsLabelStyles = {
|
|
373
|
+
fontSize: 10,
|
|
374
|
+
fontWeight: 500,
|
|
375
|
+
color: "rgba(255, 255, 255, 0.5)",
|
|
376
|
+
textTransform: "uppercase",
|
|
377
|
+
letterSpacing: "0.05em",
|
|
378
|
+
marginBottom: 8,
|
|
379
|
+
display: "block"
|
|
380
|
+
};
|
|
381
|
+
var positionGridStyles = {
|
|
382
|
+
display: "grid",
|
|
383
|
+
gridTemplateColumns: "1fr 1fr",
|
|
384
|
+
gap: 6
|
|
385
|
+
};
|
|
386
|
+
var positionButtonStyles = {
|
|
387
|
+
padding: "8px",
|
|
388
|
+
fontSize: 10,
|
|
389
|
+
fontWeight: 500,
|
|
390
|
+
color: "rgba(255, 255, 255, 0.6)",
|
|
391
|
+
backgroundColor: "rgba(255, 255, 255, 0.03)",
|
|
392
|
+
border: "1px solid rgba(255, 255, 255, 0.08)",
|
|
393
|
+
borderRadius: 6,
|
|
299
394
|
cursor: "pointer",
|
|
395
|
+
transition: "all 0.15s ease",
|
|
396
|
+
fontFamily: "inherit",
|
|
300
397
|
display: "flex",
|
|
301
398
|
alignItems: "center",
|
|
302
399
|
justifyContent: "center",
|
|
303
|
-
|
|
304
|
-
transition: "transform 0.15s, box-shadow 0.15s"
|
|
400
|
+
gap: 6
|
|
305
401
|
};
|
|
306
|
-
|
|
402
|
+
var positionButtonActiveStyles = {
|
|
403
|
+
...positionButtonStyles,
|
|
404
|
+
color: "rgba(255, 255, 255, 0.9)",
|
|
405
|
+
backgroundColor: "rgba(255, 255, 255, 0.1)",
|
|
406
|
+
borderColor: "rgba(255, 255, 255, 0.2)"
|
|
407
|
+
};
|
|
408
|
+
function FlagIcon({ size = 14 }) {
|
|
307
409
|
return /* @__PURE__ */ jsxs(
|
|
308
410
|
"svg",
|
|
309
411
|
{
|
|
310
|
-
width:
|
|
311
|
-
height:
|
|
412
|
+
width: size,
|
|
413
|
+
height: size,
|
|
312
414
|
viewBox: "0 0 24 24",
|
|
313
415
|
fill: "none",
|
|
314
416
|
stroke: "currentColor",
|
|
@@ -322,22 +424,57 @@ function FlagIcon() {
|
|
|
322
424
|
}
|
|
323
425
|
);
|
|
324
426
|
}
|
|
325
|
-
function
|
|
326
|
-
return /* @__PURE__ */
|
|
427
|
+
function ChevronIcon({ direction }) {
|
|
428
|
+
return /* @__PURE__ */ jsx2(
|
|
327
429
|
"svg",
|
|
328
430
|
{
|
|
329
|
-
width: "
|
|
330
|
-
height: "
|
|
431
|
+
width: "12",
|
|
432
|
+
height: "12",
|
|
331
433
|
viewBox: "0 0 24 24",
|
|
332
434
|
fill: "none",
|
|
333
435
|
stroke: "currentColor",
|
|
334
436
|
strokeWidth: "2",
|
|
335
437
|
strokeLinecap: "round",
|
|
336
438
|
strokeLinejoin: "round",
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
439
|
+
style: {
|
|
440
|
+
transform: direction === "up" ? "rotate(180deg)" : "rotate(0deg)",
|
|
441
|
+
transition: "transform 0.15s ease"
|
|
442
|
+
},
|
|
443
|
+
children: /* @__PURE__ */ jsx2("polyline", { points: "6 9 12 15 18 9" })
|
|
444
|
+
}
|
|
445
|
+
);
|
|
446
|
+
}
|
|
447
|
+
function PositionIcon({ position }) {
|
|
448
|
+
const dotPosition = {
|
|
449
|
+
"top-left": { top: 2, left: 2 },
|
|
450
|
+
"top-right": { top: 2, right: 2 },
|
|
451
|
+
"bottom-left": { bottom: 2, left: 2 },
|
|
452
|
+
"bottom-right": { bottom: 2, right: 2 }
|
|
453
|
+
}[position];
|
|
454
|
+
return /* @__PURE__ */ jsx2(
|
|
455
|
+
"div",
|
|
456
|
+
{
|
|
457
|
+
style: {
|
|
458
|
+
width: 14,
|
|
459
|
+
height: 14,
|
|
460
|
+
border: "1px solid currentColor",
|
|
461
|
+
borderRadius: 2,
|
|
462
|
+
position: "relative",
|
|
463
|
+
opacity: 0.7
|
|
464
|
+
},
|
|
465
|
+
children: /* @__PURE__ */ jsx2(
|
|
466
|
+
"div",
|
|
467
|
+
{
|
|
468
|
+
style: {
|
|
469
|
+
position: "absolute",
|
|
470
|
+
width: 4,
|
|
471
|
+
height: 4,
|
|
472
|
+
backgroundColor: "currentColor",
|
|
473
|
+
borderRadius: 1,
|
|
474
|
+
...dotPosition
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
)
|
|
341
478
|
}
|
|
342
479
|
);
|
|
343
480
|
}
|
|
@@ -345,9 +482,11 @@ function FlagRow({
|
|
|
345
482
|
name,
|
|
346
483
|
value,
|
|
347
484
|
defaultValue,
|
|
485
|
+
description,
|
|
348
486
|
onToggle,
|
|
349
487
|
onChange
|
|
350
488
|
}) {
|
|
489
|
+
const [isHovered, setIsHovered] = useState2(false);
|
|
351
490
|
const isOverridden = value !== defaultValue;
|
|
352
491
|
const isBoolean = typeof value === "boolean";
|
|
353
492
|
const handleInputChange = (e) => {
|
|
@@ -359,43 +498,136 @@ function FlagRow({
|
|
|
359
498
|
onChange(newValue);
|
|
360
499
|
}
|
|
361
500
|
};
|
|
362
|
-
return /* @__PURE__ */ jsxs(
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
501
|
+
return /* @__PURE__ */ jsxs(
|
|
502
|
+
"div",
|
|
503
|
+
{
|
|
504
|
+
style: {
|
|
505
|
+
...flagRowStyles,
|
|
506
|
+
...isHovered ? flagRowHoverStyles : {}
|
|
507
|
+
},
|
|
508
|
+
onMouseEnter: () => setIsHovered(true),
|
|
509
|
+
onMouseLeave: () => setIsHovered(false),
|
|
510
|
+
children: [
|
|
511
|
+
/* @__PURE__ */ jsxs("div", { style: flagNameContainerStyles, children: [
|
|
512
|
+
/* @__PURE__ */ jsxs("span", { style: flagNameStyles, children: [
|
|
513
|
+
isOverridden && /* @__PURE__ */ jsx2("span", { style: overrideDotStyles }),
|
|
514
|
+
name
|
|
515
|
+
] }),
|
|
516
|
+
description && /* @__PURE__ */ jsx2("span", { style: flagDescriptionStyles, children: description })
|
|
517
|
+
] }),
|
|
518
|
+
isBoolean ? /* @__PURE__ */ jsx2(
|
|
519
|
+
"button",
|
|
520
|
+
{
|
|
521
|
+
style: value ? toggleActiveStyles : toggleStyles,
|
|
522
|
+
onClick: onToggle,
|
|
523
|
+
type: "button",
|
|
524
|
+
"aria-label": `Toggle ${name}`,
|
|
525
|
+
children: /* @__PURE__ */ jsx2("span", { style: value ? toggleKnobActiveStyles : toggleKnobStyles })
|
|
526
|
+
}
|
|
527
|
+
) : /* @__PURE__ */ jsx2(
|
|
528
|
+
"input",
|
|
529
|
+
{
|
|
530
|
+
style: inputStyles,
|
|
531
|
+
type: "text",
|
|
532
|
+
value: String(value),
|
|
533
|
+
onChange: handleInputChange,
|
|
534
|
+
onFocus: (e) => {
|
|
535
|
+
e.target.style.borderColor = "rgba(255, 255, 255, 0.2)";
|
|
536
|
+
e.target.style.backgroundColor = "rgba(255, 255, 255, 0.08)";
|
|
537
|
+
},
|
|
538
|
+
onBlur: (e) => {
|
|
539
|
+
e.target.style.borderColor = "rgba(255, 255, 255, 0.1)";
|
|
540
|
+
e.target.style.backgroundColor = "rgba(255, 255, 255, 0.05)";
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
)
|
|
544
|
+
]
|
|
545
|
+
}
|
|
546
|
+
);
|
|
547
|
+
}
|
|
548
|
+
function OptionsTab({
|
|
549
|
+
position,
|
|
550
|
+
onPositionChange
|
|
551
|
+
}) {
|
|
552
|
+
const [hoveredPosition, setHoveredPosition] = useState2(null);
|
|
553
|
+
const positions = [
|
|
554
|
+
{ value: "top-left", label: "Top Left" },
|
|
555
|
+
{ value: "top-right", label: "Top Right" },
|
|
556
|
+
{ value: "bottom-left", label: "Bottom Left" },
|
|
557
|
+
{ value: "bottom-right", label: "Bottom Right" }
|
|
558
|
+
];
|
|
559
|
+
return /* @__PURE__ */ jsxs("div", { style: optionsSectionStyles, children: [
|
|
560
|
+
/* @__PURE__ */ jsx2("span", { style: optionsLabelStyles, children: "Position" }),
|
|
561
|
+
/* @__PURE__ */ jsx2("div", { style: positionGridStyles, children: positions.map(({ value, label }) => {
|
|
562
|
+
const isActive = position === value;
|
|
563
|
+
const isHovered = hoveredPosition === value;
|
|
564
|
+
return /* @__PURE__ */ jsxs(
|
|
565
|
+
"button",
|
|
566
|
+
{
|
|
567
|
+
style: {
|
|
568
|
+
...isActive ? positionButtonActiveStyles : positionButtonStyles,
|
|
569
|
+
...isHovered && !isActive ? {
|
|
570
|
+
backgroundColor: "rgba(255, 255, 255, 0.05)",
|
|
571
|
+
borderColor: "rgba(255, 255, 255, 0.12)"
|
|
572
|
+
} : {}
|
|
573
|
+
},
|
|
574
|
+
onClick: () => onPositionChange(value),
|
|
575
|
+
onMouseEnter: () => setHoveredPosition(value),
|
|
576
|
+
onMouseLeave: () => setHoveredPosition(null),
|
|
577
|
+
type: "button",
|
|
578
|
+
children: [
|
|
579
|
+
/* @__PURE__ */ jsx2(PositionIcon, { position: value }),
|
|
580
|
+
label
|
|
581
|
+
]
|
|
582
|
+
},
|
|
583
|
+
value
|
|
584
|
+
);
|
|
585
|
+
}) })
|
|
385
586
|
] });
|
|
386
587
|
}
|
|
387
588
|
function DevToolsInner({
|
|
388
|
-
position,
|
|
389
|
-
defaultOpen
|
|
589
|
+
position: initialPosition,
|
|
590
|
+
defaultOpen,
|
|
591
|
+
shortcut
|
|
390
592
|
}) {
|
|
391
593
|
const [isOpen, setIsOpen] = useState2(defaultOpen);
|
|
594
|
+
const [activeTab, setActiveTab] = useState2("flags");
|
|
595
|
+
const [position, setPosition] = useState2(() => {
|
|
596
|
+
if (typeof window !== "undefined") {
|
|
597
|
+
const stored = localStorage.getItem(POSITION_STORAGE_KEY);
|
|
598
|
+
if (stored && stored in positionStyles) {
|
|
599
|
+
return stored;
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
return initialPosition;
|
|
603
|
+
});
|
|
604
|
+
const [fabHovered, setFabHovered] = useState2(false);
|
|
605
|
+
const [resetHovered, setResetHovered] = useState2(false);
|
|
606
|
+
const [headerHovered, setHeaderHovered] = useState2(false);
|
|
392
607
|
const flagState = useFlagState();
|
|
393
608
|
const context = useFeatureFlagContext();
|
|
609
|
+
useEffect2(() => {
|
|
610
|
+
if (shortcut === false) return;
|
|
611
|
+
const handleKeyDown = (e) => {
|
|
612
|
+
const isMod = e.metaKey || e.ctrlKey;
|
|
613
|
+
if (isMod && e.shiftKey && e.key.toLowerCase() === "f") {
|
|
614
|
+
e.preventDefault();
|
|
615
|
+
setIsOpen((prev) => !prev);
|
|
616
|
+
}
|
|
617
|
+
};
|
|
618
|
+
window.addEventListener("keydown", handleKeyDown);
|
|
619
|
+
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
620
|
+
}, [shortcut]);
|
|
621
|
+
useEffect2(() => {
|
|
622
|
+
if (typeof window !== "undefined") {
|
|
623
|
+
localStorage.setItem(POSITION_STORAGE_KEY, position);
|
|
624
|
+
}
|
|
625
|
+
}, [position]);
|
|
394
626
|
if (!flagState) {
|
|
395
627
|
return null;
|
|
396
628
|
}
|
|
397
629
|
const { setFlag, resetFlags } = context;
|
|
398
|
-
const { flags, defaultFlags } = flagState;
|
|
630
|
+
const { flags, defaultFlags, descriptions } = flagState;
|
|
399
631
|
const flagEntries = Object.entries(flags);
|
|
400
632
|
const overrideCount = flagEntries.filter(
|
|
401
633
|
([key, value]) => value !== defaultFlags[key]
|
|
@@ -410,54 +642,169 @@ function DevToolsInner({
|
|
|
410
642
|
setFlag(key, value);
|
|
411
643
|
};
|
|
412
644
|
if (!isOpen) {
|
|
413
|
-
return /* @__PURE__ */ jsx2("div", { style: { ...baseStyles, ...positionStyles[position] }, children: /* @__PURE__ */
|
|
645
|
+
return /* @__PURE__ */ jsx2("div", { style: { ...baseStyles, ...positionStyles[position] }, children: /* @__PURE__ */ jsxs(
|
|
414
646
|
"button",
|
|
415
647
|
{
|
|
416
|
-
style:
|
|
648
|
+
style: {
|
|
649
|
+
...fabStyles,
|
|
650
|
+
...fabHovered ? {
|
|
651
|
+
backgroundColor: "#141414",
|
|
652
|
+
borderColor: "rgba(255, 255, 255, 0.15)"
|
|
653
|
+
} : {}
|
|
654
|
+
},
|
|
417
655
|
onClick: () => setIsOpen(true),
|
|
656
|
+
onMouseEnter: () => setFabHovered(true),
|
|
657
|
+
onMouseLeave: () => setFabHovered(false),
|
|
418
658
|
type: "button",
|
|
419
659
|
"aria-label": "Open feature flags devtools",
|
|
420
|
-
children:
|
|
660
|
+
children: [
|
|
661
|
+
/* @__PURE__ */ jsx2(FlagIcon, { size: 12 }),
|
|
662
|
+
/* @__PURE__ */ jsx2("span", { children: "Flags" }),
|
|
663
|
+
overrideCount > 0 && /* @__PURE__ */ jsx2("span", { style: badgeStyles, children: overrideCount })
|
|
664
|
+
]
|
|
421
665
|
}
|
|
422
666
|
) });
|
|
423
667
|
}
|
|
424
668
|
return /* @__PURE__ */ jsx2("div", { style: { ...baseStyles, ...positionStyles[position] }, children: /* @__PURE__ */ jsxs("div", { style: panelStyles, children: [
|
|
425
|
-
/* @__PURE__ */ jsxs(
|
|
426
|
-
|
|
427
|
-
/* @__PURE__ */ jsx2(FlagIcon, {}),
|
|
428
|
-
"Feature Flags",
|
|
429
|
-
overrideCount > 0 && /* @__PURE__ */ jsx2("span", { style: badgeStyles, children: overrideCount })
|
|
430
|
-
] }),
|
|
431
|
-
/* @__PURE__ */ jsx2("button", { style: buttonStyles, type: "button", "aria-label": "Close", children: /* @__PURE__ */ jsx2(CloseIcon, {}) })
|
|
432
|
-
] }),
|
|
433
|
-
/* @__PURE__ */ jsx2("div", { style: contentStyles, children: flagEntries.map(([key, value]) => /* @__PURE__ */ jsx2(
|
|
434
|
-
FlagRow,
|
|
669
|
+
/* @__PURE__ */ jsxs(
|
|
670
|
+
"div",
|
|
435
671
|
{
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
672
|
+
style: {
|
|
673
|
+
...headerStyles,
|
|
674
|
+
...headerHovered ? { backgroundColor: "rgba(255, 255, 255, 0.02)" } : {}
|
|
675
|
+
},
|
|
676
|
+
onClick: () => setIsOpen(false),
|
|
677
|
+
onMouseEnter: () => setHeaderHovered(true),
|
|
678
|
+
onMouseLeave: () => setHeaderHovered(false),
|
|
679
|
+
children: [
|
|
680
|
+
/* @__PURE__ */ jsxs("span", { style: titleStyles, children: [
|
|
681
|
+
/* @__PURE__ */ jsx2(FlagIcon, { size: 12 }),
|
|
682
|
+
"Feature Flags",
|
|
683
|
+
overrideCount > 0 && /* @__PURE__ */ jsx2("span", { style: badgeStyles, children: overrideCount })
|
|
684
|
+
] }),
|
|
685
|
+
/* @__PURE__ */ jsx2(
|
|
686
|
+
"button",
|
|
687
|
+
{
|
|
688
|
+
style: {
|
|
689
|
+
...buttonStyles,
|
|
690
|
+
...headerHovered ? { color: "rgba(255, 255, 255, 0.6)" } : {}
|
|
691
|
+
},
|
|
692
|
+
type: "button",
|
|
693
|
+
"aria-label": "Close",
|
|
694
|
+
children: /* @__PURE__ */ jsx2(ChevronIcon, { direction: "down" })
|
|
695
|
+
}
|
|
696
|
+
)
|
|
697
|
+
]
|
|
698
|
+
}
|
|
699
|
+
),
|
|
700
|
+
/* @__PURE__ */ jsxs("div", { style: tabBarStyles, children: [
|
|
701
|
+
/* @__PURE__ */ jsx2(
|
|
702
|
+
"button",
|
|
703
|
+
{
|
|
704
|
+
style: activeTab === "flags" ? tabActiveStyles : tabStyles,
|
|
705
|
+
onClick: (e) => {
|
|
706
|
+
e.stopPropagation();
|
|
707
|
+
setActiveTab("flags");
|
|
708
|
+
},
|
|
709
|
+
type: "button",
|
|
710
|
+
children: "Flags"
|
|
711
|
+
}
|
|
712
|
+
),
|
|
713
|
+
/* @__PURE__ */ jsx2(
|
|
714
|
+
"button",
|
|
715
|
+
{
|
|
716
|
+
style: activeTab === "options" ? tabActiveStyles : tabStyles,
|
|
717
|
+
onClick: (e) => {
|
|
718
|
+
e.stopPropagation();
|
|
719
|
+
setActiveTab("options");
|
|
720
|
+
},
|
|
721
|
+
type: "button",
|
|
722
|
+
children: "Options"
|
|
723
|
+
}
|
|
724
|
+
)
|
|
725
|
+
] }),
|
|
726
|
+
activeTab === "flags" ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
727
|
+
/* @__PURE__ */ jsx2("div", { style: contentStyles, children: flagEntries.map(([key, value]) => /* @__PURE__ */ jsx2(
|
|
728
|
+
FlagRow,
|
|
729
|
+
{
|
|
730
|
+
name: key,
|
|
731
|
+
value,
|
|
732
|
+
defaultValue: defaultFlags[key],
|
|
733
|
+
description: descriptions[key],
|
|
734
|
+
onToggle: () => handleToggle(key),
|
|
735
|
+
onChange: (newValue) => handleChange(key, newValue)
|
|
736
|
+
},
|
|
737
|
+
key
|
|
738
|
+
)) }),
|
|
739
|
+
overrideCount > 0 && /* @__PURE__ */ jsx2(
|
|
740
|
+
"button",
|
|
741
|
+
{
|
|
742
|
+
style: {
|
|
743
|
+
...resetButtonStyles,
|
|
744
|
+
...resetHovered ? {
|
|
745
|
+
backgroundColor: "rgba(255, 255, 255, 0.08)",
|
|
746
|
+
color: "rgba(255, 255, 255, 0.8)"
|
|
747
|
+
} : {}
|
|
748
|
+
},
|
|
749
|
+
onClick: resetFlags,
|
|
750
|
+
onMouseEnter: () => setResetHovered(true),
|
|
751
|
+
onMouseLeave: () => setResetHovered(false),
|
|
752
|
+
type: "button",
|
|
753
|
+
children: "Reset overrides"
|
|
754
|
+
}
|
|
755
|
+
)
|
|
756
|
+
] }) : /* @__PURE__ */ jsx2(OptionsTab, { position, onPositionChange: setPosition })
|
|
445
757
|
] }) });
|
|
446
758
|
}
|
|
447
|
-
function
|
|
759
|
+
function LocalFlagDevTools({
|
|
448
760
|
position = "bottom-right",
|
|
449
|
-
defaultOpen = false
|
|
761
|
+
defaultOpen = false,
|
|
762
|
+
shortcut = "mod+shift+f"
|
|
450
763
|
}) {
|
|
451
764
|
const isDev = typeof __DEV__ !== "undefined" ? __DEV__ : true;
|
|
452
765
|
if (!isDev) {
|
|
453
766
|
return null;
|
|
454
767
|
}
|
|
455
|
-
return /* @__PURE__ */ jsx2(
|
|
768
|
+
return /* @__PURE__ */ jsx2(
|
|
769
|
+
DevToolsInner,
|
|
770
|
+
{
|
|
771
|
+
position,
|
|
772
|
+
defaultOpen,
|
|
773
|
+
shortcut
|
|
774
|
+
}
|
|
775
|
+
);
|
|
776
|
+
}
|
|
777
|
+
var DevTools = LocalFlagDevTools;
|
|
778
|
+
|
|
779
|
+
// src/config.ts
|
|
780
|
+
function defineFlags(flags) {
|
|
781
|
+
return flags;
|
|
782
|
+
}
|
|
783
|
+
function createFlags(config) {
|
|
784
|
+
const flags = {};
|
|
785
|
+
const descriptions = {};
|
|
786
|
+
for (const [key, value] of Object.entries(config)) {
|
|
787
|
+
if (typeof value === "object" && value !== null && "value" in value) {
|
|
788
|
+
flags[key] = value.value;
|
|
789
|
+
if (value.description) {
|
|
790
|
+
descriptions[key] = value.description;
|
|
791
|
+
}
|
|
792
|
+
} else {
|
|
793
|
+
flags[key] = value;
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
return {
|
|
797
|
+
flags,
|
|
798
|
+
descriptions
|
|
799
|
+
};
|
|
456
800
|
}
|
|
457
801
|
export {
|
|
458
802
|
DevTools,
|
|
459
803
|
FeatureFlag,
|
|
460
804
|
FeatureFlagProvider,
|
|
805
|
+
LocalFlagDevTools,
|
|
806
|
+
createFlags,
|
|
807
|
+
defineFlags,
|
|
461
808
|
useFeatureFlag,
|
|
462
809
|
useFeatureFlagContext,
|
|
463
810
|
useFeatureFlagControls,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/context.tsx","../src/hooks.ts","../src/devtools.tsx"],"sourcesContent":["import {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useState,\n useSyncExternalStore,\n} from \"react\";\nimport type {\n FeatureFlagContextValue,\n FeatureFlagProviderProps,\n FeatureFlags,\n} from \"./types\";\n\nconst FeatureFlagContext = createContext<FeatureFlagContextValue | null>(null);\n\nconst STORAGE_KEY_DEFAULT = \"localflag:overrides\";\n\nfunction getStoredOverrides<T extends FeatureFlags>(\n storageKey: string\n): Partial<T> {\n if (typeof window === \"undefined\") return {};\n try {\n const stored = localStorage.getItem(storageKey);\n return stored ? JSON.parse(stored) : {};\n } catch {\n return {};\n }\n}\n\nfunction setStoredOverrides<T extends FeatureFlags>(\n storageKey: string,\n overrides: Partial<T>\n): void {\n if (typeof window === \"undefined\") return;\n try {\n if (Object.keys(overrides).length === 0) {\n localStorage.removeItem(storageKey);\n } else {\n localStorage.setItem(storageKey, JSON.stringify(overrides));\n }\n } catch {\n // Ignore storage errors\n }\n}\n\n// Event emitter for devtools communication\ntype Listener = () => void;\nconst listeners = new Set<Listener>();\nlet currentState: { flags: FeatureFlags; defaultFlags: FeatureFlags } | null = null;\n\nexport function subscribeToFlagChanges(listener: Listener): () => void {\n listeners.add(listener);\n return () => listeners.delete(listener);\n}\n\nexport function getFlagState() {\n return currentState;\n}\n\nfunction notifyListeners() {\n listeners.forEach((listener) => listener());\n}\n\nexport function FeatureFlagProvider<T extends FeatureFlags>({\n children,\n defaultFlags,\n storageKey = STORAGE_KEY_DEFAULT,\n persistOverrides = true,\n}: FeatureFlagProviderProps<T>) {\n const [overrides, setOverrides] = useState<Partial<T>>(() =>\n persistOverrides ? getStoredOverrides<T>(storageKey) : {}\n );\n\n const flags = useMemo(\n () => ({ ...defaultFlags, ...overrides }) as T,\n [defaultFlags, overrides]\n );\n\n // Update global state for devtools\n useEffect(() => {\n currentState = { flags, defaultFlags };\n notifyListeners();\n }, [flags, defaultFlags]);\n\n // Persist overrides to localStorage\n useEffect(() => {\n if (persistOverrides) {\n setStoredOverrides(storageKey, overrides);\n }\n }, [overrides, storageKey, persistOverrides]);\n\n const isEnabled = useCallback(\n (flagName: keyof T): boolean => {\n const value = flags[flagName];\n return Boolean(value);\n },\n [flags]\n );\n\n const getValue = useCallback(\n <K extends keyof T>(flagName: K): T[K] => {\n return flags[flagName];\n },\n [flags]\n );\n\n const setFlag = useCallback(<K extends keyof T>(flagName: K, value: T[K]) => {\n setOverrides((prev) => ({ ...prev, [flagName]: value }));\n }, []);\n\n const resetFlags = useCallback(() => {\n setOverrides({});\n }, []);\n\n const value = useMemo<FeatureFlagContextValue<T>>(\n () => ({\n flags,\n isEnabled,\n getValue,\n setFlag,\n resetFlags,\n }),\n [flags, isEnabled, getValue, setFlag, resetFlags]\n );\n\n return (\n <FeatureFlagContext.Provider value={value as unknown as FeatureFlagContextValue}>\n {children}\n </FeatureFlagContext.Provider>\n );\n}\n\nexport function useFeatureFlagContext<\n T extends FeatureFlags = FeatureFlags\n>(): FeatureFlagContextValue<T> {\n const context = useContext(FeatureFlagContext);\n if (!context) {\n throw new Error(\n \"useFeatureFlagContext must be used within a FeatureFlagProvider\"\n );\n }\n return context as unknown as FeatureFlagContextValue<T>;\n}\n\n// Hook for devtools to subscribe to flag changes\nexport function useFlagState() {\n return useSyncExternalStore(\n subscribeToFlagChanges,\n getFlagState,\n () => null\n );\n}\n","import { useMemo } from \"react\";\nimport { useFeatureFlagContext } from \"./context\";\nimport type { FeatureFlags } from \"./types\";\n\n/**\n * Hook to check if a feature flag is enabled (truthy)\n */\nexport function useFeatureFlag<T extends FeatureFlags = FeatureFlags>(\n flagName: keyof T\n): boolean {\n const { isEnabled } = useFeatureFlagContext<T>();\n return isEnabled(flagName);\n}\n\n/**\n * Hook to get the raw value of a feature flag\n */\nexport function useFeatureFlagValue<\n T extends FeatureFlags = FeatureFlags,\n K extends keyof T = keyof T\n>(flagName: K): T[K] {\n const { getValue } = useFeatureFlagContext<T>();\n return getValue(flagName);\n}\n\n/**\n * Hook to get all feature flags\n */\nexport function useFeatureFlags<T extends FeatureFlags = FeatureFlags>(): T {\n const { flags } = useFeatureFlagContext<T>();\n return flags;\n}\n\n/**\n * Hook to get flag controls (setFlag, resetFlags)\n */\nexport function useFeatureFlagControls<T extends FeatureFlags = FeatureFlags>() {\n const { setFlag, resetFlags } = useFeatureFlagContext<T>();\n return useMemo(() => ({ setFlag, resetFlags }), [setFlag, resetFlags]);\n}\n\n/**\n * Component wrapper that renders children only if flag is enabled\n */\nexport function FeatureFlag<T extends FeatureFlags = FeatureFlags>({\n flag,\n children,\n fallback = null,\n}: {\n flag: keyof T;\n children: React.ReactNode;\n fallback?: React.ReactNode;\n}): React.ReactNode {\n const enabled = useFeatureFlag<T>(flag);\n return enabled ? children : fallback;\n}\n","import { useState } from \"react\";\nimport { useFlagState, useFeatureFlagContext } from \"./context\";\nimport type { FlagValue, FeatureFlags } from \"./types\";\n\ndeclare const __DEV__: boolean | undefined;\n\ninterface DevToolsProps {\n position?: \"bottom-right\" | \"bottom-left\" | \"top-right\" | \"top-left\";\n defaultOpen?: boolean;\n}\n\nconst positionStyles: Record<string, React.CSSProperties> = {\n \"bottom-right\": { bottom: 16, right: 16 },\n \"bottom-left\": { bottom: 16, left: 16 },\n \"top-right\": { top: 16, right: 16 },\n \"top-left\": { top: 16, left: 16 },\n};\n\nconst baseStyles: React.CSSProperties = {\n position: \"fixed\",\n zIndex: 99999,\n fontFamily:\n 'ui-monospace, SFMono-Regular, \"SF Mono\", Menlo, Consolas, monospace',\n fontSize: 13,\n};\n\nconst panelStyles: React.CSSProperties = {\n backgroundColor: \"#1a1a2e\",\n border: \"1px solid #2d2d44\",\n borderRadius: 8,\n boxShadow: \"0 8px 32px rgba(0, 0, 0, 0.4)\",\n overflow: \"hidden\",\n minWidth: 280,\n maxWidth: 360,\n maxHeight: \"70vh\",\n};\n\nconst headerStyles: React.CSSProperties = {\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n padding: \"10px 12px\",\n backgroundColor: \"#16162a\",\n borderBottom: \"1px solid #2d2d44\",\n cursor: \"pointer\",\n userSelect: \"none\",\n};\n\nconst titleStyles: React.CSSProperties = {\n color: \"#e0e0e0\",\n fontWeight: 600,\n fontSize: 12,\n textTransform: \"uppercase\",\n letterSpacing: \"0.5px\",\n display: \"flex\",\n alignItems: \"center\",\n gap: 6,\n};\n\nconst contentStyles: React.CSSProperties = {\n padding: 0,\n overflowY: \"auto\",\n maxHeight: \"calc(70vh - 50px)\",\n};\n\nconst flagRowStyles: React.CSSProperties = {\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n padding: \"10px 12px\",\n borderBottom: \"1px solid #2d2d44\",\n transition: \"background-color 0.15s\",\n};\n\nconst flagNameStyles: React.CSSProperties = {\n color: \"#c0c0c0\",\n fontSize: 13,\n fontWeight: 500,\n flex: 1,\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n whiteSpace: \"nowrap\",\n};\n\nconst toggleStyles: React.CSSProperties = {\n position: \"relative\",\n width: 40,\n height: 22,\n backgroundColor: \"#3d3d5c\",\n borderRadius: 11,\n cursor: \"pointer\",\n transition: \"background-color 0.2s\",\n flexShrink: 0,\n border: \"none\",\n padding: 0,\n};\n\nconst toggleActiveStyles: React.CSSProperties = {\n ...toggleStyles,\n backgroundColor: \"#4ade80\",\n};\n\nconst toggleKnobStyles: React.CSSProperties = {\n position: \"absolute\",\n top: 2,\n left: 2,\n width: 18,\n height: 18,\n backgroundColor: \"#fff\",\n borderRadius: \"50%\",\n transition: \"transform 0.2s\",\n boxShadow: \"0 1px 3px rgba(0, 0, 0, 0.3)\",\n};\n\nconst toggleKnobActiveStyles: React.CSSProperties = {\n ...toggleKnobStyles,\n transform: \"translateX(18px)\",\n};\n\nconst inputStyles: React.CSSProperties = {\n backgroundColor: \"#2d2d44\",\n border: \"1px solid #3d3d5c\",\n borderRadius: 4,\n color: \"#e0e0e0\",\n padding: \"4px 8px\",\n fontSize: 12,\n width: 80,\n outline: \"none\",\n};\n\nconst badgeStyles: React.CSSProperties = {\n backgroundColor: \"#4ade80\",\n color: \"#1a1a2e\",\n fontSize: 10,\n fontWeight: 700,\n padding: \"2px 6px\",\n borderRadius: 4,\n marginLeft: 6,\n};\n\nconst overrideBadgeStyles: React.CSSProperties = {\n backgroundColor: \"#f59e0b\",\n color: \"#1a1a2e\",\n fontSize: 9,\n fontWeight: 600,\n padding: \"1px 4px\",\n borderRadius: 3,\n marginLeft: 6,\n};\n\nconst buttonStyles: React.CSSProperties = {\n backgroundColor: \"transparent\",\n border: \"none\",\n color: \"#888\",\n cursor: \"pointer\",\n padding: 4,\n borderRadius: 4,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n transition: \"color 0.15s, background-color 0.15s\",\n};\n\nconst resetButtonStyles: React.CSSProperties = {\n backgroundColor: \"#2d2d44\",\n border: \"1px solid #3d3d5c\",\n borderRadius: 4,\n color: \"#c0c0c0\",\n padding: \"6px 12px\",\n fontSize: 11,\n cursor: \"pointer\",\n margin: \"8px 12px 12px\",\n width: \"calc(100% - 24px)\",\n transition: \"background-color 0.15s\",\n};\n\nconst fabStyles: React.CSSProperties = {\n width: 48,\n height: 48,\n borderRadius: \"50%\",\n backgroundColor: \"#4ade80\",\n border: \"none\",\n cursor: \"pointer\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n boxShadow: \"0 4px 12px rgba(74, 222, 128, 0.4)\",\n transition: \"transform 0.15s, box-shadow 0.15s\",\n};\n\nfunction FlagIcon() {\n return (\n <svg\n width=\"20\"\n height=\"20\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"M4 15s1-1 4-1 5 2 8 2 4-1 4-1V3s-1 1-4 1-5-2-8-2-4 1-4 1z\" />\n <line x1=\"4\" y1=\"22\" x2=\"4\" y2=\"15\" />\n </svg>\n );\n}\n\nfunction CloseIcon() {\n return (\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <line x1=\"18\" y1=\"6\" x2=\"6\" y2=\"18\" />\n <line x1=\"6\" y1=\"6\" x2=\"18\" y2=\"18\" />\n </svg>\n );\n}\n\nfunction FlagRow({\n name,\n value,\n defaultValue,\n onToggle,\n onChange,\n}: {\n name: string;\n value: FlagValue;\n defaultValue: FlagValue;\n onToggle: () => void;\n onChange: (value: FlagValue) => void;\n}) {\n const isOverridden = value !== defaultValue;\n const isBoolean = typeof value === \"boolean\";\n\n const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const newValue = e.target.value;\n // Try to parse as number\n const num = Number(newValue);\n if (!isNaN(num) && newValue !== \"\") {\n onChange(num);\n } else {\n onChange(newValue);\n }\n };\n\n return (\n <div style={flagRowStyles}>\n <span style={flagNameStyles}>\n {name}\n {isOverridden && <span style={overrideBadgeStyles}>override</span>}\n </span>\n {isBoolean ? (\n <button\n style={value ? toggleActiveStyles : toggleStyles}\n onClick={onToggle}\n type=\"button\"\n aria-label={`Toggle ${name}`}\n >\n <span style={value ? toggleKnobActiveStyles : toggleKnobStyles} />\n </button>\n ) : (\n <input\n style={inputStyles}\n type=\"text\"\n value={String(value)}\n onChange={handleInputChange}\n />\n )}\n </div>\n );\n}\n\nfunction DevToolsInner({\n position,\n defaultOpen,\n}: {\n position: \"bottom-right\" | \"bottom-left\" | \"top-right\" | \"top-left\";\n defaultOpen: boolean;\n}) {\n const [isOpen, setIsOpen] = useState(defaultOpen);\n const flagState = useFlagState();\n const context = useFeatureFlagContext<FeatureFlags>();\n\n if (!flagState) {\n return null;\n }\n\n const { setFlag, resetFlags } = context;\n\n const { flags, defaultFlags } = flagState;\n const flagEntries = Object.entries(flags);\n const overrideCount = flagEntries.filter(\n ([key, value]) => value !== defaultFlags[key]\n ).length;\n\n const handleToggle = (key: string) => {\n const currentValue = flags[key];\n if (typeof currentValue === \"boolean\") {\n setFlag(key, !currentValue);\n }\n };\n\n const handleChange = (key: string, value: FlagValue) => {\n setFlag(key, value);\n };\n\n if (!isOpen) {\n return (\n <div style={{ ...baseStyles, ...positionStyles[position] }}>\n <button\n style={fabStyles}\n onClick={() => setIsOpen(true)}\n type=\"button\"\n aria-label=\"Open feature flags devtools\"\n >\n <span style={{ color: \"#1a1a2e\" }}>\n <FlagIcon />\n </span>\n </button>\n </div>\n );\n }\n\n return (\n <div style={{ ...baseStyles, ...positionStyles[position] }}>\n <div style={panelStyles}>\n <div style={headerStyles} onClick={() => setIsOpen(false)}>\n <span style={titleStyles}>\n <FlagIcon />\n Feature Flags\n {overrideCount > 0 && (\n <span style={badgeStyles}>{overrideCount}</span>\n )}\n </span>\n <button style={buttonStyles} type=\"button\" aria-label=\"Close\">\n <CloseIcon />\n </button>\n </div>\n <div style={contentStyles}>\n {flagEntries.map(([key, value]) => (\n <FlagRow\n key={key}\n name={key}\n value={value}\n defaultValue={defaultFlags[key]}\n onToggle={() => handleToggle(key)}\n onChange={(newValue) => handleChange(key, newValue)}\n />\n ))}\n </div>\n {overrideCount > 0 && (\n <button style={resetButtonStyles} onClick={resetFlags} type=\"button\">\n Reset all overrides\n </button>\n )}\n </div>\n </div>\n );\n}\n\nexport function DevTools({\n position = \"bottom-right\",\n defaultOpen = false,\n}: DevToolsProps) {\n // Don't render in production - check via global __DEV__ or fallback to always showing\n const isDev = typeof __DEV__ !== \"undefined\" ? __DEV__ : true;\n if (!isDev) {\n return null;\n }\n\n return <DevToolsInner position={position} defaultOpen={defaultOpen} />;\n}\n\nexport default DevTools;\n"],"mappings":"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","names":["value","useMemo","useMemo","useState","jsx","useState"]}
|
|
1
|
+
{"version":3,"sources":["../src/context.tsx","../src/hooks.ts","../src/devtools.tsx","../src/config.ts"],"sourcesContent":["import {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useState,\n useSyncExternalStore,\n} from \"react\";\nimport type {\n FeatureFlagContextValue,\n FeatureFlagProviderProps,\n FeatureFlags,\n} from \"./types\";\n\nconst FeatureFlagContext = createContext<FeatureFlagContextValue | null>(null);\n\nconst STORAGE_KEY_DEFAULT = \"localflag:overrides\";\n\nfunction getStoredOverrides<T extends FeatureFlags>(\n storageKey: string\n): Partial<T> {\n if (typeof window === \"undefined\") return {};\n try {\n const stored = localStorage.getItem(storageKey);\n return stored ? JSON.parse(stored) : {};\n } catch {\n return {};\n }\n}\n\nfunction setStoredOverrides<T extends FeatureFlags>(\n storageKey: string,\n overrides: Partial<T>\n): void {\n if (typeof window === \"undefined\") return;\n try {\n if (Object.keys(overrides).length === 0) {\n localStorage.removeItem(storageKey);\n } else {\n localStorage.setItem(storageKey, JSON.stringify(overrides));\n }\n } catch {\n // Ignore storage errors\n }\n}\n\n// Event emitter for devtools communication\ntype Listener = () => void;\nconst listeners = new Set<Listener>();\nlet currentState: {\n flags: FeatureFlags;\n defaultFlags: FeatureFlags;\n descriptions: Record<string, string>;\n} | null = null;\n\nexport function subscribeToFlagChanges(listener: Listener): () => void {\n listeners.add(listener);\n return () => listeners.delete(listener);\n}\n\nexport function getFlagState() {\n return currentState;\n}\n\nfunction notifyListeners() {\n listeners.forEach((listener) => listener());\n}\n\nexport function FeatureFlagProvider<T extends FeatureFlags>({\n children,\n defaultFlags,\n descriptions = {},\n storageKey = STORAGE_KEY_DEFAULT,\n persistOverrides = true,\n}: FeatureFlagProviderProps<T>) {\n const [overrides, setOverrides] = useState<Partial<T>>(() =>\n persistOverrides ? getStoredOverrides<T>(storageKey) : {}\n );\n\n const flags = useMemo(\n () => ({ ...defaultFlags, ...overrides }) as T,\n [defaultFlags, overrides]\n );\n\n // Update global state for devtools\n useEffect(() => {\n currentState = {\n flags,\n defaultFlags,\n descriptions: descriptions as Record<string, string>,\n };\n notifyListeners();\n }, [flags, defaultFlags, descriptions]);\n\n // Persist overrides to localStorage\n useEffect(() => {\n if (persistOverrides) {\n setStoredOverrides(storageKey, overrides);\n }\n }, [overrides, storageKey, persistOverrides]);\n\n const isEnabled = useCallback(\n (flagName: keyof T): boolean => {\n const value = flags[flagName];\n return Boolean(value);\n },\n [flags]\n );\n\n const getValue = useCallback(\n <K extends keyof T>(flagName: K): T[K] => {\n return flags[flagName];\n },\n [flags]\n );\n\n const setFlag = useCallback(<K extends keyof T>(flagName: K, value: T[K]) => {\n setOverrides((prev) => ({ ...prev, [flagName]: value }));\n }, []);\n\n const resetFlags = useCallback(() => {\n setOverrides({});\n }, []);\n\n const value = useMemo<FeatureFlagContextValue<T>>(\n () => ({\n flags,\n isEnabled,\n getValue,\n setFlag,\n resetFlags,\n }),\n [flags, isEnabled, getValue, setFlag, resetFlags]\n );\n\n return (\n <FeatureFlagContext.Provider value={value as unknown as FeatureFlagContextValue}>\n {children}\n </FeatureFlagContext.Provider>\n );\n}\n\nexport function useFeatureFlagContext<\n T extends FeatureFlags = FeatureFlags\n>(): FeatureFlagContextValue<T> {\n const context = useContext(FeatureFlagContext);\n if (!context) {\n throw new Error(\n \"useFeatureFlagContext must be used within a FeatureFlagProvider\"\n );\n }\n return context as unknown as FeatureFlagContextValue<T>;\n}\n\n// Hook for devtools to subscribe to flag changes\nexport function useFlagState() {\n return useSyncExternalStore(\n subscribeToFlagChanges,\n getFlagState,\n () => null\n );\n}\n","import { useMemo } from \"react\";\nimport { useFeatureFlagContext } from \"./context\";\nimport type { FeatureFlags } from \"./types\";\n\n/**\n * Hook to check if a feature flag is enabled (truthy)\n */\nexport function useFeatureFlag<T extends FeatureFlags = FeatureFlags>(\n flagName: keyof T\n): boolean {\n const { isEnabled } = useFeatureFlagContext<T>();\n return isEnabled(flagName);\n}\n\n/**\n * Hook to get the raw value of a feature flag\n */\nexport function useFeatureFlagValue<\n T extends FeatureFlags = FeatureFlags,\n K extends keyof T = keyof T\n>(flagName: K): T[K] {\n const { getValue } = useFeatureFlagContext<T>();\n return getValue(flagName);\n}\n\n/**\n * Hook to get all feature flags\n */\nexport function useFeatureFlags<T extends FeatureFlags = FeatureFlags>(): T {\n const { flags } = useFeatureFlagContext<T>();\n return flags;\n}\n\n/**\n * Hook to get flag controls (setFlag, resetFlags)\n */\nexport function useFeatureFlagControls<T extends FeatureFlags = FeatureFlags>() {\n const { setFlag, resetFlags } = useFeatureFlagContext<T>();\n return useMemo(() => ({ setFlag, resetFlags }), [setFlag, resetFlags]);\n}\n\n/**\n * Component wrapper that renders children only if flag is enabled\n */\nexport function FeatureFlag<T extends FeatureFlags = FeatureFlags>({\n flag,\n children,\n fallback = null,\n}: {\n flag: keyof T;\n children: React.ReactNode;\n fallback?: React.ReactNode;\n}): React.ReactNode {\n const enabled = useFeatureFlag<T>(flag);\n return enabled ? children : fallback;\n}\n","import { useState, useEffect } from \"react\";\nimport { useFlagState, useFeatureFlagContext } from \"./context\";\nimport type { FlagValue, FeatureFlags } from \"./types\";\n\ndeclare const __DEV__: boolean | undefined;\n\ntype Position = \"bottom-right\" | \"bottom-left\" | \"top-right\" | \"top-left\";\n\ninterface DevToolsProps {\n position?: Position;\n defaultOpen?: boolean;\n /**\n * Keyboard shortcut to toggle the DevTools panel.\n * Set to `false` to disable the shortcut.\n * @default \"mod+shift+f\" (Cmd+Shift+F on Mac, Ctrl+Shift+F on Windows/Linux)\n */\n shortcut?: string | false;\n}\n\nconst POSITION_STORAGE_KEY = \"localflag:position\";\n\nconst positionStyles: Record<string, React.CSSProperties> = {\n \"bottom-right\": { bottom: 12, right: 12 },\n \"bottom-left\": { bottom: 12, left: 12 },\n \"top-right\": { top: 12, right: 12 },\n \"top-left\": { top: 12, left: 12 },\n};\n\nconst baseStyles: React.CSSProperties = {\n position: \"fixed\",\n zIndex: 99999,\n fontFamily:\n 'ui-monospace, SFMono-Regular, \"SF Mono\", Menlo, Consolas, \"Liberation Mono\", monospace',\n fontSize: 12,\n lineHeight: 1.5,\n WebkitFontSmoothing: \"antialiased\",\n};\n\nconst panelStyles: React.CSSProperties = {\n backgroundColor: \"#0a0a0a\",\n border: \"1px solid rgba(255, 255, 255, 0.08)\",\n borderRadius: 10,\n boxShadow:\n \"0 0 0 1px rgba(0, 0, 0, 0.5), 0 16px 70px rgba(0, 0, 0, 0.6)\",\n overflow: \"hidden\",\n minWidth: 260,\n maxWidth: 320,\n maxHeight: \"60vh\",\n};\n\nconst headerStyles: React.CSSProperties = {\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n padding: \"10px 12px\",\n borderBottom: \"1px solid rgba(255, 255, 255, 0.06)\",\n cursor: \"pointer\",\n userSelect: \"none\",\n};\n\nconst titleStyles: React.CSSProperties = {\n color: \"rgba(255, 255, 255, 0.9)\",\n fontWeight: 500,\n fontSize: 11,\n letterSpacing: \"0.01em\",\n display: \"flex\",\n alignItems: \"center\",\n gap: 8,\n};\n\nconst tabBarStyles: React.CSSProperties = {\n display: \"flex\",\n borderBottom: \"1px solid rgba(255, 255, 255, 0.06)\",\n padding: \"0 12px\",\n gap: 4,\n};\n\nconst tabStyles: React.CSSProperties = {\n padding: \"8px 10px\",\n fontSize: 11,\n fontWeight: 500,\n color: \"rgba(255, 255, 255, 0.5)\",\n backgroundColor: \"transparent\",\n border: \"none\",\n borderBottom: \"2px solid transparent\",\n cursor: \"pointer\",\n transition: \"color 0.15s ease\",\n fontFamily: \"inherit\",\n marginBottom: -1,\n};\n\nconst tabActiveStyles: React.CSSProperties = {\n ...tabStyles,\n color: \"rgba(255, 255, 255, 0.9)\",\n borderBottomColor: \"#fff\",\n};\n\nconst contentStyles: React.CSSProperties = {\n padding: 0,\n overflowY: \"auto\",\n maxHeight: \"calc(60vh - 84px)\",\n};\n\nconst flagRowStyles: React.CSSProperties = {\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n padding: \"8px 12px\",\n borderBottom: \"1px solid rgba(255, 255, 255, 0.04)\",\n transition: \"background-color 0.15s ease\",\n gap: 12,\n};\n\nconst flagRowHoverStyles: React.CSSProperties = {\n backgroundColor: \"rgba(255, 255, 255, 0.03)\",\n};\n\nconst flagNameContainerStyles: React.CSSProperties = {\n flex: 1,\n overflow: \"hidden\",\n display: \"flex\",\n flexDirection: \"column\",\n gap: 2,\n minWidth: 0,\n};\n\nconst flagNameStyles: React.CSSProperties = {\n color: \"rgba(255, 255, 255, 0.7)\",\n fontSize: 12,\n fontWeight: 400,\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n whiteSpace: \"nowrap\",\n display: \"flex\",\n alignItems: \"center\",\n gap: 6,\n};\n\nconst flagDescriptionStyles: React.CSSProperties = {\n color: \"rgba(255, 255, 255, 0.4)\",\n fontSize: 10,\n fontWeight: 400,\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n whiteSpace: \"nowrap\",\n};\n\nconst toggleStyles: React.CSSProperties = {\n position: \"relative\",\n width: 28,\n height: 16,\n backgroundColor: \"rgba(255, 255, 255, 0.1)\",\n borderRadius: 8,\n cursor: \"pointer\",\n transition: \"background-color 0.15s ease\",\n flexShrink: 0,\n border: \"none\",\n padding: 0,\n};\n\nconst toggleActiveStyles: React.CSSProperties = {\n ...toggleStyles,\n backgroundColor: \"#fff\",\n};\n\nconst toggleKnobStyles: React.CSSProperties = {\n position: \"absolute\",\n top: 2,\n left: 2,\n width: 12,\n height: 12,\n backgroundColor: \"rgba(255, 255, 255, 0.5)\",\n borderRadius: \"50%\",\n transition: \"transform 0.15s ease, background-color 0.15s ease\",\n};\n\nconst toggleKnobActiveStyles: React.CSSProperties = {\n ...toggleKnobStyles,\n transform: \"translateX(12px)\",\n backgroundColor: \"#0a0a0a\",\n};\n\nconst inputStyles: React.CSSProperties = {\n backgroundColor: \"rgba(255, 255, 255, 0.05)\",\n border: \"1px solid rgba(255, 255, 255, 0.1)\",\n borderRadius: 5,\n color: \"rgba(255, 255, 255, 0.9)\",\n padding: \"3px 8px\",\n fontSize: 11,\n width: 72,\n outline: \"none\",\n transition: \"border-color 0.15s ease, background-color 0.15s ease\",\n};\n\nconst overrideDotStyles: React.CSSProperties = {\n width: 5,\n height: 5,\n borderRadius: \"50%\",\n backgroundColor: \"#3b82f6\",\n flexShrink: 0,\n};\n\nconst buttonStyles: React.CSSProperties = {\n backgroundColor: \"transparent\",\n border: \"none\",\n color: \"rgba(255, 255, 255, 0.4)\",\n cursor: \"pointer\",\n padding: 4,\n borderRadius: 4,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n transition: \"color 0.15s ease\",\n};\n\nconst resetButtonStyles: React.CSSProperties = {\n backgroundColor: \"rgba(255, 255, 255, 0.05)\",\n border: \"1px solid rgba(255, 255, 255, 0.08)\",\n borderRadius: 6,\n color: \"rgba(255, 255, 255, 0.6)\",\n padding: \"6px 10px\",\n fontSize: 11,\n fontWeight: 500,\n cursor: \"pointer\",\n margin: \"8px 12px 10px\",\n width: \"calc(100% - 24px)\",\n transition: \"background-color 0.15s ease, color 0.15s ease\",\n fontFamily: \"inherit\",\n};\n\nconst fabStyles: React.CSSProperties = {\n height: 32,\n paddingLeft: 10,\n paddingRight: 10,\n borderRadius: 8,\n backgroundColor: \"#0a0a0a\",\n border: \"1px solid rgba(255, 255, 255, 0.1)\",\n cursor: \"pointer\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n gap: 6,\n boxShadow:\n \"0 0 0 1px rgba(0, 0, 0, 0.5), 0 4px 16px rgba(0, 0, 0, 0.4)\",\n transition: \"background-color 0.15s ease, border-color 0.15s ease\",\n fontFamily: \"inherit\",\n fontSize: 11,\n fontWeight: 500,\n color: \"rgba(255, 255, 255, 0.8)\",\n};\n\nconst badgeStyles: React.CSSProperties = {\n backgroundColor: \"#3b82f6\",\n color: \"#fff\",\n fontSize: 9,\n fontWeight: 600,\n minWidth: 14,\n height: 14,\n padding: \"0 4px\",\n borderRadius: 7,\n display: \"inline-flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n};\n\nconst optionsSectionStyles: React.CSSProperties = {\n padding: \"12px\",\n};\n\nconst optionsLabelStyles: React.CSSProperties = {\n fontSize: 10,\n fontWeight: 500,\n color: \"rgba(255, 255, 255, 0.5)\",\n textTransform: \"uppercase\",\n letterSpacing: \"0.05em\",\n marginBottom: 8,\n display: \"block\",\n};\n\nconst positionGridStyles: React.CSSProperties = {\n display: \"grid\",\n gridTemplateColumns: \"1fr 1fr\",\n gap: 6,\n};\n\nconst positionButtonStyles: React.CSSProperties = {\n padding: \"8px\",\n fontSize: 10,\n fontWeight: 500,\n color: \"rgba(255, 255, 255, 0.6)\",\n backgroundColor: \"rgba(255, 255, 255, 0.03)\",\n border: \"1px solid rgba(255, 255, 255, 0.08)\",\n borderRadius: 6,\n cursor: \"pointer\",\n transition: \"all 0.15s ease\",\n fontFamily: \"inherit\",\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n gap: 6,\n};\n\nconst positionButtonActiveStyles: React.CSSProperties = {\n ...positionButtonStyles,\n color: \"rgba(255, 255, 255, 0.9)\",\n backgroundColor: \"rgba(255, 255, 255, 0.1)\",\n borderColor: \"rgba(255, 255, 255, 0.2)\",\n};\n\nfunction FlagIcon({ size = 14 }: { size?: number }) {\n return (\n <svg\n width={size}\n height={size}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n >\n <path d=\"M4 15s1-1 4-1 5 2 8 2 4-1 4-1V3s-1 1-4 1-5-2-8-2-4 1-4 1z\" />\n <line x1=\"4\" y1=\"22\" x2=\"4\" y2=\"15\" />\n </svg>\n );\n}\n\nfunction ChevronIcon({ direction }: { direction: \"up\" | \"down\" }) {\n return (\n <svg\n width=\"12\"\n height=\"12\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n style={{\n transform: direction === \"up\" ? \"rotate(180deg)\" : \"rotate(0deg)\",\n transition: \"transform 0.15s ease\",\n }}\n >\n <polyline points=\"6 9 12 15 18 9\" />\n </svg>\n );\n}\n\nfunction PositionIcon({ position }: { position: Position }) {\n const dotPosition = {\n \"top-left\": { top: 2, left: 2 },\n \"top-right\": { top: 2, right: 2 },\n \"bottom-left\": { bottom: 2, left: 2 },\n \"bottom-right\": { bottom: 2, right: 2 },\n }[position];\n\n return (\n <div\n style={{\n width: 14,\n height: 14,\n border: \"1px solid currentColor\",\n borderRadius: 2,\n position: \"relative\",\n opacity: 0.7,\n }}\n >\n <div\n style={{\n position: \"absolute\",\n width: 4,\n height: 4,\n backgroundColor: \"currentColor\",\n borderRadius: 1,\n ...dotPosition,\n }}\n />\n </div>\n );\n}\n\nfunction FlagRow({\n name,\n value,\n defaultValue,\n description,\n onToggle,\n onChange,\n}: {\n name: string;\n value: FlagValue;\n defaultValue: FlagValue;\n description?: string;\n onToggle: () => void;\n onChange: (value: FlagValue) => void;\n}) {\n const [isHovered, setIsHovered] = useState(false);\n const isOverridden = value !== defaultValue;\n const isBoolean = typeof value === \"boolean\";\n\n const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const newValue = e.target.value;\n const num = Number(newValue);\n if (!isNaN(num) && newValue !== \"\") {\n onChange(num);\n } else {\n onChange(newValue);\n }\n };\n\n return (\n <div\n style={{\n ...flagRowStyles,\n ...(isHovered ? flagRowHoverStyles : {}),\n }}\n onMouseEnter={() => setIsHovered(true)}\n onMouseLeave={() => setIsHovered(false)}\n >\n <div style={flagNameContainerStyles}>\n <span style={flagNameStyles}>\n {isOverridden && <span style={overrideDotStyles} />}\n {name}\n </span>\n {description && (\n <span style={flagDescriptionStyles}>{description}</span>\n )}\n </div>\n {isBoolean ? (\n <button\n style={value ? toggleActiveStyles : toggleStyles}\n onClick={onToggle}\n type=\"button\"\n aria-label={`Toggle ${name}`}\n >\n <span style={value ? toggleKnobActiveStyles : toggleKnobStyles} />\n </button>\n ) : (\n <input\n style={inputStyles}\n type=\"text\"\n value={String(value)}\n onChange={handleInputChange}\n onFocus={(e) => {\n e.target.style.borderColor = \"rgba(255, 255, 255, 0.2)\";\n e.target.style.backgroundColor = \"rgba(255, 255, 255, 0.08)\";\n }}\n onBlur={(e) => {\n e.target.style.borderColor = \"rgba(255, 255, 255, 0.1)\";\n e.target.style.backgroundColor = \"rgba(255, 255, 255, 0.05)\";\n }}\n />\n )}\n </div>\n );\n}\n\nfunction OptionsTab({\n position,\n onPositionChange,\n}: {\n position: Position;\n onPositionChange: (position: Position) => void;\n}) {\n const [hoveredPosition, setHoveredPosition] = useState<Position | null>(null);\n const positions: { value: Position; label: string }[] = [\n { value: \"top-left\", label: \"Top Left\" },\n { value: \"top-right\", label: \"Top Right\" },\n { value: \"bottom-left\", label: \"Bottom Left\" },\n { value: \"bottom-right\", label: \"Bottom Right\" },\n ];\n\n return (\n <div style={optionsSectionStyles}>\n <span style={optionsLabelStyles}>Position</span>\n <div style={positionGridStyles}>\n {positions.map(({ value, label }) => {\n const isActive = position === value;\n const isHovered = hoveredPosition === value;\n return (\n <button\n key={value}\n style={{\n ...(isActive ? positionButtonActiveStyles : positionButtonStyles),\n ...(isHovered && !isActive\n ? {\n backgroundColor: \"rgba(255, 255, 255, 0.05)\",\n borderColor: \"rgba(255, 255, 255, 0.12)\",\n }\n : {}),\n }}\n onClick={() => onPositionChange(value)}\n onMouseEnter={() => setHoveredPosition(value)}\n onMouseLeave={() => setHoveredPosition(null)}\n type=\"button\"\n >\n <PositionIcon position={value} />\n {label}\n </button>\n );\n })}\n </div>\n </div>\n );\n}\n\nfunction DevToolsInner({\n position: initialPosition,\n defaultOpen,\n shortcut,\n}: {\n position: Position;\n defaultOpen: boolean;\n shortcut: string | false;\n}) {\n const [isOpen, setIsOpen] = useState(defaultOpen);\n const [activeTab, setActiveTab] = useState<\"flags\" | \"options\">(\"flags\");\n const [position, setPosition] = useState<Position>(() => {\n if (typeof window !== \"undefined\") {\n const stored = localStorage.getItem(POSITION_STORAGE_KEY);\n if (stored && stored in positionStyles) {\n return stored as Position;\n }\n }\n return initialPosition;\n });\n const [fabHovered, setFabHovered] = useState(false);\n const [resetHovered, setResetHovered] = useState(false);\n const [headerHovered, setHeaderHovered] = useState(false);\n const flagState = useFlagState();\n const context = useFeatureFlagContext<FeatureFlags>();\n\n // Keyboard shortcut\n useEffect(() => {\n if (shortcut === false) return;\n\n const handleKeyDown = (e: KeyboardEvent) => {\n const isMod = e.metaKey || e.ctrlKey;\n if (isMod && e.shiftKey && e.key.toLowerCase() === \"f\") {\n e.preventDefault();\n setIsOpen((prev) => !prev);\n }\n };\n\n window.addEventListener(\"keydown\", handleKeyDown);\n return () => window.removeEventListener(\"keydown\", handleKeyDown);\n }, [shortcut]);\n\n useEffect(() => {\n if (typeof window !== \"undefined\") {\n localStorage.setItem(POSITION_STORAGE_KEY, position);\n }\n }, [position]);\n\n if (!flagState) {\n return null;\n }\n\n const { setFlag, resetFlags } = context;\n const { flags, defaultFlags, descriptions } = flagState;\n const flagEntries = Object.entries(flags);\n const overrideCount = flagEntries.filter(\n ([key, value]) => value !== defaultFlags[key]\n ).length;\n\n const handleToggle = (key: string) => {\n const currentValue = flags[key];\n if (typeof currentValue === \"boolean\") {\n setFlag(key, !currentValue);\n }\n };\n\n const handleChange = (key: string, value: FlagValue) => {\n setFlag(key, value);\n };\n\n if (!isOpen) {\n return (\n <div style={{ ...baseStyles, ...positionStyles[position] }}>\n <button\n style={{\n ...fabStyles,\n ...(fabHovered\n ? {\n backgroundColor: \"#141414\",\n borderColor: \"rgba(255, 255, 255, 0.15)\",\n }\n : {}),\n }}\n onClick={() => setIsOpen(true)}\n onMouseEnter={() => setFabHovered(true)}\n onMouseLeave={() => setFabHovered(false)}\n type=\"button\"\n aria-label=\"Open feature flags devtools\"\n >\n <FlagIcon size={12} />\n <span>Flags</span>\n {overrideCount > 0 && <span style={badgeStyles}>{overrideCount}</span>}\n </button>\n </div>\n );\n }\n\n return (\n <div style={{ ...baseStyles, ...positionStyles[position] }}>\n <div style={panelStyles}>\n <div\n style={{\n ...headerStyles,\n ...(headerHovered\n ? { backgroundColor: \"rgba(255, 255, 255, 0.02)\" }\n : {}),\n }}\n onClick={() => setIsOpen(false)}\n onMouseEnter={() => setHeaderHovered(true)}\n onMouseLeave={() => setHeaderHovered(false)}\n >\n <span style={titleStyles}>\n <FlagIcon size={12} />\n Feature Flags\n {overrideCount > 0 && <span style={badgeStyles}>{overrideCount}</span>}\n </span>\n <button\n style={{\n ...buttonStyles,\n ...(headerHovered ? { color: \"rgba(255, 255, 255, 0.6)\" } : {}),\n }}\n type=\"button\"\n aria-label=\"Close\"\n >\n <ChevronIcon direction=\"down\" />\n </button>\n </div>\n\n <div style={tabBarStyles}>\n <button\n style={activeTab === \"flags\" ? tabActiveStyles : tabStyles}\n onClick={(e) => {\n e.stopPropagation();\n setActiveTab(\"flags\");\n }}\n type=\"button\"\n >\n Flags\n </button>\n <button\n style={activeTab === \"options\" ? tabActiveStyles : tabStyles}\n onClick={(e) => {\n e.stopPropagation();\n setActiveTab(\"options\");\n }}\n type=\"button\"\n >\n Options\n </button>\n </div>\n\n {activeTab === \"flags\" ? (\n <>\n <div style={contentStyles}>\n {flagEntries.map(([key, value]) => (\n <FlagRow\n key={key}\n name={key}\n value={value}\n defaultValue={defaultFlags[key]}\n description={descriptions[key]}\n onToggle={() => handleToggle(key)}\n onChange={(newValue) => handleChange(key, newValue)}\n />\n ))}\n </div>\n {overrideCount > 0 && (\n <button\n style={{\n ...resetButtonStyles,\n ...(resetHovered\n ? {\n backgroundColor: \"rgba(255, 255, 255, 0.08)\",\n color: \"rgba(255, 255, 255, 0.8)\",\n }\n : {}),\n }}\n onClick={resetFlags}\n onMouseEnter={() => setResetHovered(true)}\n onMouseLeave={() => setResetHovered(false)}\n type=\"button\"\n >\n Reset overrides\n </button>\n )}\n </>\n ) : (\n <OptionsTab position={position} onPositionChange={setPosition} />\n )}\n </div>\n </div>\n );\n}\n\nexport function LocalFlagDevTools({\n position = \"bottom-right\",\n defaultOpen = false,\n shortcut = \"mod+shift+f\",\n}: DevToolsProps) {\n const isDev = typeof __DEV__ !== \"undefined\" ? __DEV__ : true;\n if (!isDev) {\n return null;\n }\n\n return (\n <DevToolsInner\n position={position}\n defaultOpen={defaultOpen}\n shortcut={shortcut}\n />\n );\n}\n\n/** @deprecated Use `LocalFlagDevTools` instead */\nexport const DevTools = LocalFlagDevTools;\n\nexport default LocalFlagDevTools;\n","import type { FlagValue } from \"./types\";\n\n/**\n * Helper function to define feature flags with type safety.\n * This is a type-only helper with no runtime logic - it simply returns the flags as-is.\n *\n * @example\n * ```ts\n * // flags.config.ts\n * import { defineFlags } from '@localflag/react';\n *\n * export const flags = defineFlags({\n * darkMode: false,\n * newCheckout: true,\n * maxRetries: 3,\n * });\n *\n * export type AppFlags = typeof flags;\n * ```\n */\nexport function defineFlags<T extends Record<string, FlagValue>>(flags: T): T {\n return flags;\n}\n\n/**\n * Flag configuration with value and optional description.\n */\nexport interface FlagConfig<T extends FlagValue = FlagValue> {\n value: T;\n description?: string;\n}\n\ntype FlagInput<T extends FlagValue = FlagValue> = T | FlagConfig<T>;\n\ntype ExtractFlagValue<T> = T extends FlagConfig<infer V> ? V : T;\n\ntype ExtractFlags<T extends Record<string, FlagInput>> = {\n [K in keyof T]: ExtractFlagValue<T[K]>;\n};\n\n/**\n * Helper function to define feature flags with descriptions.\n * Returns both the flags object and a descriptions object.\n *\n * @example\n * ```ts\n * // flags.config.ts\n * import { createFlags } from '@localflag/react';\n *\n * export const { flags, descriptions } = createFlags({\n * darkMode: { value: false, description: \"Enable dark theme\" },\n * newCheckout: { value: true, description: \"Use new checkout flow\" },\n * maxRetries: 3, // Simple value without description\n * });\n *\n * export type AppFlags = typeof flags;\n * ```\n */\nexport function createFlags<T extends Record<string, FlagInput>>(\n config: T\n): {\n flags: ExtractFlags<T>;\n descriptions: Partial<Record<keyof T, string>>;\n} {\n const flags = {} as Record<string, FlagValue>;\n const descriptions = {} as Record<string, string>;\n\n for (const [key, value] of Object.entries(config)) {\n if (typeof value === \"object\" && value !== null && \"value\" in value) {\n flags[key] = value.value;\n if (value.description) {\n descriptions[key] = value.description;\n }\n } else {\n flags[key] = value as FlagValue;\n }\n }\n\n return {\n flags: flags as ExtractFlags<T>,\n descriptions: descriptions as Partial<Record<keyof T, string>>,\n };\n}\n"],"mappings":"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","names":["value","useMemo","useMemo","useState","useEffect","jsx","useState","useEffect"]}
|
package/package.json
CHANGED
|
@@ -1,7 +1,27 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@localflag/react",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.3",
|
|
4
|
+
"description": "Type-safe feature flags for React with built-in DevTools",
|
|
4
5
|
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"author": "Daniel Gietmann",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/localflag/localflag.git",
|
|
11
|
+
"directory": "packages/react"
|
|
12
|
+
},
|
|
13
|
+
"homepage": "https://localflag.io",
|
|
14
|
+
"bugs": {
|
|
15
|
+
"url": "https://github.com/localflag/localflag/issues"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [
|
|
18
|
+
"react",
|
|
19
|
+
"feature-flags",
|
|
20
|
+
"feature-toggles",
|
|
21
|
+
"devtools",
|
|
22
|
+
"typescript",
|
|
23
|
+
"hooks"
|
|
24
|
+
],
|
|
5
25
|
"main": "./dist/index.js",
|
|
6
26
|
"module": "./dist/index.js",
|
|
7
27
|
"types": "./dist/index.d.ts",
|