-
-
Notifications
You must be signed in to change notification settings - Fork 9.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Web-components: Add typescript types and CLI template #12395
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Left a couple of comments but looks good to me otherwise. Thanks for picking it up
<button | ||
type="button" | ||
class=${['storybook-button', `storybook-button--${size || 'medium'}`, mode].join(' ')} | ||
style=${backgroundColor && { backgroundColor }} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To be aligned with lit best practice we should use ifDefined(backgroundColor)
here. It can be imported from lit-html/directives/if-defined
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not a web component expert but if I'm right, there's other options than lit-html, we tried to limit this dependency in the code we provide.
@shilman WDYT ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I get that. I wasn't sure either, we want it to be as generic as possible so it isn't tied into one library.
I've since realised too I wasn't quite right as in lit we wouldn't even set this property. We could just leave it as an example if you want to keep it generic though
* | ||
* @see [Default export](https://storybook.js.org/docs/formats/component-story-format/#default-export) | ||
*/ | ||
export type Meta<Args = DefaultArgs> = BaseMeta<string> & Annotations<Args, StoryFnHtmlReturnType>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now that these are in a "types-6" file, should they still live here a second time? If so can you explain why for future reference
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My bad, they should not be here. good catch
@@ -0,0 +1,33 @@ | |||
import { html } from 'lit-html'; | |||
|
|||
export interface ButtonProps { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if we should make all properties here optional or ButtonProps
should be exported as a partial type (type ButtonProps = Partial<{...}>
). To simplify all the references to just ButtonProps
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Partial means you can skip mandatory properties. Which is not what we want
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It does but my point is everywhere we reference this, we use Partial anyway. So we should probably solve the problem at the interface here rather than every time it gets used (which could mean using partial here or just making the properties optional).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have the same interface for all frameworks. Do you have an example of where Partial would bring value ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not arguing FOR partial im telling you its used already in this PR:
const Template: Story<Partial<ButtonProps>> = (args) => Button(args);
in the stories.
which in every other framework's stories would instead be:
const Template: Story<ButtonProps> = (args) => Button(args);
so i was just trying to point out that maybe instead of using partial, we should make the optional properties in ButtonProps
optional. If that's all of them, fine, or consider using partial when defining the type rather than when using it.
@@ -1,6 +1,5 @@ | |||
import { html } from 'lit-html'; | |||
import { Header } from './Header'; | |||
import './page.css'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@43081j I'f I'm right, you removed it, is it automatically importing css ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I removed it originally because when i changed to typescript, the import couldn't be found. Where does this CSS live?
Really I don't think it should exist for the web components examples anyway.
Each component has its own scoped styles (if you decide to give it any) so it wouldn't make any sense trying to import a css file here. As you would be applying css to the document which can't even penetrate the shadow dom boundaries of these components. So I don't think it's a use case anymore unlike react for example
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In real world you would import an object like:
import {styles} from './pageStyles.js';
Which is (in lit):
export const styles = css`
:host { display: block; }
`;
In use:
class Foo extends LitElement {
static styles = styles;
}
Styles are always scoped as per the spec so most libraries will do it this way. Or they will produce something like this at build time
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Styles are shared between all frameworks and are added on user side. What you propose is probably how it should be done but we also need to find the balance with the current architecture. using css files is the best option
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The problem is, using CSS files just wouldn't have any effect with a web component.. so i'd argue we should just not have a css import in the web component examples to avoid confusion.
It isn't a pattern you will see, as the most you could do is style everything outside the component in that stylesheet. A web component would normally have its own shadow root, so those outside styles would have no effect on it (other than variables and host styles).
It isn't really a use case when dealing with web components because of this so i just want to make sure we're not including it just because non-web-component frameworks do it.
Example..
import './styles.css';
customElements.define('x-test', class XTest extends HTMLElement {
// ...
connectedCallback() {
const h1 = document.createElement('h1');
h1.textContent = 'Hello!';
this.shadowRoot.appendChild(h1);
}
});
In this, it is impossible for anything in styles.css
to ever style the h1
. So that stylesheet can't possibly contain anything of use for the component. It would just be confusing to see that import when you have previously learnt that it isn't a thing anyone does/can do.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@tooppaaa LGTM but what's the resolution on those deleted CSS imports?
Adding them back |
@tooppaaa are you planning to add those CSS imports back? does the generated storybook look correct with them? does it look correct without them (can't imagine that it would)? |
what is in those CSS files? where are they actually located? it would be helpful to know what they are trying to style... i argued against them because its impossible to style the component from a separate, standalone stylesheet. due to how web components generally work... but if its just a stylesheet of the page and not the component, fair enough it should stay. otherwise, though, you'd be including a stylesheet that does nothing. so i can't imagine its working right visually? |
i've read through the code. this is the CSS presumably: in which case, its styling outer elements (light dom) so we should keep the import. but this now raises another point... i assumed everything in |
@shilman Styles added back, all good to me ! Fix Typings as well to be exactly the same as React @43081j Styles are shared for all frameworks. Even if this method of styling is not a web component standard, at the end, it's still HTML elements with class names. Styling applies as usual. They might not be reusable component for your application but the point here is to demonstrate the stories. It's possible that due to our knowledge on WebComponents, they might not be top of the art. |
As in, the examples are definitely not making any use of web components at all.
it isn't. if you style a web component (assuming the component has a shadow root), it is not "still HTML elements with class names". Your stylesheet, by definition, cannot penetrate the boundaries of the shadow root. It would be impossible to style anything within the shadow root from that style sheet. I think this is a misunderstanding of web components, so i'll try explain. Our example here is pretty much: const button = (props) => html`<button ?disabled=${props.disabled}>Foo</button>`; Something like that. That is not a web component and may as well live in the HTML examples rather than the web component ones. Ultimately, that will produce a lit const button = (props) => `<button${props.disabled ? ' disabled' : ''}>Foo</button>`; you see? the above would be seen as a HTML example, but its behaviourally the same as our "web component" example (because its not really using web components). a real web component example would define button as this (or similar): customElements.define('my-button', class extends LitElement {
static get properties() {
return { disabled: { type: Boolean } };
}
render() {
// this button can never be styled by the outer CSS stylesheet. no selector can penetrate the boundaries
// of the shadow root this ends up in.
return html`<button ?disabled=${this.disabled}><slot></slot></button>`;
}
});
const button = (props) => html`<my-button ?disabled=${props.disabled}>Foo</my-button>`; in this case, our if we wrote our examples like this, using actual web components, the stylesheet you're importing would not do anything. because the Example DOM tree:
edit: im happy with just going ahead with this PR in the end as-is, but i think it would be very beneficial to rewrite these examples using web components. hopefully the explanation helps to show why. right now, they may as well be copies of the HTML examples (just without the html tagged template). again i don't want this PR to hang about and go stale etc so we should try get it merged for sure. i hope the explanation helped either way |
@tooppaaa would be good to get this finished off if you get chance soon. we should leave the stories and css as they are for now |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if it works, 👍
not to be a bother but can we get this merged? would be really useful to have these types 👍 |
Hello @shilman, I've been using the types from the @storybook/web-components, and I've found an issue with the types from lit-element. As you can see in the image above, I am receiving an error about the 'lit-element' module. Can you reproduce this error? Do you agree with this change? Reference to the types.ts file: |
It should probably be lit-html but there's other issues to consider too. Storybooks usual dependency mismatch problem applies here too. There can only be one copy of lit in the entire dependency tree or instanceof bugs happen (fixed in lit-next). Also your stories, components and storybook should import from the same thing, lit-html or lit-element but not a mixture. Again not the problem you're seeing but would still exist as edge case issues so figured I'd mention them. Your fix is correct for this particular issue. I'll try it today myself just to confirm too |
@ariefurtado you are correct, if you could open a PR for it that would be great. lit-element depends on lit-html, so it makes sense we pull it from the base package (lit-html) in case you don't use lit-element. edit: theres actually a fair amount of references to lit-element elsewhere,so im wondering if they all need changing or are just demo-related/example-related? something to take into account if doing a pr edit2: we actually do import so the types should also import it. and when lit-next gets released eventually, we can drop the |
@ariefurtado and @43081j thanks for the feedback and details, doing a PR right now -> #14258 About:
This shouldn't not happen as Edit:
The |
yes the e2e should only need and yes you are right about the peer dependency. the mismatch stuff is an issue outside storybook we need to take into account at a later date, unrelated to this issue. basically lit (and storybook in the file i referenced earlier) uses |
Hi @43081j and @gaetanmaisse, I'm glad that I could help with this issue. |
Issue: #12026 #11974 #11845
What I did
Review awesome work from @43081j
Setup js / ts structure for web components + e2e
web-components typings
How to test