lit / lit-element

LEGACY REPO. This repository is for maintenance of the legacy LitElement library. The LitElement base class is now part of the Lit library, which is developed in the lit monorepo.
https://lit-element.polymer-project.org
BSD 3-Clause "New" or "Revised" License
4.49k stars 318 forks source link

How to display `super.styles` and check the inherited properties #1105

Closed GHNewbiee closed 3 years ago

GHNewbiee commented 3 years ago

Description

firstElement.js

import { LitElement, customElement, html } from 'lit-element';

import firstStyles from './firstStyles.lit.css';

@customElement('first-element')
export class FirstElement extends LitElement {
  static get styles() {
    return [
      firstStyles,
    ]
  }

  render() {
    return html`
      <div>${firstStyles}</div>       <!-- Succeeded -->
      <slot></slot>
    `;
  }
}

secondElement.js

import { customElement, html } from 'lit-element';
import { FirstElement } from './firstElement';

import secondStyles from './secondStyles.lit.css';

@customElement('second-element')
export class SecondElement extends FirstElement {
  static get styles() {
    return [
      super.styles,
      secondStyles,
    ]
  }

  render() {
    return html`
      <div>${super.styles}</div>       <!-- Fails -->
      <div>${secondStyles}</div>
      <slot></slot>
    `;
  }
}

Acceptance criteria

What the card must do in order to accept it as complete. Acceptance Criteria must be concrete or measurable.

At least <div>${super.styles}</div> should display the inherited styles.

Note: I am aware that I can manually set, one-by-one, all the properties (inherited and local) and print them altogether.

sorvell commented 3 years ago

I think we'll need more information here.

First, styles should be put in static styles and not in style elements in the render method. While this is supported, it is discouraged in favor of using static styles, and you certainly should not do both.

Next, there is not yet platform support for directly importing css so it's unclear what this does import secondStyles from './secondStyles.lit.css'; in your setup. If it's importing a string, then to use it in static styles you'll need to use unsafeCSS like this:

// in the first element
static styles = [ css`${unsafeCSS(firstStyles)}`];

// in the second element
static styles = [ super.styles, css`${unsafeCSS(secondStyles)}`];

That should just work and you shouldn't need to include the <style> elements in render.

GHNewbiee commented 3 years ago

I am aware of the first one and considering that very much! My only intention and wish is to display the content of the super.styles on the browser, and this can only be done in the render method, can't it?

As regards the second one, there is really a new kind on the block who develops reboost, a dev server which supports LitElement, and css import through Lit CSS Plugin. So, importing a *.lit.css file and using its content after internally being transformed via css`` tag function is pretty straight and very easy.

In Style Editor I can see both style sheets; so, importing and parsing both lit.css files is successful, but I cannot display super.styles since <div>${super.styles}</div> fails. Any suggestion? TALIA!

kevinpschaaf commented 3 years ago

If I understand correctly, you're just wanting to display the CSS text of the styles used in the element in a <div>, just for debug purposes, correct?

Note that styles is a static property on the class, so you don't want super.styles, you want this.constructor.styles. Note that that will run the getter which in your element has both super.styles and secondStyles, so just one expression in the template should be able to show all of it.

However, note that you need to use Array.flat to turn this.constructor.styles into a flattened array, because lit-html needs a flat array of renderable objects in the expression in the div (and [super.styles, secondStyles] would result in a nested array, since super.styles is an array). Nested arrays are supported in styles, but for rendering text in the template, lit-html needs a flattened array.

So I believe this is what you want:

<div>${Array.flat(this.constructor.styles, Infinity)}</div>

And note that although you're technically passing an array of CSSResult objects to an expression in the template, which normally wouldn't do anything good, CSSResult implements a toString method that returns the CSS text, so it's actually renderable by lit as text, which sounds like what you want.

GHNewbiee commented 3 years ago

If I understand correctly, you're just wanting to display the CSS text of the styles used in the element in a <div>, just for debug purposes, correct?

That's correct!

Note that styles is a static property on the class, so you don't want super.styles, you want this.constructor.styles. Note that that will run the getter which in your element has both super.styles and secondStyles, so just one expression in the template should be able to show all of it.

It's OK, no problem at all!

However, note that you need to use Array.flat to turn this.constructor.styles into a flattened array, because lit-html needs a flat array of renderable objects in the expression in the div (and [super.styles, secondStyles] would result in a nested array, since super.styles is an array). Nested arrays are supported in styles, but for rendering text in the template, lit-html needs a flattened array.

<div>${this.constructor.styles}</div> does work fine for me! I get the CSS text on the browser!

So I believe this is what you want:

<div>${Array.flat(this.constructor.styles, Infinity)}</div>

<div>${this.constructor.styles.flat(Infinity)}</div> has also worked fine for me!

And note that although you're technically passing an array of CSSResult objects to an expression in the template, which normally wouldn't do anything good, CSSResult implements a toString method that returns the CSS text, so it's actually renderable by lit as text, which sounds like what you want.

So, in case of <div>${???.toString()}</div> or let text = ???.toString(), what is the ????

What about the inherited properties (see issue)?

TAL for your time and help!

GHNewbiee commented 3 years ago

... And note that although you're technically passing an array of CSSResult objects to an expression in the template, which normally wouldn't do anything good, ...

I think you are not very correct here. Let's get the following imaginary scenario: I create a component which draws, for example, a vector (velocity, pressure or forces) field. There are three areas displayed;

In addition, taking back or giving me back in the simplest form the data/information I have entered (properties or css) is a kind of receipt or proof of operation! Look at your laptop or pc. You plug it and immediately, before switching it on, a led gets lit. You "gave" it electrical power and it returned to you the input in the simplest form of a tiny light. Other system can give you the voltage (440V, 220V, 110V, etc, and frequency 50Hz, 60Hz, etc).

sorvell commented 3 years ago

So, in case of

${???.toString()}
or let text = ???.toString(), what is the ????

In Javascript, the string representation of an objects is [object Object]. You can observe this by doing ({}).toString().

However, objects can implement a toString method to customize this output. For example, ({toString: () => 'string representation'}).toString().

@kevinpschaaf was noting that CSSResultwhich is the output of css... is an object and therefore it normally would render as [object Object] except that it has a toString() implementation that outputs its given css as text.

Hope that helps.

GHNewbiee commented 3 years ago

@sorvell So, how do I call/get access into CSSResult from the interior of MyElement class? Tia

sorvell commented 3 years ago

It's unclear exactly what you're asking. @kevinpschaaf 's explanation seems to provide the necessary info for displaying the text of style rules applied to the element: https://github.com/Polymer/lit-element/issues/1105#issuecomment-730611454.

Based on your comment:

the right area which displays, after beautifying, the css in text form. So, if you do not give me access to css input how can I retrieve the text, pass it from a css beautifier and finally display it?

Something like this should work to beautify the CSS:

render() {
  // The CSSResults in the array will be joined as strings automatically, 
  // but you could call `toString()` on the members of this array if your code requires it.
  const rawCSS = this.constructor.styles.flat(Infinity).join('\n');
  // beautify and render the css, assuming you implement `beautifyCSS`
  return html`<div>${beautifyCSS(rawCSS)}</div>`
}

Hope that helps.

sorvell commented 3 years ago

Closing based on the previous response. Please feel free to re-open if additional discussion is necessary.