@ninetailed/experience.js-react 7.13.0-beta.1 → 7.14.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/index.cjs.js +25 -10
- package/index.esm.js +25 -10
- package/package.json +4 -4
- package/src/lib/useFlag.d.ts +6 -6
package/index.cjs.js
CHANGED
|
@@ -100,6 +100,7 @@ function __rest(s, e) {
|
|
|
100
100
|
}
|
|
101
101
|
|
|
102
102
|
function formatProfileForHook(profile) {
|
|
103
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
103
104
|
const profileStateWithoutExperiences = __rest(profile, ["experiences"]);
|
|
104
105
|
return Object.assign(Object.assign({}, profileStateWithoutExperiences), {
|
|
105
106
|
loading: profile.status === 'loading'
|
|
@@ -152,13 +153,9 @@ const usePersonalize = (baseline, variants, options = {
|
|
|
152
153
|
};
|
|
153
154
|
|
|
154
155
|
/**
|
|
155
|
-
*
|
|
156
|
-
*
|
|
157
|
-
* @param flagKey - The key of the feature flag to retrieve
|
|
158
|
-
* @param defaultValue - The default value to use if the flag is not found
|
|
159
|
-
* @returns An object containing the flag value and status information
|
|
156
|
+
* Hook to access a Ninetailed variable flag with built-in tracking.
|
|
160
157
|
*/
|
|
161
|
-
function useFlag(flagKey, defaultValue) {
|
|
158
|
+
function useFlag(flagKey, defaultValue, options = {}) {
|
|
162
159
|
const ninetailed = useNinetailed();
|
|
163
160
|
const lastProcessedState = React.useRef(null);
|
|
164
161
|
const defaultValueRef = React.useRef(defaultValue);
|
|
@@ -168,7 +165,7 @@ function useFlag(flagKey, defaultValue) {
|
|
|
168
165
|
status: 'loading',
|
|
169
166
|
error: null
|
|
170
167
|
});
|
|
171
|
-
//
|
|
168
|
+
// Reset on input change
|
|
172
169
|
React.useEffect(() => {
|
|
173
170
|
if (!radash.isEqual(defaultValueRef.current, defaultValue) || flagKeyRef.current !== flagKey) {
|
|
174
171
|
defaultValueRef.current = defaultValue;
|
|
@@ -181,7 +178,7 @@ function useFlag(flagKey, defaultValue) {
|
|
|
181
178
|
lastProcessedState.current = null;
|
|
182
179
|
}
|
|
183
180
|
}, [flagKey, defaultValue]);
|
|
184
|
-
//
|
|
181
|
+
// Track changes
|
|
185
182
|
React.useEffect(() => {
|
|
186
183
|
const unsubscribe = ninetailed.onChangesChange(changesState => {
|
|
187
184
|
if (lastProcessedState.current && radash.isEqual(lastProcessedState.current, changesState)) {
|
|
@@ -207,11 +204,26 @@ function useFlag(flagKey, defaultValue) {
|
|
|
207
204
|
try {
|
|
208
205
|
const change = changesState.changes.find(change => change.key === flagKeyRef.current);
|
|
209
206
|
if (change && change.type === experience_jsShared.ChangeTypes.Variable) {
|
|
207
|
+
const rawValue = change.value;
|
|
208
|
+
const actualValue = rawValue && typeof rawValue === 'object' && rawValue !== null && 'value' in rawValue && typeof rawValue['value'] === 'object' ? rawValue['value'] : rawValue;
|
|
210
209
|
setResult({
|
|
211
|
-
value:
|
|
210
|
+
value: actualValue,
|
|
212
211
|
status: 'success',
|
|
213
212
|
error: null
|
|
214
213
|
});
|
|
214
|
+
const key = flagKeyRef.current;
|
|
215
|
+
const shouldTrack = typeof options.shouldTrack === 'function' ? options.shouldTrack() : options.shouldTrack !== false;
|
|
216
|
+
if (shouldTrack) {
|
|
217
|
+
ninetailed.trackVariableComponentView({
|
|
218
|
+
variable: change.value,
|
|
219
|
+
variant: {
|
|
220
|
+
id: `Variable-${key}`
|
|
221
|
+
},
|
|
222
|
+
componentType: 'Variable',
|
|
223
|
+
variantIndex: change.meta.variantIndex,
|
|
224
|
+
experienceId: change.meta.experienceId
|
|
225
|
+
});
|
|
226
|
+
}
|
|
215
227
|
} else {
|
|
216
228
|
setResult({
|
|
217
229
|
value: defaultValueRef.current,
|
|
@@ -534,7 +546,9 @@ const Experience = _a => {
|
|
|
534
546
|
const componentElement = componentRef.current;
|
|
535
547
|
if (componentElement && !(componentElement instanceof Element)) {
|
|
536
548
|
const isObject = typeof componentElement === 'object' && componentElement !== null;
|
|
537
|
-
const constructorName = isObject ?
|
|
549
|
+
const constructorName = isObject ?
|
|
550
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
551
|
+
componentElement.constructor.name : '';
|
|
538
552
|
const isConstructorNameNotObject = constructorName && constructorName !== 'Object';
|
|
539
553
|
logger.warn(`The component ref being in Experience is an invalid element. Expected an Element but got ${typeof componentElement}${isConstructorNameNotObject ? ` of type ${constructorName}` : ''}. This component won't be observed.`);
|
|
540
554
|
return () => {
|
|
@@ -545,6 +559,7 @@ const Experience = _a => {
|
|
|
545
559
|
observeElement({
|
|
546
560
|
element: componentElement,
|
|
547
561
|
experience,
|
|
562
|
+
componentType: 'Entry',
|
|
548
563
|
audience,
|
|
549
564
|
variant: isVariantHidden ? Object.assign(Object.assign({}, variant), {
|
|
550
565
|
id: `${baseline.id}-hidden`
|
package/index.esm.js
CHANGED
|
@@ -78,6 +78,7 @@ function _objectWithoutPropertiesLoose(source, excluded) {
|
|
|
78
78
|
|
|
79
79
|
const _excluded$3 = ["experiences"];
|
|
80
80
|
function formatProfileForHook(profile) {
|
|
81
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
81
82
|
const profileStateWithoutExperiences = _objectWithoutPropertiesLoose(profile, _excluded$3);
|
|
82
83
|
return Object.assign({}, profileStateWithoutExperiences, {
|
|
83
84
|
loading: profile.status === 'loading'
|
|
@@ -133,13 +134,9 @@ const usePersonalize = (baseline, variants, options = {
|
|
|
133
134
|
};
|
|
134
135
|
|
|
135
136
|
/**
|
|
136
|
-
*
|
|
137
|
-
*
|
|
138
|
-
* @param flagKey - The key of the feature flag to retrieve
|
|
139
|
-
* @param defaultValue - The default value to use if the flag is not found
|
|
140
|
-
* @returns An object containing the flag value and status information
|
|
137
|
+
* Hook to access a Ninetailed variable flag with built-in tracking.
|
|
141
138
|
*/
|
|
142
|
-
function useFlag(flagKey, defaultValue) {
|
|
139
|
+
function useFlag(flagKey, defaultValue, options = {}) {
|
|
143
140
|
const ninetailed = useNinetailed();
|
|
144
141
|
const lastProcessedState = useRef(null);
|
|
145
142
|
const defaultValueRef = useRef(defaultValue);
|
|
@@ -150,7 +147,7 @@ function useFlag(flagKey, defaultValue) {
|
|
|
150
147
|
error: null
|
|
151
148
|
});
|
|
152
149
|
|
|
153
|
-
//
|
|
150
|
+
// Reset on input change
|
|
154
151
|
useEffect(() => {
|
|
155
152
|
if (!isEqual(defaultValueRef.current, defaultValue) || flagKeyRef.current !== flagKey) {
|
|
156
153
|
defaultValueRef.current = defaultValue;
|
|
@@ -164,7 +161,7 @@ function useFlag(flagKey, defaultValue) {
|
|
|
164
161
|
}
|
|
165
162
|
}, [flagKey, defaultValue]);
|
|
166
163
|
|
|
167
|
-
//
|
|
164
|
+
// Track changes
|
|
168
165
|
useEffect(() => {
|
|
169
166
|
const unsubscribe = ninetailed.onChangesChange(changesState => {
|
|
170
167
|
if (lastProcessedState.current && isEqual(lastProcessedState.current, changesState)) {
|
|
@@ -190,11 +187,26 @@ function useFlag(flagKey, defaultValue) {
|
|
|
190
187
|
try {
|
|
191
188
|
const change = changesState.changes.find(change => change.key === flagKeyRef.current);
|
|
192
189
|
if (change && change.type === ChangeTypes.Variable) {
|
|
190
|
+
const rawValue = change.value;
|
|
191
|
+
const actualValue = rawValue && typeof rawValue === 'object' && rawValue !== null && 'value' in rawValue && typeof rawValue['value'] === 'object' ? rawValue['value'] : rawValue;
|
|
193
192
|
setResult({
|
|
194
|
-
value:
|
|
193
|
+
value: actualValue,
|
|
195
194
|
status: 'success',
|
|
196
195
|
error: null
|
|
197
196
|
});
|
|
197
|
+
const key = flagKeyRef.current;
|
|
198
|
+
const shouldTrack = typeof options.shouldTrack === 'function' ? options.shouldTrack() : options.shouldTrack !== false;
|
|
199
|
+
if (shouldTrack) {
|
|
200
|
+
ninetailed.trackVariableComponentView({
|
|
201
|
+
variable: change.value,
|
|
202
|
+
variant: {
|
|
203
|
+
id: `Variable-${key}`
|
|
204
|
+
},
|
|
205
|
+
componentType: 'Variable',
|
|
206
|
+
variantIndex: change.meta.variantIndex,
|
|
207
|
+
experienceId: change.meta.experienceId
|
|
208
|
+
});
|
|
209
|
+
}
|
|
198
210
|
} else {
|
|
199
211
|
setResult({
|
|
200
212
|
value: defaultValueRef.current,
|
|
@@ -520,7 +532,9 @@ const Experience = _ref2 => {
|
|
|
520
532
|
const componentElement = componentRef.current;
|
|
521
533
|
if (componentElement && !(componentElement instanceof Element)) {
|
|
522
534
|
const isObject = typeof componentElement === 'object' && componentElement !== null;
|
|
523
|
-
const constructorName = isObject ?
|
|
535
|
+
const constructorName = isObject ?
|
|
536
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
537
|
+
componentElement.constructor.name : '';
|
|
524
538
|
const isConstructorNameNotObject = constructorName && constructorName !== 'Object';
|
|
525
539
|
logger.warn(`The component ref being in Experience is an invalid element. Expected an Element but got ${typeof componentElement}${isConstructorNameNotObject ? ` of type ${constructorName}` : ''}. This component won't be observed.`);
|
|
526
540
|
return () => {
|
|
@@ -531,6 +545,7 @@ const Experience = _ref2 => {
|
|
|
531
545
|
observeElement({
|
|
532
546
|
element: componentElement,
|
|
533
547
|
experience,
|
|
548
|
+
componentType: 'Entry',
|
|
534
549
|
audience,
|
|
535
550
|
variant: isVariantHidden ? Object.assign({}, variant, {
|
|
536
551
|
id: `${baseline.id}-hidden`
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ninetailed/experience.js-react",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.14.0",
|
|
4
4
|
"description": "Ninetailed SDK for React",
|
|
5
5
|
"dependencies": {
|
|
6
|
-
"@ninetailed/experience.js": "7.
|
|
7
|
-
"@ninetailed/experience.js-shared": "7.
|
|
8
|
-
"@ninetailed/experience.js-plugin-analytics": "7.
|
|
6
|
+
"@ninetailed/experience.js": "7.14.0",
|
|
7
|
+
"@ninetailed/experience.js-shared": "7.14.0",
|
|
8
|
+
"@ninetailed/experience.js-plugin-analytics": "7.14.0",
|
|
9
9
|
"radash": "10.9.0",
|
|
10
10
|
"react-is": "18.2.0"
|
|
11
11
|
},
|
package/src/lib/useFlag.d.ts
CHANGED
|
@@ -12,11 +12,11 @@ export type FlagResult<T> = {
|
|
|
12
12
|
value: T;
|
|
13
13
|
error: Error;
|
|
14
14
|
};
|
|
15
|
+
type UseFlagOptions = {
|
|
16
|
+
shouldTrack?: boolean | (() => boolean);
|
|
17
|
+
};
|
|
15
18
|
/**
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* @param flagKey - The key of the feature flag to retrieve
|
|
19
|
-
* @param defaultValue - The default value to use if the flag is not found
|
|
20
|
-
* @returns An object containing the flag value and status information
|
|
19
|
+
* Hook to access a Ninetailed variable flag with built-in tracking.
|
|
21
20
|
*/
|
|
22
|
-
export declare function useFlag<T extends AllowedVariableType>(flagKey: string, defaultValue: T): FlagResult<T>;
|
|
21
|
+
export declare function useFlag<T extends AllowedVariableType>(flagKey: string, defaultValue: T, options?: UseFlagOptions): FlagResult<T>;
|
|
22
|
+
export {};
|