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

Suggestion: Allow intrinsic elements to vary by component #15266

Closed
jugglingcats opened this issue Apr 19, 2017 · 8 comments
Closed

Suggestion: Allow intrinsic elements to vary by component #15266

jugglingcats opened this issue Apr 19, 2017 · 8 comments
Labels
Awaiting More Feedback This means we'd like to hear from more people who would be helped by this feature Suggestion An idea for TypeScript

Comments

@jugglingcats
Copy link

This suggestion is motivated by react-three-renderer, which creates a custom renderer for React around the THREE library, and specifically this issue: firtoz/react-three-renderer#127.

This library was not written with Typescript in mind, and uses lowercased JSX elements for children of its main React3 component. For example:

            <React3 width={800} height={400} clearColor={0xf0fff0} mainCamera="camera">
                <scene>
                    <perspectiveCamera fov={75} aspect={800/400} near={0.001} far={1000} name="camera" ref="camera"
                                       position={new THREE.Vector3(0,0,5)} rotation={new THREE.Euler()}/>

                    <ambientLight color={0x505050}/>

                    <line>
                        <geometry vertices={vertices}/>
                    </line>
                </scene>
            </React3>

While it's possible to avoid compiler warnings by modifying JSX.IntrinsicElements this causes issues where there are conflicts, for example line in the above example which is also an SVG element. Also, within the React3 component it is not sensible/valid to put normal HTML elements, so it would be good to exclude these.

I am following #14729 and #13618 which seem somewhat related, but don't appear to address this specific issue.

In summary, it should be possible to indicate somehow that a component uses a different set of intrinsic elements, other than JSX.IntrinsicElements.

@RyanCavanaugh RyanCavanaugh added Awaiting More Feedback This means we'd like to hear from more people who would be helped by this feature Suggestion An idea for TypeScript labels Apr 19, 2017
@geakstr
Copy link

geakstr commented Jun 25, 2017

+1. React Fiber should be released soon and many custom renderers will be appearing.

@jugglingcats
Copy link
Author

Hi @RyanCavanaugh you tagged with Awaiting More Feedback a while ago. Are you wanting feedback from me as the person who raised the issue or from the typescript team? Thanks!

@kitsonk
Copy link
Contributor

kitsonk commented Sep 29, 2017

as the person who raised the issue or from the typescript team?

It means it is awaiting more feedback from the community as a whole. It means that it isn't obvious to the core team that it is worth expending effort on this suggestion unless there is wider support from the community.

(I was going to point you at the label list but it appears this one isn't listed)

@RyanCavanaugh
Copy link
Member

This means we'd like to hear from more people who would be helped by this feature, understand their use cases, and possibly contrast with other proposals that might solve the problem in a simpler way (or solve many other problems at once).

If this feature looks like a good fit for you, please use the 👍 reaction on the original post. Comments outlining different scenarios that would be benefited from the feature are also welcomed.

@toxicFork
Copy link

toxicFork commented Oct 8, 2017

Hi :)

I'm the author of react-three-renderer and would like to contribute to TypeScript's support for custom renderers if possible :)

Here are a few kinds of renderers that some initial research has shown:

  • some of them do not need react-dom and an application would be using only their elements
  • some would be working to to enhance dom and add a few new elements
  • and others would be creating rendering contexts within other renderers

To go into more detail with react-three-renderer, any element that is rendered within a React3 component would be handled by react-three-renderer instead of react-dom.

To extend the above example:

function testRender() {
  return <div>
    Check out this three dimensional thing:
    <div>
      <React3 {/* diving into react-three-renderer domain now */ ...{}}>
        <webGLRenderer width={800} height={600} antialias>
          <scene>
            <mesh>
              <boxGeometry width={10} height={10} depth={10} />
              <meshBasicMaterial
                color={"FF0000"}
              />
            </mesh>
          </scene>
        </webGLRenderer>
      </React3>
    </div>
  </div>;
}

By looking at this I can think of various potential solutions (assuming no technical limitations):

  • React3 component could somehow have a tag to specify "which type of elements it may contain as children"
    • This could also be extended to any element to help support web components, for example an x-search component would be accepting only children that are x-query and x-engine, while another x-wrapper component would be accepting normal dom nodes
      • (haha and then I could make a react3 web component to have best of both worlds... :D)
  • A typescript source file could perhaps have a tag to say "any element within this file will be of this or that kind"
  • A renderer function could somehow have a tag to say what kind of elements it will be rendering, for example:
import {Ref} from "react";

declare namespace ReactThreeRenderer {
  interface IBoxGeometryProps {
    width: number;
    height: number;
    depth: number;
  }

  interface IReactThreeRendererElement<T> {
    key?: string;
    ref?: Ref<T>;
  }

  interface IntrinsicElements {
    boxGeometry: IReactThreeRendererElement<THREE.BoxGeometry> & IBoxGeometryProps;
    meshBasicMaterial: IReactThreeRendererElement<THREE.MeshBasicMaterial> & THREE.MaterialParameters;
  }
}

/// <jsx-intrinsic-elements using="ReactThreeRenderer.IntrinsicElements"/>
function testRender() {
  return <scene>
    <mesh>
      <boxGeometry width={10} height={10} depth={10} />
      <meshBasicMaterial
        color={"FF0000"}
      />
    </mesh>
  </scene>;
}
  • A project could somehow flag "what sort of elements may it have for JSX" e.g. with a compiler flag
  • For more restrictions, a mesh element can contain only geometry and material types, e.g.:
    • boxGeometry, sphereGeometry and so on, meshBasicMaterial, meshLambertMaterial and so on
    • but it's fine if TypeScript cannot handle these, I'd mark it as "future work" rather than a "must-have" though :)

I hope it helps!

Firtina.

@dyst5422
Copy link

I think this could be handled by checking the children of intrinsic elements the same as non-intrinsic elements.

I've run into a similar case where I'm leveraging JSX to do declarative xml building. I have certain constraints on child-parent relationships that are great for non-intrinsic elements, but don't appear to be type-checked for intrinsic elements.

@beshanoe
Copy link

beshanoe commented May 4, 2018

I also vote for this feature. The use case I would image is following:
in angular or vue templates we are able to use components defined and registered in top-level module, so it would be nice to use these components without importing them explicitly as modules. It could look something like

import { myModule } from '../myModule'

myModule.component({
  name: 'foo',
  render: () => (
    <sui-button size="large">Submit</sui-button>
  )
})

with render function typed somehow that it's allow to use custom JSX.IntrinsicElements inside of it

interface Component {
  name: string,
  render: JSX.RenderFunction<{
    "sui-button": {
      size?: "large" | "small"
    },
    "other-component": {
      someProp?: number
    }
  }>
}

I guess it can possibly allow supporting directives in JSX as well

@RyanCavanaugh
Copy link
Member

Two possible interpretations going on here:

  • Apply a different resolution for JSX elements based on their parents. This behavior seems unprecedented in extant JSX transpilers/renderers and is very difficult to reason about when it comes to composability. Declining this based on complexity and lack of feedback on modern frameworks.
  • Typecheck that particular parents only have particular children - see Decouple jsx element type from jsx factory return type and sfc return type #21699

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Awaiting More Feedback This means we'd like to hear from more people who would be helped by this feature Suggestion An idea for TypeScript
Projects
None yet
Development

No branches or pull requests

7 participants