Skip to content
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

Using Scale with SolidJs #615

Closed
W1ckh3ad opened this issue Oct 9, 2021 · 37 comments
Closed

Using Scale with SolidJs #615

W1ckh3ad opened this issue Oct 9, 2021 · 37 comments
Labels
support Asking for help

Comments

@W1ckh3ad
Copy link

W1ckh3ad commented Oct 9, 2021

Hello there,

I discovered SolidJs a couple of weeks ago and I decided to try it out as an alternative to react. I started with trying to use Scale components, but I failed.

I used the Solid typescript template, I didn't find the right template in CodeSandBox, but this is close.

JSX doesn't know the 'standard' Webcomponents.

I don't know if you had/have the time to check this or take a look at SolidJs.

I wrote on the SolidJs discord, if anyone of them can help me setting up using StencilJs components in SolidJs.
I will post the updates from them here.

I am grateful for every help.

@reld
Copy link
Collaborator

reld commented Oct 11, 2021

Hi @W1ckh3ad thank you for rising this issue.
As of now we don't officially support SolidJS. But you should be able to use the components with it.
I will make a small test and post my findings here.
Best Regards,
R

@christopherGdynia
Copy link
Contributor

Hi @W1ckh3ad is my privat Account. I will add the answers from the Discord below, but they didn't help me at all ^^

I appreciate your help.

@W1ckh3ad
Copy link
Author

RyanSolid answered this on my question how to use Webcomponents in Solid

"Solid supports Web Components as is without any wrapper generally although we do follow a few conventions which hopefully are compatible with Stencil. Generally we pass all props for web components as properties, converting dash-case to camelCase. If you have specific attributes or properties you want to set that don't follow this convention you can use attr: and prop: namespace on the props."

This doesn't help me, but maybe it wil help you.

@reld
Copy link
Collaborator

reld commented Oct 11, 2021

@W1ckh3ad Thanks for sharing the answer.
This is what I thought. SolidJS should not have any issues using web components.

Where exactly did you fail?
Did you go through the setup documentation? Where you able to actually use a component?
It seems to me, that your issue is on the setup of your project.

Do you have a repository showing your project's setup you can share?

@W1ckh3ad
Copy link
Author

W1ckh3ad commented Oct 11, 2021

Hey @reld, thanks for your help and time

I started
npx degit solidjs/templates/ts my-app

After that I installed the @telekom/scale-components library

I added the styles and the polyfills to the index.tsx

when I am trying to use the webcomponent in JSX, is vscode telling me
"Property 'scale-button' does not exist on type 'JSX.IntrinsicElements'.ts(2339)"

I am kinda mad, that I can't it done.

My repos here

@reld
Copy link
Collaborator

reld commented Oct 12, 2021

Hey @W1ckh3ad
I see.. it seems to be a types issue. I am checking with the team about this.

I got two examples working on Codesandbox though.
One using typescript
https://codesandbox.io/s/fast-thunder-rytq9?file=/src/main.tsx

and the other without
https://codesandbox.io/s/solidjs-starter-template-forked-gq38f?file=/src/components/TodoList.js

Both work. The only difference is that the Typescript version is yelling about the missing types. ( but still works )

I'll get back to you as soon as I know more.

Cheers and make yourself a wonderful day
R

@christopherGdynia
Copy link
Contributor

Hey @reld

OMG,
thank you very much,
why didn't I check it 🤦‍♂️

You too!

@acstll acstll added the support Asking for help label Oct 13, 2021
@acstll
Copy link
Collaborator

acstll commented Oct 13, 2021

Hey @christopherGdynia

now we know it's a TypeScript issue with custom elements in JSX. I've seen this solved somewhere, we'll come back :)

@W1ckh3ad
Copy link
Author

Hey @acstll @reld

I published my repos here

I didn't got it working what you did in your typescript codesandbox, maybe you can help on this.

The button component doesn't get rendered to the screen.

@christopherGdynia
Copy link
Contributor

@acstll is this what you ment?
JSX typescript fix

@W1ckh3ad
Copy link
Author

Hey @W1ckh3ad I see.. it seems to be a types issue. I am checking with the team about this.

I got two examples working on Codesandbox though. One using typescript https://codesandbox.io/s/fast-thunder-rytq9?file=/src/main.tsx

and the other without https://codesandbox.io/s/solidjs-starter-template-forked-gq38f?file=/src/components/TodoList.js

Both work. The only difference is that the Typescript version is yelling about the missing types. ( but still works )

I'll get back to you as soon as I know more.

