diff --git a/docs/jsx.md b/docs/jsx.md new file mode 100644 index 00000000..7c8c5019 --- /dev/null +++ b/docs/jsx.md @@ -0,0 +1,133 @@ +--- +title: JSX +--- + +As of version `0.42.0`, TypeScriptToLua supports the use of JSX. To enable it, add `"jsx": "react"` to your tsconfig - other values are not supported. + +```json title=tsconfig.json +{ + "compilerOptions": { + ... + "jsx": "react", + ... + }, +} +``` + +JSX will be translated to lua as Typescript would translate it to JS: + +```tsx +const element =
Inner text!
; +``` + +Will become: + +```lua +local element = React.createElement("div", { a = b }, "Inner text!"); +``` + +## Custom factory functions + +It is possible to supply custom factory functions using the `jsxFactory` tsconfig setting, or on a per-file basis using the `/** @jsx */` annotation. + +### Examples + +With compiler option: + +```json title=tsconfig.json +{ + "compilerOptions": { + ... + "jsx": "react", + "jsxFactory": "MyNamespace.myCreate" + ... + }, +} +``` + +or with jsx annotation: + +Note: the annotation MUST be at the top of the file! + +```tsx +/** @jsx MyNamespace.myCreate */ +``` + +```tsx +const element =
Inner text!
; +``` + +Will translate to: + +```lua +local element = MyNamespace.myCreate("div", { a = b }, "Inner text!"); +``` + +For more info on creating your own factory function, see [Creating your own JSX](#creating-your-own-jsx). + +## jsxFragmentFactory + +JSX fragments are translated as special components. + +You can provide a custom fragment component using the `jsxFragmentFactory` tsconfig setting or with the `/** @jsxFrag */` annotation. + +### Example + +With compiler option: + +```json title=tsconfig.json +{ + "compilerOptions": { + ... + "jsx": "react", + "jsxFactory": "MyNamespace.myCreate", + "jsxFragmentFactory": "MyNamespace.MyFragment" + ... + }, +} +``` + +or with `@jsxFrag` annotation: + +```tsx +/** @jsx MyNamespace.myCreate */ +/** @jsxFrag MyNamespace.MyFragment */ +``` + +```tsx +const element = <>; +``` + +Will translate to: + +```lua +local element = MyNamespace.myCreate(MyNamespace.MyFragment); +``` + +## Creating your own JSX + +### JSX typings + +The types on the jsx factory function itself do _not_ affect how typescript checks JSX types, and no type checking against the jsx factory function is done during transformation. + +Instead, typescript looks for types for jsx on the special `JSX` namespace. You can read more creating JSX types [here](https://www.typescriptlang.org/docs/handbook/jsx.html#type-checking). + +### JSX factory function + +Typescript expects the jsx factory function to be similar to the following: + +```ts +/** @noSelf */ +function createElement(type: string | Function | Class, props?: object, ...children: any[]): any; +``` + +- The function should have a `@noSelf` annotation or have a `this: void` parameter. See [here](the-self-parameter.md) for more info. +- `type` will be a string for intrinsic properties (tag name starts with a lowercase letter), or a function/class component. +- `props` will be the tag properties as an object/table, or `undefined`/`null`/`nil` if no properties are specified. +- The remaining parameters form the `children`, and should be collected with a rest parameter (`...`), and not as one array parameter. The type of the children will be strings for inner text, and values passed directly for JSX expressions and nested elements. + - No transformations are done on the children parameters, meaning they may have any type (including arrays) that you may need to handle. + - Using a jsx children spread syntax `<>{...children}` does _not_ affect how the children are passed to the createElement function -- it is equivalent to `<>{children}` + +The function may process in any way and return any value that you wish. + +It is recommended that the jsx factory function is in a namespace that is the default export of a module, or that the function itself is the default export of a module, and that the namespace/function name matches the `jsxFactory` compiler option. This is for better integration with tooling (import suggestions). This applies similarly for custom fragment components and the `jsxFragmentFactory` compiler option. diff --git a/docs/tsx.md b/docs/tsx.md deleted file mode 100644 index c52342a4..00000000 --- a/docs/tsx.md +++ /dev/null @@ -1,113 +0,0 @@ ---- -title: TSX ---- - -As of version `0.42.0`, TypeScriptToLua supports the use of TSX. To enable it, add `"jsx": "react"` to your tsconfig - other values are not supported. It is your job to make sure the required factory functions are available in the Lua environment. - -```json title=tsconfig.json -{ - "compilerOptions": { - ... - "jsx": "react", - ... - }, -} -``` - -TSX will be translated to lua as it would be translated to JS: - -```typescript -const element =
Inner text!
; -``` - -Will become: - -```lua -local element = React.createElement("div", {a = b}, "Inner text!"); -``` - -## Custom factory functions - -It is possible to supply custom factory functions using the `jsxFactory` tsconfig setting or `/** @jsx */` annotation. - -### jsxFactory tsconfig example - -```json title=tsconfig.json -{ - "compilerOptions": { - ... - "jsx": "react", - "jsxFactory": "MyNamespace.MyCreate" - ... - }, -} -``` - -```typescript -const element =
Inner text!
; -``` - -Will translate to: - -```lua -local element = MyNamespace.MyCreate("div", {a = b}, "Inner text!"); -``` - -### @jsx annotation example - -Note: the annotation MUST be at the top of the file! - -```typescript -/** @jsx MyNamespace.MyCreate */ -const element =
Inner text!
; -``` - -Will translate to: - -```lua -local element = MyNamespace.MyCreate("div", {a = b}, "Inner text!"); -``` - -## jsxFragmentFactory - -You can also provide a customfragment using the `jsxFragmentFactory` tsconfig setting or `/** @jsxFrag */` annotation. - -### jsxFragmentFactory tsconfig example - -```json title=tsconfig.json -{ - "compilerOptions": { - ... - "jsx": "react", - "jsxFactory": "MyNamespace.MyCreate", - "jsxFragmentFactory": "MyNamespace.MyFragment" - ... - }, -} -``` - -```typescript -const element = <>; -``` - -Will translate to: - -```lua -local element = MyNamespace.MyCreate(MyNamespace.MyFragment, {}); -``` - -### @jsxFrag annotation example - -Note: the annotation MUST be at the top of the file! - -```typescript -/** @jsx MyNamespace.MyCreate */ -/** @jsxFrag MyNamespace.MyCreate */ -const element = <>; -``` - -Will translate to: - -```lua -local element = MyNamespace.MyCreate(MyNamespace.MyFragment, {}); -``` diff --git a/sidebars.json b/sidebars.json index 9bd4a426..2446d13f 100644 --- a/sidebars.json +++ b/sidebars.json @@ -10,7 +10,7 @@ "advanced/writing-declarations", "advanced/compiler-annotations", "advanced/language-extensions", - "tsx", + "jsx", { "type": "category", "label": "API",