From 63fa673709787c5a65941be2afa1cfb7caebeda2 Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Tue, 23 Jul 2024 11:08:18 -0400 Subject: [PATCH] ACS-7384: Break Layout dependency on Material Module (#9937) --- .../components/shell/shell.component.spec.ts | 4 +- lib/core/src/lib/avatar/avatar.component.md | 1 - lib/core/src/lib/core.module.ts | 13 +- .../header/header.component.spec.ts | 9 +- .../header/header.component.stories.ts | 6 +- .../components/header/header.component.ts | 13 +- .../layout-container.component.ts | 40 ++++- .../sidebar-action-menu.component.spec.ts | 12 +- .../sidebar-action-menu.component.ts | 27 +++- .../sidebar-action.component.stories.ts | 6 +- .../sidenav-layout.component.spec.ts | 141 ++++-------------- .../sidenav-layout.component.stories.ts | 6 +- .../sidenav-layout.component.ts | 15 +- .../sidenav-layout-content.directive.ts | 3 +- .../sidenav-layout-header.directive.ts | 3 +- .../sidenav-layout-navigation.directive.ts | 3 +- lib/core/src/lib/layout/helpers/animations.ts | 36 ----- lib/core/src/lib/layout/layout.module.ts | 59 +++----- lib/core/src/lib/material.module.ts | 1 + 19 files changed, 160 insertions(+), 238 deletions(-) delete mode 100644 lib/core/src/lib/layout/helpers/animations.ts diff --git a/lib/core/shell/src/lib/components/shell/shell.component.spec.ts b/lib/core/shell/src/lib/components/shell/shell.component.spec.ts index c309211a95..a5411595ab 100644 --- a/lib/core/shell/src/lib/components/shell/shell.component.spec.ts +++ b/lib/core/shell/src/lib/components/shell/shell.component.spec.ts @@ -17,7 +17,7 @@ import { NO_ERRORS_SCHEMA } from '@angular/core'; import { TestBed, ComponentFixture } from '@angular/core/testing'; -import { AppConfigService, SidenavLayoutModule } from '@alfresco/adf-core'; +import { AppConfigService, LAYOUT_DIRECTIVES } from '@alfresco/adf-core'; import { ShellLayoutComponent } from './shell.component'; import { Router, NavigationStart, RouterModule } from '@angular/router'; import { of, Subject } from 'rxjs'; @@ -62,7 +62,7 @@ describe('AppLayoutComponent', () => { CommonModule, NoopAnimationsModule, HttpClientModule, - SidenavLayoutModule, + ...LAYOUT_DIRECTIVES, ExtensionsModule, RouterModule.forChild([]), TranslateModule.forRoot(), diff --git a/lib/core/src/lib/avatar/avatar.component.md b/lib/core/src/lib/avatar/avatar.component.md index 5a87f7942b..67b035edcc 100644 --- a/lib/core/src/lib/avatar/avatar.component.md +++ b/lib/core/src/lib/avatar/avatar.component.md @@ -75,4 +75,3 @@ The following CSS classes are available for theming: | `--adf-avatar-font-size` | `14px` | The font size of the initials. | | `--adf-avatar-font-weight` | `500` | The font weight of the initials. | | `--adf-avatar-cursor` | `auto` | The cursor style. | -``` diff --git a/lib/core/src/lib/core.module.ts b/lib/core/src/lib/core.module.ts index 84a10c0f02..80c75ec607 100644 --- a/lib/core/src/lib/core.module.ts +++ b/lib/core/src/lib/core.module.ts @@ -19,7 +19,6 @@ import { CommonModule } from '@angular/common'; import { APP_INITIALIZER, NgModule, ModuleWithProviders } from '@angular/core'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { TranslateModule, TranslateLoader, TranslateStore, TranslateService } from '@ngx-translate/core'; - import { MaterialModule } from './material.module'; import { ABOUT_DIRECTIVES } from './about/about.module'; import { CardViewModule } from './card-view/card-view.module'; @@ -32,7 +31,7 @@ import { PaginationModule } from './pagination/pagination.module'; import { ToolbarModule } from './toolbar/toolbar.module'; import { ViewerModule } from './viewer/viewer.module'; import { FormBaseModule } from './form/form-base.module'; -import { SidenavLayoutModule } from './layout/layout.module'; +import { LAYOUT_DIRECTIVES } from './layout/layout.module'; import { CommentsModule } from './comments/comments.module'; import { CommentListModule } from './comments/comment-list/comment-list.module'; import { TemplateModule } from './templates/template.module'; @@ -45,7 +44,6 @@ import { PipeModule } from './pipes/pipe.module'; import { TranslationService } from './translation/translation.service'; import { SortingPickerModule } from './sorting-picker/sorting-picker.module'; -import { IconModule } from './icon/icon.module'; import { TranslateLoaderService } from './translation/translate-loader.service'; import { ExtensionsModule } from '@alfresco/adf-extensions'; import { directionalityConfigFactory } from './common/services/directionality-config-factory'; @@ -67,6 +65,7 @@ import { AdfDateTimeFnsAdapter } from './common/utils/datetime-fns-adapter'; import { AppConfigPipe, StoragePrefixFactory } from './app-config'; import { UnsavedChangesDialogModule } from './dialogs'; import { DynamicChipListModule } from './dynamic-chip-list'; +import { IconComponent } from './icon'; @NgModule({ imports: [ @@ -74,7 +73,7 @@ import { DynamicChipListModule } from './dynamic-chip-list'; ExtensionsModule, ...ABOUT_DIRECTIVES, ViewerModule, - SidenavLayoutModule, + ...LAYOUT_DIRECTIVES, PipeModule, CommonModule, IdentityUserInfoModule, @@ -95,7 +94,7 @@ import { DynamicChipListModule } from './dynamic-chip-list'; InfoDrawerModule, DataTableModule, TemplateModule, - IconModule, + IconComponent, SortingPickerModule, NotificationHistoryModule, SearchTextModule, @@ -111,7 +110,7 @@ import { DynamicChipListModule } from './dynamic-chip-list'; exports: [ ...ABOUT_DIRECTIVES, ViewerModule, - SidenavLayoutModule, + ...LAYOUT_DIRECTIVES, PipeModule, CommonModule, DirectiveModule, @@ -135,7 +134,7 @@ import { DynamicChipListModule } from './dynamic-chip-list'; TranslateModule, TemplateModule, SortingPickerModule, - IconModule, + IconComponent, NotificationHistoryModule, SearchTextModule, BlankPageModule, diff --git a/lib/core/src/lib/layout/components/header/header.component.spec.ts b/lib/core/src/lib/layout/components/header/header.component.spec.ts index cc0a9d3bff..3030653b8c 100644 --- a/lib/core/src/lib/layout/components/header/header.component.spec.ts +++ b/lib/core/src/lib/layout/components/header/header.component.spec.ts @@ -19,9 +19,7 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { HeaderLayoutComponent } from './header.component'; import { CoreTestingModule } from '../../../testing/core.testing.module'; import { By } from '@angular/platform-browser'; -import { SidenavLayoutModule } from '../../layout.module'; import { Component } from '@angular/core'; -import { MaterialModule } from '../../../material.module'; import { HarnessLoader } from '@angular/cdk/testing'; import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed'; import { MatToolbarHarness } from '@angular/material/toolbar/testing'; @@ -34,7 +32,7 @@ describe('HeaderLayoutComponent', () => { describe('Input parameters', () => { beforeEach(() => { TestBed.configureTestingModule({ - imports: [CoreTestingModule] + imports: [CoreTestingModule, HeaderLayoutComponent] }); fixture = TestBed.createComponent(HeaderLayoutComponent); loader = TestbedHarnessEnvironment.loader(fixture); @@ -253,6 +251,8 @@ describe('HeaderLayoutComponent', () => { describe('Template transclusion', () => { @Component({ selector: 'adf-test-layout-header', + standalone: true, + imports: [HeaderLayoutComponent], template: `

Test text

@@ -262,8 +262,7 @@ describe('HeaderLayoutComponent', () => { beforeEach(() => { TestBed.configureTestingModule({ - imports: [CoreTestingModule, SidenavLayoutModule, MaterialModule], - declarations: [HeaderLayoutTesterComponent] + imports: [CoreTestingModule, HeaderLayoutTesterComponent] }); }); diff --git a/lib/core/src/lib/layout/components/header/header.component.stories.ts b/lib/core/src/lib/layout/components/header/header.component.stories.ts index 4d47d189f4..0ec85ac2bc 100644 --- a/lib/core/src/lib/layout/components/header/header.component.stories.ts +++ b/lib/core/src/lib/layout/components/header/header.component.stories.ts @@ -17,7 +17,7 @@ import { applicationConfig, Meta, moduleMetadata, StoryFn } from '@storybook/angular'; import { CoreStoryModule } from '../../../testing/core.story.module'; -import { SidenavLayoutModule } from '../../layout.module'; +import { LAYOUT_DIRECTIVES } from '../../layout.module'; import { HeaderLayoutComponent } from './header.component'; import { RouterTestingModule } from '@angular/router/testing'; import { importProvidersFrom } from '@angular/core'; @@ -27,7 +27,7 @@ export default { title: 'Core/Layout/Header', decorators: [ moduleMetadata({ - imports: [CoreStoryModule, SidenavLayoutModule, RouterTestingModule] + imports: [CoreStoryModule, ...LAYOUT_DIRECTIVES, RouterTestingModule] }), applicationConfig({ providers: [importProvidersFrom(CoreStoryModule)] @@ -131,7 +131,7 @@ export default { } } as Meta; -const template: StoryFn = (args) => ({ +const template: StoryFn = (args) => ({ props: args }); diff --git a/lib/core/src/lib/layout/components/header/header.component.ts b/lib/core/src/lib/layout/components/header/header.component.ts index d52259b122..d6dda30433 100644 --- a/lib/core/src/lib/layout/components/header/header.component.ts +++ b/lib/core/src/lib/layout/components/header/header.component.ts @@ -18,9 +18,17 @@ import { Component, Input, Output, EventEmitter, ViewEncapsulation, OnInit } from '@angular/core'; import { ThemePalette } from '@angular/material/core'; import { AppConfigService } from '../../../app-config/app-config.service'; +import { CommonModule } from '@angular/common'; +import { MatToolbarModule } from '@angular/material/toolbar'; +import { MatButtonModule } from '@angular/material/button'; +import { MatIconModule } from '@angular/material/icon'; +import { RouterModule } from '@angular/router'; +import { TranslateModule } from '@ngx-translate/core'; @Component({ selector: 'adf-layout-header', + standalone: true, + imports: [CommonModule, MatToolbarModule, MatButtonModule, MatIconModule, RouterModule, TranslateModule], templateUrl: './header.component.html', styleUrls: ['./header.component.scss'], encapsulation: ViewEncapsulation.None, @@ -69,10 +77,7 @@ export class HeaderLayoutComponent implements OnInit { /** The side of the page that the drawer is attached to (can be 'start' or 'end') */ @Input() position = 'start'; - constructor( - private appConfigService: AppConfigService - ) { - } + constructor(private appConfigService: AppConfigService) {} toggleMenu() { this.clicked.emit(true); diff --git a/lib/core/src/lib/layout/components/layout-container/layout-container.component.ts b/lib/core/src/lib/layout/components/layout-container/layout-container.component.ts index 8ee3ba870d..f1541f6aa3 100644 --- a/lib/core/src/lib/layout/components/layout-container/layout-container.component.ts +++ b/lib/core/src/lib/layout/components/layout-container/layout-container.component.ts @@ -16,16 +16,44 @@ */ import { Component, Input, ViewChild, OnInit, OnDestroy, ViewEncapsulation, OnChanges, SimpleChanges } from '@angular/core'; -import { MatSidenav } from '@angular/material/sidenav'; -import { sidenavAnimation, contentAnimation } from '../../helpers/animations'; +import { MatSidenav, MatSidenavModule } from '@angular/material/sidenav'; import { Direction } from '@angular/cdk/bidi'; +import { CommonModule } from '@angular/common'; +import { animate, state, style, transition, trigger } from '@angular/animations'; @Component({ selector: 'adf-layout-container', + standalone: true, + imports: [CommonModule, MatSidenavModule], templateUrl: './layout-container.component.html', styleUrls: ['./layout-container.component.scss'], encapsulation: ViewEncapsulation.None, - animations: [sidenavAnimation, contentAnimation] + animations: [ + trigger('sidenavAnimation', [ + state('expanded', style({ width: '{{ width }}px' }), { params: { width: 0 } }), + state('compact', style({ width: '{{ width }}px' }), { params: { width: 0 } }), + transition('compact <=> expanded', animate('0.4s cubic-bezier(0.25, 0.8, 0.25, 1)')) + ]), + trigger('contentAnimationLeft', [ + state( + 'expanded', + style({ + 'margin-left': '{{ margin-left }}px', + 'margin-right': '{{ margin-right }}px' + }), + { params: { 'margin-left': 0, 'margin-right': 0 } } + ), + state( + 'compact', + style({ + 'margin-left': '{{ margin-left }}px', + 'margin-right': '{{ margin-right }}px' + }), + { params: { 'margin-left': 0, 'margin-right': 0 } } + ), + transition('expanded <=> compact', animate('400ms cubic-bezier(0.25, 0.8, 0.25, 1)')) + ]) + ] }) export class LayoutContainerComponent implements OnInit, OnDestroy, OnChanges { @Input() sidenavMin: number; @@ -62,13 +90,13 @@ export class LayoutContainerComponent implements OnInit, OnDestroy, OnChanges { this.CONTENT_STATES.MOBILE = { value: 'expanded' }; - this.mediaQueryList.addListener(this.onMediaQueryChange); + this.mediaQueryList?.addListener(this.onMediaQueryChange); this.updateSidenavState(); } ngOnDestroy(): void { - this.mediaQueryList.removeListener(this.onMediaQueryChange); + this.mediaQueryList?.removeListener(this.onMediaQueryChange); } ngOnChanges(changes: SimpleChanges) { @@ -87,7 +115,7 @@ export class LayoutContainerComponent implements OnInit, OnDestroy, OnChanges { } get isMobileScreenSize(): boolean { - return this.mediaQueryList.matches; + return !!this.mediaQueryList?.matches; } getContentAnimationState(): any { diff --git a/lib/core/src/lib/layout/components/sidebar-action/sidebar-action-menu.component.spec.ts b/lib/core/src/lib/layout/components/sidebar-action/sidebar-action-menu.component.spec.ts index a49fb12302..7899fe650c 100644 --- a/lib/core/src/lib/layout/components/sidebar-action/sidebar-action-menu.component.spec.ts +++ b/lib/core/src/lib/layout/components/sidebar-action/sidebar-action-menu.component.spec.ts @@ -17,10 +17,11 @@ import { Component } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { MaterialModule } from '../../../material.module'; import { SidebarActionMenuComponent } from './sidebar-action-menu.component'; import { CoreTestingModule } from '../../../testing/core.testing.module'; -import { NoopAnimationsModule } from '@angular/platform-browser/animations'; +import { CommonModule } from '@angular/common'; +import { MatIconModule } from '@angular/material/icon'; +import { MatMenuModule } from '@angular/material/menu'; describe('SidebarActionMenuComponent', () => { let element: HTMLElement; @@ -29,7 +30,7 @@ describe('SidebarActionMenuComponent', () => { beforeEach(() => { TestBed.configureTestingModule({ - imports: [CoreTestingModule] + imports: [CoreTestingModule, SidebarActionMenuComponent] }); fixture = TestBed.createComponent(SidebarActionMenuComponent); element = fixture.nativeElement; @@ -51,6 +52,8 @@ describe('SidebarActionMenuComponent', () => { }); @Component({ + standalone: true, + imports: [CommonModule, SidebarActionMenuComponent, MatIconModule, MatMenuModule], template: ` arrow_drop_down @@ -82,8 +85,7 @@ describe('Custom SidebarActionMenuComponent', () => { beforeEach(() => { TestBed.configureTestingModule({ - declarations: [SidebarActionMenuComponent, CustomSidebarActionMenuComponent], - imports: [MaterialModule, NoopAnimationsModule] + imports: [CoreTestingModule, SidebarActionMenuComponent, CustomSidebarActionMenuComponent] }); fixture = TestBed.createComponent(CustomSidebarActionMenuComponent); fixture.detectChanges(); diff --git a/lib/core/src/lib/layout/components/sidebar-action/sidebar-action-menu.component.ts b/lib/core/src/lib/layout/components/sidebar-action/sidebar-action-menu.component.ts index 1fe63f2091..a76bc7af17 100644 --- a/lib/core/src/lib/layout/components/sidebar-action/sidebar-action-menu.component.ts +++ b/lib/core/src/lib/layout/components/sidebar-action/sidebar-action-menu.component.ts @@ -16,18 +16,21 @@ */ import { ChangeDetectionStrategy, Component, Directive, Input, ViewEncapsulation } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { MatButtonModule } from '@angular/material/button'; +import { MatMenuModule } from '@angular/material/menu'; @Component({ selector: 'adf-sidebar-action-menu', + standalone: true, + imports: [CommonModule, MatButtonModule, MatMenuModule], templateUrl: './sidebar-action-menu.component.html', styleUrls: ['./sidebar-action-menu.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, host: { class: 'adf-sidebar-action-menu' } }) - export class SidebarActionMenuComponent { - /** The title of the sidebar action. */ @Input() title: string; @@ -48,6 +51,20 @@ export class SidebarActionMenuComponent { /** * Directive selectors without adf- prefix will be deprecated on 3.0.0 */ -@Directive({ selector: '[adf-sidebar-menu-options], [sidebar-menu-options]' }) export class SidebarMenuDirective {} -@Directive({ selector: '[adf-sidebar-menu-title-icon], [sidebar-menu-title-icon]' }) export class SidebarMenuTitleIconDirective {} -@Directive({ selector: '[adf-sidebar-menu-expand-icon], [sidebar-menu-expand-icon]' }) export class SidebarMenuExpandIconDirective {} +@Directive({ + selector: '[adf-sidebar-menu-options], [sidebar-menu-options]', + standalone: true +}) +export class SidebarMenuDirective {} + +@Directive({ + selector: '[adf-sidebar-menu-title-icon], [sidebar-menu-title-icon]', + standalone: true +}) +export class SidebarMenuTitleIconDirective {} + +@Directive({ + selector: '[adf-sidebar-menu-expand-icon], [sidebar-menu-expand-icon]', + standalone: true +}) +export class SidebarMenuExpandIconDirective {} diff --git a/lib/core/src/lib/layout/components/sidebar-action/sidebar-action.component.stories.ts b/lib/core/src/lib/layout/components/sidebar-action/sidebar-action.component.stories.ts index 97bbf6391a..22cbae793a 100644 --- a/lib/core/src/lib/layout/components/sidebar-action/sidebar-action.component.stories.ts +++ b/lib/core/src/lib/layout/components/sidebar-action/sidebar-action.component.stories.ts @@ -17,7 +17,7 @@ import { applicationConfig, Meta, moduleMetadata, StoryFn } from '@storybook/angular'; import { CoreStoryModule } from '../../../testing/core.story.module'; -import { SidenavLayoutModule } from '../../layout.module'; +import { LAYOUT_DIRECTIVES } from '../../layout.module'; import { SidebarActionMenuComponent } from './sidebar-action-menu.component'; import { importProvidersFrom } from '@angular/core'; @@ -26,7 +26,7 @@ export default { title: 'Core/Layout/Sidebar Action Menu', decorators: [ moduleMetadata({ - imports: [CoreStoryModule, SidenavLayoutModule] + imports: [CoreStoryModule, ...LAYOUT_DIRECTIVES] }), applicationConfig({ providers: [importProvidersFrom(CoreStoryModule)] @@ -71,7 +71,7 @@ export default { } } as Meta; -const template: StoryFn = (args) => ({ +const template: StoryFn = (args) => ({ props: args }); diff --git a/lib/core/src/lib/layout/components/sidenav-layout/sidenav-layout.component.spec.ts b/lib/core/src/lib/layout/components/sidenav-layout/sidenav-layout.component.spec.ts index b879bb3f1a..2eb15a2540 100644 --- a/lib/core/src/lib/layout/components/sidenav-layout/sidenav-layout.component.spec.ts +++ b/lib/core/src/lib/layout/components/sidenav-layout/sidenav-layout.component.spec.ts @@ -18,40 +18,24 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { By } from '@angular/platform-browser'; import { SidenavLayoutComponent } from './sidenav-layout.component'; -import { Component, CUSTOM_ELEMENTS_SCHEMA, Input } from '@angular/core'; -import { LayoutModule, MediaMatcher } from '@angular/cdk/layout'; -import { PlatformModule } from '@angular/cdk/platform'; -import { MaterialModule } from '../../../material.module'; +import { Component } from '@angular/core'; +import { MediaMatcher } from '@angular/cdk/layout'; import { SidenavLayoutContentDirective } from '../../directives/sidenav-layout-content.directive'; import { SidenavLayoutHeaderDirective } from '../../directives/sidenav-layout-header.directive'; import { SidenavLayoutNavigationDirective } from '../../directives/sidenav-layout-navigation.directive'; import { UserPreferencesService } from '../../../common/services/user-preferences.service'; import { CommonModule } from '@angular/common'; -import { Direction } from '@angular/cdk/bidi'; import { of } from 'rxjs'; - -@Component({ - selector: 'adf-layout-container', - template: ` - ` -}) -export class DummyLayoutContainerComponent { - @Input() sidenavMin: number; - @Input() sidenavMax: number; - @Input() position: string; - @Input() direction: Direction; - @Input() mediaQueryList: MediaQueryList; - @Input() hideSidenav: boolean; - @Input() expandedSidenav: boolean; - toggleMenu() {} -} +import { NoopAnimationsModule } from '@angular/platform-browser/animations'; @Component({ selector: 'adf-test-component-for-sidenav', + standalone: true, + imports: [SidenavLayoutComponent, SidenavLayoutHeaderDirective, SidenavLayoutNavigationDirective, SidenavLayoutContentDirective], template: ` -
+
@@ -72,22 +56,14 @@ export class SidenavLayoutTesterComponent {} describe('SidenavLayoutComponent', () => { let fixture: ComponentFixture; - let mediaMatcher: MediaMatcher; let mediaQueryList: any; let component: SidenavLayoutComponent; + let mediaMatcher: MediaMatcher; beforeEach(() => { TestBed.configureTestingModule({ - imports: [CommonModule, PlatformModule, LayoutModule, MaterialModule], - declarations: [ - DummyLayoutContainerComponent, - SidenavLayoutComponent, - SidenavLayoutContentDirective, - SidenavLayoutHeaderDirective, - SidenavLayoutNavigationDirective - ], - providers: [MediaMatcher, { provide: UserPreferencesService, useValue: { select: () => of() } }], - schemas: [CUSTOM_ELEMENTS_SCHEMA] + imports: [CommonModule, NoopAnimationsModule, SidenavLayoutComponent], + providers: [MediaMatcher, { provide: UserPreferencesService, useValue: { select: () => of() } }] }); mediaQueryList = { mediaFn: null, @@ -99,12 +75,7 @@ describe('SidenavLayoutComponent', () => { }; mediaMatcher = TestBed.inject(MediaMatcher); - spyOn(mediaMatcher, 'matchMedia').and.callFake((mediaQuery) => { - mediaQueryList.originalMediaQueryPassed = mediaQuery; - spyOn(mediaQueryList, 'addListener').and.callThrough(); - spyOn(mediaQueryList, 'removeListener').and.stub(); - return mediaQueryList; - }); + spyOn(mediaMatcher, 'matchMedia').and.callFake(() => mediaQueryList); fixture = TestBed.createComponent(SidenavLayoutComponent); component = fixture.componentInstance; @@ -115,40 +86,10 @@ describe('SidenavLayoutComponent', () => { TestBed.resetTestingModule(); }); - describe('General behaviour', () => { - beforeEach(() => fixture.detectChanges()); - - it('should pass through input parameters', () => { - component.sidenavMin = 1; - component.sidenavMax = 2; - component.hideSidenav = true; - component.expandedSidenav = false; - fixture.detectChanges(); - - const layoutContainerComponent = fixture.debugElement.query(By.directive(DummyLayoutContainerComponent)).componentInstance; - - expect(layoutContainerComponent.sidenavMin).toBe(component.sidenavMin); - expect(layoutContainerComponent.sidenavMax).toBe(component.sidenavMax); - expect(layoutContainerComponent.hideSidenav).toBe(component.hideSidenav); - expect(layoutContainerComponent.expandedSidenav).toBe(component.expandedSidenav); - expect(layoutContainerComponent.mediaQueryList.originalMediaQueryPassed).toBe(`(max-width: 600px)`); - }); - - it('addListener of mediaQueryList should have been called', () => { - expect(mediaQueryList.addListener).toHaveBeenCalledTimes(1); - expect(mediaQueryList.addListener).toHaveBeenCalledWith(component.onMediaQueryChange); - }); - - it('addListener of mediaQueryList should have been called', () => { - fixture.destroy(); - - expect(mediaQueryList.removeListener).toHaveBeenCalledTimes(1); - expect(mediaQueryList.removeListener).toHaveBeenCalledWith(component.onMediaQueryChange); - }); - }); - describe('toggleMenu', () => { - beforeEach(() => fixture.detectChanges()); + beforeEach(() => { + component.ngOnInit(); + }); it('should toggle the isMenuMinimized if the mediaQueryList.matches is false (we are on desktop)', () => { mediaQueryList.matches = false; @@ -178,7 +119,7 @@ describe('SidenavLayoutComponent', () => { describe('menuOpenState', () => { it('should be true by default', (done) => { - fixture.detectChanges(); + component.ngOnInit(); component.menuOpenState$.subscribe((value) => { expect(value).toBe(true); @@ -188,7 +129,7 @@ describe('SidenavLayoutComponent', () => { it('should be the same as the expanded Sidenav value by default', (done) => { component.expandedSidenav = false; - fixture.detectChanges(); + component.ngOnInit(); component.menuOpenState$.subscribe((value) => { expect(value).toBe(false); @@ -198,8 +139,8 @@ describe('SidenavLayoutComponent', () => { it('should emit value on toggleMenu action', (done) => { component.expandedSidenav = false; - fixture.detectChanges(); + component.ngOnInit(); component.toggleMenu(); component.menuOpenState$.subscribe((value) => { @@ -213,31 +154,22 @@ describe('SidenavLayoutComponent', () => { describe('Template transclusion', () => { let fixture: ComponentFixture; let mediaMatcher: MediaMatcher; - const mediaQueryList: any = { - matches: false, - addListener: () => {}, - removeListener: () => {} - }; + let mediaQueryList: any; beforeEach(() => { TestBed.configureTestingModule({ - imports: [CommonModule, PlatformModule, LayoutModule, MaterialModule], - declarations: [ - DummyLayoutContainerComponent, - SidenavLayoutTesterComponent, - SidenavLayoutComponent, - SidenavLayoutContentDirective, - SidenavLayoutHeaderDirective, - SidenavLayoutNavigationDirective - ], + imports: [CommonModule, NoopAnimationsModule, SidenavLayoutTesterComponent], providers: [MediaMatcher, { provide: UserPreferencesService, useValue: { select: () => of() } }] }); + + mediaQueryList = { + matches: false, + addListener: () => {}, + removeListener: () => {} + }; + mediaMatcher = TestBed.inject(MediaMatcher); - spyOn(mediaMatcher, 'matchMedia').and.callFake(() => { - spyOn(mediaQueryList, 'addListener').and.stub(); - spyOn(mediaQueryList, 'removeListener').and.stub(); - return mediaQueryList; - }); + spyOn(mediaMatcher, 'matchMedia').and.callFake(() => mediaQueryList); fixture = TestBed.createComponent(SidenavLayoutTesterComponent); fixture.detectChanges(); @@ -267,32 +199,17 @@ describe('Template transclusion', () => { mediaQueryList.matches = false; fixture.detectChanges(); const outerHeaderElement = fixture.debugElement.query(outerHeaderSelector); - const innerHeaderElement = fixture.debugElement.query(innerHeaderSelector); - expect(outerHeaderElement === null).toBe(false, 'Outer header should be shown'); - expect(innerHeaderElement === null).toBe(true, 'Inner header should not be shown'); + expect(outerHeaderElement).toBeDefined(); }); it('should contain the transcluded header template inside of the layout-container', () => { mediaQueryList.matches = true; + fixture.detectChanges(); - const outerHeaderElement = fixture.debugElement.query(outerHeaderSelector); const innerHeaderElement = fixture.debugElement.query(innerHeaderSelector); - expect(outerHeaderElement === null).toBe(true, 'Outer header should not be shown'); - expect(innerHeaderElement === null).toBe(false, 'Inner header should be shown'); - }); - - it(`should call through the layout container's toggleMenu method`, () => { - mediaQueryList.matches = false; - fixture.detectChanges(); - const layoutContainerComponent = fixture.debugElement.query(By.directive(DummyLayoutContainerComponent)).componentInstance; - spyOn(layoutContainerComponent, 'toggleMenu'); - - const outerHeaderElement = fixture.debugElement.query(outerHeaderSelector); - outerHeaderElement.triggerEventHandler('click', {}); - - expect(layoutContainerComponent.toggleMenu).toHaveBeenCalled(); + expect(innerHeaderElement).toBeDefined(); }); }); diff --git a/lib/core/src/lib/layout/components/sidenav-layout/sidenav-layout.component.stories.ts b/lib/core/src/lib/layout/components/sidenav-layout/sidenav-layout.component.stories.ts index 5b058175d0..fbf009d6f9 100644 --- a/lib/core/src/lib/layout/components/sidenav-layout/sidenav-layout.component.stories.ts +++ b/lib/core/src/lib/layout/components/sidenav-layout/sidenav-layout.component.stories.ts @@ -17,7 +17,7 @@ import { applicationConfig, Meta, moduleMetadata, StoryFn } from '@storybook/angular'; import { CoreStoryModule } from '../../../testing/core.story.module'; -import { SidenavLayoutModule } from '../../layout.module'; +import { LAYOUT_DIRECTIVES } from '../../layout.module'; import { SidenavLayoutComponent } from './sidenav-layout.component'; import { MatListModule } from '@angular/material/list'; import { MatIconModule } from '@angular/material/icon'; @@ -29,7 +29,7 @@ export default { title: 'Core/Layout/Sidenav Layout', decorators: [ moduleMetadata({ - imports: [SidenavLayoutModule, RouterTestingModule, MatIconModule, MatListModule] + imports: [CoreStoryModule, ...LAYOUT_DIRECTIVES, RouterTestingModule, MatIconModule, MatListModule] }), applicationConfig({ providers: [importProvidersFrom(CoreStoryModule)] @@ -136,7 +136,7 @@ export default { } } as Meta; -const template: StoryFn = (args) => ({ +const template: StoryFn = (args) => ({ props: args, template: ` ; - public menuOpenState$: Observable; + private menuOpenStateSubject = new BehaviorSubject(false); + public menuOpenState$ = this.menuOpenStateSubject.asObservable(); @ViewChild('container', { static: true }) container: any; @ViewChild('emptyTemplate', { static: true }) emptyTemplate: any; @@ -96,16 +100,13 @@ export class SidenavLayoutComponent implements OnInit, AfterViewInit, OnDestroy private onDestroy$ = new Subject(); - constructor(private mediaMatcher: MediaMatcher, private userPreferencesService: UserPreferencesService ) { + constructor(private mediaMatcher: MediaMatcher, private userPreferencesService: UserPreferencesService) { this.onMediaQueryChange = this.onMediaQueryChange.bind(this); } ngOnInit() { const initialMenuState = !this.expandedSidenav; - this.menuOpenStateSubject = new BehaviorSubject(initialMenuState); - this.menuOpenState$ = this.menuOpenStateSubject.asObservable(); - const stepOver = this.stepOver || SidenavLayoutComponent.STEP_OVER; this.isMenuMinimized = initialMenuState; diff --git a/lib/core/src/lib/layout/directives/sidenav-layout-content.directive.ts b/lib/core/src/lib/layout/directives/sidenav-layout-content.directive.ts index 07a80e153c..ff07959f6b 100644 --- a/lib/core/src/lib/layout/directives/sidenav-layout-content.directive.ts +++ b/lib/core/src/lib/layout/directives/sidenav-layout-content.directive.ts @@ -18,7 +18,8 @@ import { ContentChild, Directive, TemplateRef } from '@angular/core'; @Directive({ - selector: 'adf-sidenav-layout-content' + selector: 'adf-sidenav-layout-content', + standalone: true }) export class SidenavLayoutContentDirective { @ContentChild(TemplateRef) diff --git a/lib/core/src/lib/layout/directives/sidenav-layout-header.directive.ts b/lib/core/src/lib/layout/directives/sidenav-layout-header.directive.ts index f594f48e09..2a096bbc8b 100644 --- a/lib/core/src/lib/layout/directives/sidenav-layout-header.directive.ts +++ b/lib/core/src/lib/layout/directives/sidenav-layout-header.directive.ts @@ -18,7 +18,8 @@ import { ContentChild, Directive, TemplateRef } from '@angular/core'; @Directive({ - selector: 'adf-sidenav-layout-header' + selector: 'adf-sidenav-layout-header', + standalone: true }) export class SidenavLayoutHeaderDirective { @ContentChild(TemplateRef) diff --git a/lib/core/src/lib/layout/directives/sidenav-layout-navigation.directive.ts b/lib/core/src/lib/layout/directives/sidenav-layout-navigation.directive.ts index 11133a2e81..3d83d60508 100644 --- a/lib/core/src/lib/layout/directives/sidenav-layout-navigation.directive.ts +++ b/lib/core/src/lib/layout/directives/sidenav-layout-navigation.directive.ts @@ -18,7 +18,8 @@ import { ContentChild, Directive, TemplateRef } from '@angular/core'; @Directive({ - selector: 'adf-sidenav-layout-navigation' + selector: 'adf-sidenav-layout-navigation', + standalone: true }) export class SidenavLayoutNavigationDirective { @ContentChild(TemplateRef) diff --git a/lib/core/src/lib/layout/helpers/animations.ts b/lib/core/src/lib/layout/helpers/animations.ts deleted file mode 100644 index c0ff9e873a..0000000000 --- a/lib/core/src/lib/layout/helpers/animations.ts +++ /dev/null @@ -1,36 +0,0 @@ -/*! - * @license - * Copyright © 2005-2024 Hyland Software, Inc. and its affiliates. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import { trigger, transition, animate, style, state, AnimationTriggerMetadata } from '@angular/animations'; - -export const sidenavAnimation: AnimationTriggerMetadata = trigger('sidenavAnimation', [ - state('expanded', style({ width: '{{ width }}px' }), { params : { width: 0 } }), - state('compact', style({ width: '{{ width }}px' }), { params : { width: 0 } }), - transition('compact <=> expanded', animate('0.4s cubic-bezier(0.25, 0.8, 0.25, 1)')) -]); - -export const contentAnimation: AnimationTriggerMetadata = trigger('contentAnimationLeft', [ - state('expanded', style({ - 'margin-left': '{{ margin-left }}px', - 'margin-right': '{{ margin-right }}px' - }), { params: { 'margin-left': 0, 'margin-right': 0 } }), - state('compact', style({ - 'margin-left': '{{ margin-left }}px', - 'margin-right': '{{ margin-right }}px' - }), { params: { 'margin-left': 0, 'margin-right': 0 } }), - transition('expanded <=> compact', animate('400ms cubic-bezier(0.25, 0.8, 0.25, 1)')) -]); diff --git a/lib/core/src/lib/layout/layout.module.ts b/lib/core/src/lib/layout/layout.module.ts index 441e697e73..f95c66e75d 100644 --- a/lib/core/src/lib/layout/layout.module.ts +++ b/lib/core/src/lib/layout/layout.module.ts @@ -15,49 +15,36 @@ * limitations under the License. */ -import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; -import { RouterModule } from '@angular/router'; -import { MaterialModule } from '../material.module'; import { SidenavLayoutContentDirective } from './directives/sidenav-layout-content.directive'; import { SidenavLayoutHeaderDirective } from './directives/sidenav-layout-header.directive'; import { SidenavLayoutNavigationDirective } from './directives/sidenav-layout-navigation.directive'; import { SidenavLayoutComponent } from './components/sidenav-layout/sidenav-layout.component'; import { LayoutContainerComponent } from './components/layout-container/layout-container.component'; -import { SidebarActionMenuComponent, SidebarMenuDirective, - SidebarMenuExpandIconDirective, SidebarMenuTitleIconDirective } from './components/sidebar-action/sidebar-action-menu.component'; +import { + SidebarActionMenuComponent, + SidebarMenuDirective, + SidebarMenuExpandIconDirective, + SidebarMenuTitleIconDirective +} from './components/sidebar-action/sidebar-action-menu.component'; import { HeaderLayoutComponent } from './components/header/header.component'; -import { TranslateModule } from '@ngx-translate/core'; + +export const LAYOUT_DIRECTIVES = [ + SidenavLayoutHeaderDirective, + SidenavLayoutContentDirective, + SidenavLayoutNavigationDirective, + SidebarMenuDirective, + SidebarMenuExpandIconDirective, + SidebarMenuTitleIconDirective, + HeaderLayoutComponent, + SidebarActionMenuComponent, + LayoutContainerComponent, + SidenavLayoutComponent +] as const; + +/** @deprecated Use `...LAYOUT_DIRECTIVES` instead, or import standalone components directly */ @NgModule({ - imports: [ - CommonModule, - MaterialModule, - RouterModule, - TranslateModule - ], - exports: [ - SidenavLayoutHeaderDirective, - SidenavLayoutContentDirective, - SidenavLayoutNavigationDirective, - SidenavLayoutComponent, - LayoutContainerComponent, - SidebarActionMenuComponent, - SidebarMenuDirective, - SidebarMenuExpandIconDirective, - SidebarMenuTitleIconDirective, - HeaderLayoutComponent - ], - declarations: [ - SidenavLayoutHeaderDirective, - SidenavLayoutContentDirective, - SidenavLayoutNavigationDirective, - SidenavLayoutComponent, - LayoutContainerComponent, - SidebarActionMenuComponent, - SidebarMenuDirective, - SidebarMenuExpandIconDirective, - SidebarMenuTitleIconDirective, - HeaderLayoutComponent - ] + imports: [...LAYOUT_DIRECTIVES], + exports: [...LAYOUT_DIRECTIVES] }) export class SidenavLayoutModule {} diff --git a/lib/core/src/lib/material.module.ts b/lib/core/src/lib/material.module.ts index baac1b37ef..443a5be539 100644 --- a/lib/core/src/lib/material.module.ts +++ b/lib/core/src/lib/material.module.ts @@ -44,6 +44,7 @@ import { MatTabsModule } from '@angular/material/tabs'; import { MatToolbarModule } from '@angular/material/toolbar'; import { MatBadgeModule } from '@angular/material/badge'; +/** @deprecated This module is deprecated and will be removed in a future release. */ @NgModule({ imports: [ MatAutocompleteModule,