Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Repo info
Activity
  • Mar 05 20:20
    smalluban closed #144
  • Feb 19 11:26
    smalluban synchronize #136
  • Feb 17 08:57
    smalluban synchronize #136
  • Feb 17 08:57
    smalluban synchronize #136
  • Feb 17 08:55
    smalluban synchronize #136
  • Feb 11 13:37
    smalluban synchronize #136
  • Feb 11 13:17
    smalluban synchronize #136
  • Feb 10 07:04
    smalluban closed #145
  • Feb 09 21:53
    smalluban labeled #145
  • Feb 09 21:53
    smalluban labeled #145
  • Feb 09 20:07
    benash opened #145
  • Feb 08 14:00
    smalluban synchronize #136
  • Feb 03 20:58
    smalluban synchronize #136
  • Feb 03 20:54
    smalluban closed #143
  • Feb 03 20:51
    smalluban synchronize #143
  • Feb 03 20:36
    smalluban synchronize #143
  • Feb 03 20:17
    smalluban synchronize #143
  • Feb 03 19:59
    smalluban synchronize #136
  • Feb 03 19:57
    smalluban synchronize #143
  • Feb 03 19:43
    smalluban synchronize #136
Georges Gomes
@georges-gomes
Updated with latest hybrids đź‘Ť
Dominik Lubański
@smalluban
Thanks for the notice :)
Tov Are Jacobsen
@tovare

Is there an easy way to use code instead of templates? Like this subtemplate

const tableRows = function (d) {
  return html`
    ${d.map(function (row) {
      return html`<tr>
        ${row.map(function ({ id, day, date, visible,selected }) {
          return html` <td>
            ${visible && html`<t-day id="${id}" day=${day} selected=${selected}></t-day>`}
          </td>`;
        })}
      </tr>`;
    })}
  `;
};

The code above is called by a parent template with this line in it, where d is a promise returned by a library used to access indexeddb.

 ${html.resolve(d.then((res) => tableRows(res)))}

I use lit highlighting in VS-coode, but still I had to try and fail a bit before getting it to work :-). Full source here: https://github.com/tovare/days

Jay Leimer
@CodingJinxx
hi, im new to hybrids and was wondering if there is a way to get syntax highlighting for the html inside js using vscode. thanks
Tov Are Jacobsen
@tovare
@CodingJinxx yess, pretty ure I installed lit-html to enable that. Looks good :-)
Jay Leimer
@CodingJinxx
thank you so much, installing it right now
looks great thx
Tov Are Jacobsen
@tovare
np :)
Jay Leimer
@CodingJinxx
is there webpack support for hybrids?
Tov Are Jacobsen
@tovare
you can use webpack. I use parcel myself and I don´t really do anything special. Just point it at the entry-point. .
Jay Leimer
@CodingJinxx
There are a few problems when using webpack got them fixed though. Documentation is pretty good in regards to that
Jay Leimer
@CodingJinxx
Do u use bootstrap with hybrid js?
Tov Are Jacobsen
@tovare
no, I have used various techniques such as tailwind. But, I found it cleanest to use plain css when using shadowdom.
The solution with tailwind, since it is a huge framework I needed to configure tailwind to purge unuset css. I use a link to the stylesheet in the component. If you look at https://alleyoop.no/ and inspect the <admin-app> you can se it. Tailwind got down to 4.6kb and loads once despite being referenced multiple times. (And I use some firebase.css as well).
Tov Are Jacobsen
@tovare
An inconvenient thing with Parcel is that it doesn´t parse the stylesheet link in the template string, so I need to give the css target a name and use that. Another downside is that the component will then depend on the stylesheet.
Jay Leimer
@CodingJinxx
so u can link inside an element?
why not use the .style() method as described in the docs
Tov Are Jacobsen
@tovare
yes, you can either write a <style> inside the template, or you can have the styles in a string and add them using .style()
Jay Leimer
@CodingJinxx
the .style() seems to work with css classes for me
Tov Are Jacobsen
@tovare
I use it inside <style> because I like it.
Jay Leimer
@CodingJinxx
id probably use that aswell but i have to use bootstrap for my assignment
Tov Are Jacobsen
@tovare
ok :)
Jay Leimer
@CodingJinxx
sorry, .style() seems to not work with css classes for me
have u used it?
Tov Are Jacobsen
@tovare
I tried to once, I think it worked as I remember as just an alternative to having a <style> in your template.
Not sure if it does any neat magic.
Jay Leimer
@CodingJinxx
hm, ok. Im not sure if im doing something wrong if it doesnt work with classes well. I submitted an issue on the repo
i just tried your method of linking and it works
are there any drawbacks of linking inside the component
Tov Are Jacobsen
@tovare
Yes, yor component depends on the external style. Alternatives that could be considered is disabling shadw dom, if you don´t want any of that encapsulation.
Jay Leimer
@CodingJinxx
Hm ok im fine that. Think im just going to use your method, thx
Dominik Lubański
@smalluban
@tovare About your question: "Is there an easy way to use code instead of templates?" above.. If your data is promise-based, you can create a store model, with the source from your data. Then you can use store model in the template synchronously, and render it only when it is ready:
const Model = {
  id: true,
  day: "",
  date: "",
  visible: false,
  selected: false,
  [store.connect]: {
    list: () => yourIndexDBPromiseApi(id),
  },
};

