featuredrop 2.7.1 → 3.0.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.
Files changed (52) hide show
  1. package/README.md +34 -1
  2. package/dist/astro.cjs +333 -0
  3. package/dist/astro.cjs.map +1 -0
  4. package/dist/astro.d.cts +242 -0
  5. package/dist/astro.d.ts +242 -0
  6. package/dist/astro.js +329 -0
  7. package/dist/astro.js.map +1 -0
  8. package/dist/engine.cjs +552 -0
  9. package/dist/engine.cjs.map +1 -0
  10. package/dist/engine.d.cts +422 -0
  11. package/dist/engine.d.ts +422 -0
  12. package/dist/engine.js +545 -0
  13. package/dist/engine.js.map +1 -0
  14. package/dist/featuredrop.cjs +208 -1
  15. package/dist/featuredrop.cjs.map +1 -1
  16. package/dist/next.cjs +336 -0
  17. package/dist/next.cjs.map +1 -0
  18. package/dist/next.d.cts +243 -0
  19. package/dist/next.d.ts +243 -0
  20. package/dist/next.js +332 -0
  21. package/dist/next.js.map +1 -0
  22. package/dist/nuxt.cjs +352 -0
  23. package/dist/nuxt.cjs.map +1 -0
  24. package/dist/nuxt.d.cts +282 -0
  25. package/dist/nuxt.d.ts +282 -0
  26. package/dist/nuxt.js +347 -0
  27. package/dist/nuxt.js.map +1 -0
  28. package/dist/preact.cjs +354 -0
  29. package/dist/preact.cjs.map +1 -1
  30. package/dist/preact.d.cts +170 -1
  31. package/dist/preact.d.ts +170 -1
  32. package/dist/preact.js +350 -1
  33. package/dist/preact.js.map +1 -1
  34. package/dist/react-hooks.cjs +82 -0
  35. package/dist/react-hooks.cjs.map +1 -1
  36. package/dist/react-hooks.d.cts +117 -1
  37. package/dist/react-hooks.d.ts +117 -1
  38. package/dist/react-hooks.js +80 -1
  39. package/dist/react-hooks.js.map +1 -1
  40. package/dist/react.cjs +354 -0
  41. package/dist/react.cjs.map +1 -1
  42. package/dist/react.d.cts +170 -1
  43. package/dist/react.d.ts +170 -1
  44. package/dist/react.js +350 -1
  45. package/dist/react.js.map +1 -1
  46. package/dist/remix.cjs +331 -0
  47. package/dist/remix.cjs.map +1 -0
  48. package/dist/remix.d.cts +305 -0
  49. package/dist/remix.d.ts +305 -0
  50. package/dist/remix.js +327 -0
  51. package/dist/remix.js.map +1 -0
  52. package/package.json +70 -2
package/dist/react.cjs CHANGED
@@ -2245,6 +2245,111 @@ function useSurvey(id) {
2245
2245
  [askLater, hide, show, snapshot]
2246
2246
  );
2247
2247
  }
