angular / components

Component infrastructure and Material Design components for Angular
https://material.angular.io
MIT License
24.32k stars 6.72k forks source link

Component request: Banner #11452

Open thw0rted opened 6 years ago

thw0rted commented 6 years ago

Bug, feature request, or proposal:

Feature request

What is the use-case or motivation for changing an existing behavior?

Material spec has been updated to add a Banner component, and I don't think anything in the current library fits the use cases laid out there. It's pretty similar mechanically to a Snackbar but movement is handled differently.

djtahl commented 5 years ago

Hello, any inputs on this feature dev ? We will need it as well.

Best Regards

renearaujo commented 5 years ago

news about this feature ???

pedrohills commented 5 years ago

news?

joeson1 commented 5 years ago

news?

thw0rted commented 5 years ago

Just as an experiment, I called snackbar.open with a custom panelClass: "snackbar-banner", which I put in my top level CSS as

snack-bar-container.mat-snack-bar-container.mat-snack-bar-center.snackbar-banner {
    width: 100vw;
    max-width: 100vw;
    border-radius: 0;
    padding: 8px 8px 8px 24px; /* Per Banner spec */
}
snack-bar-container.snackbar-banner simple-snack-bar {
    align-items: flex-end;
}
.snackbar-banner .mat-simple-snackbar-action {
    margin: 0 0 0 90px;
}

I believe this basically converts the snackbar styling to the Banner spec. You can just pass duration: 0 to keep it from automatically closing. This allows you to show a simple Banner with a single action. You could pretty easily use a custom component for the contents to support icons and a second action, to provide the full capabilities per the spec.

The bad news is that I can't figure out how to tell the Snackbar service to attach its Overlay to my main content component. As it stands, snackbars (and thus, this hacky snackbar-based "banner") always appear over top of my sidenav and can't push content down the way a banner is supposed to. If I could have it use the same overlay that my sidenav does (div.mat-drawer-backdrop) or just give it a parent component instance as its OverlayContainer, it would at least be closer to on-spec behavior for my use case. I'm doing more research into how to make this happen but I don't want to spend a ton of time on it.

magnusbakken commented 5 years ago

I realize it's impossible to implement every part of the Material spec for Angular, but I have to say I find it confusing that Angular Material has a "bottom sheet" component but no banner component, considering I don't think I've ever seen a website use a bottom sheet on desktop, whereas banners are pretty common on the web.

I'll try to implement a banner component myself, but I hope this one is on the Angular team's radar.

thw0rted commented 5 years ago

I had to do it myself, in the end. I made a service, and an Outlet component that takes the service through injection and registers itself. The service exposes a method to show the component, with a message and some action button labels, and emits an event when one of the button is clicked. It was pretty straightforward, though I did wind up adding queueing logic to make sure that all calls to the service's open method will be shown eventually.

I found it easier to manually place a single instance of the Outlet component in my app -- in the right place, to make sure it opens over pannable content but under the sidebar / app toolbar -- than to try to make some kind of globally consistent logic for automatically inserting an overlay in the right place. I'm not sure that kind of design would fly in a library like this.

andrantis commented 5 years ago

@thw0rted Do you happen to have a code example? I'm trying to implement the same component

thw0rted commented 5 years ago

It's not perfect, and I had to remove one or two references to other classes in my project, but this is what I'm using now. You just place one <banner-outlet></banner-outlet> in your app wherever the banner should be displayed. Based on the Material guidelines, I'm pretty confident that there's no way to automatically determine the right place for the outlet, so this seemed like the least-worst way to handle it. Mine is styled as position: relative; flex-grow: 0;.

ETA: to open the banner you inject the BannerService and call open("Banner message", ["OK", "Cancel", "Whatever"]) which returns an Observable that emits the array index corresponding to the clicked button. You don't have to call the init method, it's called from the component constructor; note that it will throw if you try to have more than one banner outlet per application.

owenmecham commented 5 years ago

@thw0rted do you have a complete example that's open source? I understand if what you've done is closed source, but I'd love to see a stackblitz if you have one.

thw0rted commented 5 years ago

It's part of a closed source project but I went ahead and pasted the relevant stuff into the Material2 doc example for Buttons. StackBlitz

This doesn't have all the styling in place but you get the general idea. There's no magic for positioning the resulting banner but the CSS needed isn't too complex.

stevebor1 commented 2 years ago

Another deficiency in support for the 'material' specification. Can we get an update on when this will be supported out-of-the-box?