Cheers and make yourself a wonderful day R

Hey,

I tried to get this work, but I didn't
Today, I forked your sandbox, created a github repository, cloned it and tryed it.
This doens't work either, I am kinda lost.

@acstll
Copy link
Collaborator

acstll commented Oct 25, 2021

hey @W1ckh3ad

I'm taking a look at this again today… thanks for trying that out 🙏

@acstll
Copy link
Collaborator

acstll commented Nov 15, 2021

Hey @christopherGdynia I'm sorry we haven't been able to solve this one yet!

Yes, ionic-team/stencil#1636 is exactly the problem. You can see there's no official solution from Stencil. But it's definitely something we need to address at some point.

Is this blocking you now or can we put it in the backlog and close?

@christopherGdynia
Copy link
Contributor

Hi @acstll,
thanks for your help, no this isn't blocking.

My goal is it to test if we can use SolidJS instead of ReactJs

@W1ckh3ad
Copy link
Author

Hello guys,

I have found something :D,

ionic-team/stencil-ds-output-targets#213

can you implement the output wrapper? :D

@acstll
Copy link
Collaborator

acstll commented Jan 11, 2022

Hey @W1ckh3ad that looks quite interesting. Thanks for sharing!

That Solid plugin is not yet merged, so we couldn't implement it right away unless we use a fork.

I would be hesitant to add yet another output wrapper since we want to actually deprecate/remove the current ones (probably except for React), and encourage devs to use the components directly, as long as support for web components is good (which is the case for almost all frameworks except for React, which in turn is also improving).

Apart from fixing the JSX/TS issue described above, are there any other benefits in using this wrappers with Solid?


EDIT 20220124: I updated the comment to make it clear that the React wrapper is not being deprecated. The benefits still outweigh the drawbacks.

@christopherGdynia
Copy link
Contributor

christopherGdynia commented Jan 11, 2022

Hey @acstll,

I understand your point,

I am trying to get to know some other Frameworks and SolidJS seems like a nice alternative to React.

It is quite easy to transform from React to Solid js.
SolidJs is close to native JavaScript in terms of speed in most of the benchmarks.
Theire statemanagementsystem is way easier than react und supports global state without any providers, because you can define state outside any component in seperate files.

But if I cant get it running the packages I am using, it's not a alternative.

Additionally, I don't have the expertise about Stencil, Webcomponents and Frameworkbuilding to get it fixed myself.

It is quiete new and there is not much content about it concerning these topics.

EDIT:

It's not that I didn't try several times to get it up and running with typescript, but I didn't manage to do it. :(

@acstll
Copy link
Collaborator

acstll commented Jan 11, 2022

Oh, maybe my question was not well formulated, sorry. I was not asking for the benefits of using the Solid framework itself. This is a personal choice. Our job is to try and make Scale work well with every framework. That's not a problem (I really like Solid by the way!) 🙂

I was asking specifically about the benefits of a possible wrapper package, like @telekom/scale-components-solid, instead of using @telekom/scale-components directly. Since Solid has great support for web components already. I think such a package would be redundant or unnecessary.

We currently have the issue you described above (the Property 'scale-button' does not exist on type 'JSX.IntrinsicElements'.ts(2339) error when using TypeScript). We still need to find a solution for that.

I'm guessing the wrapper package would solve this issue. So I was wondering what other benefits would a @telekom/scale-components-solid package provide. Because I don't see any other than having IDE autocompletion. But that's because I'm not a TypeScript user, so I'm probably missing things, and I know you work with TypeScript. That's why I was asking 🤓

@christopherGdynia
Copy link
Contributor

I am hoping that it will finally work with this helper package, I forked and cloned booth of @reld examples and they didn't work on my pcs (private and work).

I have added Scale to the solidjs hello world template, it works in codesandbox,
I have saved this repos in my github, cloned it, installed it and doesn't work too.

I am kinda loosing my mind about it.
I

@acstll
Copy link
Collaborator

acstll commented Jan 11, 2022

@christopherGdynia I'm working on this, there's something else in your repo causing trouble I think. Will write again later today! Thanks for the feedback.

@acstll
Copy link
Collaborator

acstll commented Jan 11, 2022

Hey @christopherGdynia

I found the cause of an error in your repo here:

https://github.com/W1ckh3ad/solidjs/blob/master/src/index.tsx#L7

The defineCustomElements() won't work with Vite because Stencil lazy loading system is broken in that context. You can see this opened issue in the Stencil repo: ionic-team/stencil#2827 which we also track in #369