2248
+ function useChangelog() {
2249
+ const ctx = useFeatureDrop();
2250
+ const markAllSeen = react.useCallback(() => {
2251
+ void ctx.dismissAll();
2252
+ }, [ctx]);
2253
+ const getByCategory = react.useCallback(
2254
+ (category) => {
2255
+ return ctx.newFeatures.filter((f) => f.category === category);
2256
+ },
2257
+ [ctx.newFeatures]
2258
+ );
2259
+ return react.useMemo(
2260
+ () => ({
2261
+ features: ctx.manifest,
2262
+ newFeatures: ctx.newFeatures,
2263
+ newCount: ctx.newCount,
2264
+ newFeaturesSorted: ctx.newFeaturesSorted,
2265
+ dismiss: ctx.dismiss,
2266
+ dismissAll: () => void ctx.dismissAll(),
2267
+ isNew: ctx.isNew,
2268
+ markAllSeen,
2269
+ getByCategory
2270
+ }),
2271
+ [ctx.manifest, ctx.newFeatures, ctx.newCount, ctx.newFeaturesSorted, ctx.dismiss, ctx.dismissAll, ctx.isNew, markAllSeen, getByCategory]
2272
+ );
2273
+ }
2274
+ function useSmartFeature(featureId) {
2275
+ const { engine, manifest, dismiss: providerDismiss } = useFeatureDrop();
2276
+ const sessionStartRef = react.useRef(Date.now());
2277
+ const feature = manifest.find((f) => f.id === featureId);
2278
+ const dismiss = react.useCallback(() => {
2279
+ engine?.trackInteraction(featureId, "dismissed");
2280
+ providerDismiss(featureId);
2281
+ }, [engine, featureId, providerDismiss]);
2282
+ if (!engine) {
2283
+ return {
2284
+ show: !!feature,
2285
+ format: "badge",
2286
+ fallbackFormat: "inline",
2287
+ feature,
2288
+ dismiss,
2289
+ confidence: 1,
2290
+ reason: "no_engine"
2291
+ };
2292
+ }
2293
+ const currentPath = typeof window !== "undefined" ? window.location.pathname : "/";
2294
+ const sessionAge = (Date.now() - sessionStartRef.current) / 1e3;
2295
+ const timing = engine.shouldShow(featureId, {
2296
+ currentPath,
2297
+ sessionAge,
2298
+ recentDismissals: 0,
2299
+ featurePriority: feature?.priority ?? "normal"
2300
+ });
2301
+ const formatRec = engine.recommendFormat(featureId);
2302
+ return {
2303
+ show: timing.show,
2304
+ format: formatRec.primary,
2305
+ fallbackFormat: formatRec.fallback,
2306
+ feature,
2307
+ dismiss,
2308
+ confidence: timing.confidence,
2309
+ reason: timing.reason
2310
+ };
2311
+ }
2312
+ var DEFAULT_SCORE = {
2313
+ score: 100,
2314
+ grade: "A",
2315
+ breakdown: {
2316
+ featuresExplored: 0,
2317
+ dismissRate: 0,
2318
+ completionRate: 0,
2319
+ engagementTrend: "stable"
2320
+ },
2321
+ recommendations: []
2322
+ };
2323
+ function useAdoptionScore() {
2324
+ const { engine } = useFeatureDrop();
2325
+ return react.useMemo(() => {
2326
+ if (!engine) return DEFAULT_SCORE;
2327
+ return engine.getAdoptionScore();
2328
+ }, [engine]);
2329
+ }
2330
+ var DEFAULT_PROFILE = {
2331
+ sessionCount: 0,
2332
+ dismissRate: 0,
2333
+ engagementRate: 0,
2334
+ preferredFormat: "badge",
2335
+ hasEngine: false
2336
+ };
2337
+ function useBehaviorProfile() {
2338
+ const { engine } = useFeatureDrop();
2339
+ return react.useMemo(() => {
2340
+ if (!engine) return DEFAULT_PROFILE;
2341
+ const score = engine.getAdoptionScore();
2342
+ return {
2343
+ sessionCount: 0,
2344
+ // Not directly exposed by FeatureDropEngine interface
2345
+ dismissRate: score.breakdown.dismissRate,
2346
+ engagementRate: 1 - score.breakdown.dismissRate,
2347
+ preferredFormat: "badge",
2348
+ // Default — full profile requires AdoptionEngine
2349
+ hasEngine: true
2350
+ };
2351
+ }, [engine]);
2352
+ }
2248
2353
  var FeatureDropComponentBoundary = class extends react.Component {
2249
2354
  state = { hasError: false };
2250
2355
  componentDidCatch(error, info) {
@@ -7774,6 +7879,249 @@ function FeatureRequestForm({
7774
7879
  }
7775
7880
  );
7776
7881
  }
7882
+ var badgeStyles = {
7883
+ display: "inline-flex",
7884
+ alignItems: "center",
7885
+ justifyContent: "center",
7886
+ padding: "2px 6px",
7887
+ borderRadius: "9999px",
7888
+ fontSize: "var(--featuredrop-font-size, 10px)",
7889
+ fontWeight: 700,
7890
+ textTransform: "uppercase",
7891
+ letterSpacing: "0.05em",
7892
+ lineHeight: 1,
7893
+ color: "var(--featuredrop-color, #b45309)",
7894
+ backgroundColor: "var(--featuredrop-bg, rgba(245, 158, 11, 0.15))",
7895
+ fontFamily: "inherit"
7896
+ };
7897
+ var toastStyles2 = {
7898
+ position: "fixed",
7899
+ bottom: 16,
7900
+ right: 16,
7901
+ zIndex: 9999,
7902
+ maxWidth: 360,
7903
+ padding: "12px 16px",
7904
+ borderRadius: "var(--featuredrop-toast-radius, 8px)",
7905
+ backgroundColor: "var(--featuredrop-toast-bg, white)",
7906
+ color: "var(--featuredrop-toast-color, #1f2937)",
7907
+ boxShadow: "var(--featuredrop-toast-shadow, 0 4px 12px rgba(0, 0, 0, 0.15))",
7908
+ border: "1px solid var(--featuredrop-toast-border, #e5e7eb)",
7909
+ fontFamily: "inherit",
7910
+ fontSize: 14,
7911
+ lineHeight: 1.5
7912
+ };
7913
+ var bannerStyles = {
7914
+ width: "100%",
7915
+ padding: "10px 16px",
7916
+ backgroundColor: "var(--featuredrop-banner-bg, #eff6ff)",
7917
+ borderBottom: "1px solid var(--featuredrop-banner-border, #bfdbfe)",
7918
+ color: "var(--featuredrop-banner-color, #1e40af)",
7919
+ fontFamily: "inherit",
7920
+ fontSize: 14,
7921
+ lineHeight: 1.5,
7922
+ display: "flex",
7923
+ alignItems: "center",
7924
+ justifyContent: "space-between"
7925
+ };
7926
+ var inlineStyles = {
7927
+ display: "inline",
7928
+ color: "var(--featuredrop-inline-color, #6b7280)",
7929
+ fontFamily: "inherit",
7930
+ fontSize: 13
7931
+ };
7932
+ var dismissButtonStyles = {
7933
+ background: "none",
7934
+ border: "none",
7935
+ cursor: "pointer",
7936
+ padding: "4px",
7937
+ fontSize: 16,
7938
+ lineHeight: 1,
7939
+ color: "inherit",
7940
+ opacity: 0.6
7941
+ };
7942
+ function SmartAnnouncement({
7943
+ id,
7944
+ format: formatOverride,
7945
+ className,
7946
+ style,
7947
+ children
7948
+ }) {
7949
+ const smartFeature = useSmartFeature(id);
7950
+ const { engine } = useFeatureDrop();
7951
+ const hasTrackedSeen = react.useRef(false);
7952
+ const resolvedFormat = formatOverride ?? smartFeature.format;
7953
+ react.useEffect(() => {
7954
+ ensureFeatureDropAnimationStyles();
7955
+ }, []);
7956
+ react.useEffect(() => {
7957
+ if (smartFeature.show && !hasTrackedSeen.current) {
7958
+ hasTrackedSeen.current = true;
7959
+ engine?.trackInteraction(id, "seen");
7960
+ }
7961
+ }, [smartFeature.show, engine, id]);
7962
+ if (children) {
7963
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: children({
7964
+ show: smartFeature.show,
7965
+ format: resolvedFormat,
7966
+ fallbackFormat: smartFeature.fallbackFormat,
7967
+ feature: smartFeature.feature,
7968
+ dismiss: smartFeature.dismiss,
7969
+ confidence: smartFeature.confidence,
7970
+ reason: smartFeature.reason
7971
+ }) });
7972
+ }
7973
+ if (!smartFeature.show || !smartFeature.feature) return null;
7974
+ const feature = smartFeature.feature;
7975
+ const description = parseDescription(feature.description ?? "");
7976
+ switch (resolvedFormat) {
7977
+ case "badge":
7978
+ return /* @__PURE__ */ jsxRuntime.jsx(
7979
+ "span",
7980
+ {
7981
+ "data-featuredrop": "smart-badge",
7982
+ className,
7983
+ style: { ...badgeStyles, ...style },
7984
+ role: "status",
7985
+ "aria-label": `New: ${feature.label}`,
7986
+ children: "New"
7987
+ }
7988
+ );
7989
+ case "toast":
7990
+ return /* @__PURE__ */ jsxRuntime.jsx(
7991
+ "div",
7992
+ {
7993
+ "data-featuredrop": "smart-toast",
7994
+ className,
7995
+ style: {
7996
+ ...toastStyles2,
7997
+ animation: getEnterAnimation("normal", "toast") ?? void 0,
7998
+ ...style
7999
+ },
8000
+ role: "alert",
8001
+ "aria-live": "polite",
8002
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "flex-start", gap: 8 }, children: [
8003
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
8004
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontWeight: 600, marginBottom: 2 }, children: feature.label }),
8005
+ /* @__PURE__ */ jsxRuntime.jsx(
8006
+ "div",
8007
+ {
8008
+ style: { fontSize: 13, opacity: 0.8 },
8009
+ dangerouslySetInnerHTML: { __html: description }
8010
+ }
8011
+ )
8012
+ ] }),
8013
+ /* @__PURE__ */ jsxRuntime.jsx(
8014
+ "button",
8015
+ {
8016
+ onClick: smartFeature.dismiss,
8017
+ style: dismissButtonStyles,
8018
+ "aria-label": "Dismiss",
8019
+ type: "button",
8020
+ children: "\xD7"
8021
+ }
8022
+ )
8023
+ ] })
8024
+ }
8025
+ );
8026
+ case "banner":
8027
+ return /* @__PURE__ */ jsxRuntime.jsxs(
8028
+ "div",
8029
+ {
8030
+ "data-featuredrop": "smart-banner",
8031
+ className,
8032
+ style: { ...bannerStyles, ...style },
8033
+ role: "alert",
8034
+ children: [
8035
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
8036
+ /* @__PURE__ */ jsxRuntime.jsx("strong", { children: feature.label }),
8037
+ feature.description ? ` \u2014 ${feature.description}` : ""
8038
+ ] }),
8039
+ /* @__PURE__ */ jsxRuntime.jsx(
8040
+ "button",
8041
+ {
8042
+ onClick: smartFeature.dismiss,
8043
+ style: dismissButtonStyles,
8044
+ "aria-label": "Dismiss",
8045
+ type: "button",
8046
+ children: "\xD7"
8047
+ }
8048
+ )
8049
+ ]
8050
+ }
8051
+ );
8052
+ case "inline":
8053
+ return /* @__PURE__ */ jsxRuntime.jsx(
8054
+ "span",
8055
+ {
8056
+ "data-featuredrop": "smart-inline",
8057
+ className,
8058
+ style: { ...inlineStyles, ...style },
8059
+ children: feature.label
8060
+ }
8061
+ );
8062
+ case "modal":
8063
+ return /* @__PURE__ */ jsxRuntime.jsx(
8064
+ "div",
8065
+ {
8066
+ "data-featuredrop": "smart-toast",
8067
+ className,
8068
+ style: {
8069
+ ...toastStyles2,
8070
+ animation: getEnterAnimation("normal", "toast") ?? void 0,
8071
+ ...style
8072
+ },
8073
+ role: "alert",
8074
+ "aria-live": "polite",
8075
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "flex-start", gap: 8 }, children: [
8076
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
8077
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontWeight: 600, marginBottom: 2 }, children: feature.label }),
8078
+ /* @__PURE__ */ jsxRuntime.jsx(
8079
+ "div",
8080
+ {
8081
+ style: { fontSize: 13, opacity: 0.8 },
8082
+ dangerouslySetInnerHTML: { __html: description }
8083
+ }
8084
+ )
8085
+ ] }),
8086
+ /* @__PURE__ */ jsxRuntime.jsx(
8087
+ "button",
8088
+ {
8089
+ onClick: smartFeature.dismiss,
8090
+ style: dismissButtonStyles,
8091
+ "aria-label": "Dismiss",
8092
+ type: "button",
8093
+ children: "\xD7"
8094
+ }
8095
+ )
8096
+ ] })
8097
+ }
8098
+ );
8099
+ case "spotlight":
8100
+ return /* @__PURE__ */ jsxRuntime.jsx(
8101
+ "span",
8102
+ {
8103
+ "data-featuredrop": "smart-badge",
8104
+ className,
8105
+ style: { ...badgeStyles, ...style },
8106
+ role: "status",
8107
+ "aria-label": `New: ${feature.label}`,
8108
+ children: "New"
8109
+ }
8110
+ );
8111
+ default:
8112
+ return /* @__PURE__ */ jsxRuntime.jsx(
8113
+ "span",
8114
+ {
8115
+ "data-featuredrop": "smart-badge",
8116
+ className,
8117
+ style: { ...badgeStyles, ...style },
8118
+ role: "status",
8119
+ "aria-label": `New: ${feature.label}`,
8120
+ children: "New"
8121
+ }
8122
+ );
8123
+ }
8124
+ }
7777
8125
 
