-
Notifications
You must be signed in to change notification settings - Fork 26
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
[Component]: adds event types to react #440
[Component]: adds event types to react #440
Conversation
9c6748d
to
5d8b1c1
Compare
src/scripts/gen-react-bindings.js
Outdated
return ` | ||
export type ${componentName}EventProps = { | ||
${componentEventNames.map((event) => ` ${event}?: (event: CustomEvent) => void`).join(';\n')} | ||
} | ||
` |
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.
Creates a type that gets associated with the component type during the generation of the react components.
5d8b1c1
to
ff69dbe
Compare
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.
Wow thanks for this @benjaminknox - I'm going to take a couple of days to mull it over (and I'm away the rest of this week) but this seems like a sensible approach.
The main thing we might be missing is the ability to accept standard HTML events. When we wrap these in a WebComponent, it actually supports all the standard events (onClick, onMouseEnter, onMouseDown, onKeyDown ect), so we should make sure we are still able to accept those events too
625074b
to
d3e2927
Compare
Note: The method below is not preferred and the PR it references is closed because the html events are not available yet, see this comment: benjaminknox#1 (comment)
Thanks @fallaciousreasoning, I think I have a possible solution for this, the details are in a PR I created against this branch in my fork of leo: benjaminknox#1 Basically, the solutions works when a component imports and uses <script lang="ts">
import type { SvelteHTMLElements } from 'svelte/elements'
type TableProps = Partial<SvelteHTMLElements['table']>
type $$Props = TableProps
let newValue: string = ''
let table: HTMLTableElement = undefined
</script>
<table bind:this={table} {...$$restProps}><slot /></table>
The resulting react type file would be: import type * as React from 'react'
import type { ReactProps } from '../src/components/svelte-react'
import type { TableEvents as SvelteEvents, TableProps as SvelteProps } from '../types/components/table/table.svelte';
export type TableProps = TableEventProps & ReactProps<SvelteProps, SvelteEvents>;
export default function TableReact(props: React.PropsWithChildren<React.HTMLAttributes<HTMLElement | HTMLTableElement> | TableProps>): JSX.Element
// As we don't currently have type definitions for the web components, export
// the Type Definitions from the Svelte component.
export * from '../types/components/table/table.svelte'
|
e90e7e2
to
8af2e2d
Compare
@fallaciousreasoning I think I've addressed all of your comments here. Although there's one more thing bothering me, we end up with event names that are not quite camelcase, like in the Is this ok to keep this way? I have a few ideas on how to fix this:
Any thoughts? |
Hmm, you're right, that's not ideal - shall we see if we can solve it? I think I'd be pretty happy with a solution which just handles the standard HTML events, which we can probably do as a Typescript-only fix: type EventNames = 'onMouseDown' | 'onMouseEnter' | 'onClick' | 'onKeyDown' | 'onKeyUp'
type EventNameMap = {
[P in EventNames as Lowercase<P>]: P
}
type Events<T> = {
[P in keyof T as (P extends Lowercase<EventNames> ? EventNameMap[P] : P)]: T[P]
}
let f: Events<{ 'onclick': () => {}, 'ondidthething': () => {}, onmouseenter: () => {} }>
f.<CTRL+Space> |
b6f0fbd
to
17ea850
Compare
1ad276f
to
e8f9a50
Compare
@benjaminknox I finally got around to testing this out in https://github.com/brave/brave-core, which is our main consumer of this repo. This is mostly working great but I did notice a couple of things:
I think if we fix these it should be good to land 😄 for capitalizing type Events = ['onclick', 'onclose', 'onopen', 'onchange', 'oninput']
type CasedBetter<T> = T extends `on${infer K}` ? `on${Capitalize<K>}` : never
type CapitalOn = CasedBetter<Events[number]>
// type CapitalOn = "onClick" | "onClose" | "onOpen" | "onChange" | "onInput" |
@benjaminknox I pushed a commit to fix the event names 😄 |
905fa2a
to
79a8627
Compare
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.
This LGTM - if you sign the commits I can land it 😄
remove lodash.capitalize dependency define types on createEventDispatcher in place of CustomEvent adds warning when finding an untyped createEventDispatcher run format add event detail type adds back event type to dialog dispatch matches react type camelcase for standard events
79a8627
to
7a3dcba
Compare
Done!
Good catch thanks @fallaciousreasoning |
Thanks heaps for this @benjaminknox! |
Resolves #407
For react components, currently generic typing allows any event prop to be used (e.g.
<LeoButton onClick={...}>
), if an incorrect event name is used (e.g.<LeoButton onClicked={...}>
) there is no type error. Ideally a type error for an incorrect prop name would show.This solves this by generating an event type for the react components by parsing the corresponding svelte type file, it should contain event types resulting from the typed
createEventDispatcher
. When there are no events defined in the svelte file it doesn't include any event types.For example, in input.svelte#L74-L84:
Results in a type definition that looks like this:
Screen.Recording.2023-10-17.at.1.17.50.PM.mov