featuredrop 1.0.1 → 1.1.0
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/README.md +263 -195
- package/dist/index.cjs +14 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +43 -2
- package/dist/index.d.ts +43 -2
- package/dist/index.js +14 -1
- package/dist/index.js.map +1 -1
- package/dist/react.cjs +1077 -2
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +324 -5
- package/dist/react.d.ts +324 -5
- package/dist/react.js +1075 -5
- package/dist/react.js.map +1 -1
- package/package.json +1 -1
package/dist/react.d.ts
CHANGED
|
@@ -1,14 +1,25 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import * as react from 'react';
|
|
3
|
-
import { ReactNode, CSSProperties } from 'react';
|
|
3
|
+
import { ReactNode, CSSProperties, RefObject } from 'react';
|
|
4
4
|
|
|
5
|
+
/** Entry type label — determines default icon/color in UI */
|
|
6
|
+
type FeatureType = "feature" | "improvement" | "fix" | "breaking";
|
|
7
|
+
/** Priority level for announcements */
|
|
8
|
+
type FeaturePriority = "critical" | "normal" | "low";
|
|
9
|
+
/** Call-to-action for a feature entry */
|
|
10
|
+
interface FeatureCTA {
|
|
11
|
+
/** Button/link label */
|
|
12
|
+
label: string;
|
|
13
|
+
/** URL to navigate to */
|
|
14
|
+
url: string;
|
|
15
|
+
}
|
|
5
16
|
/** A single feature entry in the manifest */
|
|
6
17
|
interface FeatureEntry {
|
|
7
18
|
/** Unique identifier for the feature */
|
|
8
19
|
id: string;
|
|
9
20
|
/** Human-readable label (e.g. "Decision Journal") */
|
|
10
21
|
label: string;
|
|
11
|
-
/** Optional longer description */
|
|
22
|
+
/** Optional longer description (supports markdown in UI components) */
|
|
12
23
|
description?: string;
|
|
13
24
|
/** ISO date when this feature was released */
|
|
14
25
|
releasedAt: string;
|
|
@@ -22,6 +33,16 @@ interface FeatureEntry {
|
|
|
22
33
|
url?: string;
|
|
23
34
|
/** Optional version string when this feature shipped */
|
|
24
35
|
version?: string;
|
|
36
|
+
/** Entry type — determines default icon/color in UI components */
|
|
37
|
+
type?: FeatureType;
|
|
38
|
+
/** Priority level — critical entries get special treatment in UI */
|
|
39
|
+
priority?: FeaturePriority;
|
|
40
|
+
/** Optional image/screenshot URL */
|
|
41
|
+
image?: string;
|
|
42
|
+
/** Optional call-to-action button */
|
|
43
|
+
cta?: FeatureCTA;
|
|
44
|
+
/** ISO date — entry is hidden until this date (scheduled publishing) */
|
|
45
|
+
publishAt?: string;
|
|
25
46
|
/** Optional arbitrary metadata */
|
|
26
47
|
meta?: Record<string, unknown>;
|
|
27
48
|
}
|
|
@@ -44,27 +65,46 @@ interface StorageAdapter {
|
|
|
44
65
|
/** Dismiss all features — sets watermark to `now` and clears dismissals */
|
|
45
66
|
dismissAll(now: Date): Promise<void>;
|
|
46
67
|
}
|
|
68
|
+
/** Analytics event callbacks — pipe to your analytics provider */
|
|
69
|
+
interface AnalyticsCallbacks {
|
|
70
|
+
/** Fired when a feature badge becomes visible to the user */
|
|
71
|
+
onFeatureSeen?: (feature: FeatureEntry) => void;
|
|
72
|
+
/** Fired when a user dismisses a single feature */
|
|
73
|
+
onFeatureDismissed?: (feature: FeatureEntry) => void;
|
|
74
|
+
/** Fired when a user clicks a feature link or CTA */
|
|
75
|
+
onFeatureClicked?: (feature: FeatureEntry) => void;
|
|
76
|
+
/** Fired when the changelog widget is opened */
|
|
77
|
+
onWidgetOpened?: () => void;
|
|
78
|
+
/** Fired when the changelog widget is closed */
|
|
79
|
+
onWidgetClosed?: () => void;
|
|
80
|
+
/** Fired when all features are dismissed at once */
|
|
81
|
+
onAllDismissed?: () => void;
|
|
82
|
+
}
|
|
47
83
|
|
|
48
84
|
interface FeatureDropProviderProps {
|
|
49
85
|
/** The feature manifest — typically a frozen array of FeatureEntry objects */
|
|
50
86
|
manifest: FeatureManifest;
|
|
51
87
|
/** Storage adapter instance (e.g. LocalStorageAdapter, MemoryAdapter) */
|
|
52
88
|
storage: StorageAdapter;
|
|
89
|
+
/** Optional analytics callbacks — pipe to your analytics provider */
|
|
90
|
+
analytics?: AnalyticsCallbacks;
|
|
53
91
|
children: ReactNode;
|
|
54
92
|
}
|
|
55
93
|
/**
|
|
56
94
|
* Provides feature discovery state to the component tree.
|
|
57
95
|
*
|
|
58
96
|
* Wrap your app (or a subtree) with this provider to enable
|
|
59
|
-
* `useFeatureDrop`, `useNewFeature`,
|
|
97
|
+
* `useFeatureDrop`, `useNewFeature`, `useNewCount`, and other hooks.
|
|
60
98
|
*/
|
|
61
|
-
declare function FeatureDropProvider({ manifest, storage, children, }: FeatureDropProviderProps): react_jsx_runtime.JSX.Element;
|
|
99
|
+
declare function FeatureDropProvider({ manifest, storage, analytics, children, }: FeatureDropProviderProps): react_jsx_runtime.JSX.Element;
|
|
62
100
|
|
|
63
101
|
interface FeatureDropContextValue {
|
|
64
102
|
/** All currently "new" features */
|
|
65
103
|
newFeatures: FeatureEntry[];
|
|
66
104
|
/** Count of new features */
|
|
67
105
|
newCount: number;
|
|
106
|
+
/** All new features sorted by priority then release date */
|
|
107
|
+
newFeaturesSorted: FeatureEntry[];
|
|
68
108
|
/** Check if a sidebar key has any new features */
|
|
69
109
|
isNew: (sidebarKey: string) => boolean;
|
|
70
110
|
/** Dismiss a single feature by ID */
|
|
@@ -110,6 +150,37 @@ declare function useNewFeature(sidebarKey: string): UseNewFeatureResult;
|
|
|
110
150
|
*/
|
|
111
151
|
declare function useNewCount(): number;
|
|
112
152
|
|
|
153
|
+
interface UseTabNotificationOptions {
|
|
154
|
+
/** Whether tab notifications are enabled. Default: true */
|
|
155
|
+
enabled?: boolean;
|
|
156
|
+
/** Template string. `{count}` is replaced with the number. Default: "({count}) {title}" */
|
|
157
|
+
template?: string;
|
|
158
|
+
/** Enable flashing/blinking pattern for attention. Default: false */
|
|
159
|
+
flash?: boolean;
|
|
160
|
+
/** Flash interval in ms. Default: 1500 */
|
|
161
|
+
flashInterval?: number;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Updates the browser tab title with the unread feature count.
|
|
165
|
+
*
|
|
166
|
+
* Shows "(3) My App" when there are new features, restores the original
|
|
167
|
+
* title when all features are read. Optional flash/blink pattern for attention.
|
|
168
|
+
*
|
|
169
|
+
* @example
|
|
170
|
+
* ```tsx
|
|
171
|
+
* function App() {
|
|
172
|
+
* useTabNotification();
|
|
173
|
+
* return <div>...</div>;
|
|
174
|
+
* }
|
|
175
|
+
* ```
|
|
176
|
+
*
|
|
177
|
+
* @example With flash
|
|
178
|
+
* ```tsx
|
|
179
|
+
* useTabNotification({ flash: true, template: "[{count} new] {title}" });
|
|
180
|
+
* ```
|
|
181
|
+
*/
|
|
182
|
+
declare function useTabNotification(options?: UseTabNotificationOptions): void;
|
|
183
|
+
|
|
113
184
|
interface NewBadgeRenderProps {
|
|
114
185
|
/** Whether the feature is currently new */
|
|
115
186
|
isNew: boolean;
|
|
@@ -151,4 +222,252 @@ interface NewBadgeProps {
|
|
|
151
222
|
*/
|
|
152
223
|
declare function NewBadge({ variant, show, count, label, onDismiss, dismissOnClick, className, style, children, }: NewBadgeProps): react_jsx_runtime.JSX.Element | null;
|
|
153
224
|
|
|
154
|
-
|
|
225
|
+
interface ChangelogEntryRenderProps {
|
|
226
|
+
feature: FeatureEntry;
|
|
227
|
+
dismiss: () => void;
|
|
228
|
+
}
|
|
229
|
+
interface ChangelogWidgetRenderProps {
|
|
230
|
+
/** Whether the widget is currently open */
|
|
231
|
+
isOpen: boolean;
|
|
232
|
+
/** Open the widget */
|
|
233
|
+
open: () => void;
|
|
234
|
+
/** Close the widget */
|
|
235
|
+
close: () => void;
|
|
236
|
+
/** Toggle open/close */
|
|
237
|
+
toggle: () => void;
|
|
238
|
+
/** Current new feature count */
|
|
239
|
+
count: number;
|
|
240
|
+
/** Sorted features to display */
|
|
241
|
+
features: FeatureEntry[];
|
|
242
|
+
/** Dismiss a single feature */
|
|
243
|
+
dismiss: (id: string) => void;
|
|
244
|
+
/** Dismiss all features */
|
|
245
|
+
dismissAll: () => Promise<void>;
|
|
246
|
+
}
|
|
247
|
+
interface ChangelogWidgetProps {
|
|
248
|
+
/** Display variant */
|
|
249
|
+
variant?: "panel" | "modal" | "popover";
|
|
250
|
+
/** Title shown in the widget header. Default: "What's New" */
|
|
251
|
+
title?: string;
|
|
252
|
+
/** Text for the trigger button. Default: "What's New" */
|
|
253
|
+
triggerLabel?: string;
|
|
254
|
+
/** Show trigger badge count. Default: true */
|
|
255
|
+
showCount?: boolean;
|
|
256
|
+
/** Text for the "mark all as read" button. Default: "Mark all as read" */
|
|
257
|
+
markAllLabel?: string;
|
|
258
|
+
/** Whether to show the mark-all button. Default: true */
|
|
259
|
+
showMarkAll?: boolean;
|
|
260
|
+
/** Text shown when no new features exist. Default: "You're all caught up!" */
|
|
261
|
+
emptyLabel?: string;
|
|
262
|
+
/** Max height for the feed area. Default: "400px" */
|
|
263
|
+
maxHeight?: string;
|
|
264
|
+
/** Analytics callbacks */
|
|
265
|
+
analytics?: AnalyticsCallbacks;
|
|
266
|
+
/** Additional CSS class for the container */
|
|
267
|
+
className?: string;
|
|
268
|
+
/** Additional inline styles for the container */
|
|
269
|
+
style?: CSSProperties;
|
|
270
|
+
/** Render prop for full customization — receives widget state */
|
|
271
|
+
children?: (props: ChangelogWidgetRenderProps) => ReactNode;
|
|
272
|
+
/** Custom render for each entry — receives feature + dismiss callback */
|
|
273
|
+
renderEntry?: (props: ChangelogEntryRenderProps) => ReactNode;
|
|
274
|
+
/** Custom render for the trigger button */
|
|
275
|
+
renderTrigger?: (props: {
|
|
276
|
+
count: number;
|
|
277
|
+
onClick: () => void;
|
|
278
|
+
}) => ReactNode;
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Changelog widget — the #1 feature for feature discovery tools.
|
|
282
|
+
*
|
|
283
|
+
* Renders a trigger button with an unread count badge and a
|
|
284
|
+
* slide-out panel, modal, or popover with the changelog feed.
|
|
285
|
+
*
|
|
286
|
+
* Styled via CSS custom properties — zero framework dependency.
|
|
287
|
+
* Use `children` render prop for full headless control.
|
|
288
|
+
*
|
|
289
|
+
* @example
|
|
290
|
+
* ```tsx
|
|
291
|
+
* <ChangelogWidget variant="panel" />
|
|
292
|
+
* ```
|
|
293
|
+
*
|
|
294
|
+
* @example Headless mode
|
|
295
|
+
* ```tsx
|
|
296
|
+
* <ChangelogWidget>
|
|
297
|
+
* {({ isOpen, toggle, features, count }) => (
|
|
298
|
+
* <MyCustomUI ... />
|
|
299
|
+
* )}
|
|
300
|
+
* </ChangelogWidget>
|
|
301
|
+
* ```
|
|
302
|
+
*/
|
|
303
|
+
declare function ChangelogWidget({ variant, title, triggerLabel, showCount, markAllLabel, showMarkAll, emptyLabel, maxHeight, analytics, className, style, children, renderEntry, renderTrigger, }: ChangelogWidgetProps): react_jsx_runtime.JSX.Element;
|
|
304
|
+
|
|
305
|
+
interface SpotlightRenderProps {
|
|
306
|
+
/** The feature being spotlighted */
|
|
307
|
+
feature: FeatureEntry | undefined;
|
|
308
|
+
/** Whether the spotlight is active */
|
|
309
|
+
isActive: boolean;
|
|
310
|
+
/** Whether the tooltip is visible */
|
|
311
|
+
isTooltipOpen: boolean;
|
|
312
|
+
/** Show the tooltip */
|
|
313
|
+
openTooltip: () => void;
|
|
314
|
+
/** Hide the tooltip */
|
|
315
|
+
closeTooltip: () => void;
|
|
316
|
+
/** Dismiss this spotlight permanently */
|
|
317
|
+
dismiss: () => void;
|
|
318
|
+
}
|
|
319
|
+
interface SpotlightProps {
|
|
320
|
+
/** The feature ID to spotlight */
|
|
321
|
+
featureId: string;
|
|
322
|
+
/** Ref to the target DOM element — beacon will be positioned over it */
|
|
323
|
+
targetRef?: RefObject<HTMLElement | null>;
|
|
324
|
+
/** CSS selector for the target element (alternative to targetRef) */
|
|
325
|
+
targetSelector?: string;
|
|
326
|
+
/** Tooltip placement relative to target */
|
|
327
|
+
placement?: "top" | "bottom" | "left" | "right";
|
|
328
|
+
/** Beacon size in pixels. Default: 12 */
|
|
329
|
+
beaconSize?: number;
|
|
330
|
+
/** Auto-dismiss after the tooltip is seen */
|
|
331
|
+
autoDismiss?: boolean;
|
|
332
|
+
/** Delay before auto-dismiss in ms. Default: 5000 */
|
|
333
|
+
autoDismissDelay?: number;
|
|
334
|
+
/** Analytics callbacks */
|
|
335
|
+
analytics?: AnalyticsCallbacks;
|
|
336
|
+
/** Additional CSS class */
|
|
337
|
+
className?: string;
|
|
338
|
+
/** Custom tooltip content */
|
|
339
|
+
tooltipContent?: ReactNode;
|
|
340
|
+
/** Render prop for full customization */
|
|
341
|
+
children?: (props: SpotlightRenderProps) => ReactNode;
|
|
342
|
+
}
|
|
343
|
+
/**
|
|
344
|
+
* Pulsing beacon that attaches to any DOM element to highlight a new feature.
|
|
345
|
+
*
|
|
346
|
+
* Clicking the beacon reveals a tooltip with feature info.
|
|
347
|
+
* After dismissal, the beacon disappears permanently for this user.
|
|
348
|
+
*
|
|
349
|
+
* @example
|
|
350
|
+
* ```tsx
|
|
351
|
+
* const ref = useRef<HTMLButtonElement>(null);
|
|
352
|
+
* <button ref={ref}>Analytics</button>
|
|
353
|
+
* <Spotlight featureId="analytics-v2" targetRef={ref} />
|
|
354
|
+
* ```
|
|
355
|
+
*
|
|
356
|
+
* @example With CSS selector
|
|
357
|
+
* ```tsx
|
|
358
|
+
* <Spotlight featureId="analytics-v2" targetSelector="#analytics-btn" />
|
|
359
|
+
* ```
|
|
360
|
+
*/
|
|
361
|
+
declare function Spotlight({ featureId, targetRef, targetSelector, placement, beaconSize, autoDismiss, autoDismissDelay, analytics, className, tooltipContent, children, }: SpotlightProps): react_jsx_runtime.JSX.Element | null;
|
|
362
|
+
|
|
363
|
+
type BannerVariant = "info" | "success" | "warning" | "announcement";
|
|
364
|
+
interface BannerRenderProps {
|
|
365
|
+
/** The feature being announced */
|
|
366
|
+
feature: FeatureEntry | undefined;
|
|
367
|
+
/** Whether the banner is active */
|
|
368
|
+
isActive: boolean;
|
|
369
|
+
/** Whether the banner has been dismissed this session */
|
|
370
|
+
isDismissed: boolean;
|
|
371
|
+
/** Dismiss the banner permanently */
|
|
372
|
+
dismiss: () => void;
|
|
373
|
+
}
|
|
374
|
+
interface BannerProps {
|
|
375
|
+
/** Feature ID to display as a banner */
|
|
376
|
+
featureId: string;
|
|
377
|
+
/** Banner visual variant. Default: "announcement" */
|
|
378
|
+
variant?: BannerVariant;
|
|
379
|
+
/** Whether the banner is dismissible. Default: true */
|
|
380
|
+
dismissible?: boolean;
|
|
381
|
+
/** Position mode. Default: "sticky" */
|
|
382
|
+
position?: "sticky" | "inline" | "fixed";
|
|
383
|
+
/** Analytics callbacks */
|
|
384
|
+
analytics?: AnalyticsCallbacks;
|
|
385
|
+
/** Additional CSS class */
|
|
386
|
+
className?: string;
|
|
387
|
+
/** Additional inline styles */
|
|
388
|
+
style?: CSSProperties;
|
|
389
|
+
/** Render prop for full customization */
|
|
390
|
+
children?: (props: BannerRenderProps) => ReactNode;
|
|
391
|
+
}
|
|
392
|
+
/**
|
|
393
|
+
* Announcement banner for major feature launches or important notices.
|
|
394
|
+
*
|
|
395
|
+
* Shows at the top of the page (sticky/fixed) or inline in content.
|
|
396
|
+
* Auto-expires using the same `showNewUntil` logic as badges.
|
|
397
|
+
* Styled via CSS custom properties for each variant.
|
|
398
|
+
*
|
|
399
|
+
* @example
|
|
400
|
+
* ```tsx
|
|
401
|
+
* <Banner featureId="v2-launch" variant="announcement" />
|
|
402
|
+
* ```
|
|
403
|
+
*
|
|
404
|
+
* @example Headless
|
|
405
|
+
* ```tsx
|
|
406
|
+
* <Banner featureId="v2-launch">
|
|
407
|
+
* {({ feature, dismiss }) => (
|
|
408
|
+
* <div>New: {feature?.label} <button onClick={dismiss}>x</button></div>
|
|
409
|
+
* )}
|
|
410
|
+
* </Banner>
|
|
411
|
+
* ```
|
|
412
|
+
*/
|
|
413
|
+
declare function Banner({ featureId, variant, dismissible, position, analytics, className, style, children, }: BannerProps): react_jsx_runtime.JSX.Element | null;
|
|
414
|
+
|
|
415
|
+
interface ToastRenderProps {
|
|
416
|
+
/** Features currently showing as toasts */
|
|
417
|
+
toasts: FeatureEntry[];
|
|
418
|
+
/** Dismiss a specific toast */
|
|
419
|
+
dismiss: (id: string) => void;
|
|
420
|
+
/** Dismiss all toasts */
|
|
421
|
+
dismissAll: () => void;
|
|
422
|
+
}
|
|
423
|
+
interface ToastProps {
|
|
424
|
+
/** Feature IDs to show as toasts. If omitted, shows all new features. */
|
|
425
|
+
featureIds?: string[];
|
|
426
|
+
/** Max number of visible toasts at once. Default: 3 */
|
|
427
|
+
maxVisible?: number;
|
|
428
|
+
/** Auto-dismiss delay in ms. Default: 8000. Set to 0 to disable. */
|
|
429
|
+
autoDismissMs?: number;
|
|
430
|
+
/** Position on screen. Default: "bottom-right" */
|
|
431
|
+
position?: "top-right" | "top-left" | "bottom-right" | "bottom-left" | "top-center" | "bottom-center";
|
|
432
|
+
/** Analytics callbacks */
|
|
433
|
+
analytics?: AnalyticsCallbacks;
|
|
434
|
+
/** Additional CSS class for the container */
|
|
435
|
+
className?: string;
|
|
436
|
+
/** Additional inline styles for the container */
|
|
437
|
+
style?: CSSProperties;
|
|
438
|
+
/** Render prop for full customization */
|
|
439
|
+
children?: (props: ToastRenderProps) => ReactNode;
|
|
440
|
+
/** Custom render for each toast */
|
|
441
|
+
renderToast?: (props: {
|
|
442
|
+
feature: FeatureEntry;
|
|
443
|
+
dismiss: () => void;
|
|
444
|
+
}) => ReactNode;
|
|
445
|
+
}
|
|
446
|
+
/**
|
|
447
|
+
* Toast notification component for feature announcements.
|
|
448
|
+
*
|
|
449
|
+
* Shows brief popups for new features. Auto-dismisses after a timeout.
|
|
450
|
+
* Stacks multiple toasts with configurable max visible count.
|
|
451
|
+
*
|
|
452
|
+
* @example
|
|
453
|
+
* ```tsx
|
|
454
|
+
* <Toast position="bottom-right" maxVisible={3} />
|
|
455
|
+
* ```
|
|
456
|
+
*
|
|
457
|
+
* @example Specific features
|
|
458
|
+
* ```tsx
|
|
459
|
+
* <Toast featureIds={["ai-journal", "analytics-v2"]} />
|
|
460
|
+
* ```
|
|
461
|
+
*
|
|
462
|
+
* @example Headless
|
|
463
|
+
* ```tsx
|
|
464
|
+
* <Toast>
|
|
465
|
+
* {({ toasts, dismiss }) => toasts.map(t => (
|
|
466
|
+
* <div key={t.id}>{t.label} <button onClick={() => dismiss(t.id)}>x</button></div>
|
|
467
|
+
* ))}
|
|
468
|
+
* </Toast>
|
|
469
|
+
* ```
|
|
470
|
+
*/
|
|
471
|
+
declare function Toast({ featureIds, maxVisible, autoDismissMs, position, analytics, className, style, children, renderToast, }: ToastProps): react_jsx_runtime.JSX.Element | null;
|
|
472
|
+
|
|
473
|
+
export { Banner, type BannerProps, type BannerRenderProps, type BannerVariant, type ChangelogEntryRenderProps, ChangelogWidget, type ChangelogWidgetProps, type ChangelogWidgetRenderProps, FeatureDropContext, type FeatureDropContextValue, FeatureDropProvider, type FeatureDropProviderProps, NewBadge, type NewBadgeProps, type NewBadgeRenderProps, Spotlight, type SpotlightProps, type SpotlightRenderProps, Toast, type ToastProps, type ToastRenderProps, type UseNewFeatureResult, type UseTabNotificationOptions, useFeatureDrop, useNewCount, useNewFeature, useTabNotification };
|