featuredrop 2.7.2 → 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 +32 -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.js CHANGED
@@ -2222,6 +2222,111 @@ function useSurvey(id) {
2222
2222
  [askLater, hide, show, snapshot]
2223
2223
  );
2224
2224
  }
2225
+ function useChangelog() {
2226
+ const ctx = useFeatureDrop();
2227
+ const markAllSeen = useCallback(() => {
2228
+ void ctx.dismissAll();
2229
+ }, [ctx]);
2230
+ const getByCategory = useCallback(
2231
+ (category) => {
2232
+ return ctx.newFeatures.filter((f) => f.category === category);
2233
+ },
2234
+ [ctx.newFeatures]
2235
+ );
2236
+ return useMemo(
2237
+ () => ({
2238
+ features: ctx.manifest,
2239
+ newFeatures: ctx.newFeatures,
2240
+ newCount: ctx.newCount,
2241
+ newFeaturesSorted: ctx.newFeaturesSorted,
2242
+ dismiss: ctx.dismiss,
2243
+ dismissAll: () => void ctx.dismissAll(),
2244
+ isNew: ctx.isNew,
2245
+ markAllSeen,
2246
+ getByCategory
2247
+ }),
2248
+ [ctx.manifest, ctx.newFeatures, ctx.newCount, ctx.newFeaturesSorted, ctx.dismiss, ctx.dismissAll, ctx.isNew, markAllSeen, getByCategory]
2249
+ );
2250
+ }
2251
+ function useSmartFeature(featureId) {
2252
+ const { engine, manifest, dismiss: providerDismiss } = useFeatureDrop();
2253
+ const sessionStartRef = useRef(Date.now());
2254
+ const feature = manifest.find((f) => f.id === featureId);
2255
+ const dismiss = useCallback(() => {
2256
+ engine?.trackInteraction(featureId, "dismissed");
2257
+ providerDismiss(featureId);
2258
+ }, [engine, featureId, providerDismiss]);
2259
+ if (!engine) {
2260
+ return {
2261
+ show: !!feature,
2262
+ format: "badge",
2263
+ fallbackFormat: "inline",
2264
+ feature,
2265
+ dismiss,
2266
+ confidence: 1,
2267
+ reason: "no_engine"
2268
+ };
2269
+ }
2270
+ const currentPath = typeof window !== "undefined" ? window.location.pathname : "/";
2271
+ const sessionAge = (Date.now() - sessionStartRef.current) / 1e3;
2272
+ const timing = engine.shouldShow(featureId, {
2273
+ currentPath,
2274
+ sessionAge,
2275
+ recentDismissals: 0,
2276
+ featurePriority: feature?.priority ?? "normal"
2277
+ });
2278
+ const formatRec = engine.recommendFormat(featureId);
2279
+ return {
2280
+ show: timing.show,
2281
+ format: formatRec.primary,
2282
+ fallbackFormat: formatRec.fallback,
2283
+ feature,
2284
+ dismiss,
2285
+ confidence: timing.confidence,
2286
+ reason: timing.reason
2287
+ };
2288
+ }
2289
+ var DEFAULT_SCORE = {
2290
+ score: 100,
2291
+ grade: "A",
2292
+ breakdown: {
2293
+ featuresExplored: 0,
2294
+ dismissRate: 0,
2295
+ completionRate: 0,
2296
+ engagementTrend: "stable"
2297
+ },
2298
+ recommendations: []
2299
+ };
2300
+ function useAdoptionScore() {
2301
+ const { engine } = useFeatureDrop();
2302
+ return useMemo(() => {
2303
+ if (!engine) return DEFAULT_SCORE;
2304
+ return engine.getAdoptionScore();
2305
+ }, [engine]);
2306
+ }
2307
+ var DEFAULT_PROFILE = {
2308
+ sessionCount: 0,
2309
+ dismissRate: 0,
2310
+ engagementRate: 0,
2311
+ preferredFormat: "badge",
2312
+ hasEngine: false
2313
+ };
2314
+ function useBehaviorProfile() {
2315
+ const { engine } = useFeatureDrop();
2316
+ return useMemo(() => {
2317
+ if (!engine) return DEFAULT_PROFILE;
2318
+ const score = engine.getAdoptionScore();
2319
+ return {
2320
+ sessionCount: 0,
2321
+ // Not directly exposed by FeatureDropEngine interface
2322
+ dismissRate: score.breakdown.dismissRate,
2323
+ engagementRate: 1 - score.breakdown.dismissRate,
2324
+ preferredFormat: "badge",
2325
+ // Default — full profile requires AdoptionEngine
2326
+ hasEngine: true
2327
+ };
2328
+ }, [engine]);
2329
+ }
2225
2330
  var FeatureDropComponentBoundary = class extends Component {
2226
2331
  state = { hasError: false };
2227
2332
  componentDidCatch(error, info) {
@@ -7751,6 +7856,249 @@ function FeatureRequestForm({
7751
7856
  }
7752
7857
  );
7753
7858
  }
7859
+ var badgeStyles = {
7860
+ display: "inline-flex",
7861
+ alignItems: "center",
7862
+ justifyContent: "center",
7863
+ padding: "2px 6px",
7864
+ borderRadius: "9999px",
7865
+ fontSize: "var(--featuredrop-font-size, 10px)",
7866
+ fontWeight: 700,
7867
+ textTransform: "uppercase",
7868
+ letterSpacing: "0.05em",
7869
+ lineHeight: 1,
7870
+ color: "var(--featuredrop-color, #b45309)",
7871
+ backgroundColor: "var(--featuredrop-bg, rgba(245, 158, 11, 0.15))",
7872
+ fontFamily: "inherit"
7873
+ };
7874
+ var toastStyles2 = {
7875
+ position: "fixed",
7876
+ bottom: 16,
7877
+ right: 16,
7878
+ zIndex: 9999,
7879
+ maxWidth: 360,
7880
+ padding: "12px 16px",
7881
+ borderRadius: "var(--featuredrop-toast-radius, 8px)",
7882
+ backgroundColor: "var(--featuredrop-toast-bg, white)",
7883
+ color: "var(--featuredrop-toast-color, #1f2937)",
7884
+ boxShadow: "var(--featuredrop-toast-shadow, 0 4px 12px rgba(0, 0, 0, 0.15))",
7885
+ border: "1px solid var(--featuredrop-toast-border, #e5e7eb)",
7886
+ fontFamily: "inherit",
7887
+ fontSize: 14,
7888
+ lineHeight: 1.5
7889
+ };
7890
+ var bannerStyles = {
7891
+ width: "100%",
7892
+ padding: "10px 16px",
7893
+ backgroundColor: "var(--featuredrop-banner-bg, #eff6ff)",
7894
+ borderBottom: "1px solid var(--featuredrop-banner-border, #bfdbfe)",
7895
+ color: "var(--featuredrop-banner-color, #1e40af)",
7896
+ fontFamily: "inherit",
7897
+ fontSize: 14,
7898
+ lineHeight: 1.5,
7899
+ display: "flex",
7900
+ alignItems: "center",
7901
+ justifyContent: "space-between"
7902
+ };
7903
+ var inlineStyles = {
7904
+ display: "inline",
7905
+ color: "var(--featuredrop-inline-color, #6b7280)",
7906
+ fontFamily: "inherit",
7907
+ fontSize: 13
7908
+ };
7909
+ var dismissButtonStyles = {
7910
+ background: "none",
7911
+ border: "none",
7912
+ cursor: "pointer",
7913
+ padding: "4px",
7914
+ fontSize: 16,
7915
+ lineHeight: 1,
7916
+ color: "inherit",
7917
+ opacity: 0.6
7918
+ };
7919
+ function SmartAnnouncement({
7920
+ id,
7921
+ format: formatOverride,
7922
+ className,
7923
+ style,
7924
+ children
7925
+ }) {
7926
+ const smartFeature = useSmartFeature(id);
7927
+ const { engine } = useFeatureDrop();
7928
+ const hasTrackedSeen = useRef(false);
7929
+ const resolvedFormat = formatOverride ?? smartFeature.format;
7930
+ useEffect(() => {
7931
+ ensureFeatureDropAnimationStyles();
7932
+ }, []);
7933
+ useEffect(() => {
7934
+ if (smartFeature.show && !hasTrackedSeen.current) {
7935
+ hasTrackedSeen.current = true;
7936
+ engine?.trackInteraction(id, "seen");
7937
+ }
7938
+ }, [smartFeature.show, engine, id]);
7939
+ if (children) {
7940
+ return /* @__PURE__ */ jsx(Fragment, { children: children({
7941
+ show: smartFeature.show,
7942
+ format: resolvedFormat,
7943
+ fallbackFormat: smartFeature.fallbackFormat,
7944
+ feature: smartFeature.feature,
7945
+ dismiss: smartFeature.dismiss,
7946
+ confidence: smartFeature.confidence,
7947
+ reason: smartFeature.reason
7948
+ }) });
7949
+ }
7950
+ if (!smartFeature.show || !smartFeature.feature) return null;
7951
+ const feature = smartFeature.feature;
7952
+ const description = parseDescription(feature.description ?? "");
7953
+ switch (resolvedFormat) {
7954
+ case "badge":
7955
+ return /* @__PURE__ */ jsx(
7956
+ "span",
7957
+ {
7958
+ "data-featuredrop": "smart-badge",
7959
+ className,
7960
+ style: { ...badgeStyles, ...style },
7961
+ role: "status",
7962
+ "aria-label": `New: ${feature.label}`,
7963
+ children: "New"
7964
+ }
7965
+ );
7966
+ case "toast":
7967
+ return /* @__PURE__ */ jsx(
7968
+ "div",
7969
+ {
7970
+ "data-featuredrop": "smart-toast",
7971
+ className,
7972
+ style: {
7973
+ ...toastStyles2,
7974
+ animation: getEnterAnimation("normal", "toast") ?? void 0,
7975
+ ...style
7976
+ },
7977
+ role: "alert",
7978
+ "aria-live": "polite",
7979
+ children: /* @__PURE__ */ jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "flex-start", gap: 8 }, children: [
7980
+ /* @__PURE__ */ jsxs("div", { children: [
7981
+ /* @__PURE__ */ jsx("div", { style: { fontWeight: 600, marginBottom: 2 }, children: feature.label }),
7982
+ /* @__PURE__ */ jsx(
7983
+ "div",
7984
+ {
7985
+ style: { fontSize: 13, opacity: 0.8 },
7986
+ dangerouslySetInnerHTML: { __html: description }
7987
+ }
7988
+ )
7989
+ ] }),
7990
+ /* @__PURE__ */ jsx(
7991
+ "button",
7992
+ {
7993
+ onClick: smartFeature.dismiss,
7994
+ style: dismissButtonStyles,
7995
+ "aria-label": "Dismiss",
7996
+ type: "button",
7997
+ children: "\xD7"
7998
+ }
7999
+ )
8000
+ ] })
8001
+ }
8002
+ );
8003
+ case "banner":
8004
+ return /* @__PURE__ */ jsxs(
8005
+ "div",
8006
+ {
8007
+ "data-featuredrop": "smart-banner",
8008
+ className,
8009
+ style: { ...bannerStyles, ...style },
8010
+ role: "alert",
8011
+ children: [
8012
+ /* @__PURE__ */ jsxs("span", { children: [
8013
+ /* @__PURE__ */ jsx("strong", { children: feature.label }),
8014
+ feature.description ? ` \u2014 ${feature.description}` : ""
8015
+ ] }),
8016
+ /* @__PURE__ */ jsx(
8017
+ "button",
8018
+ {
8019
+ onClick: smartFeature.dismiss,
8020
+ style: dismissButtonStyles,
8021
+ "aria-label": "Dismiss",
8022
+ type: "button",
8023
+ children: "\xD7"
8024
+ }
8025
+ )
8026
+ ]
8027
+ }
8028
+ );
8029
+ case "inline":
8030
+ return /* @__PURE__ */ jsx(
8031
+ "span",
8032
+ {
8033
+ "data-featuredrop": "smart-inline",
8034
+ className,
8035
+ style: { ...inlineStyles, ...style },
8036
+ children: feature.label
8037
+ }
8038
+ );
8039
+ case "modal":
8040
+ return /* @__PURE__ */ jsx(
8041
+ "div",
8042
+ {
8043
+ "data-featuredrop": "smart-toast",
8044
+ className,
8045
+ style: {
8046
+ ...toastStyles2,
8047
+ animation: getEnterAnimation("normal", "toast") ?? void 0,
8048
+ ...style
8049
+ },
8050
+ role: "alert",
8051
+ "aria-live": "polite",
8052
+ children: /* @__PURE__ */ jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "flex-start", gap: 8 }, children: [
8053
+ /* @__PURE__ */ jsxs("div", { children: [
8054
+ /* @__PURE__ */ jsx("div", { style: { fontWeight: 600, marginBottom: 2 }, children: feature.label }),
8055
+ /* @__PURE__ */ jsx(
8056
+ "div",
8057
+ {
8058
+ style: { fontSize: 13, opacity: 0.8 },
8059
+ dangerouslySetInnerHTML: { __html: description }
8060
+ }
8061
+ )
8062
+ ] }),
8063
+ /* @__PURE__ */ jsx(
8064
+ "button",
8065
+ {
8066
+ onClick: smartFeature.dismiss,
8067
+ style: dismissButtonStyles,
8068
+ "aria-label": "Dismiss",
8069
+ type: "button",
8070
+ children: "\xD7"
8071
+ }
8072
+ )
8073
+ ] })
8074
+ }
8075
+ );
8076
+ case "spotlight":
8077
+ return /* @__PURE__ */ jsx(
8078
+ "span",
8079
+ {
8080
+ "data-featuredrop": "smart-badge",
8081
+ className,
8082
+ style: { ...badgeStyles, ...style },
8083
+ role: "status",
8084
+ "aria-label": `New: ${feature.label}`,
8085
+ children: "New"
8086
+ }
8087
+ );
8088
+ default:
8089
+ return /* @__PURE__ */ jsx(
8090
+ "span",
8091
+ {
8092
+ "data-featuredrop": "smart-badge",
8093
+ className,
8094
+ style: { ...badgeStyles, ...style },
8095
+ role: "status",
8096
+ "aria-label": `New: ${feature.label}`,
8097
+ children: "New"
8098
+ }
8099
+ );
8100
+ }
8101
+ }
7754
8102
 
