feat(useNotifications): add new plugin composable#146
Merged
johnleider merged 67 commits intomasterfrom Mar 23, 2026
Merged
Conversation
|
commit: |
a54eb68 to
50d5acc
Compare
- Types: NotificationInput, NotificationTicket, NotificationsContext - Core: createNotifications wrapping createQueue with lifecycle state mutations (read/seen/archive/snooze), bulk ops, reactive counts - Plugin: createNotificationsContext, createNotificationsPlugin, useNotifications - Adapter: event-driven integration hook for external services - Barrel export from composables/index.ts
Core lifecycle, state mutations, events, and adapter integration.
Built-in adapters for popular notification services: - createFcmAdapter: Firebase Cloud Messaging (inbound) - createOneSignalAdapter: OneSignal Web SDK (inbound) - createKnockAdapter: Knock feeds (inbound + outbound) Available via `@vuetify/v0/notifications` subpath export.
primaryAction/secondaryAction are component-level concerns. Use the data bag for custom payloads instead.
Aligns with plugin convention — useTheme, useLogger, useFeatures, etc.
- Add fallback to createPluginContext (useNotifications works without provider) - Remove double onScopeDispose (queue already self-disposes) - Fix stale "actions" references in JSDoc and docs - Fix mermaid diagram arrow direction - Fix dismiss(id) → unregister(id) in docs - Remove redundant type assertions - Add @see URL to @module JSDoc
- unreadItems: notifications without readAt - archivedItems: notifications with archivedAt - snoozedItems: notifications with snoozedUntil unreadCount now derives from unreadItems.length for efficiency.
- Adapter: interface with setup/dispose, wired in plugin setup callback with app.onUnmount cleanup (matches useFeatures/useTheme pattern) - Adapter removed from NotificationsOptions, lives on NotificationsPluginOptions - createNotifications() is now adapter-agnostic - Bulk ops (readAll/archiveAll) wrapped in queue.batch() - Updated all 3 adapters (FCM, OneSignal, Knock) to implement interface - Manual sync pattern confirmed correct (reactive:true doesn't help)
Interactive example demonstrating derived collections, ticket convenience methods, seen/read distinction, bulk operations, and state lifecycle diagram.
Eliminates shallowRef + triggerRef + event subscriptions in favor of useProxyRegistry which handles reactive state via shallowReactive. Derived collections (unreadItems, archivedItems, snoozedItems) now compute from proxy.values instead of items.value.
Bulk ops (readAll/archiveAll) now emit per-item domain events so adapters like Knock correctly sync state. Fixes type safety issues, adapter memory leaks, and aligns fallback with established patterns.
…ean itemStyle - SnackbarRoot: use useId() as prop default (stable) instead of inside toRef getter - NotificationProvider example: remove stale :severity prop (no longer on SnackbarRoot) - queue.vue example: remove unused _total param from itemStyle - index.test.ts: fix scoped slot render syntax in integration test
… Novu tests, docs fixes - Add app.onUnmount for context/queue disposal before adapter guard - Add tests for 6 untested events (unread, seen, archived, unarchived, snoozed, unsnoozed) - Add Novu adapter test suite (8 tests) - Strengthen persistent timeout test to verify timer survival - Document Snackbar.Close queue removal behavior - Replace inline inject type with SnackbarQueueContext - Remove empty SnackbarCloseSlotProps interface - Add JSDoc to NotificationTicket.dismiss - Simplify Knock adapter dispose with single ctx guard
…s, Knock tests Snackbar contexts switched from static to dynamic keys with suffix pattern (matching Pagination/Dialog). All sub-components now accept namespace prop defaulting to 'v0:notifications'. Inspection fixes: Novu adapter disposed guard for async race, default role="status" on SnackbarRoot, isNull type guards, fallback stub unregister/batch, Novu adapter docs, queue anatomy v-slot. Added Knock adapter tests and missing Novu outbound sync tests.
…e, remove dead Portal context Add seed() method to NotificationsAdapterContext — enriches like send() but bypasses the toast queue. Adapters now use seed() for initial fetch and send() for realtime, preventing historical notification toast flood. SnackbarQueue pause/resume now uses reference-counted reasons (hover, focus) so mouse-leave doesn't resume while keyboard focus is inside. focusout checks relatedTarget to avoid spurious cycles from internal focus movement (WCAG 2.2.1). Remove dead SnackbarContext from Portal — z-index is applied via inline style and slot props, no child consumed the context.
…attrs, pause fixes Override register and onboard in createNotifications return to route through enrich(), matching the createQueue precedent. Raw registry methods would produce tickets without createdAt or lifecycle methods. SnackbarQueue: move event handlers to slotProps.attrs pattern. Re-pause queue after dismiss when hover/focus is active. Resume on unmount to prevent permanently paused queue. SnackbarRoot: move role="status" to slotProps.attrs for explicit override. Rename queueContext to queue. Add defineSlots to SnackbarContent and SnackbarAction. Add Novu keyword to docs frontmatter.
Adds regex for `export const [createXContext, createXPlugin, useX]` pattern. Picks up plugin trinity exports (useNotifications, useTheme, useLocale, etc.) that were missed by the function-only scan.
…, Close attrs, JSDoc Drop seed() in favor of register() — matches every other registry-based composable. register() overrides the base to hydrate with timestamps and lifecycle methods. onboard() is the bulk variant. Remove SnackbarAction — no precedent across components, zero behavior, users use native <button> or their own component. SnackbarClose: move onClick, aria-label, type to slotProps.attrs for renderless mode support. Export SnackbarCloseSlotProps. NotificationSeverity now uses Extensible<> — users can add custom values like 'critical' with autocomplete for defaults. Add full JSDoc with @param, @remarks, @see, @example on all useNotifications functions and interfaces.
…cs links NotificationSeverity uses Extensible<> for custom values with autocomplete defaults. Snackbar barrel: full JSDoc with script imports, descriptions mentioning key behaviors, and renderless mode notes. Snackbar docs: link useNotifications in intro, queue example, and dismiss warning.
…plugin # Conflicts: # packages/0/src/maturity.json
Remove @mdi/js from playground dependencies (flagged by knip). Add tests for useNotifications fallback, onboard hydration, SnackbarQueue focusin/focusout/unmount cleanup, and Portal default teleport path.
…nd components Add tests for fallback queue/context stubs, hydrate auto-ID, queue cascade on unregister, Close branch for custom as prop, Portal slotProps, Queue focusout with null relatedTarget, Queue unmount when not paused, Knock page event with missing items, Novu empty list response, and Novu disposed flag on realtime events.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds
useNotificationscomposable andSnackbarcompound component for notification lifecycle management.useNotifications
read,unread,seen,archive,unarchive,snooze,wakereadAll,archiveAll,clearcreateNotificationsPluginwithcreatePluginContexttrinity patternsend()creates notification + enqueues for toast;seed()creates notification in registry only (no toast) for historical itemsnovu.notifications.list(), real-time vianotification_received, outbound sync for all 5 lifecycle eventsfeed.fetch()page events, real-time viaitems.received.realtime, outbound sync for read/archiveSnackbar
useStackuseNotificationsby namespace, exposes items via slot, pause/resume on hover and focus (WCAG 2.2.1) with reference-counted reasons to prevent mouse/focus racerole="status"(overridable via attrs)namespacepropQuality
since— will be set at release)