@ninetailed/experience.js-react 4.3.0-beta.2 → 4.4.0-beta.1

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 CHANGED
@@ -5,7 +5,6 @@ Object.defineProperty(exports, '__esModule', { value: true });
5
5
  var jsxRuntime = require('react/jsx-runtime');
6
6
  var React = require('react');
7
7
  var experience_js = require('@ninetailed/experience.js');
8
- var reactIs = require('react-is');
9
8
  var reactIntersectionObserver = require('react-intersection-observer');
10
9
  var experience_jsShared = require('@ninetailed/experience.js-shared');
11
10
  var radash = require('radash');
@@ -1930,23 +1929,6 @@ const useProfile = () => {
1930
1929
  });
1931
1930
  };
1932
1931
 
1933
- const ExperimentsContext = /*#__PURE__*/React.createContext(undefined);
1934
-
1935
- const useExperimentsContext = () => {
1936
- const context = React.useContext(ExperimentsContext);
1937
- if (context === undefined) {
1938
- throw new Error('The component using the the context must be a descendant of the ExperimentsProvider');
1939
- }
1940
- return context;
1941
- };
1942
-
1943
- const useExperiments = () => {
1944
- const context = useExperimentsContext();
1945
- return {
1946
- experiments: context.experiments
1947
- };
1948
- };
1949
-
1950
1932
  const useExperienceSelectionMiddleware = ({
1951
1933
  experiences,
1952
1934
  baseline,
@@ -1981,9 +1963,6 @@ const useExperience = ({
1981
1963
  experiences
1982
1964
  }) => {
1983
1965
  const profileState = useProfile();
1984
- const {
1985
- experiments
1986
- } = useExperiments();
1987
1966
  const hasVariants = experiences.map(experience => experience_js.selectHasExperienceVariants(experience, baseline)).reduce((acc, curr) => acc || curr, false);
1988
1967
  const {
1989
1968
  status,
@@ -2040,7 +2019,7 @@ const useExperience = ({
2040
2019
  // @ts-ignore
2041
2020
  return overrideResult(emptyReturn);
2042
2021
  }
2043
- const activeExperiments = experience_js.selectActiveExperiments(experiments, profile);
2022
+ const activeExperiments = experience_js.selectActiveExperiments(experiences, profile);
2044
2023
  const experience = experience_js.selectExperience({
2045
2024
  experiences,
2046
2025
  activeExperiments,
@@ -2083,41 +2062,21 @@ const useExperience = ({
2083
2062
  }));
2084
2063
  };
2085
2064
 
2065
+ const ExperimentsContext = /*#__PURE__*/React.createContext(undefined);
2066
+
2067
+ const useExperimentsContext = () => {
2068
+ const context = React.useContext(ExperimentsContext);
2069
+ if (context === undefined) {
2070
+ throw new Error('The component using the the context must be a descendant of the ExperimentsProvider');
2071
+ }
2072
+ return context;
2073
+ };
2074
+
2086
2075
  const useJoinExperiment = () => {
2087
2076
  const context = useExperimentsContext();
2088
2077
  return context.joinExperiment;
2089
2078
  };
2090
2079
 
2091
- const ComponentMarker = /*#__PURE__*/React.forwardRef((_, ref) => {
2092
- const {
2093
- logger
2094
- } = useNinetailed();
2095
- const markerRef = React.useRef(null);
2096
- React.useEffect(() => {
2097
- // TODO: Create a better message
2098
- logger.debug('Using fallback mechanism to select component.');
2099
- }, [logger]);
2100
- React.useEffect(() => {
2101
- if (markerRef.current) {
2102
- const nextSibling = markerRef.current.nextSibling;
2103
- if (ref) {
2104
- if (typeof ref === 'function') {
2105
- ref(nextSibling);
2106
- } else {
2107
- ref.current = nextSibling;
2108
- }
2109
- }
2110
- }
2111
- }, []);
2112
- return jsxRuntime.jsx("div", {
2113
- className: "nt-cmp-marker",
2114
- style: {
2115
- display: 'none !important'
2116
- },
2117
- ref: markerRef
2118
- });
2119
- });
2120
-
2121
2080
  const DefaultExperienceLoadingComponent = _a => {
2122
2081
  var {
2123
2082
  component: Component,
@@ -2171,10 +2130,6 @@ const Experience = _a => {
2171
2130
  passthroughProps
2172
2131
  } = _a,
2173
2132
  baseline = __rest(_a, ["experiences", "component", "loadingComponent", "passthroughProps"]);
2174
- const {
2175
- observeElement,
2176
- unobserveElement
2177
- } = useNinetailed();
2178
2133
  // TODO we actually could hook into the experience hook here with the plugins
2179
2134
  const {
2180
2135
  status,
@@ -2189,46 +2144,22 @@ const Experience = _a => {
2189
2144
  experiences
2190
2145
  });
2191
2146
  const joinExperiment = useJoinExperiment();
2192
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
2193
- // @ts-ignore
2194
- const isComponentForwardRef = reactIs.isForwardRef(jsxRuntime.jsx(Component, {}));
2195
- const componentRef = React.useRef(null);
2196
2147
  React.useEffect(() => {
2197
- if (status === 'success' && experience && profile) {
2148
+ if (status === 'success' && experience && experience.type === 'nt_experiment' && variant && profile) {
2198
2149
  joinExperiment({
2199
2150
  experiences,
2200
2151
  experiment: experience,
2152
+ variant: Object.assign(Object.assign({}, variant), {
2153
+ hidden: 'hidden' in variant ? variant.hidden : false
2154
+ }),
2201
2155
  profile
2202
2156
  });
2203
2157
  }
2204
- }, [status, experience, profile]);
2205
- React.useEffect(() => {
2206
- const componentElement = componentRef.current;
2207
- if (componentElement) {
2208
- observeElement({
2209
- element: componentElement,
2210
- experienceId: experience === null || experience === void 0 ? void 0 : experience.id,
2211
- variantId: variant === null || variant === void 0 ? void 0 : variant.id,
2212
- baselineId: baseline.id,
2213
- audienceId: audience === null || audience === void 0 ? void 0 : audience.id
2214
- });
2215
- }
2216
- return () => {
2217
- if (componentElement) {
2218
- unobserveElement(componentElement);
2219
- }
2220
- };
2221
- }, [observeElement, unobserveElement, experience, baseline, variant, audience]);
2158
+ }, [status, experience, variant, profile]);
2222
2159
  if (!hasVariants) {
2223
- return jsxRuntime.jsxs(jsxRuntime.Fragment, {
2224
- children: [!isComponentForwardRef && jsxRuntime.jsx(ComponentMarker, {
2225
- ref: componentRef
2226
- }), /*#__PURE__*/React.createElement(Component, Object.assign({}, passthroughProps, baseline, {
2227
- key: baseline.id
2228
- }, isComponentForwardRef ? {
2229
- ref: componentRef
2230
- } : {}))]
2231
- });
2160
+ return /*#__PURE__*/React.createElement(Component, Object.assign({}, passthroughProps, baseline, {
2161
+ key: baseline.id
2162
+ }));
2232
2163
  }
2233
2164
  if (status === 'loading') {
2234
2165
  return /*#__PURE__*/React.createElement(LoadingComponent, Object.assign({}, baseline, {
@@ -2239,20 +2170,14 @@ const Experience = _a => {
2239
2170
  }));
2240
2171
  }
2241
2172
  if (!experience) {
2242
- return jsxRuntime.jsxs(jsxRuntime.Fragment, {
2243
- children: [!isComponentForwardRef && jsxRuntime.jsx(ComponentMarker, {
2244
- ref: componentRef
2245
- }), jsxRuntime.jsx(Component, Object.assign({}, passthroughProps, baseline, {
2246
- ninetailed: {
2247
- isPersonalized: false,
2248
- audience: {
2249
- id: 'baseline'
2250
- }
2173
+ return jsxRuntime.jsx(Component, Object.assign({}, passthroughProps, baseline, {
2174
+ ninetailed: {
2175
+ isPersonalized: false,
2176
+ audience: {
2177
+ id: 'baseline'
2251
2178
  }
2252
- }, isComponentForwardRef ? {
2253
- ref: componentRef
2254
- } : {}))]
2255
- });
2179
+ }
2180
+ }));
2256
2181
  }
2257
2182
  if (!variant) {
2258
2183
  return jsxRuntime.jsx(TrackExperience, Object.assign({
@@ -2261,20 +2186,14 @@ const Experience = _a => {
2261
2186
  // the profile is definitely defined, otherwise there wouldn't be an experience selected
2262
2187
  profile: profile
2263
2188
  }, {
2264
- children: jsxRuntime.jsxs(jsxRuntime.Fragment, {
2265
- children: [!isComponentForwardRef && jsxRuntime.jsx(ComponentMarker, {
2266
- ref: componentRef
2267
- }), jsxRuntime.jsx(Component, Object.assign({}, passthroughProps, baseline, {
2268
- ninetailed: {
2269
- isPersonalized: false,
2270
- audience: {
2271
- id: (audience === null || audience === void 0 ? void 0 : audience.id) || 'all visitors'
2272
- }
2189
+ children: jsxRuntime.jsx(Component, Object.assign({}, passthroughProps, baseline, {
2190
+ ninetailed: {
2191
+ isPersonalized: false,
2192
+ audience: {
2193
+ id: (audience === null || audience === void 0 ? void 0 : audience.id) || 'all visitors'
2273
2194
  }
2274
- }, isComponentForwardRef ? {
2275
- ref: componentRef
2276
- } : {}))]
2277
- })
2195
+ }
2196
+ }))
2278
2197
  }), baseline.id);
2279
2198
  }
2280
2199
  const isVariantHidden = 'hidden' in variant && variant.hidden;
@@ -2284,21 +2203,15 @@ const Experience = _a => {
2284
2203
  // the profile is definitely defined, otherwise there wouldn't be an experience selected
2285
2204
  profile: profile
2286
2205
  }, {
2287
- children: !isVariantHidden ? jsxRuntime.jsxs(jsxRuntime.Fragment, {
2288
- children: [!isComponentForwardRef && jsxRuntime.jsx(ComponentMarker, {
2289
- ref: componentRef
2290
- }), /*#__PURE__*/React.createElement(Component, Object.assign({}, Object.assign(Object.assign({}, passthroughProps), variant), {
2291
- key: `${experience.id}-${variant.id}`,
2292
- ninetailed: {
2293
- isPersonalized,
2294
- audience: {
2295
- id: (audience === null || audience === void 0 ? void 0 : audience.id) || 'all visitors'
2296
- }
2206
+ children: !isVariantHidden ? /*#__PURE__*/React.createElement(Component, Object.assign({}, Object.assign(Object.assign({}, passthroughProps), variant), {
2207
+ key: `${experience.id}-${variant.id}`,
2208
+ ninetailed: {
2209
+ isPersonalized,
2210
+ audience: {
2211
+ id: (audience === null || audience === void 0 ? void 0 : audience.id) || 'all visitors'
2297
2212
  }
2298
- }, isComponentForwardRef ? {
2299
- ref: componentRef
2300
- } : {}))]
2301
- }) : null
2213
+ }
2214
+ })) : null
2302
2215
  }));
2303
2216
  };
2304
2217
 
@@ -2402,15 +2315,13 @@ const debounce = (fn, wait) => {
2402
2315
  debouncedFn();
2403
2316
  };
2404
2317
  };
2405
- const useProvideJoinExperiment = ({
2406
- experiments,
2407
- maximumActiveExperiments: _maximumActiveExperiments = 1
2408
- }) => {
2318
+ // TODO: the majority of this code should be moved to the experience.js javascript package
2319
+ const useProvideJoinExperiment = _ => {
2409
2320
  const {
2410
2321
  identify
2411
2322
  } = useNinetailed();
2412
2323
  const joinExperimentIdentify = debounce(args => {
2413
- const traits = args.slice(0, _maximumActiveExperiments).reduce((traits, [experimentJoinTraits]) => {
2324
+ const traits = args.reduce((traits, [experimentJoinTraits]) => {
2414
2325
  return Object.assign(Object.assign({}, experimentJoinTraits), traits);
2415
2326
  }, {});
2416
2327
  identify('', traits);
@@ -2418,6 +2329,7 @@ const useProvideJoinExperiment = ({
2418
2329
  return React.useCallback(data => __awaiter(void 0, void 0, void 0, function* () {
2419
2330
  const {
2420
2331
  experiment,
2332
+ variant,
2421
2333
  profile
2422
2334
  } = data;
2423
2335
  const isExperiment = experiment.type === 'nt_experiment';
@@ -2425,17 +2337,17 @@ const useProvideJoinExperiment = ({
2425
2337
  experience_jsShared.logger.warn(`The experience ${experiment.id}, which you tried to join, is not an experiment.`);
2426
2338
  return;
2427
2339
  }
2428
- const activeExperiments = experience_js.selectActiveExperiments(experiments, profile);
2429
- if (activeExperiments.length >= _maximumActiveExperiments) {
2430
- experience_jsShared.logger.warn(`The maximum number of active experiments (${_maximumActiveExperiments}) has been reached.`);
2340
+ if (!experience_jsShared.isExperienceSticky(experiment)) {
2341
+ experience_jsShared.logger.debug("Won't add experiment to traits, as it's not sticky.");
2431
2342
  return;
2432
2343
  }
2433
- if (activeExperiments.some(activeExperiment => activeExperiment.id === experiment.id)) {
2344
+ const activeExperimentIds = experience_jsShared.selectActiveExperimentIds(profile);
2345
+ if (activeExperimentIds.some(activeExperimentId => activeExperimentId === experiment.id)) {
2434
2346
  experience_jsShared.logger.debug(`The user is already part of experiment ${experiment.id}. Won't join again.`);
2435
2347
  return;
2436
2348
  }
2437
2349
  joinExperimentIdentify({
2438
- [`${EXPERIENCE_TRAIT_PREFIX}${experiment.id}`]: true
2350
+ [`${EXPERIENCE_TRAIT_PREFIX}${experiment.id}`]: variant.hidden ? 'hidden' : variant.id
2439
2351
  });
2440
2352
  experience_jsShared.logger.debug(`Sent event to join experiment ${experiment.id}.`);
2441
2353
  }), []);
@@ -2446,10 +2358,7 @@ const ExperimentsProvider = ({
2446
2358
  maximumActiveExperiments: _maximumActiveExperiments = 1,
2447
2359
  children
2448
2360
  }) => {
2449
- const joinExperiment = useProvideJoinExperiment({
2450
- experiments,
2451
- maximumActiveExperiments: _maximumActiveExperiments
2452
- });
2361
+ const joinExperiment = useProvideJoinExperiment();
2453
2362
  return jsxRuntime.jsx(ExperimentsContext.Provider, Object.assign({
2454
2363
  value: {
2455
2364
  experiments,
@@ -2460,40 +2369,58 @@ const ExperimentsProvider = ({
2460
2369
  }));
2461
2370
  };
2462
2371
 
2463
- const NinetailedProvider = ({
2464
- children,
2465
- clientId,
2466
- experiments: _experiments = [],
2467
- maximumActiveExperiments,
2468
- environment,
2469
- preview,
2470
- url,
2471
- profile,
2472
- locale,
2473
- requestTimeout,
2474
- plugins: _plugins = [],
2475
- onLog,
2476
- onError
2477
- }) => {
2478
- const ninetailed = React.useMemo(() => new experience_js.Ninetailed({
2479
- clientId,
2480
- environment,
2481
- preview
2482
- }, {
2483
- url,
2484
- plugins: _plugins,
2485
- profile,
2486
- locale,
2487
- requestTimeout,
2488
- onLog,
2489
- onError
2490
- }), []);
2372
+ /**
2373
+ * @deprecated
2374
+ *
2375
+ * This will get removed in v5 of the SDK.
2376
+ */
2377
+ const useExperiments = () => {
2378
+ const context = useExperimentsContext();
2379
+ return {
2380
+ experiments: context.experiments
2381
+ };
2382
+ };
2383
+
2384
+ const NinetailedProvider = props => {
2385
+ const ninetailed = React.useMemo(() => {
2386
+ if ('ninetailed' in props) {
2387
+ return props.ninetailed;
2388
+ }
2389
+ const {
2390
+ clientId,
2391
+ environment,
2392
+ preview,
2393
+ url,
2394
+ profile,
2395
+ locale,
2396
+ requestTimeout,
2397
+ plugins = [],
2398
+ onLog,
2399
+ onError
2400
+ } = props;
2401
+ return new experience_js.Ninetailed({
2402
+ clientId,
2403
+ environment,
2404
+ preview
2405
+ }, {
2406
+ url,
2407
+ plugins,
2408
+ profile,
2409
+ locale,
2410
+ requestTimeout,
2411
+ onLog,
2412
+ onError
2413
+ });
2414
+ }, []);
2415
+ const {
2416
+ children
2417
+ } = props;
2491
2418
  return jsxRuntime.jsx(NinetailedContext.Provider, Object.assign({
2492
2419
  value: ninetailed
2493
2420
  }, {
2494
2421
  children: jsxRuntime.jsx(ExperimentsProvider, Object.assign({
2495
- experiments: _experiments,
2496
- maximumActiveExperiments: maximumActiveExperiments
2422
+ experiments: [],
2423
+ maximumActiveExperiments: 10000
2497
2424
  }, {
2498
2425
  children: children
2499
2426
  }))
package/index.js CHANGED
@@ -1,9 +1,8 @@
1
1
  import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
2
- import React, { createContext, useContext, useEffect, useState, useRef, useMemo, forwardRef, createElement as createElement$1, useCallback } from 'react';
2
+ import React, { createContext, useContext, useEffect, useState, useRef, useMemo, createElement as createElement$1, useCallback } from 'react';
3
3
  import { selectDistribution, makeExperienceSelectMiddleware, selectHasExperienceVariants, selectActiveExperiments, selectExperience, selectExperienceVariant, Ninetailed, selectVariant } from '@ninetailed/experience.js';
4
- import { isForwardRef } from 'react-is';
5
4
  import { useInView } from 'react-intersection-observer';
6
- import { isBrowser, logger } from '@ninetailed/experience.js-shared';
5
+ import { isBrowser, logger, isExperienceSticky, selectActiveExperimentIds } from '@ninetailed/experience.js-shared';
7
6
  import { isEqual, debounce as debounce$1, get as get$1 } from 'radash';
8
7
 
9
8
  var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
@@ -1922,23 +1921,6 @@ const useProfile = () => {
1922
1921
  });
1923
1922
  };
1924
1923
 
1925
- const ExperimentsContext = /*#__PURE__*/createContext(undefined);
1926
-
1927
- const useExperimentsContext = () => {
1928
- const context = useContext(ExperimentsContext);
1929
- if (context === undefined) {
1930
- throw new Error('The component using the the context must be a descendant of the ExperimentsProvider');
1931
- }
1932
- return context;
1933
- };
1934
-
1935
- const useExperiments = () => {
1936
- const context = useExperimentsContext();
1937
- return {
1938
- experiments: context.experiments
1939
- };
1940
- };
1941
-
1942
1924
  const useExperienceSelectionMiddleware = ({
1943
1925
  experiences,
1944
1926
  baseline,
@@ -1973,9 +1955,6 @@ const useExperience = ({
1973
1955
  experiences
1974
1956
  }) => {
1975
1957
  const profileState = useProfile();
1976
- const {
1977
- experiments
1978
- } = useExperiments();
1979
1958
  const hasVariants = experiences.map(experience => selectHasExperienceVariants(experience, baseline)).reduce((acc, curr) => acc || curr, false);
1980
1959
  const {
1981
1960
  status,
@@ -2032,7 +2011,7 @@ const useExperience = ({
2032
2011
  // @ts-ignore
2033
2012
  return overrideResult(emptyReturn);
2034
2013
  }
2035
- const activeExperiments = selectActiveExperiments(experiments, profile);
2014
+ const activeExperiments = selectActiveExperiments(experiences, profile);
2036
2015
  const experience = selectExperience({
2037
2016
  experiences,
2038
2017
  activeExperiments,
@@ -2075,41 +2054,21 @@ const useExperience = ({
2075
2054
  }));
2076
2055
  };
2077
2056
 
2057
+ const ExperimentsContext = /*#__PURE__*/createContext(undefined);
2058
+
2059
+ const useExperimentsContext = () => {
2060
+ const context = useContext(ExperimentsContext);
2061
+ if (context === undefined) {
2062
+ throw new Error('The component using the the context must be a descendant of the ExperimentsProvider');
2063
+ }
2064
+ return context;
2065
+ };
2066
+
2078
2067
  const useJoinExperiment = () => {
2079
2068
  const context = useExperimentsContext();
2080
2069
  return context.joinExperiment;
2081
2070
  };
2082
2071
 
2083
- const ComponentMarker = /*#__PURE__*/forwardRef((_, ref) => {
2084
- const {
2085
- logger
2086
- } = useNinetailed();
2087
- const markerRef = useRef(null);
2088
- useEffect(() => {
2089
- // TODO: Create a better message
2090
- logger.debug('Using fallback mechanism to select component.');
2091
- }, [logger]);
2092
- useEffect(() => {
2093
- if (markerRef.current) {
2094
- const nextSibling = markerRef.current.nextSibling;
2095
- if (ref) {
2096
- if (typeof ref === 'function') {
2097
- ref(nextSibling);
2098
- } else {
2099
- ref.current = nextSibling;
2100
- }
2101
- }
2102
- }
2103
- }, []);
2104
- return jsx("div", {
2105
- className: "nt-cmp-marker",
2106
- style: {
2107
- display: 'none !important'
2108
- },
2109
- ref: markerRef
2110
- });
2111
- });
2112
-
2113
2072
  const DefaultExperienceLoadingComponent = _a => {
2114
2073
  var {
2115
2074
  component: Component,
@@ -2163,10 +2122,6 @@ const Experience = _a => {
2163
2122
  passthroughProps
2164
2123
  } = _a,
2165
2124
  baseline = __rest(_a, ["experiences", "component", "loadingComponent", "passthroughProps"]);
2166
- const {
2167
- observeElement,
2168
- unobserveElement
2169
- } = useNinetailed();
2170
2125
  // TODO we actually could hook into the experience hook here with the plugins
2171
2126
  const {
2172
2127
  status,
@@ -2181,46 +2136,22 @@ const Experience = _a => {
2181
2136
  experiences
2182
2137
  });
2183
2138
  const joinExperiment = useJoinExperiment();
2184
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
2185
- // @ts-ignore
2186
- const isComponentForwardRef = isForwardRef(jsx(Component, {}));
2187
- const componentRef = useRef(null);
2188
2139
  useEffect(() => {
2189
- if (status === 'success' && experience && profile) {
2140
+ if (status === 'success' && experience && experience.type === 'nt_experiment' && variant && profile) {
2190
2141
  joinExperiment({
2191
2142
  experiences,
2192
2143
  experiment: experience,
2144
+ variant: Object.assign(Object.assign({}, variant), {
2145
+ hidden: 'hidden' in variant ? variant.hidden : false
2146
+ }),
2193
2147
  profile
2194
2148
  });
2195
2149
  }
2196
- }, [status, experience, profile]);
2197
- useEffect(() => {
2198
- const componentElement = componentRef.current;
2199
- if (componentElement) {
2200
- observeElement({
2201
- element: componentElement,
2202
- experienceId: experience === null || experience === void 0 ? void 0 : experience.id,
2203
- variantId: variant === null || variant === void 0 ? void 0 : variant.id,
2204
- baselineId: baseline.id,
2205
- audienceId: audience === null || audience === void 0 ? void 0 : audience.id
2206
- });
2207
- }
2208
- return () => {
2209
- if (componentElement) {
2210
- unobserveElement(componentElement);
2211
- }
2212
- };
2213
- }, [observeElement, unobserveElement, experience, baseline, variant, audience]);
2150
+ }, [status, experience, variant, profile]);
2214
2151
  if (!hasVariants) {
2215
- return jsxs(Fragment, {
2216
- children: [!isComponentForwardRef && jsx(ComponentMarker, {
2217
- ref: componentRef
2218
- }), /*#__PURE__*/createElement$1(Component, Object.assign({}, passthroughProps, baseline, {
2219
- key: baseline.id
2220
- }, isComponentForwardRef ? {
2221
- ref: componentRef
2222
- } : {}))]
2223
- });
2152
+ return /*#__PURE__*/createElement$1(Component, Object.assign({}, passthroughProps, baseline, {
2153
+ key: baseline.id
2154
+ }));
2224
2155
  }
2225
2156
  if (status === 'loading') {
2226
2157
  return /*#__PURE__*/createElement$1(LoadingComponent, Object.assign({}, baseline, {
@@ -2231,20 +2162,14 @@ const Experience = _a => {
2231
2162
  }));
2232
2163
  }
2233
2164
  if (!experience) {
2234
- return jsxs(Fragment, {
2235
- children: [!isComponentForwardRef && jsx(ComponentMarker, {
2236
- ref: componentRef
2237
- }), jsx(Component, Object.assign({}, passthroughProps, baseline, {
2238
- ninetailed: {
2239
- isPersonalized: false,
2240
- audience: {
2241
- id: 'baseline'
2242
- }
2165
+ return jsx(Component, Object.assign({}, passthroughProps, baseline, {
2166
+ ninetailed: {
2167
+ isPersonalized: false,
2168
+ audience: {
2169
+ id: 'baseline'
2243
2170
  }
2244
- }, isComponentForwardRef ? {
2245
- ref: componentRef
2246
- } : {}))]
2247
- });
2171
+ }
2172
+ }));
2248
2173
  }
2249
2174
  if (!variant) {
2250
2175
  return jsx(TrackExperience, Object.assign({
@@ -2253,20 +2178,14 @@ const Experience = _a => {
2253
2178
  // the profile is definitely defined, otherwise there wouldn't be an experience selected
2254
2179
  profile: profile
2255
2180
  }, {
2256
- children: jsxs(Fragment, {
2257
- children: [!isComponentForwardRef && jsx(ComponentMarker, {
2258
- ref: componentRef
2259
- }), jsx(Component, Object.assign({}, passthroughProps, baseline, {
2260
- ninetailed: {
2261
- isPersonalized: false,
2262
- audience: {
2263
- id: (audience === null || audience === void 0 ? void 0 : audience.id) || 'all visitors'
2264
- }
2181
+ children: jsx(Component, Object.assign({}, passthroughProps, baseline, {
2182
+ ninetailed: {
2183
+ isPersonalized: false,
2184
+ audience: {
2185
+ id: (audience === null || audience === void 0 ? void 0 : audience.id) || 'all visitors'
2265
2186
  }
2266
- }, isComponentForwardRef ? {
2267
- ref: componentRef
2268
- } : {}))]
2269
- })
2187
+ }
2188
+ }))
2270
2189
  }), baseline.id);
2271
2190
  }
2272
2191
  const isVariantHidden = 'hidden' in variant && variant.hidden;
@@ -2276,21 +2195,15 @@ const Experience = _a => {
2276
2195
  // the profile is definitely defined, otherwise there wouldn't be an experience selected
2277
2196
  profile: profile
2278
2197
  }, {
2279
- children: !isVariantHidden ? jsxs(Fragment, {
2280
- children: [!isComponentForwardRef && jsx(ComponentMarker, {
2281
- ref: componentRef
2282
- }), /*#__PURE__*/createElement$1(Component, Object.assign({}, Object.assign(Object.assign({}, passthroughProps), variant), {
2283
- key: `${experience.id}-${variant.id}`,
2284
- ninetailed: {
2285
- isPersonalized,
2286
- audience: {
2287
- id: (audience === null || audience === void 0 ? void 0 : audience.id) || 'all visitors'
2288
- }
2198
+ children: !isVariantHidden ? /*#__PURE__*/createElement$1(Component, Object.assign({}, Object.assign(Object.assign({}, passthroughProps), variant), {
2199
+ key: `${experience.id}-${variant.id}`,
2200
+ ninetailed: {
2201
+ isPersonalized,
2202
+ audience: {
2203
+ id: (audience === null || audience === void 0 ? void 0 : audience.id) || 'all visitors'
2289
2204
  }
2290
- }, isComponentForwardRef ? {
2291
- ref: componentRef
2292
- } : {}))]
2293
- }) : null
2205
+ }
2206
+ })) : null
2294
2207
  }));
2295
2208
  };
2296
2209
 
@@ -2394,15 +2307,13 @@ const debounce = (fn, wait) => {
2394
2307
  debouncedFn();
2395
2308
  };
2396
2309
  };
2397
- const useProvideJoinExperiment = ({
2398
- experiments,
2399
- maximumActiveExperiments: _maximumActiveExperiments = 1
2400
- }) => {
2310
+ // TODO: the majority of this code should be moved to the experience.js javascript package
2311
+ const useProvideJoinExperiment = _ => {
2401
2312
  const {
2402
2313
  identify
2403
2314
  } = useNinetailed();
2404
2315
  const joinExperimentIdentify = debounce(args => {
2405
- const traits = args.slice(0, _maximumActiveExperiments).reduce((traits, [experimentJoinTraits]) => {
2316
+ const traits = args.reduce((traits, [experimentJoinTraits]) => {
2406
2317
  return Object.assign(Object.assign({}, experimentJoinTraits), traits);
2407
2318
  }, {});
2408
2319
  identify('', traits);
@@ -2410,6 +2321,7 @@ const useProvideJoinExperiment = ({
2410
2321
  return useCallback(data => __awaiter(void 0, void 0, void 0, function* () {
2411
2322
  const {
2412
2323
  experiment,
2324
+ variant,
2413
2325
  profile
2414
2326
  } = data;
2415
2327
  const isExperiment = experiment.type === 'nt_experiment';
@@ -2417,17 +2329,17 @@ const useProvideJoinExperiment = ({
2417
2329
  logger.warn(`The experience ${experiment.id}, which you tried to join, is not an experiment.`);
2418
2330
  return;
2419
2331
  }
2420
- const activeExperiments = selectActiveExperiments(experiments, profile);
2421
- if (activeExperiments.length >= _maximumActiveExperiments) {
2422
- logger.warn(`The maximum number of active experiments (${_maximumActiveExperiments}) has been reached.`);
2332
+ if (!isExperienceSticky(experiment)) {
2333
+ logger.debug("Won't add experiment to traits, as it's not sticky.");
2423
2334
  return;
2424
2335
  }
2425
- if (activeExperiments.some(activeExperiment => activeExperiment.id === experiment.id)) {
2336
+ const activeExperimentIds = selectActiveExperimentIds(profile);
2337
+ if (activeExperimentIds.some(activeExperimentId => activeExperimentId === experiment.id)) {
2426
2338
  logger.debug(`The user is already part of experiment ${experiment.id}. Won't join again.`);
2427
2339
  return;
2428
2340
  }
2429
2341
  joinExperimentIdentify({
2430
- [`${EXPERIENCE_TRAIT_PREFIX}${experiment.id}`]: true
2342
+ [`${EXPERIENCE_TRAIT_PREFIX}${experiment.id}`]: variant.hidden ? 'hidden' : variant.id
2431
2343
  });
2432
2344
  logger.debug(`Sent event to join experiment ${experiment.id}.`);
2433
2345
  }), []);
@@ -2438,10 +2350,7 @@ const ExperimentsProvider = ({
2438
2350
  maximumActiveExperiments: _maximumActiveExperiments = 1,
2439
2351
  children
2440
2352
  }) => {
2441
- const joinExperiment = useProvideJoinExperiment({
2442
- experiments,
2443
- maximumActiveExperiments: _maximumActiveExperiments
2444
- });
2353
+ const joinExperiment = useProvideJoinExperiment();
2445
2354
  return jsx(ExperimentsContext.Provider, Object.assign({
2446
2355
  value: {
2447
2356
  experiments,
@@ -2452,40 +2361,58 @@ const ExperimentsProvider = ({
2452
2361
  }));
2453
2362
  };
2454
2363
 
2455
- const NinetailedProvider = ({
2456
- children,
2457
- clientId,
2458
- experiments: _experiments = [],
2459
- maximumActiveExperiments,
2460
- environment,
2461
- preview,
2462
- url,
2463
- profile,
2464
- locale,
2465
- requestTimeout,
2466
- plugins: _plugins = [],
2467
- onLog,
2468
- onError
2469
- }) => {
2470
- const ninetailed = useMemo(() => new Ninetailed({
2471
- clientId,
2472
- environment,
2473
- preview
2474
- }, {
2475
- url,
2476
- plugins: _plugins,
2477
- profile,
2478
- locale,
2479
- requestTimeout,
2480
- onLog,
2481
- onError
2482
- }), []);
2364
+ /**
2365
+ * @deprecated
2366
+ *
2367
+ * This will get removed in v5 of the SDK.
2368
+ */
2369
+ const useExperiments = () => {
2370
+ const context = useExperimentsContext();
2371
+ return {
2372
+ experiments: context.experiments
2373
+ };
2374
+ };
2375
+
2376
+ const NinetailedProvider = props => {
2377
+ const ninetailed = useMemo(() => {
2378
+ if ('ninetailed' in props) {
2379
+ return props.ninetailed;
2380
+ }
2381
+ const {
2382
+ clientId,
2383
+ environment,
2384
+ preview,
2385
+ url,
2386
+ profile,
2387
+ locale,
2388
+ requestTimeout,
2389
+ plugins = [],
2390
+ onLog,
2391
+ onError
2392
+ } = props;
2393
+ return new Ninetailed({
2394
+ clientId,
2395
+ environment,
2396
+ preview
2397
+ }, {
2398
+ url,
2399
+ plugins,
2400
+ profile,
2401
+ locale,
2402
+ requestTimeout,
2403
+ onLog,
2404
+ onError
2405
+ });
2406
+ }, []);
2407
+ const {
2408
+ children
2409
+ } = props;
2483
2410
  return jsx(NinetailedContext.Provider, Object.assign({
2484
2411
  value: ninetailed
2485
2412
  }, {
2486
2413
  children: jsx(ExperimentsProvider, Object.assign({
2487
- experiments: _experiments,
2488
- maximumActiveExperiments: maximumActiveExperiments
2414
+ experiments: [],
2415
+ maximumActiveExperiments: 10000
2489
2416
  }, {
2490
2417
  children: children
2491
2418
  }))
@@ -1,7 +1,17 @@
1
1
  import React, { PropsWithChildren } from 'react';
2
2
  import { ExperienceConfiguration, Reference } from '@ninetailed/experience.js';
3
3
  type ExperimentsProviderProps<Variant extends Reference> = React.PropsWithChildren<{
4
+ /**
5
+ * @deprecated
6
+ *
7
+ * This will get removed in v5
8
+ */
4
9
  experiments: ExperienceConfiguration<Variant>[];
10
+ /**
11
+ * @deprecated
12
+ *
13
+ * This will get removed in v5
14
+ */
5
15
  maximumActiveExperiments?: number;
6
16
  }>;
7
17
  export declare const ExperimentsProvider: <Variant extends Reference>({ experiments, maximumActiveExperiments, children, }: React.PropsWithChildren<ExperimentsProviderProps<Variant>>) => JSX.Element;
@@ -1,3 +1,8 @@
1
+ /**
2
+ * @deprecated
3
+ *
4
+ * This will get removed in v5 of the SDK.
5
+ */
1
6
  export declare const useExperiments: () => {
2
7
  experiments: import("@ninetailed/experience.js-shared").ExperienceConfiguration<any>[];
3
8
  };
@@ -2,12 +2,18 @@ import { Profile, ExperienceConfiguration, Reference, VariantRef } from '@nineta
2
2
  export type JoinExperimentArgs = {
3
3
  experiences: ExperienceConfiguration[];
4
4
  experiment: ExperienceConfiguration<Reference | VariantRef>;
5
+ variant: VariantRef;
5
6
  profile: Profile;
6
7
  };
7
8
  export type JoinExperiment = (args: JoinExperimentArgs) => Promise<void>;
8
9
  type UseJoinExperimentArgs = {
9
10
  experiments: ExperienceConfiguration[];
11
+ /**
12
+ * @deprecated
13
+ *
14
+ * This will get removed in v5 of the sdk
15
+ */
10
16
  maximumActiveExperiments?: number;
11
17
  };
12
- export declare const useProvideJoinExperiment: ({ experiments, maximumActiveExperiments, }: UseJoinExperimentArgs) => (data: JoinExperimentArgs) => Promise<void>;
18
+ export declare const useProvideJoinExperiment: (_: UseJoinExperimentArgs) => (data: JoinExperimentArgs) => Promise<void>;
13
19
  export {};
@@ -1,11 +1,19 @@
1
1
  import React from 'react';
2
- import { NinetailedPlugin, ExperienceConfiguration } from '@ninetailed/experience.js';
2
+ import { Ninetailed, NinetailedPlugin, ExperienceConfiguration } from '@ninetailed/experience.js';
3
3
  import { Profile, Locale, OnErrorHandler, OnLogHandler } from '@ninetailed/experience.js-shared';
4
- export type NinetailedProviderProps = {
5
- clientId: string;
6
- environment?: string;
4
+ type ExperimentProviderProps = {
5
+ /**
6
+ * @deprecated
7
+ */
7
8
  experiments?: ExperienceConfiguration<any>[];
9
+ /**
10
+ * @deprecated
11
+ */
8
12
  maximumActiveExperiments?: number;
13
+ };
14
+ export type NinetailedProviderInstantiationProps = {
15
+ clientId: string;
16
+ environment?: string;
9
17
  preview?: boolean;
10
18
  url?: string;
11
19
  plugins?: (NinetailedPlugin | NinetailedPlugin[])[];
@@ -14,5 +22,9 @@ export type NinetailedProviderProps = {
14
22
  requestTimeout?: number;
15
23
  onLog?: OnLogHandler;
16
24
  onError?: OnErrorHandler;
17
- };
18
- export declare const NinetailedProvider: ({ children, clientId, experiments, maximumActiveExperiments, environment, preview, url, profile, locale, requestTimeout, plugins, onLog, onError, }: React.PropsWithChildren<NinetailedProviderProps>) => JSX.Element;
25
+ } & ExperimentProviderProps;
26
+ export type NinetailedProviderProps = NinetailedProviderInstantiationProps | ({
27
+ ninetailed: Ninetailed;
28
+ } & ExperimentProviderProps);
29
+ export declare const NinetailedProvider: (props: React.PropsWithChildren<NinetailedProviderProps>) => JSX.Element;
30
+ export {};
package/lib/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  export type { Profile, Variant } from '@ninetailed/experience.js-shared';
2
2
  export type { ExperienceConfiguration, ExperienceType, EXPERIENCE_TRAIT_PREFIX, } from '@ninetailed/experience.js';
3
3
  export { NinetailedProvider } from './NinetailedProvider';
4
- export type { NinetailedProviderProps } from './NinetailedProvider';
4
+ export type { NinetailedProviderProps, NinetailedProviderInstantiationProps, } from './NinetailedProvider';
5
5
  export { useNinetailed } from './useNinetailed';
6
6
  export { useProfile } from './useProfile';
7
7
  export { usePersonalize } from './usePersonalize';
@@ -10,7 +10,6 @@ export declare const useProfile: () => {
10
10
  status: "success";
11
11
  profile: {
12
12
  id: string;
13
- stableId: string;
14
13
  random: number;
15
14
  audiences: string[];
16
15
  traits: import("@ninetailed/experience.js-shared").Properties;
@@ -29,7 +28,6 @@ export declare const useProfile: () => {
29
28
  timezone?: string | undefined;
30
29
  };
31
30
  session: {
32
- id: string;
33
31
  isReturningVisitor: boolean;
34
32
  landingPage: {
35
33
  path: string;
package/package.json CHANGED
@@ -1,16 +1,15 @@
1
1
  {
2
2
  "name": "@ninetailed/experience.js-react",
3
- "version": "4.3.0-beta.2",
3
+ "version": "4.4.0-beta.1",
4
4
  "peerDependencies": {
5
5
  "react": ">=16.8.0"
6
6
  },
7
7
  "dependencies": {
8
8
  "@analytics/google-analytics": "0.5.3",
9
9
  "react-visibility-sensor": "5.1.1",
10
- "@ninetailed/experience.js": "4.3.0-beta.2",
11
- "react-is": "18.2.0",
10
+ "@ninetailed/experience.js": "4.4.0-beta.1",
12
11
  "react-intersection-observer": "8.34.0",
13
- "@ninetailed/experience.js-shared": "4.3.0-beta.2",
12
+ "@ninetailed/experience.js-shared": "4.4.0-beta.1",
14
13
  "radash": "10.9.0",
15
14
  "analytics": "0.8.1"
16
15
  },
@@ -1,2 +0,0 @@
1
- import React from 'react';
2
- export declare const ComponentMarker: React.ForwardRefExoticComponent<React.RefAttributes<unknown>>;