featuredrop 2.6.1 → 2.7.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/.claude-plugin/plugin.json +21 -0
- package/README.md +77 -11
- package/context7.json +15 -0
- package/dist/index.d.cts +89 -1
- package/dist/index.d.ts +89 -1
- package/dist/preact.cjs +19 -10
- package/dist/preact.cjs.map +1 -1
- package/dist/preact.d.cts +93 -1
- package/dist/preact.d.ts +93 -1
- package/dist/preact.js +19 -10
- package/dist/preact.js.map +1 -1
- package/dist/react-hooks.cjs +472 -0
- package/dist/react-hooks.cjs.map +1 -0
- package/dist/react-hooks.d.cts +540 -0
- package/dist/react-hooks.d.ts +540 -0
- package/dist/react-hooks.js +461 -0
- package/dist/react-hooks.js.map +1 -0
- package/dist/react.cjs +19 -10
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +93 -1
- package/dist/react.d.ts +93 -1
- package/dist/react.js +19 -10
- package/dist/react.js.map +1 -1
- package/dist/tailwind.cjs +148 -0
- package/dist/tailwind.cjs.map +1 -0
- package/dist/tailwind.d.cts +38 -0
- package/dist/tailwind.d.ts +38 -0
- package/dist/tailwind.js +146 -0
- package/dist/tailwind.js.map +1 -0
- package/dist/testing.cjs +19 -10
- package/dist/testing.cjs.map +1 -1
- package/dist/testing.d.cts +90 -0
- package/dist/testing.d.ts +90 -0
- package/dist/testing.js +19 -10
- package/dist/testing.js.map +1 -1
- package/package.json +32 -1
- package/skills/featuredrop-setup/SKILL.md +124 -0
- package/src/ai/claude-skill.md +109 -0
- package/src/ai/cursorrules.txt +13 -0
package/dist/testing.d.cts
CHANGED
|
@@ -252,6 +252,94 @@ interface AnalyticsCallbacks {
|
|
|
252
252
|
/** Fired when all features are dismissed at once */
|
|
253
253
|
onAllDismissed?: () => void;
|
|
254
254
|
}
|
|
255
|
+
/** Display format hint from the engine */
|
|
256
|
+
type DisplayFormat = "badge" | "toast" | "modal" | "banner" | "inline" | "spotlight";
|
|
257
|
+
/** Interaction type tracked by the engine */
|
|
258
|
+
type InteractionType = "seen" | "dismissed" | "clicked" | "completed" | "snoozed" | "hovered" | "expanded";
|
|
259
|
+
/** Timing decision returned by the engine */
|
|
260
|
+
interface TimingDecision {
|
|
261
|
+
/** Whether to show the announcement now */
|
|
262
|
+
show: boolean;
|
|
263
|
+
/** Reason for the decision */
|
|
264
|
+
reason: string;
|
|
265
|
+
/** Suggested delay in ms if not showing now */
|
|
266
|
+
delayMs?: number;
|
|
267
|
+
/** Confidence level (0-1) */
|
|
268
|
+
confidence: number;
|
|
269
|
+
}
|
|
270
|
+
/** Format recommendation from the engine */
|
|
271
|
+
interface FormatRecommendation {
|
|
272
|
+
/** Recommended display format */
|
|
273
|
+
primary: DisplayFormat;
|
|
274
|
+
/** Fallback format if primary component isn't used */
|
|
275
|
+
fallback: DisplayFormat;
|
|
276
|
+
/** Reason for the recommendation */
|
|
277
|
+
reason: string;
|
|
278
|
+
}
|
|
279
|
+
/** Adoption score breakdown */
|
|
280
|
+
interface AdoptionScore {
|
|
281
|
+
/** Overall score (0-100) */
|
|
282
|
+
score: number;
|
|
283
|
+
/** Letter grade */
|
|
284
|
+
grade: "A" | "B" | "C" | "D" | "F";
|
|
285
|
+
/** Score breakdown */
|
|
286
|
+
breakdown: {
|
|
287
|
+
/** % of features the user has explored */
|
|
288
|
+
featuresExplored: number;
|
|
289
|
+
/** Rate of dismissals (lower is better) */
|
|
290
|
+
dismissRate: number;
|
|
291
|
+
/** Rate of tour/checklist completion */
|
|
292
|
+
completionRate: number;
|
|
293
|
+
/** Whether engagement is rising, stable, or declining */
|
|
294
|
+
engagementTrend: "rising" | "stable" | "declining";
|
|
295
|
+
};
|
|
296
|
+
/** Actionable recommendations */
|
|
297
|
+
recommendations: string[];
|
|
298
|
+
}
|
|
299
|
+
/** Per-feature adoption status */
|
|
300
|
+
interface FeatureAdoptionStatus {
|
|
301
|
+
featureId: string;
|
|
302
|
+
status: "unseen" | "seen" | "explored" | "adopted" | "dismissed";
|
|
303
|
+
firstSeen?: string;
|
|
304
|
+
lastInteraction?: string;
|
|
305
|
+
interactionCount: number;
|
|
306
|
+
}
|
|
307
|
+
/** Delivery context passed to the engine for timing decisions */
|
|
308
|
+
interface DeliveryContext {
|
|
309
|
+
/** Current route/path */
|
|
310
|
+
currentPath: string;
|
|
311
|
+
/** Seconds since session start */
|
|
312
|
+
sessionAge: number;
|
|
313
|
+
/** Dismissals in last 5 minutes */
|
|
314
|
+
recentDismissals: number;
|
|
315
|
+
/** Feature priority */
|
|
316
|
+
featurePriority: FeaturePriority;
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* Plugin interface for the FeatureDrop engine.
|
|
320
|
+
*
|
|
321
|
+
* The open-source library defines this interface.
|
|
322
|
+
* The proprietary @featuredrop/engine implements it.
|
|
323
|
+
* Users can also build their own engine implementation.
|
|
324
|
+
*
|
|
325
|
+
* The free library works perfectly without any engine.
|
|
326
|
+
*/
|
|
327
|
+
interface FeatureDropEngine {
|
|
328
|
+
/** Decide whether to show a feature announcement now */
|
|
329
|
+
shouldShow(featureId: string, context: DeliveryContext): TimingDecision;
|
|
330
|
+
/** Recommend the best display format for a feature */
|
|
331
|
+
recommendFormat(featureId: string): FormatRecommendation;
|
|
332
|
+
/** Get the user's overall adoption score */
|
|
333
|
+
getAdoptionScore(): AdoptionScore;
|
|
334
|
+
/** Track a user interaction with a feature */
|
|
335
|
+
trackInteraction(featureId: string, type: InteractionType): void;
|
|
336
|
+
/** Get adoption status for a specific feature */
|
|
337
|
+
getFeatureAdoption(featureId: string): FeatureAdoptionStatus;
|
|
338
|
+
/** Initialize the engine (called by provider on mount) */
|
|
339
|
+
initialize?(): void;
|
|
340
|
+
/** Cleanup resources (called by provider on unmount) */
|
|
341
|
+
destroy?(): void;
|
|
342
|
+
}
|
|
255
343
|
|
|
256
344
|
interface ThrottleOptions {
|
|
257
345
|
maxSimultaneousBadges?: number;
|
|
@@ -326,6 +414,8 @@ interface FeatureDropProviderProps {
|
|
|
326
414
|
animation?: FeatureDropAnimationPreset;
|
|
327
415
|
/** Custom translation overrides for built-in component strings */
|
|
328
416
|
translations?: Partial<FeatureDropTranslations>;
|
|
417
|
+
/** Optional engine for AI-powered delivery intelligence (@featuredrop/engine) */
|
|
418
|
+
engine?: FeatureDropEngine;
|
|
329
419
|
children: ReactNode;
|
|
330
420
|
}
|
|
331
421
|
|
package/dist/testing.d.ts
CHANGED
|
@@ -252,6 +252,94 @@ interface AnalyticsCallbacks {
|
|
|
252
252
|
/** Fired when all features are dismissed at once */
|
|
253
253
|
onAllDismissed?: () => void;
|
|
254
254
|
}
|
|
255
|
+
/** Display format hint from the engine */
|
|
256
|
+
type DisplayFormat = "badge" | "toast" | "modal" | "banner" | "inline" | "spotlight";
|
|
257
|
+
/** Interaction type tracked by the engine */
|
|
258
|
+
type InteractionType = "seen" | "dismissed" | "clicked" | "completed" | "snoozed" | "hovered" | "expanded";
|
|
259
|
+
/** Timing decision returned by the engine */
|
|
260
|
+
interface TimingDecision {
|
|
261
|
+
/** Whether to show the announcement now */
|
|
262
|
+
show: boolean;
|
|
263
|
+
/** Reason for the decision */
|
|
264
|
+
reason: string;
|
|
265
|
+
/** Suggested delay in ms if not showing now */
|
|
266
|
+
delayMs?: number;
|
|
267
|
+
/** Confidence level (0-1) */
|
|
268
|
+
confidence: number;
|
|
269
|
+
}
|
|
270
|
+
/** Format recommendation from the engine */
|
|
271
|
+
interface FormatRecommendation {
|
|
272
|
+
/** Recommended display format */
|
|
273
|
+
primary: DisplayFormat;
|
|
274
|
+
/** Fallback format if primary component isn't used */
|
|
275
|
+
fallback: DisplayFormat;
|
|
276
|
+
/** Reason for the recommendation */
|
|
277
|
+
reason: string;
|
|
278
|
+
}
|
|
279
|
+
/** Adoption score breakdown */
|
|
280
|
+
interface AdoptionScore {
|
|
281
|
+
/** Overall score (0-100) */
|
|
282
|
+
score: number;
|
|
283
|
+
/** Letter grade */
|
|
284
|
+
grade: "A" | "B" | "C" | "D" | "F";
|
|
285
|
+
/** Score breakdown */
|
|
286
|
+
breakdown: {
|
|
287
|
+
/** % of features the user has explored */
|
|
288
|
+
featuresExplored: number;
|
|
289
|
+
/** Rate of dismissals (lower is better) */
|
|
290
|
+
dismissRate: number;
|
|
291
|
+
/** Rate of tour/checklist completion */
|
|
292
|
+
completionRate: number;
|
|
293
|
+
/** Whether engagement is rising, stable, or declining */
|
|
294
|
+
engagementTrend: "rising" | "stable" | "declining";
|
|
295
|
+
};
|
|
296
|
+
/** Actionable recommendations */
|
|
297
|
+
recommendations: string[];
|
|
298
|
+
}
|
|
299
|
+
/** Per-feature adoption status */
|
|
300
|
+
interface FeatureAdoptionStatus {
|
|
301
|
+
featureId: string;
|
|
302
|
+
status: "unseen" | "seen" | "explored" | "adopted" | "dismissed";
|
|
303
|
+
firstSeen?: string;
|
|
304
|
+
lastInteraction?: string;
|
|
305
|
+
interactionCount: number;
|
|
306
|
+
}
|
|
307
|
+
/** Delivery context passed to the engine for timing decisions */
|
|
308
|
+
interface DeliveryContext {
|
|
309
|
+
/** Current route/path */
|
|
310
|
+
currentPath: string;
|
|
311
|
+
/** Seconds since session start */
|
|
312
|
+
sessionAge: number;
|
|
313
|
+
/** Dismissals in last 5 minutes */
|
|
314
|
+
recentDismissals: number;
|
|
315
|
+
/** Feature priority */
|
|
316
|
+
featurePriority: FeaturePriority;
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* Plugin interface for the FeatureDrop engine.
|
|
320
|
+
*
|
|
321
|
+
* The open-source library defines this interface.
|
|
322
|
+
* The proprietary @featuredrop/engine implements it.
|
|
323
|
+
* Users can also build their own engine implementation.
|
|
324
|
+
*
|
|
325
|
+
* The free library works perfectly without any engine.
|
|
326
|
+
*/
|
|
327
|
+
interface FeatureDropEngine {
|
|
328
|
+
/** Decide whether to show a feature announcement now */
|
|
329
|
+
shouldShow(featureId: string, context: DeliveryContext): TimingDecision;
|
|
330
|
+
/** Recommend the best display format for a feature */
|
|
331
|
+
recommendFormat(featureId: string): FormatRecommendation;
|
|
332
|
+
/** Get the user's overall adoption score */
|
|
333
|
+
getAdoptionScore(): AdoptionScore;
|
|
334
|
+
/** Track a user interaction with a feature */
|
|
335
|
+
trackInteraction(featureId: string, type: InteractionType): void;
|
|
336
|
+
/** Get adoption status for a specific feature */
|
|
337
|
+
getFeatureAdoption(featureId: string): FeatureAdoptionStatus;
|
|
338
|
+
/** Initialize the engine (called by provider on mount) */
|
|
339
|
+
initialize?(): void;
|
|
340
|
+
/** Cleanup resources (called by provider on unmount) */
|
|
341
|
+
destroy?(): void;
|
|
342
|
+
}
|
|
255
343
|
|
|
256
344
|
interface ThrottleOptions {
|
|
257
345
|
maxSimultaneousBadges?: number;
|
|
@@ -326,6 +414,8 @@ interface FeatureDropProviderProps {
|
|
|
326
414
|
animation?: FeatureDropAnimationPreset;
|
|
327
415
|
/** Custom translation overrides for built-in component strings */
|
|
328
416
|
translations?: Partial<FeatureDropTranslations>;
|
|
417
|
+
/** Optional engine for AI-powered delivery intelligence (@featuredrop/engine) */
|
|
418
|
+
engine?: FeatureDropEngine;
|
|
329
419
|
children: ReactNode;
|
|
330
420
|
}
|
|
331
421
|
|
package/dist/testing.js
CHANGED
|
@@ -982,6 +982,7 @@ function FeatureDropProvider({
|
|
|
982
982
|
locale = "en",
|
|
983
983
|
animation = "normal",
|
|
984
984
|
translations: translationOverrides,
|
|
985
|
+
engine,
|
|
985
986
|
children
|
|
986
987
|
}) {
|
|
987
988
|
const analyticsRef = useRef(analytics);
|
|
@@ -1038,20 +1039,20 @@ function FeatureDropProvider({
|
|
|
1038
1039
|
seenFeatureIds: readIdSet(SEEN_FEATURES_STORAGE_KEY),
|
|
1039
1040
|
clickedFeatureIds: readIdSet(CLICKED_FEATURES_STORAGE_KEY),
|
|
1040
1041
|
triggerContext: (() => {
|
|
1041
|
-
const
|
|
1042
|
-
if (!
|
|
1043
|
-
|
|
1044
|
-
return
|
|
1042
|
+
const engine2 = triggerEngineRef.current;
|
|
1043
|
+
if (!engine2) return void 0;
|
|
1044
|
+
engine2.setElapsedMs(Date.now() - sessionStartedAtRef.current);
|
|
1045
|
+
return engine2.getContext();
|
|
1045
1046
|
})(),
|
|
1046
1047
|
flagBridge
|
|
1047
1048
|
})
|
|
1048
1049
|
);
|
|
1049
1050
|
const recompute = useCallback(() => {
|
|
1050
|
-
const
|
|
1051
|
+
const engine2 = triggerEngineRef.current;
|
|
1051
1052
|
let triggerContext;
|
|
1052
|
-
if (
|
|
1053
|
-
|
|
1054
|
-
triggerContext =
|
|
1053
|
+
if (engine2) {
|
|
1054
|
+
engine2.setElapsedMs(Date.now() - sessionStartedAtRef.current);
|
|
1055
|
+
triggerContext = engine2.getContext();
|
|
1055
1056
|
}
|
|
1056
1057
|
setFeatureState(
|
|
1057
1058
|
computeFeatureState({
|
|
@@ -1088,6 +1089,12 @@ function FeatureDropProvider({
|
|
|
1088
1089
|
useEffect(() => {
|
|
1089
1090
|
recompute();
|
|
1090
1091
|
}, [recompute]);
|
|
1092
|
+
useEffect(() => {
|
|
1093
|
+
engine?.initialize?.();
|
|
1094
|
+
return () => {
|
|
1095
|
+
engine?.destroy?.();
|
|
1096
|
+
};
|
|
1097
|
+
}, [engine]);
|
|
1091
1098
|
const hasTimeTriggers = useMemo(
|
|
1092
1099
|
() => resolvedManifest.some((feature) => feature.trigger?.type === "time"),
|
|
1093
1100
|
[resolvedManifest]
|
|
@@ -1370,7 +1377,8 @@ function FeatureDropProvider({
|
|
|
1370
1377
|
trackUsageEvent,
|
|
1371
1378
|
trackTriggerEvent,
|
|
1372
1379
|
trackMilestone,
|
|
1373
|
-
setTriggerPath
|
|
1380
|
+
setTriggerPath,
|
|
1381
|
+
engine: engine ?? null
|
|
1374
1382
|
}),
|
|
1375
1383
|
[
|
|
1376
1384
|
resolvedManifest,
|
|
@@ -1404,7 +1412,8 @@ function FeatureDropProvider({
|
|
|
1404
1412
|
trackUsageEvent,
|
|
1405
1413
|
trackTriggerEvent,
|
|
1406
1414
|
trackMilestone,
|
|
1407
|
-
setTriggerPath
|
|
1415
|
+
setTriggerPath,
|
|
1416
|
+
engine
|
|
1408
1417
|
]
|
|
1409
1418
|
);
|
|
1410
1419
|
return /* @__PURE__ */ jsx(FeatureDropContext.Provider, { value, children });
|