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