To work around this. You can import the library via script tag. You can add this in the index.html template in your Solid project.

<script type="module" src="https://unpkg.com/@telekom/scale-components/dist/scale-components/scale-components.esm.js"></script>

The CSS loading part can stay the same.


I was able to get Solid working with this setup (screenshot below).

However, I do get TS complaining about Property 'scale-button' does not exist on type 'JSX.IntrinsicElements'.ts(2339). But, as much as this is annoying, I can run the dev server, and also build the project.

We're gonna try and find a solution for this before even considering adding a new wrapper package. I believe it's a matter of extending JSX.IntrinsicElements with the custom elements being used. As discussed here in a few places (my TypeScript knowledge is pretty basic, so I cannot figure this one out as much as I wish):

Would you know how to create/generate such a declarations file?

Thanks for the patience.

image

image

@christopherGdynia
Copy link
Contributor

@acstll

Thank you very much.
This really worked in booth apps :D
I have created a new repos yesterday https://github.com/christopherGdynia/soldiJsTry and its there working too.
Babel with Parcel has the same issue.

About the JSX.IntrinsicElements I will look at the SolidJS Discord and ask the creator for any hints, I have tryied multiple things, but none worked properly.

I will tell him about the problem, maybe they will add it to their documentation.

Thank you very much!

@christopherGdynia
Copy link
Contributor

christopherGdynia commented Jan 12, 2022

@acstll

I have got an solution, the members from the solid discord are quite insane :D

solid-js.d.ts

import "solid-js"

declare module "solid-js" {
  namespace JSX {
    interface IntrinsicElements {
      "scale-button": any;
    }
  }
}

If we want intellisence, we need to import the right

The Components.ScaleButton is missing the event properties or is it intended to use the ButtonHTMLAttributes<HTMLButtonElement>

BTW: Some properties aren't optional like ScaleButton.setFocus and ScaleButton.iconPosition

import { JSX } from "solid-js";
import { Components } from "@telekom/scale-components";

interface MyElementProps {
  children?: JSX.Element;
}

interface ScaleButton {
  /**
   * (optional) If `true`, the button is disabled
   */
  disabled?: boolean;
  /**
   * (optional) Name of a file to be downloaded
   */
  download?: string;
  /**
   * (optional) When present, an <a> tag will be used
   */
  href?: string;
  /**
   * (optional) Set to `true` when the button contains only an icon
   */
  iconOnly?: boolean;
  /**
   * (optional) Icon position related to the label
   */
  iconPosition?: "before" | "after";
  /**
   * (optional) Set `tabindex` in the inner button or link element
   */
  innerTabindex?: number;
  setFocus?: () => Promise<void>;
  /**
   * (optional) The size of the button
   */
  size?: "small" | "large";
  /**
   * (optional) Injected CSS styles
   */
  styles?: string;
  /**
   * (optional) The target attribute for the <a> tag
   */
  target?: string;
  /**
   * (optional) Button type
   */
  type?: "reset" | "submit" | "button";
  /**
   * (optional) Button variant
   */
  variant?: string;
}

declare module "solid-js" {
  namespace JSX {
    interface IntrinsicElements {
      "scale-button": ScaleButton & MyElementProps & ButtonHTMLAttributes<HTMLButtonElement>;
    }
  }
}

@acstll
Copy link
Collaborator

acstll commented Jan 12, 2022

That's amazing, I'm glad to hear.

I wonder if there's a way to provide this in a generic way, so people can use it with different frameworks. We're adding this to the backlog (figure out a way to provide either generic or specific JSX declarations).

We're also looking into the optional props (that's important I think otherwise you get annoying by the linter as well).

Thanks again!

@acstll
Copy link
Collaborator

acstll commented Jan 12, 2022

I'm closing but we can of course keep the exchange going.

@acstll acstll closed this as completed Jan 12, 2022
@christopherGdynia
Copy link
Contributor

Yeah that seems reasonable to find a solution for this.

I will check every component for not having an optional flag and create a pr for this :)

Let's keep in touch, this will be important for deprecating the proxy packages!

@acstll
Copy link
Collaborator

acstll commented Jan 12, 2022

Thanks a bunch @christopherGdynia 🙏

@christopherGdynia
Copy link
Contributor

@acstll Concerning the JSX typescript issue, do we want to open another issue
I have tried something for React and took a deeper look into SolidJS, what we will need for it to work properly. :)

@christopherGdynia
Copy link
Contributor

christopherGdynia commented Jan 13, 2022

Nevermind I got it working for React and SolidJS

ReactJS

