Native web component: style host differently depending on slotted content - web-component

Say I have a native web component with an HTML template like so:
<wc-grid>
<slot></slot>
</wc-grid>
Now I have the following two use cases (one with a text input the other with a radio):
<wc-grid> <input type="text"> </wc-grid>
<wc-grid> <input type="radio"> </wc-grid>
Is it possible to style the <wc-grid> differently depending on when whether it contains a text or radio type input?
e.g. If has() was around it would be something like this: (trying to change whether the grid is vertical or horizontal depending on the widget inside of it):
:host:has(> input[type="text"]) { flex-direction: row; }
:host:has(> input[type="radio"]) { flex-direction: column; }
Research has lead me to learn about :has(), but that has not landed yet.
And as far as I can tell :host-context would not help either as it looks up, not down, besides its poor support.

The easiest and cleanest implementation of such a problem I can solve by using a named slot.
example of web component
class MyComp extends HTMLElement {
constructor() {
super();
const shadow = this.attachShadow({ mode: 'open' });
this.shadowRoot.innerHTML = `
<style>
.flex {
display: flex;
justify-content: space-between;
}
.row {
flex-direction: row;
background: red;
}
.column {
flex-direction: column;
background: green;
}
</style>
<div>
<div class="flex row"><slot name="row"></slot></div>
<div class="flex column"><slot name="column"></slot></div>
</div>`;
}
}
customElements.define('my-comp', MyComp);
usage in HTML
<my-comp>
<div slot="row">This is row 1</div>
<div slot="row">this is row 2</div>
<div slot="row">This is row 3</div>
</my-comp>
<my-comp>
<div slot="column">This is colum 1</div>
<div slot="column">This is colum 2</div>
<div slot="column">This is colum 3</div>
</my-comp>
example screenshot
Another good way to have a attribute which can add respective classes to root elements to modify css based on it

Related

how to Fix Display Message in multiple line

.abc{
white-space:pre-wrap;
}
<label >student</Label>:<span class="abc">He is a good boy </br> he is also kind'</span>
Say I am displaying the message in Angular application in 2 line Like this:
LabelStudent:Ram is a good boy,
he is also kind.
I want the second line message i.e. He is also kind, should be displayed just below the first message and not beneath the label
This can easily be achieved with flexbox. I have reproduced a demo over here.
HTML:
<div class="container">
<label>student :</label>
<div class="information">
<span>He is a good boy</span>
<span> he is also kind'</span>
</div>
</div>
CSS:
.container {
display: flex;
flex-direction: row;
}
.information {
display: flex;
flex-direction: column;
}

create table using weex

I need to build an app that has a table. I tried using html <table> tags to build a table. Even though it shows the table as i require when i run using npm run serve when i build an apk and run it on my android device the output is messed up.
Does anyone know how to build a table in weex.
And does anyone have any good documentations or tutorials regarding weex.
thanks
It looks like HTML but Weex does not render actual HTML on native. The <div>s you write are Weex components that get translated to the target platform.
So while running on a browser may render tables, until Weex has a default <table> component, it won't render on native as you expect.
You can create your own component and lay it out using flexbox.
As others have commented, Weex doesn't use HTML but rather has a XML syntax which looks alike. So you need to implement something akin to a using only <div>s. I had to do exacly that, so I might as well post it here.
<template>
<div class="table">
<div class="row heading">
<div class="cell headingColumn">Table</div>
<div class="cell">2</div>
<div class="cell">3</div>
</div>
<div class="row">
<div class="cell headingColumn">Row 1</div>
<div class="cell">2</div>
<div class="cell">3</div>
</div>
<div class="row">
<div class="cell headingColumn">Row 2</div>
<div class="cell">2</div>
<div class="cell">3</div>
</div>
</div>
</template>
<style scoped>
.table {
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: stretch;
}
.row {
display: flex;
flex-direction: row;
justify-content: space-between;
height: 60px;
}
.cell {
display: flex;
justify-content: center;
align-items: center;
flex-grow: 1;
/*width: 100px;*/
padding: 20px;
}
.heading {
background-color: grey;
font-weight: bold;
}
.headingColumn {
width: 120px;
}
</style>
Copy and paste it into dotwe.org and it will work and be rendered as expected in Android & the web.
As a side note, if you specify fixed widths (or min-widths) for the columns, styling will be much easier. That's why I've specified a .headingColumn class and there's a commented width:100px value inside .cell.
BTW, you might need to edit the and add a tag inside them with the text content you want.

Flexbox toolbar with a ton of nesting

I am trying to build a flexbox type container with a search and filters and buttons. I am having trouble getting the desired behaviour. The toolbar-container class is the main flex container, which holds search-bar and filter-group as the top-level flex-items. I am getting confused as to how approach setting up filter-group as a nested flex-container to which the desired behavior is to push the buttons to the end of the row (far right, equivalent to float: right) and give the filters the largest amount of space, wrapping below as the window resizes but maintaining the positions of search and buttons on either side. I have tried using the below css the seperate the fitlers from the buttons but there filters and buttons stay grouped together like this:
search-bar-filters-buttons---------------------------------------------------
Below is desired layout, with only the filters wrapping to the space below when the space decreases.
search-bar-filters-----------------------------------------------------buttons
<div class="toolbar-container">
<div class="search-bar"></div>
<div class="filter-group">
<div class="filters"></div>
<div class="buttons"></div>
</div>
</div>
.toolbar-container {
display: flex;
}
.search {
}
.filter-group {
display: flex;
justify-content: space-between;
}
.filters {
flex-wrap: wrap;
}
.buttons {
}
You need to add flex: 1 for you .filter-group to take all remaining space. Demo:
.toolbar-container {
display: flex;
}
.filter-group {
display: flex;
flex: 1; /* new */
justify-content: space-between;
}
.filters {
flex-wrap: wrap;
}
<div class="toolbar-container">
<div class="search-bar">Search bar</div>
<div class="filter-group">
<div class="filters">Filters</div>
<div class="buttons">Buttons</div>
</div>
</div>

