feat: integrate sonner as brain entry#1252
feat: integrate sonner as brain entry#1252marcjulian wants to merge 21 commits intospartan-ng:mainfrom
Conversation
…sts grouped by position
…UMENT for window access * remove dir prop
Greptile SummaryThis PR replaces the third-party Key changes and issues found:
Confidence Score: 3/5
Important Files Changed
Sequence DiagramsequenceDiagram
participant App as Application Code
participant State as toastState (singleton)
participant Toaster as BrnSonnerToaster
participant Toast as BrnSonnerToast
participant Pipe as ToastFilterPipe
App->>State: toast('message') / toast.success() / toast.promise()
State->>State: create() — adds ToastT to toasts signal
State-->>Toaster: toasts signal changes
Toaster->>Toaster: _possiblePositions() recomputed
Toaster->>Pipe: _toasts() | toastFilter: $index : pos
Pipe-->>Toaster: filtered ToastT[] per position group
Toaster->>Toast: renders <brn-sonner-toast [position]="pos" ...>
Toast->>Toast: ngAfterViewInit() — measures height
Toast->>State: addHeight({ toastId, height, position })
State-->>Toaster: heights signal changes → _toasterStyles() recomputed
Note over Toast: afterRenderEffect — startTimer()
Toast->>Toast: startTimer() — schedules deleteToast()
Toast->>State: dismiss(id) after duration
State-->>Toaster: toasts signal changes → _expanded recomputed
Note over App,Toaster: User hover / keyboard
App->>Toaster: mouseenter / mousemove → _expanded.set(true)
App->>Toaster: Alt+T hotkey → _expanded.set(true), listRef.focus()
App->>Toaster: Escape → _expanded.set(false)
App->>Toast: pointerdown/move/up → swipe-to-dismiss
Last reviewed commit: 6e8bdc7 |
| } | ||
|
|
||
| if (content.includes('ngx-sonner')) { | ||
| content = content.replace('ngx-sonner', '@spartan-ng/brain/sonner'); |
There was a problem hiding this comment.
String.prototype.replace with a plain string only replaces the first occurrence. A file with both a value import and a type import from ngx-sonner would only have the first one migrated, leaving a broken import behind.
Use replaceAll to ensure all occurrences are replaced:
| content = content.replace('ngx-sonner', '@spartan-ng/brain/sonner'); | |
| content = content.replaceAll('ngx-sonner', '@spartan-ng/brain/sonner'); |
| }); | ||
| }); | ||
|
|
||
| it('should add HlmContextMenuImports import (Standalone)', async () => { |
There was a problem hiding this comment.
The test description is a copy-paste from a different generator and does not describe what this test verifies. It should reflect the actual behavior being tested.
| it('should add HlmContextMenuImports import (Standalone)', async () => { | |
| it('should replace ngx-sonner imports with @spartan-ng/brain/sonner', async () => { |
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
| /** internal **/ | ||
| public readonly direction = this._dir.valueSignal; | ||
|
|
||
| private readonly _listRef = viewChild<ElementRef<HTMLOListElement>>('listRef'); |
There was a problem hiding this comment.
The template uses @for (pos of _possiblePositions()) to render multiple <ol #listRef> elements, one per position. However, viewChild always resolves to the first matching element in template order. When toasts appear at multiple positions, the keyboard handlers (Alt+T hotkey and Escape key) will only affect the first position group.
Consider using viewChildren instead to handle all position groups:
private readonly _listRefs = viewChildren<ElementRef<HTMLOListElement>>('listRef');Then in handleKeydown, iterate over all lists or focus the most relevant one based on current context.
|
@greptileai review again |
|
@greptileai review again |
| @@ -0,0 +1,3 @@ | |||
| export function cn(...classes: (string | undefined)[]) { | |||
There was a problem hiding this comment.
Is there a reason for not using the hlm function?
There was a problem hiding this comment.
I copied over the code from ngx-sonner, which has this cn function. I also thought about using the helm version, but the brain package cannot rely on helm. Helm should consume the brain only. But the brain has a deps on clsx which we could use instead of this custom function. What do you think?
There was a problem hiding this comment.
Ohh I missed that the hlm function is only available in hlm but that totally makes sense. My bad!
Using clsx directly is a great idea when its already available.
But if not I guess its also fine. I just wanted to make sure that this didn't slip your eyes when doing the integration.
There was a problem hiding this comment.
No worries, I totally had the same thought as you to use hlm there! Thanks for the review :) I will go with clsx here!
MerlinMoos
left a comment
There was a problem hiding this comment.
LGTM thanks for moving that to our repo
| /> | ||
| > | ||
| <ng-template #loadingIcon> | ||
| <ng-icon name="lucideLoader2" class="overflow-visible! text-base [&>svg]:motion-safe:animate-spin" /> |
There was a problem hiding this comment.
@ashley-hunter the sonner styles moves the svg to the left or right, but because ng-icon has overflow hidden it looks like its cut of. I set overflow to visible. Do you think that is fine in this case?
|
@MerlinMoos we reference ngx-sonner on the sonner page and about page. Should we keep it or should we update the text? |
I would say we can remove it, now we are maintaining that. We can keep it simple and remove the reference to the ngx-sonner |
PR Checklist
Please check if your PR fulfills the following requirements:
guidelines: https://github.com/spartan-ng/spartan/blob/main/CONTRIBUTING.md#-commit-message-guidelines
PR Type
What kind of change does this PR introduce?
Which package are you modifying?
Primitives
Others
What is the current behavior?
Closes #1240
What is the new behavior?
@spartan-ng/brain/sonnerentry which replaces ngx-sonnerDoes this PR introduce a breaking change?
@spartan-ng/brain/sonnerentry which replaces ngx-sonnerAdded healthcheck and migration to replace
ngx-sonnerwith@spartan-ng/brain/sonnerfor the toast call.Requires two steps:
Other information