//react-app-env.d.ts

import { HTMLAttributes, RefAttributes } from 'react';
import { JSX as LocalJSX } from '@telekom/scale-components/loader';

type StencilToReact<T> = {
  [P in keyof T]?: T[P] &
    Omit<HTMLAttributes<Element>, 'className'> & {
      class?: string;
    } & RefAttributes<T[P]>;
};

declare global {
  export namespace JSX {
    export interface IntrinsicElements extends StencilToReact<LocalJSX.IntrinsicElements> {}
  }
}

SolidJS

declarations.d.ts

import { JSX as SolidJSX } from "solid-js";
import { JSX as ScaleJSX } from "@telekom/scale-components/loader";

interface MyElementProps {
  children?: SolidJSX.Element;
}

type StencilToSolid<T> = {
  [P in keyof T]?: T[P] &
    MyElementProps &
    Omit<SolidJSX.HTMLAttributes<Element>, "className"> & {
      class?: string;
    };
};

declare module "solid-js" {
  namespace JSX {
    interface IntrinsicElements extends StencilToSolid<ScaleJSX.IntrinsicElements> {
    }
  }
}

@raulfdm
Copy link

raulfdm commented Jan 31, 2022

thanks @christopherGdynia. I was having some issues with a similar react/ts algebra types and yours just solves all my problems.

@filipjnc
Copy link

filipjnc commented Jul 22, 2022

I'm wondering whether it is possible to update the generics so that the property values are also type-safe. Example:

image

The variant property of <scale-button> accepts a string, but doesn't specify the enum of valid string values.

@acstll
Copy link
Collaborator

acstll commented Aug 1, 2022

Is this what you mean @filipjnc?

-@Prop() variant?: string = 'primary';
+@Prop() variant?: 'primary' | 'secondary' | 'ghost' = 'primary';

https://github.com/telekom/scale/blob/main/packages/components/src/components/button/button.tsx#L42

@filipjnc
Copy link

filipjnc commented Aug 1, 2022

Is this what you mean @filipjnc?

-@Prop() variant?: string = 'primary';

+@Prop() variant?: 'primary' | 'secondary' | 'ghost' = 'primary';

https://github.com/telekom/scale/blob/main/packages/components/src/components/button/button.tsx#L42

Exactly.

@filipjnc
Copy link

filipjnc commented Aug 17, 2022

SolidJS

declarations.d.ts

@christopherGdynia How did you fix the types for camel-cased props that need to be appended with the prop: namespace in order for them to work? Example:

     <scale-app-shell
        claimLang="de"
        prop:mainNavigation={mainNavigation}
        prop:activeRouteId={activeRouteId || '/'}
        prop:addonNavigation={addonNavigation}
        prop:iconNavigation={iconNavigation}
        prop:userNavigation={userNavigation}
        class={styles.shell}
     >

Without adding prop: the navigation items do not render. When adding it everything works, but typescript complains.

@AlexErrant
Copy link

AlexErrant commented Aug 17, 2022

@filipjnc you may find this comment interesting; in particular:

[K in keyof T as `prop:${string & K}`]?: T[K];

@filipjnc
Copy link

filipjnc commented Aug 17, 2022

@filipjnc you may find this comment interesting; in particular:

[K in keyof T as `prop:${string & K}`]?: T[K];

Thanks, Alex, you got me on the right path. The following type declaration allows me now to use all the props also with the props: prefix:

import { JSX as SolidJSX } from 'solid-js'
import { JSX as ScaleJSX } from '@telekom/scale-components/loader'

interface MyElementProps {
  children?: SolidJSX.Element
}

declare module 'solid-js' {
  namespace JSX {
    type ElementProps<T> = {
      // Add both the element's prefixed properties and the attributes
      [K in keyof T]: Props<T[K]> & HTMLAttributes<T[K]> & MyElementProps
    }
    // Prefixes all properties with `prop:` to match Solid's property setting syntax
    type Props<T> = {
      [K in keyof T as `prop:${string & K}`]?: T[K]
    } & {
      [K in keyof T]?: T[K]
    }
    interface IntrinsicElements extends ElementProps<ScaleJSX.IntrinsicElements & MyElementProps> {}
  }
}

Still not ideal that I have to prefix the camel-cased props, but that's on SolidJS to address.

@christopherGdynia
Copy link
Contributor

Hello @filipjnc, @AlexErrant,

I was on vacation and didn't read my emails. Thanks for your contribution @AlexErrant.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
support Asking for help
Projects
None yet
Development

No branches or pull requests

7 participants