How can I extend or overwrite component decorators in Angular Material 2? - angular-material2

I am nesting a <mat-nav-list> inside of a <mat-expansion-panel> component. At runtime, Angular Material 2 is creating html, in my specific case:
<div class="mat-expansion-panel-body">...</div>
Which also is getting styles assigned to it. I am unable to overwrite these styles using the component style sheet like I normally would.
Looking through the source, I am seeing this:
/node_modules/#angular/material/esm2015/expansion.js
MatExpansionPanel.decorators = [
{ type: Component, args: [{styles: [".mat-expansion-panel{transition:box-shadow 280ms cubic-bezier(.4,0,.2,1);box-sizing:content-box;display:block;margin:0;transition:margin 225ms cubic-bezier(.4,0,.2,1)}.mat-expansion-panel:not([class*=mat-elevation-z]){box-shadow:0 3px 1px -2px rgba(0,0,0,.2),0 2px 2px 0 rgba(0,0,0,.14),0 1px 5px 0 rgba(0,0,0,.12)}.mat-expansion-panel-content{overflow:hidden}.mat-expansion-panel-body{margin:0 24px 16px;overflow:auto}
...
I'm sure this isn't the exact code that is creating the component, but it does contain the css I would like to override:
...
.mat-expansion-panel-body{margin:0 24px 16px;overflow:auto}
...
How can I modify the decorator to remove the margin?
Here is what my .ts file looks like so far:
#Component({
selector: 'my-selector',
templateUrl: './my-selector.component.html',
styleUrls: ['./my-selector.component.scss']
})
export class MyComponent implements OnInit, OnDestroy {...}
Thank you for any suggestions!

I wish I could take credit for the solution that seems to work, but here is a thread with a similar problem.
I was able to remove the margin like this:
my-template.component.html
<mat-expansion-panel *ngFor="let foo of bar" class="my-sidenav">
<mat-expansion-panel-header>
...
</mat-expansion-panel-header>
<mat-nav-list>
<mat-list-item>...</mat-list-item>
</mat-nav-list>
</mat-expansion-panel>
my-component.component.scss
/deep/ .my-sidenav {
.mat-expansion-panel-body {
margin: 0;
}
}

Related

Angular primeng tabview style defined in one component is affecting the style in another component

I am not an expert with styling and encapsulation.
Need help with fixing style issue. Style used in a component is overriding the global style.
i am using primeng tabview component in component A for eg:
ComponentA.html:
<p-tabView styleClass="tab-view"></p-tabview>
ComponentA.scss:
.p-tabview {
padding: 0rem;
li.p-highlight span {
font-weight: $semibold-font-weight;
}
}
But this padding is applied to all primeng tabview setting in global style
Component B:
<p-tabView class="tab-view-scheduler"></p-tabview>
global style scss:
.p-tabview {
#media screen and (min-width: $tablet-break) {
padding: 0 4rem 2rem; //this is getting overridden
font-size: $desktop-small-font-size;
}
}

Custom postion for v-dialog Vuetify

I need to open a v-dialog of certain width and height on right bottom side of my page, but, I can't understand how to do.
V-dialog always are centered on the page, I searched on official doc, tried use CSS, but wasn't able
any ideas?
Note: Other provided solutions are not satisfying because they mess up transitions, or we can't use scoped-styles, or they suggest using !important etc.
Solution
Add arbitrary content-class class to your dialog:
<v-dialog content-class="my-custom-dialog">
Then we can use scoped styles:
<style scoped>
>>> .my-custom-dialog {
align-self: flex-end;
}
</style>
This feature is being looked at but for now you can use edit the CSS class yourself. For instance, to get it to display in the bottom right use:
.v-dialog {
position: absolute;
bottom: 0;
right: 0;
}
style="position: absolute; bottom: 0;"
On the first v-card inside the v-dialog
Add this to your styles:
.v-dialog:not(.v-dialog--fullscreen) {
bottom: 0 !important;
right: 0 !important;
position: absolute !important;
}
For anyone new coming to this post, its worth checking out VBottomSheet for this functionality.
https://vuetifyjs.com/en/components/bottom-sheets
Came to this page looking for answers but none of the above suggestions worked for me with Vuetiful 2.2.11. Ended up doing this:
.v-dialog__content {
align-items: flex-end;
justify-content: flex-end;
}
Using Vue 3 and Vuetify 3.0 alpha this solution allows to use the dialog with current mouse position. v-dialog is inside the v-overlay-container which is outside the v-app element hierarchy so the global CSS file must be used. In Vuetify 2.x v-overlay-container is inside the v-app hierarchy.
I guess a solution with scoped CSS and usage of deep() is possible in this case.
CSS variables are defined and a rule for v-overlay__content which is responsible for the position is added :
:root {
--dialog-xpos: 22px;
--dialog-ypos: 55px;
}
.v-overlay__content {
top: var(--dialog-ypos);
left: var(--dialog-xpos);
}
The click event handler modifies the variables before dialog activation :
function onClick(ev: MouseEvent) {
document.documentElement.style.setProperty('--dialog-xpos', ev.clientX.toString() + 'px');
document.documentElement.style.setProperty('--dialog-ypos', ev.clientY.toString() + 'px');
showDialog.value = true;
}

Angular Animation: Page transition without style `position: absolute`?

Purpose: I want to add a nice transition effect when click from one page to another
I tried lots of solution online, including:
Angular 2 — Animating Router transitions
Page transition animations with Angular 2.0 router and component interface promises
....
one thing in common is that they all have style like position: absolute or position: fixed added, which breaks my existing app layout.
I remember when I using Angular 1, there's no need to add position: absolute to <div ui-view><div>
Is it possible in Angular 2 or 4?
You can add the absolute positioning exclusively to the leaving animation.
transition(':enter', [
style({transform: 'translateX(100%)'}),
animate('0.3s ease-in-out', style({transform: 'translateX(0%)'}))
]),
transition(':leave', [
style({transform: 'translateX(0%)', position: 'absolute', left: 0, right: 0, top: 0}),
animate('0.3s ease-in-out', style({transform: 'translateX(-100%)'}))
])
So only the leaving route is positioned absolutely, while the entering route is positioned staticly.
If it doesn't work, make sure that your router-outlet is wrapped by position: relative
<div style="position: relative;">
<router-outlet></router-outlet>
</div>
And that your route-components have display: block
#Component({
styles:[':host {display: block;}']
Talking about Angular version 4.3.x. Reading the router documentation, they explain how to add animation between routes. Here is a resume for the lazy ones (including myself).
You want to import animations libraries from #angular/core (and not #angular/animations):
import {
AnimationEntryMetadata,
animate,
state,
style,
trigger
} from '#angular/core';
export const fadeInAnimation: AnimationEntryMetadata = trigger('fadeInAnimation', [
transition(':enter', [
style({
opacity: 0,
transform: 'translateY(20px)'
}),
animate(
'.3s',
style({
opacity: 1,
transform: 'translateY(0)'
})
)
])
]);
Then in your component, use the HostBinding decorator in order to specify the component's layout css properties (you don't need use a fixed or absolute position):
import { Component, OnInit, HostBinding } from '#angular/core';
import { fadeInAnimation } from './../animations/fadein';
#Component({
animations: [fadeInAnimation],
selector: 'app-posts',
templateUrl: './posts.component.html'
})
export class DemandsComponent implements OnInit {
#HostBinding('#fadeInAnimation') fadeInAnimation = true;
#HostBinding('style.display') display = 'block';
#HostBinding('style.position') position = 'relative';
// Rest of the code
}
Adding this to each routed component can be cumbersome. The documentation suggest, and I quote:
Applying route animations to individual components works for a simple demo, but in a real life app, it is better to animate routes based on route paths.
This article from Matias Niemelä can help https://www.yearofmoo.com/2017/06/new-wave-of-animation-features.html#routable-animations

