@openfeature/react-sdk 1.0.2 → 1.2.0
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/LICENSE +1 -1
- package/README.md +86 -17
- package/dist/cjs/index.js +90 -25
- package/dist/cjs/index.js.map +4 -4
- package/dist/esm/index.js +90 -31
- package/dist/esm/index.js.map +4 -4
- package/dist/types.d.ts +107 -39
- package/package.json +1 -1
package/LICENSE
CHANGED
|
@@ -186,7 +186,7 @@
|
|
|
186
186
|
same "printed page" as the copyright notice for easier
|
|
187
187
|
identification within third-party archives.
|
|
188
188
|
|
|
189
|
-
Copyright
|
|
189
|
+
Copyright OpenFeature Maintainers
|
|
190
190
|
|
|
191
191
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
192
192
|
you may not use this file except in compliance with the License.
|
package/README.md
CHANGED
|
@@ -16,8 +16,8 @@
|
|
|
16
16
|
<img alt="Specification" src="https://img.shields.io/static/v1?label=specification&message=v0.8.0&color=yellow&style=for-the-badge" />
|
|
17
17
|
</a>
|
|
18
18
|
<!-- x-release-please-start-version -->
|
|
19
|
-
<a href="https://github.com/open-feature/js-sdk/releases/tag/react-sdk-v1.0
|
|
20
|
-
<img alt="Release" src="https://img.shields.io/static/v1?label=release&message=v1.0
|
|
19
|
+
<a href="https://github.com/open-feature/js-sdk/releases/tag/react-sdk-v1.2.0">
|
|
20
|
+
<img alt="Release" src="https://img.shields.io/static/v1?label=release&message=v1.2.0&color=blue&style=for-the-badge" />
|
|
21
21
|
</a>
|
|
22
22
|
<!-- x-release-please-end -->
|
|
23
23
|
<br/>
|
|
@@ -50,6 +50,8 @@ In addition to the feature provided by the [web sdk](https://openfeature.dev/doc
|
|
|
50
50
|
- [Usage](#usage)
|
|
51
51
|
- [OpenFeatureProvider context provider](#openfeatureprovider-context-provider)
|
|
52
52
|
- [Evaluation hooks](#evaluation-hooks)
|
|
53
|
+
- [Declarative components](#declarative-components)
|
|
54
|
+
- [FeatureFlag Component](#featureflag-component)
|
|
53
55
|
- [Multiple Providers and Domains](#multiple-providers-and-domains)
|
|
54
56
|
- [Re-rendering with Context Changes](#re-rendering-with-context-changes)
|
|
55
57
|
- [Re-rendering with Flag Configuration Changes](#re-rendering-with-flag-configuration-changes)
|
|
@@ -87,8 +89,8 @@ yarn add @openfeature/react-sdk @openfeature/web-sdk @openfeature/core
|
|
|
87
89
|
The following list contains the peer dependencies of `@openfeature/react-sdk`.
|
|
88
90
|
See the [package.json](./package.json) for the required versions.
|
|
89
91
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
+
- `@openfeature/web-sdk`
|
|
93
|
+
- `react`
|
|
92
94
|
|
|
93
95
|
### Usage
|
|
94
96
|
|
|
@@ -108,13 +110,13 @@ const flagConfig = {
|
|
|
108
110
|
on: true,
|
|
109
111
|
off: false,
|
|
110
112
|
},
|
|
111
|
-
defaultVariant:
|
|
113
|
+
defaultVariant: 'on',
|
|
112
114
|
contextEvaluator: (context: EvaluationContext) => {
|
|
113
115
|
if (context.silly) {
|
|
114
116
|
return 'on';
|
|
115
117
|
}
|
|
116
|
-
return 'off'
|
|
117
|
-
}
|
|
118
|
+
return 'off';
|
|
119
|
+
},
|
|
118
120
|
},
|
|
119
121
|
};
|
|
120
122
|
|
|
@@ -146,7 +148,7 @@ function Page() {
|
|
|
146
148
|
{showNewMessage ? <p>Welcome to this OpenFeature-enabled React app!</p> : <p>Welcome to this React app.</p>}
|
|
147
149
|
</header>
|
|
148
150
|
</div>
|
|
149
|
-
)
|
|
151
|
+
);
|
|
150
152
|
}
|
|
151
153
|
```
|
|
152
154
|
|
|
@@ -163,14 +165,71 @@ const value = useBooleanFlagValue('new-message', false);
|
|
|
163
165
|
import { useBooleanFlagDetails } from '@openfeature/react-sdk';
|
|
164
166
|
|
|
165
167
|
// "detailed" boolean flag evaluation
|
|
166
|
-
const {
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
168
|
+
const { value, variant, reason, flagMetadata } = useBooleanFlagDetails('new-message', false);
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
#### Declarative components
|
|
172
|
+
|
|
173
|
+
The React SDK includes declarative components for feature flagging that provide a more JSX-native approach to conditional rendering.
|
|
174
|
+
|
|
175
|
+
##### FeatureFlag Component
|
|
176
|
+
|
|
177
|
+
The `FeatureFlag` component conditionally renders its children based on feature flag evaluation:
|
|
178
|
+
|
|
179
|
+
```tsx
|
|
180
|
+
import { FeatureFlag } from '@openfeature/react-sdk';
|
|
181
|
+
|
|
182
|
+
function App() {
|
|
183
|
+
return (
|
|
184
|
+
<OpenFeatureProvider>
|
|
185
|
+
{/* Basic usage - renders children when flag is truthy */}
|
|
186
|
+
<FeatureFlag flagKey="new-feature" defaultValue={false}>
|
|
187
|
+
<NewFeatureComponent />
|
|
188
|
+
</FeatureFlag>
|
|
189
|
+
|
|
190
|
+
{/* Match specific values */}
|
|
191
|
+
<FeatureFlag flagKey="theme" matchValue="dark" defaultValue="light">
|
|
192
|
+
<DarkThemeStyles />
|
|
193
|
+
</FeatureFlag>
|
|
194
|
+
|
|
195
|
+
{/* Boolean flag with fallback */}
|
|
196
|
+
<FeatureFlag flagKey="premium-feature" matchValue={true} defaultValue={false} fallback={<UpgradePrompt />}>
|
|
197
|
+
<PremiumContent />
|
|
198
|
+
</FeatureFlag>
|
|
199
|
+
|
|
200
|
+
{/* Custom predicate function for complex matching */}
|
|
201
|
+
<FeatureFlag
|
|
202
|
+
flagKey="user-segment"
|
|
203
|
+
defaultValue=""
|
|
204
|
+
matchValue="beta"
|
|
205
|
+
// check if the actual flag value includes the match ('beta')
|
|
206
|
+
predicate={(expected, actual) => !!expected && actual.value.includes(expected)}
|
|
207
|
+
>
|
|
208
|
+
<BetaFeatures />
|
|
209
|
+
</FeatureFlag>
|
|
210
|
+
|
|
211
|
+
{/* Function as children for accessing flag details */}
|
|
212
|
+
<FeatureFlag flagKey="experiment" defaultValue="control" matchValue="beta">
|
|
213
|
+
{({ value, reason }) => (
|
|
214
|
+
<span>
|
|
215
|
+
value is {value}, reason is {reason?.toString()}
|
|
216
|
+
</span>
|
|
217
|
+
)}
|
|
218
|
+
</FeatureFlag>
|
|
219
|
+
</OpenFeatureProvider>
|
|
220
|
+
);
|
|
221
|
+
}
|
|
172
222
|
```
|
|
173
223
|
|
|
224
|
+
The `FeatureFlag` component supports the following props:
|
|
225
|
+
|
|
226
|
+
- **`flagKey`** (required): The feature flag key to evaluate
|
|
227
|
+
- **`defaultValue`** (required): Default value when the flag is not available
|
|
228
|
+
- **`matchValue`** (required, except for boolean flags): Value to match against the flag value. By default, an optimized deep-comparison function is used.
|
|
229
|
+
- **`predicate`** (optional): Custom function for matching logic that receives the expected value and evaluation details
|
|
230
|
+
- **`children`**: Content to render when condition is met (can be JSX or a function receiving flag details)
|
|
231
|
+
- **`fallback`** (optional): Content to render when condition is not met
|
|
232
|
+
|
|
174
233
|
#### Multiple Providers and Domains
|
|
175
234
|
|
|
176
235
|
Multiple providers can be used by passing a `domain` to the `OpenFeatureProvider`:
|
|
@@ -313,8 +372,8 @@ The [OpenFeature debounce hook](https://github.com/open-feature/js-sdk-contrib/t
|
|
|
313
372
|
### Testing
|
|
314
373
|
|
|
315
374
|
The React SDK includes a built-in context provider for testing.
|
|
316
|
-
This allows you to easily test components that use evaluation hooks
|
|
317
|
-
If you try to test a component (in this case, `MyComponent`) which uses
|
|
375
|
+
This allows you to easily test components that use evaluation hooks (such as `useFlag`) or declarative components (such as `FeatureFlag`).
|
|
376
|
+
If you try to test a component (in this case, `MyComponent`) which uses feature flags, you might see an error message like:
|
|
318
377
|
|
|
319
378
|
> No OpenFeature client available - components using OpenFeature must be wrapped with an `<OpenFeatureProvider>`.
|
|
320
379
|
|
|
@@ -335,6 +394,16 @@ If you'd like to control the values returned by the evaluation hooks, you can pa
|
|
|
335
394
|
<OpenFeatureTestProvider flagValueMap={{ 'my-boolean-flag': true }}>
|
|
336
395
|
<MyComponent />
|
|
337
396
|
</OpenFeatureTestProvider>
|
|
397
|
+
|
|
398
|
+
// testing declarative FeatureFlag components
|
|
399
|
+
<OpenFeatureTestProvider flagValueMap={{ 'new-feature': true, 'theme': 'dark' }}>
|
|
400
|
+
<FeatureFlag flagKey="new-feature" defaultValue={false}>
|
|
401
|
+
<NewFeature />
|
|
402
|
+
</FeatureFlag>
|
|
403
|
+
<FeatureFlag flagKey="theme" matchValue="dark" defaultValue="light">
|
|
404
|
+
<DarkMode />
|
|
405
|
+
</FeatureFlag>
|
|
406
|
+
</OpenFeatureTestProvider>
|
|
338
407
|
```
|
|
339
408
|
|
|
340
409
|
Additionally, you can pass an artificial delay for the provider startup to test your suspense boundaries or loaders/spinners impacted by feature flags:
|
|
@@ -406,4 +475,4 @@ Avoid importing anything from `@openfeature/web-sdk` or `@openfeature/core`.
|
|
|
406
475
|
|
|
407
476
|
## Resources
|
|
408
477
|
|
|
409
|
-
|
|
478
|
+
- [Example repo](https://github.com/open-feature/react-test-app)
|
package/dist/cjs/index.js
CHANGED
|
@@ -80,6 +80,7 @@ var __async = (__this, __arguments, generator) => {
|
|
|
80
80
|
// src/index.ts
|
|
81
81
|
var index_exports = {};
|
|
82
82
|
__export(index_exports, {
|
|
83
|
+
FeatureFlag: () => FeatureFlag,
|
|
83
84
|
OpenFeatureProvider: () => OpenFeatureProvider,
|
|
84
85
|
OpenFeatureTestProvider: () => OpenFeatureTestProvider,
|
|
85
86
|
useBooleanFlagDetails: () => useBooleanFlagDetails,
|
|
@@ -100,13 +101,18 @@ __export(index_exports, {
|
|
|
100
101
|
});
|
|
101
102
|
module.exports = __toCommonJS(index_exports);
|
|
102
103
|
|
|
104
|
+
// src/declarative/FeatureFlag.tsx
|
|
105
|
+
var import_react7 = __toESM(require("react"));
|
|
106
|
+
|
|
103
107
|
// src/evaluation/use-feature-flag.ts
|
|
104
108
|
var import_web_sdk5 = require("@openfeature/web-sdk");
|
|
105
109
|
var import_react6 = require("react");
|
|
106
110
|
|
|
107
111
|
// src/internal/context.ts
|
|
108
112
|
var import_react = __toESM(require("react"));
|
|
109
|
-
var Context = import_react.default.createContext(
|
|
113
|
+
var Context = import_react.default.createContext(
|
|
114
|
+
void 0
|
|
115
|
+
);
|
|
110
116
|
function useProviderOptions() {
|
|
111
117
|
const { options } = import_react.default.useContext(Context) || {};
|
|
112
118
|
return normalizeOptions(options);
|
|
@@ -120,7 +126,7 @@ function isEqual(value, other) {
|
|
|
120
126
|
if (typeof value !== typeof other) {
|
|
121
127
|
return false;
|
|
122
128
|
}
|
|
123
|
-
if (typeof value === "object" && value !== null && other !== null) {
|
|
129
|
+
if (typeof value === "object" && value !== null && typeof other === "object" && other !== null) {
|
|
124
130
|
const valueKeys = Object.keys(value);
|
|
125
131
|
const otherKeys = Object.keys(other);
|
|
126
132
|
if (valueKeys.length !== otherKeys.length) {
|
|
@@ -242,8 +248,8 @@ var import_web_sdk2 = require("@openfeature/web-sdk");
|
|
|
242
248
|
function useOpenFeatureClientStatus() {
|
|
243
249
|
const client = useOpenFeatureClient();
|
|
244
250
|
const [status, setStatus] = (0, import_react4.useState)(client.providerStatus);
|
|
245
|
-
const controller = new AbortController();
|
|
246
251
|
(0, import_react4.useEffect)(() => {
|
|
252
|
+
const controller = new AbortController();
|
|
247
253
|
const updateStatus = () => setStatus(client.providerStatus);
|
|
248
254
|
client.addHandler(import_web_sdk2.ProviderEvents.ConfigurationChanged, updateStatus, { signal: controller.signal });
|
|
249
255
|
client.addHandler(import_web_sdk2.ProviderEvents.ContextChanged, updateStatus, { signal: controller.signal });
|
|
@@ -266,7 +272,7 @@ function useOpenFeatureProvider() {
|
|
|
266
272
|
if (!openFeatureContext) {
|
|
267
273
|
throw new MissingContextError("No OpenFeature context available");
|
|
268
274
|
}
|
|
269
|
-
return import_web_sdk3.OpenFeature.getProvider(openFeatureContext.domain);
|
|
275
|
+
return import_web_sdk3.OpenFeature.getProvider(openFeatureContext.client.metadata.domain);
|
|
270
276
|
}
|
|
271
277
|
|
|
272
278
|
// src/internal/hook-flag-query.ts
|
|
@@ -395,7 +401,7 @@ function attachHandlersAndResolve(flagKey, defaultValue, resolver, options) {
|
|
|
395
401
|
return;
|
|
396
402
|
}
|
|
397
403
|
const newDetails = resolver(client).call(client, flagKey, defaultValue, options);
|
|
398
|
-
if (!isEqual(newDetails
|
|
404
|
+
if (!isEqual(newDetails, evaluationDetails)) {
|
|
399
405
|
setEvaluationDetails(newDetails);
|
|
400
406
|
}
|
|
401
407
|
}, [client, flagKey, defaultValue, options, resolver, evaluationDetails]);
|
|
@@ -405,7 +411,7 @@ function attachHandlersAndResolve(flagKey, defaultValue, resolver, options) {
|
|
|
405
411
|
}, [evaluationDetails]);
|
|
406
412
|
const updateEvaluationDetailsCallback = (0, import_react6.useCallback)(() => {
|
|
407
413
|
const updatedEvaluationDetails = resolver(client).call(client, flagKey, defaultValue, options);
|
|
408
|
-
if (!isEqual(updatedEvaluationDetails
|
|
414
|
+
if (!isEqual(updatedEvaluationDetails, evaluationDetailsRef.current)) {
|
|
409
415
|
setEvaluationDetails(updatedEvaluationDetails);
|
|
410
416
|
}
|
|
411
417
|
}, [client, flagKey, defaultValue, options, resolver]);
|
|
@@ -444,13 +450,51 @@ function attachHandlersAndResolve(flagKey, defaultValue, resolver, options) {
|
|
|
444
450
|
return evaluationDetails;
|
|
445
451
|
}
|
|
446
452
|
|
|
453
|
+
// src/declarative/FeatureFlag.tsx
|
|
454
|
+
function equals(expected, actual) {
|
|
455
|
+
return isEqual(expected, actual.value);
|
|
456
|
+
}
|
|
457
|
+
function FeatureFlag({
|
|
458
|
+
flagKey,
|
|
459
|
+
matchValue,
|
|
460
|
+
predicate,
|
|
461
|
+
defaultValue,
|
|
462
|
+
children,
|
|
463
|
+
evaluationOptions = {},
|
|
464
|
+
fallback = null
|
|
465
|
+
}) {
|
|
466
|
+
const details = useFlag(flagKey, defaultValue, __spreadValues({
|
|
467
|
+
updateOnContextChanged: true
|
|
468
|
+
}, evaluationOptions));
|
|
469
|
+
if (details.reason === "ERROR") {
|
|
470
|
+
const fallbackNode2 = typeof fallback === "function" ? fallback(details.details) : fallback;
|
|
471
|
+
return /* @__PURE__ */ import_react7.default.createElement(import_react7.default.Fragment, null, fallbackNode2);
|
|
472
|
+
}
|
|
473
|
+
let shouldRender = false;
|
|
474
|
+
if (predicate) {
|
|
475
|
+
shouldRender = predicate(matchValue, details.details);
|
|
476
|
+
} else if (matchValue !== void 0) {
|
|
477
|
+
shouldRender = equals(matchValue, details.details);
|
|
478
|
+
} else if (details.type === "boolean") {
|
|
479
|
+
shouldRender = Boolean(details.value);
|
|
480
|
+
} else {
|
|
481
|
+
shouldRender = false;
|
|
482
|
+
}
|
|
483
|
+
if (shouldRender) {
|
|
484
|
+
const childNode = typeof children === "function" ? children(details) : children;
|
|
485
|
+
return /* @__PURE__ */ import_react7.default.createElement(import_react7.default.Fragment, null, childNode);
|
|
486
|
+
}
|
|
487
|
+
const fallbackNode = typeof fallback === "function" ? fallback(details.details) : fallback;
|
|
488
|
+
return /* @__PURE__ */ import_react7.default.createElement(import_react7.default.Fragment, null, fallbackNode);
|
|
489
|
+
}
|
|
490
|
+
|
|
447
491
|
// src/provider/provider.tsx
|
|
448
492
|
var import_web_sdk6 = require("@openfeature/web-sdk");
|
|
449
|
-
var
|
|
493
|
+
var React6 = __toESM(require("react"));
|
|
450
494
|
function OpenFeatureProvider(_a) {
|
|
451
495
|
var _b = _a, { client, domain, children } = _b, options = __objRest(_b, ["client", "domain", "children"]);
|
|
452
|
-
const stableClient =
|
|
453
|
-
return /* @__PURE__ */
|
|
496
|
+
const stableClient = React6.useMemo(() => client || import_web_sdk6.OpenFeature.getClient(domain), [client, domain]);
|
|
497
|
+
return /* @__PURE__ */ React6.createElement(Context.Provider, { value: { client: stableClient, options } }, children);
|
|
454
498
|
}
|
|
455
499
|
|
|
456
500
|
// src/provider/use-when-provider-ready.ts
|
|
@@ -468,7 +512,7 @@ function useWhenProviderReady(options) {
|
|
|
468
512
|
|
|
469
513
|
// src/provider/test-provider.tsx
|
|
470
514
|
var import_web_sdk8 = require("@openfeature/web-sdk");
|
|
471
|
-
var
|
|
515
|
+
var import_react8 = __toESM(require("react"));
|
|
472
516
|
var TEST_VARIANT = "test-variant";
|
|
473
517
|
var TEST_PROVIDER = "test-provider";
|
|
474
518
|
var TestProvider = class extends import_web_sdk8.InMemoryProvider {
|
|
@@ -508,10 +552,12 @@ function OpenFeatureTestProvider(testProviderOptions) {
|
|
|
508
552
|
const { flagValueMap, provider } = testProviderOptions;
|
|
509
553
|
const effectiveProvider = flagValueMap ? new TestProvider(flagValueMap, testProviderOptions.delayMs) : mixInNoop(provider) || import_web_sdk8.NOOP_PROVIDER;
|
|
510
554
|
testProviderOptions.domain ? import_web_sdk8.OpenFeature.setProvider(testProviderOptions.domain, effectiveProvider) : import_web_sdk8.OpenFeature.setProvider(effectiveProvider);
|
|
511
|
-
return /* @__PURE__ */
|
|
555
|
+
return /* @__PURE__ */ import_react8.default.createElement(OpenFeatureProvider, __spreadProps(__spreadValues({}, testProviderOptions), { domain: testProviderOptions.domain }), testProviderOptions.children);
|
|
512
556
|
}
|
|
513
557
|
function mixInNoop(provider = {}) {
|
|
514
|
-
for (const prop of Object.getOwnPropertyNames(Object.getPrototypeOf(import_web_sdk8.NOOP_PROVIDER)).filter(
|
|
558
|
+
for (const prop of Object.getOwnPropertyNames(Object.getPrototypeOf(import_web_sdk8.NOOP_PROVIDER)).filter(
|
|
559
|
+
(prop2) => prop2 !== "constructor"
|
|
560
|
+
)) {
|
|
515
561
|
const patchedProvider = provider;
|
|
516
562
|
if (!Object.getPrototypeOf(patchedProvider)[prop] && !patchedProvider[prop]) {
|
|
517
563
|
patchedProvider[prop] = Object.getPrototypeOf(import_web_sdk8.NOOP_PROVIDER)[prop];
|
|
@@ -524,31 +570,50 @@ function mixInNoop(provider = {}) {
|
|
|
524
570
|
}
|
|
525
571
|
|
|
526
572
|
// src/context/use-context-mutator.ts
|
|
527
|
-
var
|
|
573
|
+
var import_react9 = require("react");
|
|
528
574
|
var import_web_sdk9 = require("@openfeature/web-sdk");
|
|
529
575
|
function useContextMutator(options = { defaultContext: false }) {
|
|
530
|
-
const {
|
|
531
|
-
const
|
|
532
|
-
const
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
import_web_sdk9.OpenFeature.setContext(domain, updatedContext);
|
|
576
|
+
const { client } = (0, import_react9.useContext)(Context) || {};
|
|
577
|
+
const domain = client == null ? void 0 : client.metadata.domain;
|
|
578
|
+
const [warned, setWarned] = (0, import_react9.useState)(false);
|
|
579
|
+
(0, import_react9.useEffect)(() => {
|
|
580
|
+
if (options.defaultContext || domain) {
|
|
581
|
+
if (warned) {
|
|
582
|
+
setWarned(false);
|
|
538
583
|
}
|
|
539
|
-
|
|
584
|
+
return;
|
|
585
|
+
}
|
|
586
|
+
if (!warned) {
|
|
587
|
+
console.warn(
|
|
588
|
+
"[useContextMutator] No domain available from OpenFeature context; are you using <OpenFeatureProvider/>? setContext will mutate the default context, as if `defaultContext: true` were set. This may result in a thrown error in the future."
|
|
589
|
+
);
|
|
590
|
+
setWarned(true);
|
|
540
591
|
}
|
|
541
|
-
}
|
|
592
|
+
}, [warned]);
|
|
593
|
+
const setContext = (0, import_react9.useCallback)(
|
|
594
|
+
(updatedContext) => __async(null, null, function* () {
|
|
595
|
+
const previousContext = import_web_sdk9.OpenFeature.getContext((options == null ? void 0 : options.defaultContext) ? void 0 : domain);
|
|
596
|
+
const resolvedContext = typeof updatedContext === "function" ? updatedContext(previousContext) : updatedContext;
|
|
597
|
+
if (previousContext !== resolvedContext) {
|
|
598
|
+
if (!domain || (options == null ? void 0 : options.defaultContext)) {
|
|
599
|
+
yield import_web_sdk9.OpenFeature.setContext(resolvedContext);
|
|
600
|
+
} else {
|
|
601
|
+
yield import_web_sdk9.OpenFeature.setContext(domain, resolvedContext);
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
}),
|
|
605
|
+
[domain, options == null ? void 0 : options.defaultContext]
|
|
606
|
+
);
|
|
542
607
|
return {
|
|
543
608
|
setContext
|
|
544
609
|
};
|
|
545
610
|
}
|
|
546
611
|
|
|
547
612
|
// src/tracking/use-track.ts
|
|
548
|
-
var
|
|
613
|
+
var import_react10 = require("react");
|
|
549
614
|
function useTrack() {
|
|
550
615
|
const client = useOpenFeatureClient();
|
|
551
|
-
const track = (0,
|
|
616
|
+
const track = (0, import_react10.useCallback)((trackingEventName, trackingEventDetails) => {
|
|
552
617
|
client.track(trackingEventName, trackingEventDetails);
|
|
553
618
|
}, []);
|
|
554
619
|
return {
|