const MyElement = {
  models: store([Model]),
  render: ({ models}) => html`
    ${store.ready(models) && tableRows(models)}
  `,
}
Tov Are Jacobsen
@tovare
oh, thanks for that @smalluban. I actually thought about the store, but I got a bit confused on exactly how.
Fran
@Paker30
Hi people, I have a doubt which is driven me crazy (and I'm not sure how to do it); I want to run a piece of JS when the web component is added to the DOM, how should I do it? Should I do it with the connect property of a descriptor?
Tov Are Jacobsen
@tovare
I think there are several ways, but once i needed to use the Google Maps API and I just implemented the render : () initMap. , where initmap(host,target) does everything and renders to target.
Fran
@Paker30
@tovare if I understood well, render would return initMap, wouldn't it?
Tov Are Jacobsen
@tovare
yes, so in my case function initmap(map,target) would add a div and configure google maps. I had render and run some javascript at the same time.
What to you need to do when the component is added?
Fran
@Paker30
I'm making a picture gallery, I've figured out a solution (but I'm not sure it's the "cleanest" and "best" way), here is the piece of code
import { html, property } from 'hybrids';

const parseJSON = (value = []) => typeof value === 'string' ? JSON.parse(value) : value;

const nextImage = (host) => {
  host.current = host.current + 1 > host.content.length - 1 ? 0 : host.current + 1;
};

const inlineStyles = `
.figure {
  object-fit: cover;
  width: 100%;
  height: 100%;
}

.ui-slideshow {
  overflow: hidden;
}

.slide {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  overflow: hidden;
  transition: opacity ease-out 0.3s;
}

.show {
  opacity: 1;
  z-index: 10;
}

.hide {
  opacity: 0;
  z-index: 9;
}
`;

export const slider = {
  content: property(parseJSON),
  timeout: 5000,
  current: {
    get: (_, lastValue) => lastValue || 0,
    set: (_, value) => value || 0,
    observe: (host) => {
      setTimeout(nextImage, host.timeout, host);
    },
  },
  render: ({ content, current }) => html`
    <div class="ui-slideshow">
      ${content.map(({ src }, index) => html`
        <div class="slide ${current === index ? 'show' : 'hide'}">
          <figure>
              <img class="figure" src="${src}">
          </figure>
        </div>
      `.style(inlineStyles))}
    </div>
  `,
};
Tov Are Jacobsen
@tovare
Interessting. I haven´t done anything like it. Makes sense though.
1 reply
Dominik Lubański
@smalluban

Hi @Paker30! I have to say that your solution looks clever :) However, the observe method is called as an effect of property change, so it won't change timeout delay when host.timeout changes. It's worth thinking about where that side effect fits best. In this case, it is related to timeout and sets current property. Because of that, I would create an interval, which uses the timeout property and sets the current value.

