feat(core): add overflow shadow directives (#DS-3478)#1633
Conversation
|
Visit the preview URL for this PR (updated for commit ce64e39): https://koobiq-next--prs-1633-ov2qkikl.web.app (expires Sat, 20 Jun 2026 15:59:06 GMT) 🔥 via Firebase Hosting GitHub Action 🌎 Sign: c9e37e518febda70d0317d07e8ceb35ac43c534c |
🚨 E2E tests failedReview the report for details. 💡 Comment |
|
🚨 Failed to update snapshots. |
🚨 E2E tests failedReview the report for details. 💡 Comment |
|
/approve-snapshots |
|
🔄 Updating snapshots. |
|
✅ Snapshots updated! |
There was a problem hiding this comment.
Pull request overview
This PR introduces a shared overflow shadow mechanism in @koobiq/components/core (container + top/bottom marker directives + optional scroll-source DI token), and migrates multiple scrollable components (sidepanel, popover, modal, notification-center, content-panel) to use it instead of bespoke overflow checks and CSS class toggles.
Changes:
- Added
KbqOverflowShadowContainer,KbqOverflowShadowTop,KbqOverflowShadowBottom,KbqOverflowShadowState, andKBQ_OVERFLOW_SHADOW_SOURCEto core. - Updated
KbqScrollbarto implement/provideKbqOverflowShadowSourceso overflow shadows can follow the real scroll viewport. - Reworked component styles/templates/e2e tests to rely on
box-shadow(via the directives) rather than overflow CSS classes.
Reviewed changes
Copilot reviewed 33 out of 34 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| tools/public_api_guard/components/sidepanel.api.md | Public API snapshot updates for sidepanel overflow-shadow integration/types. |
| tools/public_api_guard/components/scrollbar.api.md | Public API snapshot updates for KbqScrollbar implementing KbqOverflowShadowSource. |
| tools/public_api_guard/components/popover.api.md | Public API snapshot updates for popover removing old overflow fields and exposing overflow container ref. |
| tools/public_api_guard/components/notification-center.api.md | Public API snapshot updates reflecting removal of old overflow fields. |
| tools/public_api_guard/components/modal.api.md | Public API snapshot updates reflecting removal of old overflow fields/methods. |
| tools/public_api_guard/components/core.api.md | Public API snapshot adds overflow-shadow directives/interfaces/token. |
| tools/public_api_guard/components/content-panel.api.md | Public API snapshot updates for content-panel overflow state and container ref. |
| packages/e2e/utils/overflow-shadow.ts | New Playwright helper to assert overflow shadow presence via computed box-shadow. |
| packages/e2e/utils/index.ts | Re-export the new overflow shadow e2e helper. |
| packages/components/sidepanel/sidepanel.scss | Removes class-based overflow shadow styling (now applied inline by directives/bindings). |
| packages/components/sidepanel/sidepanel-ref.ts | Types bodyOverflow as KbqOverflowShadowState. |
| packages/components/sidepanel/sidepanel-directives.ts | Uses KbqOverflowShadowContainer + signal/effect wiring; header/footer now bind inline box-shadow. |
| packages/components/sidepanel/e2e.playwright-spec.ts | Updates assertions to check computed shadow rather than CSS classes. |
| packages/components/scrollbar/scrollbar.component.ts | Provides KBQ_OVERFLOW_SHADOW_SOURCE and adds getScrollElement() for overflow-shadow container. |
| packages/components/popover/popover.scss | Simplifies header/footer overflow styling (inline shadow now). |
| packages/components/popover/popover.component.ts | Removes manual overflow tracking logic; uses overflow-shadow directives instead. |
| packages/components/popover/popover.component.html | Adds kbqOverflowShadowContainer + top/bottom marker directives; triggers manual checkOverflow() on content mutation. |
| packages/components/popover/e2e.playwright-spec.ts | Updates assertions to check computed shadow rather than CSS classes. |
| packages/components/notification-center/notification-center.ts | Removes manual overflow tracking; imports overflow-shadow directives. |
| packages/components/notification-center/notification-center.scss | Removes class-based overflow shadow styling (inline shadow now). |
| packages/components/notification-center/notification-center.html | Adds overflow-shadow container + markers; customizes bottom shadow token via [shadow]. |
| packages/components/modal/modal.component.ts | Removes manual overflow tracking logic; imports overflow-shadow directives. |
| packages/components/modal/modal.component.html | Adds overflow-shadow container + top/bottom markers around modal body. |
| packages/components/modal/e2e.playwright-spec.ts | Updates assertions to check computed shadow rather than CSS classes. |
| packages/components/modal/_modal-theme.scss | Removes class-based overflow shadow styling (inline shadow now). |
| packages/components/core/public-api.ts | Exports the new overflow-shadow entrypoint. |
| packages/components/core/overflow-shadow/public-api.ts | New barrel for overflow-shadow public surface. |
| packages/components/core/overflow-shadow/overflow-shadow.ts | New overflow shadow directives + token/source abstraction. |
| packages/components/core/overflow-shadow/overflow-shadow.spec.ts | Unit tests for container + marker directives and external scroll source behavior. |
| packages/components/core/overflow-shadow/index.ts | New index barrel for overflow-shadow. |
| packages/components/content-panel/e2e.playwright-spec.ts | Updates assertions to check computed shadow rather than CSS classes. |
| packages/components/content-panel/content-panel.ts | Replaces class toggling logic with computed overflow state from KbqOverflowShadowContainer. |
| packages/components/content-panel/content-panel.scss | Removes class-based overflow shadow styling (inline shadow now). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| constructor() { | ||
| afterNextRender(() => { | ||
| this.checkOverflow(); | ||
| }); | ||
| } | ||
|
|
||
| /** @docs-private */ | ||
| protected checkOverflow() { | ||
| const nativeElement = this.elementRef.nativeElement; | ||
|
|
||
| if (!isHtmlElement(nativeElement)) return; | ||
|
|
||
| const { scrollTop, offsetHeight, scrollHeight } = nativeElement; | ||
|
|
||
| this.sidepanelRef.bodyOverflow.set({ | ||
| top: scrollTop > 0, | ||
| bottom: scrollTop + offsetHeight < scrollHeight | ||
| }); | ||
| effect(() => this.sidepanelRef.bodyOverflow.set(this.overflowContainer.overflow())); | ||
| } |
| * In addition to scroll events, the directive observes scroll source size changes via | ||
| * `ResizeObserver` — this covers cases where layout changes without a scroll (modal open | ||
| * animation, dynamic content load, window resize). |
| this.destroyRef.onDestroy(() => this.resizeObserver?.disconnect()); | ||
| } | ||
|
|
||
| ngOnInit(): void { |
There was a problem hiding this comment.
лучше использовать afterNextRender чтобы это точно работало в ssr
There was a problem hiding this comment.
в конструкторе afterNextRender, а тут только подписки на события..
|
|
||
| if (!source) return; | ||
|
|
||
| this.resizeObserver = new ResizeObserver(() => this.checkOverflow()); |
There was a problem hiding this comment.
у cdk есть SharedResizeObserver, кажется что лучше его использовать, он удобен тем что возвращает готовый Observable
import { SharedResizeObserver } from '@angular/cdk/observers/private';| export class KbqContentPanelFooter {} | ||
| export class KbqContentPanelFooter { | ||
| /** @docs-private */ | ||
| protected readonly contentPanel = inject(KbqContentPanel, { optional: true }); |
There was a problem hiding this comment.
KbqContentPanelFooter и KbqContentPanelHeader не могут быть использованы без KbqContentPanel
| protected readonly contentPanel = inject(KbqContentPanel, { optional: true }); | |
| protected readonly contentPanel = inject(KbqContentPanel); |
|
тень в шапке еще есть у code-block: |
No description provided.