How can I shrink a 4-column flexbox layout to 2 columns in Polymer?

I have a dashboard I made with Polymer and the flex layout, however there's some issues. Basically I need it to be 4 columns long, but when the screen shrinks I need it to go to 2 columns, and then finally to 1 column. (basically laptop - 4, tablet - 2, phone - 1). Right now it goes 4 to 3 to 2 to 1. How can I achieve the 4 to 2 to 1?
Here's what I currently have:
<style>
#container {
display: flex;
-webkit-flex-wrap: wrap; /* Safari */
flex-wrap: wrap;
-webkit-flex-direction: row; /* Safari */
flex-direction: row;
-webkit-justify-content: space-between; /* Safari */
justify-content: space-between;
}
</style>
and
<div id="container">
<paper-card heading="ep-gw-ops-node1">
<div class="card-content">
<paper-card heading="Temperature" id="temperature" class="blue" style="width: 275px; margin: 2px">
<div class="card-content">
<div>
<h3 id="tv_temperature" style="color:#fff; text-align: center"> 0 </h3>
</div>
<div style="" id="chart_div_0"></div>
</div>
</paper-card>
...
...
...
</paper-card>
</div>
I've attached a basic wireframe of what I am trying to accomplish.
If there is a better way to do it without paper-cards I'm more than open to suggestions.
Note* the last column will be lowered so the 'node 1' header will stretch all the way across and the columns will be the same size.
I do something like this
<dom-module id="my-element">
<template>
<style>
.grouph[wide-layout] {
#apply(--layout-horizontal);
#apply(--layout-wrap);
#apply(--layout-center-justified);
}
.grouph:not([wide-layout]). .groupv {
#apply(--layout-vertical);
}
</style>
<iron-media-query query="(min-width: 600px)" query-matches="{{wide}}"></iron-media-query>
<div class="grouph" wide-layout$="[[wide]]">
<paper-card>...</paper-card>
<paper-card>...</paper-card>
</div>
</template>
<script>
Polymer ({
is: 'my-element'
});
</dom-module>
This doesn't match your case exactly but the principal is the same. Use a media query to define a boolean property (in my case wide) that can be set for one of your two cases and unset for the other.
Use wide-layour$="[[wide]]" on an element that you want to alter dependant on the width.
Use CSS with a selector of [wide-layout] or :not([wide-layout]) to define how a container lays out its children.
You can do it at multiple levels to get whatever re-arrangement you want.

Use display: flex as the 'opened' state instead of display: block with fancy-box 2

I want to use display: flex as the 'opened' state instead of display: block with fancy-box 2.
Currently the element gets display: block; inline.
I'm trying to track down where to change it, but maybe I just need to nest a div in the pop-up. Has anyone done this before?
markup
<div class='thing-that-triggers'>
<span>thing</span>
<div class='pop-up'>
<div class='text'>
text
</div>
<div class='image'>
image
</div>
</div>
</div>
<div class='thing-that-triggers'>...</div>
<div class='thing-that-triggers'>...</div>
styles
.pop-up
display: flex // setup
flex-direction: column
display: none // hide it for fancybox
.text
width: 100%
.image
display: none // hide on small screen
#media $break-point-2
flex-direction: row
align-items: center
.block
split-in(2)
.text
flex-center-child()
.recipe
// centered
.image
display: block // show second panel
jQuery
$('.thing-that-triggers').fancybox({...});
You have 3 choices if fancybox doesn't give you any options to change it.
Change it directly in the source code (not the best approach).
Nest another div so that the added display doesn't affect yours (as you mentioned).
Override it yourself in the beforeShow callback. You'll need to use jQuery each to get a reference to the current .pop-up and a closure to keep the reference and use it later:
function handleDisplay($popup) {
var closure = function() { $popup.css('display', 'flex'); };
return closure;
}
$('.thing-that-triggers').each(function() {
var displayHandler = handleDisplay($(this).children('.pop-up'));
$(this).fancybox({
beforeShow: displayHandler
}
});
See the documentation for other available callbacks.
Just add an inner div and set the flex stuff on it - and leave the outer div for fancybox.
This IS an answer, but I'd much prefer not to change my markup + I think this question is going to get asked a lot in the near future. So, a JS solution is what'll I'll mark as the best answer.
markup
<div class='thing-that-triggers'>
<span>thing</span>
<div class='pop-up'>
<div class='inner'>
<div class='text'>
text
</div>
<div class='image'>
image
</div>
</div>
</div>
</div>
styles
.pop-up
display: none
.inner
display: flex // setup
flex-direction: column
.text
width: 100%
.image
display: none // hide on small screen
#media $break-point-2
.inner
flex-direction: row
align-items: center
.block
split-in(2)
.text
flex-center-child()
.recipe
// centered
.image
display: block // show second panel

Resources