7755
8103
  // src/react/index.ts
7756
8104
  var NewBadge2 = withFeatureDropBoundary(NewBadge, "NewBadge");
@@ -7769,7 +8117,8 @@ var SpotlightChain2 = withFeatureDropBoundary(SpotlightChain, "SpotlightChain");
7769
8117
  var Survey2 = withFeatureDropBoundary(Survey, "Survey");
7770
8118
  var FeatureRequestButton2 = withFeatureDropBoundary(FeatureRequestButton, "FeatureRequestButton");
7771
8119
  var FeatureRequestForm2 = withFeatureDropBoundary(FeatureRequestForm, "FeatureRequestForm");
8120
+ var SmartAnnouncement2 = withFeatureDropBoundary(SmartAnnouncement, "SmartAnnouncement");
7772
8121
 
7773
- export { AnnouncementModal2 as AnnouncementModal, Banner2 as Banner, ChangelogPage2 as ChangelogPage, ChangelogWidget2 as ChangelogWidget, Checklist2 as Checklist, FeatureDropContext, FeatureDropProvider, FeatureRequestButton2 as FeatureRequestButton, FeatureRequestForm2 as FeatureRequestForm, FeedbackWidget2 as FeedbackWidget, Hotspot2 as Hotspot, NewBadge2 as NewBadge, Spotlight2 as Spotlight, SpotlightChain2 as SpotlightChain, Survey2 as Survey, ThemeProvider, Toast2 as Toast, TooltipGroup2 as TooltipGroup, Tour2 as Tour, useAdoptionAnalytics, useChecklist, useFeatureDrop, useNewCount, useNewFeature, useSurvey, useTabNotification, useTour, useTourSequencer };
8122
+ export { AnnouncementModal2 as AnnouncementModal, Banner2 as Banner, ChangelogPage2 as ChangelogPage, ChangelogWidget2 as ChangelogWidget, Checklist2 as Checklist, FeatureDropContext, FeatureDropProvider, FeatureRequestButton2 as FeatureRequestButton, FeatureRequestForm2 as FeatureRequestForm, FeedbackWidget2 as FeedbackWidget, Hotspot2 as Hotspot, NewBadge2 as NewBadge, SmartAnnouncement2 as SmartAnnouncement, Spotlight2 as Spotlight, SpotlightChain2 as SpotlightChain, Survey2 as Survey, ThemeProvider, Toast2 as Toast, TooltipGroup2 as TooltipGroup, Tour2 as Tour, useAdoptionAnalytics, useAdoptionScore, useBehaviorProfile, useChangelog, useChecklist, useFeatureDrop, useNewCount, useNewFeature, useSmartFeature, useSurvey, useTabNotification, useTour, useTourSequencer };
7774
8123
  //# sourceMappingURL=react.js.map
7775
8124
  //# sourceMappingURL=react.js.map