7778
8126
  // src/react/index.ts
7779
8127
  var NewBadge2 = withFeatureDropBoundary(NewBadge, "NewBadge");
@@ -7792,6 +8140,7 @@ var SpotlightChain2 = withFeatureDropBoundary(SpotlightChain, "SpotlightChain");
7792
8140
  var Survey2 = withFeatureDropBoundary(Survey, "Survey");
7793
8141
  var FeatureRequestButton2 = withFeatureDropBoundary(FeatureRequestButton, "FeatureRequestButton");
7794
8142
  var FeatureRequestForm2 = withFeatureDropBoundary(FeatureRequestForm, "FeatureRequestForm");
8143
+ var SmartAnnouncement2 = withFeatureDropBoundary(SmartAnnouncement, "SmartAnnouncement");
7795
8144
 
7796
8145
  exports.AnnouncementModal = AnnouncementModal2;
7797
8146
  exports.Banner = Banner2;
@@ -7805,6 +8154,7 @@ exports.FeatureRequestForm = FeatureRequestForm2;
7805
8154
  exports.FeedbackWidget = FeedbackWidget2;
7806
8155
  exports.Hotspot = Hotspot2;
7807
8156
  exports.NewBadge = NewBadge2;
8157
+ exports.SmartAnnouncement = SmartAnnouncement2;
7808
8158
  exports.Spotlight = Spotlight2;
7809
8159
  exports.SpotlightChain = SpotlightChain2;
7810
8160
  exports.Survey = Survey2;
@@ -7813,10 +8163,14 @@ exports.Toast = Toast2;
7813
8163
  exports.TooltipGroup = TooltipGroup2;
7814
8164
  exports.Tour = Tour2;
7815
8165
  exports.useAdoptionAnalytics = useAdoptionAnalytics;
8166
+ exports.useAdoptionScore = useAdoptionScore;
8167
+ exports.useBehaviorProfile = useBehaviorProfile;
8168
+ exports.useChangelog = useChangelog;
7816
8169
  exports.useChecklist = useChecklist;
7817
8170
  exports.useFeatureDrop = useFeatureDrop;
7818
8171
  exports.useNewCount = useNewCount;
7819
8172
  exports.useNewFeature = useNewFeature;
8173
+ exports.useSmartFeature = useSmartFeature;
7820
8174
  exports.useSurvey = useSurvey;
7821
8175
  exports.useTabNotification = useTabNotification;
7822
8176
  exports.useTour = useTour;