Is it possible to select the parent of the parent with SCSS

I have a SCSS file with the following
input{
&[type="text"],
&[type="search"]{
margin: 0 0.5em;
}
}
which works as expected. I would also like a textarea to have the same CSS. Does SCSS have a selector that will allow me to place textarea with the
&[type="text"], &[type="search"]
in the SCSS file but not place the 'input' parent before textarea. The output I'm trying to achieve is as follows
input[type="text"], input[type="search"], textarea {
margin: 0 0.5em;
}
I know I could do this with a mixin however I was thought this feature was added to SCSS.
#extend works really great in these situations. % is good as a way of implying that this class will only ever be extended.
%baseClass{
margin: 0 0.5em;
}
input{
&[type="text"],
&[type="search"]{
#extend %baseClass;
}
}
textarea{
#extend %baseClass;
}
No, you cannot. For a lengthy selector, The best you can do is set it as a variable and use that.
$form-input-text: unquote('input[type="text"], input[type="password"], input[type="search"], input[type="email"], input[type="tel"], input[type="url"]');
#{$form-input-text} {
// styles;
}
#{$form-input-text}, textarea {
// styles
}

Sass: Create mixin for input fields

I'm new to Sass so I need help with the creation of a mixing for my input fields.
However, if anyone knows of an already made mixin for this or if Compass has one that accomplishes this, please let me (us) know.
I currently have the following CSS rules in my .scss file:
input[type="text"],
input[type="password"],
input[type="email"],
input[type="search"],
input[type="url"],
textarea,
select { ... }
input[type="text"]:hover,
input[type="text"]:focus,
input[type="password"]:hover,
input[type="password"]:focus,
input[type="email"]:hover,
input[type="email"]:focus,
input[type="search"]:hover,
input[type="search"]:focus,
input[type="url"]:hover,
input[type="url"]:focus,
textarea:hover,
textarea:focus,
select:hover,
select:focus { ... }
Now, as we know HTML5 provides a nice new set of input types, but right now I don't need to add input types like date, month or week, that's why I don't have them listed "yet".
So in the case I need to add them in the future, I'll update that list you see above.
However, my problem is that I feel I'm repeating myself all over here, plus, the work of selecting items, copying, pasting and editing every time for every new input type I add to the list is just plain dumb and I almost sure Sass' mixins can be of help with this. The problem is that creating a mixin for this is honestly very confusing to me.
I've looked around here and the web for something similar but haven't been able to find anything.
Any help with this is greatly appreciated.
Ok, I eventually found the Sass mixing library Bourbon.
They have an 'add-on' for HTML5 input types (here's a link to the .scss file they created), but it doesn't have the :hover or :focus pseudo elements. So I added them.
I honestly don't know if what I did is the best way to write this mixin, but the thing works marvelously:
//************************************************************************//
// Generate a variable ($all-text-inputs) with a list of all html5
// input types that have a text-based input, excluding textarea.
// http://diveintohtml5.org/forms.html
//************************************************************************//
$inputs-list: 'input[type="email"]',
'input[type="number"]',
'input[type="password"]',
'input[type="search"]',
'input[type="tel"]',
'input[type="text"]',
'input[type="url"]',
// Webkit & Gecko may change the display of these in the future
'input[type="color"]',
'input[type="date"]',
'input[type="datetime"]',
'input[type="datetime-local"]',
'input[type="month"]',
'input[type="time"]',
'input[type="week"]';
$unquoted-inputs-list: ();
#each $input-type in $inputs-list {
$unquoted-inputs-list: append($unquoted-inputs-list, unquote($input-type), comma);
}
$all-text-inputs: $unquoted-inputs-list;
// You must use interpolation on the variable:
// #{$all-text-inputs}
//************************************************************************//
// #{$all-text-inputs}, textarea {
// border: 1px solid red;
// }
// :hover and :focus pseudo elements
// Added by Ricardo Zea
// http://ricardozea.net
// #ricardozea
// Tracking: http://stackoverflow.com/questions/13180807/sass-create-mixin-for-input-fields
$inputs-list-hf:'input[type="email"]:hover',
'input[type="number"]:hover',
'input[type="password"]:hover',
'input[type="search"]:hover',
'input[type="tel"]:hover',
'input[type="text"]:hover',
'input[type="url"]:hover',
'input[type="color"]:hover',
'input[type="date"]:hover',
'input[type="datetime"]:hover',
'input[type="datetime-local"]:hover',
'input[type="month"]:hover',
'input[type="time"]:hover',
'input[type="week"]:hover',
'input[type="email"]:focus',
'input[type="number"]:focus',
'input[type="password"]:focus',
'input[type="search"]:focus',
'input[type="tel"]:focus',
'input[type="text"]:focus',
'input[type="url"]:focus',
'input[type="color"]:focus',
'input[type="date"]:focus',
'input[type="datetime"]:focus',
'input[type="datetime-local"]:focus',
'input[type="month"]:focus',
'input[type="time"]:focus',
'input[type="week"]:focus';
$unquoted-inputs-list-hf: ();
#each $input-type-hf in $inputs-list-hf {
$unquoted-inputs-list-hf: append($unquoted-inputs-list-hf, unquote($input-type-hf), comma);
}
$all-text-inputs-hf: $unquoted-inputs-list-hf;
// You must use interpolation on the variable:
// #{$all-text-inputs-hf}
//************************************************************************//
// #{$all-text-inputs-hf}, textarea {
// border: 1px solid red;
// }
As you can see I copied and pasted the original mixing and added the prefix -hf and of course the :hover and :focus to the new rules.
And in my .scss file I added this #import:
#import "html5-input-types"; (no need for the underline _ or file extension .scss)
And in the 'Forms' section of my .scss file I added these rules:
/*Normal state*/
#{$all-text-inputs},
textarea,
select { ... }
/*:hover and :focus states*/
#{$all-text-inputs-hf},
textarea:hover,
textarea:focus,
select:hover,
select:focus { ... }
I know I have textarea and select outside the mixin file (html5-input-types.scss), not sure yet if I'm including them in it or not, gotta think about it.
Anyway, this worked for me pretty well and although I will still need to update the html5-input-types.scss if anything changes in the future, at least I'm handling these input fields way more efficiently than before.
Hopefully what I did here helps someone else.
And if any of you has a suggestion to improve the mixin, by all means let me (us) know.
Thanks.
In case anyone comes across this for the same reason I did. Why not let SASS do the work?
CodePen
$form-background: #f8f8f8;
$form-color: #000;
$form-border: 1px solid lighten($form-color, 50%);
$form-focus-background: darken($form-background, 10%);
$form-focus-color: #999;
$form-focus-border: 1px solid $form-color;
%input-styles {
width: 15em;
min-height: 30px;
margin: 0 0 15px 15px;
background: $form-background;
color: $form-color;
border: $form-border;
transition: .2s ease-in-out;
transition-property: color, background-color, border;
}
%input-styles--focus {
background-color: $form-focus-background;
color: $form-focus-color;
border: $form-focus-border;
}
#mixin input-styles($styles, $focus_styles) {
$types: 'email', 'number', 'radio', 'password', 'search', 'tel',
'text', 'url', 'color', 'date', 'datetime',
'datetime-local', 'month', 'time', 'week';
#each $type in $types {
input[type="#{$type}"] {
#extend #{$styles};
&:focus {
#extend #{$focus_styles};
}
}
}
select,
textarea {
#extend #{$styles};
&:focus {
#extend #{$focus_styles};
}
}
}
#include input-styles('%input-styles', '%input-styles--focus');

Resources