Mercurial
comparison design_system/test/storybook_test.js @ 253:fdf3816959cb
[ui] Add Sonner-like notification stack
Co-authored-by: Copilot <[email protected]>
| author | MrJuneJune <me@mrjunejune.com> |
|---|---|
| date | Tue, 04 Aug 2026 12:21:19 -0700 |
| parents | 7a7581f040e8 |
| children | 2b6e732087ff |
comparison
equal
deleted
inserted
replaced
| 252:7a7581f040e8 | 253:fdf3816959cb |
|---|---|
| 436 assert.deepEqual(bounded, { accepted: 25, size: 23, visible: 3 }); | 436 assert.deepEqual(bounded, { accepted: 25, size: 23, visible: 3 }); |
| 437 assert.equal( | 437 assert.equal( |
| 438 await notificationScope.locator('article').count(), | 438 await notificationScope.locator('article').count(), |
| 439 3, | 439 3, |
| 440 ); | 440 ); |
| 441 await page.waitForFunction(() => | |
| 442 [...document.querySelectorAll( | |
| 443 'zen-notifications article', | |
| 444 )].some(article => article.dataset.depth === '2') | |
| 445 ); | |
| 446 const collapsedStack = await notificationScope.locator( | |
| 447 '[data-zen-notification-stack]', | |
| 448 ).evaluate(stack => { | |
| 449 const articles = [...stack.querySelectorAll('article')]; | |
| 450 return { | |
| 451 depths: articles.map(article => article.dataset.depth), | |
| 452 height: stack.getBoundingClientRect().height, | |
| 453 positions: articles.map(article => | |
| 454 getComputedStyle(article).position | |
| 455 ), | |
| 456 transforms: articles.map(article => | |
| 457 getComputedStyle(article).transform | |
| 458 ), | |
| 459 }; | |
| 460 }); | |
| 461 assert.deepEqual(collapsedStack.depths, ['2', '1', '0']); | |
| 462 assert.deepEqual( | |
| 463 collapsedStack.positions, | |
| 464 ['absolute', 'absolute', 'absolute'], | |
| 465 ); | |
| 466 await notificationScope.locator('article').last().hover(); | |
| 467 await page.waitForTimeout(300); | |
| 468 const expandedStack = await notificationScope.locator( | |
| 469 '[data-zen-notification-stack]', | |
| 470 ).evaluate(stack => ({ | |
| 471 height: stack.getBoundingClientRect().height, | |
| 472 rects: [...stack.querySelectorAll('article')].map(article => { | |
| 473 const bounds = article.getBoundingClientRect(); | |
| 474 return { | |
| 475 bottom: bounds.bottom, | |
| 476 left: bounds.left, | |
| 477 right: bounds.right, | |
| 478 top: bounds.top, | |
| 479 }; | |
| 480 }), | |
| 481 tops: [...stack.querySelectorAll('article')].map( | |
| 482 article => Math.round(article.getBoundingClientRect().top), | |
| 483 ), | |
| 484 transforms: [...stack.querySelectorAll('article')].map( | |
| 485 article => getComputedStyle(article).transform, | |
| 486 ), | |
| 487 })); | |
| 488 assert.ok(expandedStack.height > collapsedStack.height); | |
| 489 assert.equal(new Set(expandedStack.tops).size, 3); | |
| 490 const expandedGaps = [ | |
| 491 expandedStack.rects[1].top - expandedStack.rects[0].bottom, | |
| 492 expandedStack.rects[2].top - expandedStack.rects[1].bottom, | |
| 493 ]; | |
| 494 for (const gap of expandedGaps) { | |
| 495 assert.ok(gap >= 10 && gap <= 14, JSON.stringify(expandedGaps)); | |
| 496 } | |
| 497 assert.notDeepEqual( | |
| 498 expandedStack.transforms, | |
| 499 collapsedStack.transforms, | |
| 500 ); | |
| 501 const gapX = | |
| 502 (expandedStack.rects[0].left + expandedStack.rects[0].right) / 2; | |
| 503 const gapY = | |
| 504 (expandedStack.rects[0].bottom + expandedStack.rects[1].top) / 2; | |
| 505 await page.mouse.move(gapX, gapY); | |
| 506 await page.waitForTimeout(100); | |
| 507 const gapState = await notificationScope.locator( | |
| 508 '[data-zen-notification-stack]', | |
| 509 ).evaluate(stack => ({ | |
| 510 height: stack.getBoundingClientRect().height, | |
| 511 hovered: stack.matches(':hover'), | |
| 512 })); | |
| 513 assert.equal(gapState.hovered, true); | |
| 514 assert.ok(gapState.height >= expandedStack.height - 1); | |
| 515 await page.mouse.move(0, 0); | |
| 441 | 516 |
| 442 const actionScope = await page.evaluate(() => { | 517 const actionScope = await page.evaluate(() => { |
| 443 const scope = document.createElement('zen-notifications'); | 518 const scope = document.createElement('zen-notifications'); |
| 444 scope.id = 'action-scope'; | 519 scope.id = 'action-scope'; |
| 445 const source = document.createElement('button'); | 520 const source = document.createElement('button'); |
| 520 composed: false, | 595 composed: false, |
| 521 detail: { version: 1, id: 'action' }, | 596 detail: { version: 1, id: 'action' }, |
| 522 }, | 597 }, |
| 523 )); | 598 )); |
| 524 }); | 599 }); |
| 525 assert.equal(await actionArticle.count(), 0); | 600 await actionArticle.waitFor({ state: 'detached' }); |
| 526 | 601 |
| 527 await page.evaluate(() => { | 602 await page.evaluate(() => { |
| 528 const scope = document.createElement('zen-notifications'); | 603 const scope = document.createElement('zen-notifications'); |
| 529 scope.id = 'announcement-scope'; | 604 scope.id = 'announcement-scope'; |
| 530 const source = document.createElement('button'); | 605 const source = document.createElement('button'); |