const slider = {
  ..., 
  timeout: 5000,
  interval: {
    get: (host, lastValue) => {
      if (lastValue) clearInterval(lastValue);
      return setInterval(nextImage, host.timeout, host);
    }, 
    connect: (host, key): {
      return () => host[key] && clearInterval(host[key]);
    },
    observe() {},
  }, 
  render: ...,
};

As you can see above example also clears the interval when leaving the DOM. As everything in the library is lazy, the interval property is not required by render method, so without an empty observe method, it's get method won't be called.

It is also a good candidate for a factory. Instead of setting directly interval method, the above property could be closed in the function like intervalFactory(fn, timeoutKey) like this

const slider = 
  timeout: 5000,
  interval: intervalFactory(nextImage, “timeout”), 
  current:..., 
  ...,
};
1 reply
Benjamin Nash
@benash
Hi everyone, I'm wondering how to pass an object from a parent to a child element. I see from the docs that it won't work to do that through an attribute, but I don't see how it can be done otherwise.
Benjamin Nash
@benash
The closest thing I see in the docs is in the Attribute Fallback section where it shows: myElement.someValue = 1000;. But in the parent, I don't have a reference to the child like that, as I'm doing something like:
render: ({ myObj }) => html`
    <my-child></my-child>
`
Benjamin Nash
@benash

Ah, I got it. I was confused about the distinction between attributes and properties and just needed to use the non-dashed name to use it as a property. So instead of this:

<my-child my-details=${myObj}></my-child>

I did this:

<my-child myDetails=${myObj}></my-child>
Dominik Lubański
@smalluban
That's right! Template engine supports properties (case-sensitive), so usually it's better to use them over the attributes. The dashed version is a fallback of the property factory, mainly for outside usage of the template engine (as the attributes are not case-sensitive).
Benjamin Nash
@benash

@smalluban In #145, you helped me come up with a way to add a .style('@import "custom.css"'), and while that mechanism is working fine, I'm noticing some FOUC from the browser when rendering the child element. I assume this is more of a Web Components/browser issue, but I was wondering if you had any pointers.

I can see from the Network devtools tab that, when the child is rendered, all the CSS is re-retrieved, and I'm wondering if that's part of the problem. (I thought it was odd that the parent custom element didn't require a network request, but it's included in the html file.) So to summarize I have:

<!-- No FOUC, single network retrieval of CSS -->
. . .
 <link href="custom.css" rel="stylesheet" />
. . .
<my-parent></my-parent>
const myParent = {
  showChild: false,
  render: ({ showChild }) => html`
    ${showChild && <my-child></my-child>}
  `.style('@import "custom.css"')
}

// When child is shown, I see FOUC and an additional uncached request of all the CSS
const myChild = {
  render: () => html`
    . . .
  `.style('@import "custom.css"')
}

Any ideas?

Benjamin Nash
@benash
(Also, that line for the parent component should be this):
    ${showChild && html`<my-child></my-child>`}
Benjamin Nash
@benash
I'm thinking that the ShadowDOM is making CSS too difficult, so I'm inclined to give { shadowRoot: false } a shot. It looks like slot functionality is lost is that case, but I'm wondering if there are any workarounds to achieve nested/transcluded templates with without ShadowDOM? Maybe through some manual query selectors or something? I'd like achieve what React.children basically provides, e.g.:
<my-parent>
  <div class="custom-stuff-here">
    . . .
  </div>
</my-parent>
Dominik Lubański
@smalluban
@benash In Constructed StyleSheets @import statement was deprecated. I think it might be related to your problem. Generally, it's better to write styles in place, and only those, which are used by the current element (I suppose, that your custom.css has styles for all your elements). Mentioned constructed stylesheets were created for better performance, so they will work even better than your way (as you still include style tag to each instance of the element). It will be easier to help you if you build a live code - you can use codesandbox examples from the docs to get started with it.
You can avoid @import statement by using <link rel="stylesheet" href="custom.css"> in the template (however, it is not supported by the ShadyCSS polyfill).