Skip to content

Commit

Permalink
Merge pull request #114 from break-stuff/react-extended-types
Browse files Browse the repository at this point in the history
make react types extendable
  • Loading branch information
break-stuff committed May 7, 2024
2 parents 691a720 + a670416 commit a700ce1
Show file tree
Hide file tree
Showing 9 changed files with 156 additions and 174 deletions.
23 changes: 1 addition & 22 deletions demo/lit-app/custom-elements-manifest.config.mjs
Expand Up @@ -19,8 +19,6 @@ export default {
dev: false,
/** Run in watch mode, runs on file changes */
watch: false,
/** Include third party custom elements manifests */
dependencies: true,
/** Output CEM path to `package.json`, defaults to true */
packagejson: true,
/** Enable special handling for litelement */
Expand Down Expand Up @@ -48,26 +46,7 @@ export default {
customElementReactWrapperPlugin({
outdir: "./dist/react",
modulePath: () => `../index.js`,
globalEvents: [
{
event: "onChange",
description: "Fired when the value of an input element changes.",
type: "React.ChangeEventHandler",
},
{
event: "onSubmit",
description: "Fired when a form is submitted.",
type: "React.FormEventHandler",
},
{
event: "onFocus",
description: "Triggered when an element receives focus.",
type: "React.FocusEventHandler",
},
],
attributeMapping: {
"for": "_for",
}
reactProps: true,
}),
customElementVuejsPlugin({
componentTypePath: (name, tag) => `./dist/${tag}/${name}.d.ts`,
Expand Down
1 change: 1 addition & 0 deletions demo/lit-app/package.json
Expand Up @@ -16,6 +16,7 @@
"lit": "^2.7.6"
},
"devDependencies": {
"@types/react-dom": "^18.2.24",
"cem-plugin-expanded-types": "*",
"cem-plugin-custom-jsdoc-tags": "*",
"custom-element-jet-brains-integration": "*",
Expand Down
15 changes: 14 additions & 1 deletion demo/react-app/src/App.tsx
Expand Up @@ -29,7 +29,20 @@ function App() {
<p className="read-the-docs">
Click on the Vite and React logos to learn more
</p>
<RadioGroup variants="primary" complex="multi" external2="value5" external="value1" disabled={false}>
<RadioGroup
className={"test-1 test-2"}
variants="primary"
complexUnion={"large"}
complex={"multi"}
test-attr={"test"}
data={{ name: "test" }}
external2="value5"
data-test-id={"test"}
external="value1"
disabled={false}
myAttribute="test"
my-attribute={"zinger"}
>
<RadioButton value=""></RadioButton>
<RadioButton></RadioButton>
<RadioButton></RadioButton>
Expand Down
14 changes: 8 additions & 6 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions packages/react-wrappers/CHANGELOG.md
@@ -1,5 +1,10 @@
# CHANGELOG

## Next

- Added ability to extend react types
- Added attribute mapping

## 1.4.2

- Fix boolean properties when setting them to `false`
Expand Down
79 changes: 44 additions & 35 deletions packages/react-wrappers/README.md
Expand Up @@ -306,45 +306,15 @@ Event information will display with the element description during autocompletio
### Global Events
To keep the API clean, standard HTML Element events have been excluded with the exception of `onClick`. All components have a click handler by default, but if you want to include more events, you can use the `globalEvents` option. Pass it an array of events you want to add to your components. Here are some examples:
If you want to include global custom events, you can use the `globalEvents` option. Pass it an array of events you want to add to your components. Here are some examples:
```ts
globalEvents: [
{
event: "onMouseEnter",
description: "Triggered when the mouse pointer enters an element.",
type: "React.MouseEventHandler",
},
{
event: "onMouseLeave",
description: "Fired when the mouse pointer leaves an element.",
type: "React.MouseEventHandler",
},
{
event: "onKeyPress",
description: "Fired when a key is pressed.",
type: "React.KeyboardEventHandler",
},
{
event: "onKeyDown",
description: "Triggered when a key is pressed down.",
type: "React.KeyboardEventHandler",
},
{
event: "onKeyUp",
description: "Fired when a key is released.",
type: "React.KeyboardEventHandler",
},
{
event: "onDoubleClick",
description: "Triggered when an element is double-clicked.",
type: "React.MouseEventHandler",
},
{
event: "onScroll",
description: "Triggered when the user scrolls an element.",
type: "React.UIEventHandler",
},
event: "onMyCustomEvent",
description: "Triggered when you do a specific thing.",
type: "CustomEvent<MyDetails>",
}
];
```
Expand Down Expand Up @@ -413,3 +383,42 @@ export default () => {
return <MyButton variant={buttonVariant}>Button</MyButton>;
};
```
### Extending Types
All components will come with the following default prop types:
```ts
[
"children",
"className",
"dir",
"exportparts",
"htmlFor",
"hidden",
"id",
"key",
"lang",
"part",
"ref",
"slot",
"style",
"tabIndex",
"title",
"translate",
"onClick",
"onFocus",
"onBlur",
]
```
If you would like to extend the types to include those from [React's props list](https://react.dev/reference/react-dom/components/common#common-props), they can be added using the `reactProps` option in the configuration. Pass it a string array of the props you would like to include.
```ts
{
/* other config options */
reactProps: ['autoCapitalize', 'draggable', 'onAnimationEnd']
}
```
To include all props and events for the `HTMLElement` type, set the `reactProps` option to `true`.
97 changes: 23 additions & 74 deletions packages/react-wrappers/src/global.ts
@@ -1,40 +1,14 @@
import { GlobalEvent, MappedAttribute } from "./types";
import { MappedAttribute } from "./types";

export const baseProperties: MappedAttribute[] = [
{
name: "children",
propName: "children",
description: "Content between the opening and closing component tags.",
type: {
text: "any",
},
},
export const MAPPED_PROPS: MappedAttribute[] = [
{
name: "className",
propName: "className",
originalName: "class",
description:
"A space-separated list of the classes of the element. Classes allows CSS and JavaScript to select and access specific elements via the class selectors or functions like the method `Document.getElementsByClassName()`.",
},
{
name: "classList",
propName: "classList",
originalName: "classList",
description:
"Takes an object where the key is the class name(s) and the value is a boolean expression. When true, the class is applied, and when false, it is removed.",
type: {
text: "Record<string, boolean | undefined>",
},
},
{
name: "dir",
propName: "dir",
description:
"Specifies the text direction of the element.",
type: {
text: "'ltr' | 'rtl'",
},
},

{
name: "exportparts",
propName: "exportparts",
Expand All @@ -50,20 +24,6 @@ export const baseProperties: MappedAttribute[] = [
text: "string",
},
},
{
name: "hidden",
propName: "hidden",
description: "Prevents content from being rendered by the browser.",
type: {
text: "boolean",
},
},
{
name: "id",
propName: "id",
description:
"Defines a unique identifier (ID) which must be unique in the whole document. Its purpose is to identify the element when linking (using a fragment identifier), scripting, or styling (with CSS).",
},
{
name: "key",
propName: "key",
Expand All @@ -73,11 +33,6 @@ export const baseProperties: MappedAttribute[] = [
text: "number | string",
},
},
{
name: "lang",
propName: "lang",
description: "Specifies the language of the element.",
},
{
name: "part",
propName: "part",
Expand All @@ -93,12 +48,6 @@ export const baseProperties: MappedAttribute[] = [
text: "any",
},
},
{
name: "slot",
propName: "slot",
description:
"Assigns a slot in a shadow DOM shadow tree to an element: An element with a slot attribute is assigned to the slot created by the `<slot>` element whose [name](https://developer.mozilla.org/docs/Web/HTML/Element/slot#attr-name) attribute's value matches that slot attribute's value.",
},
{
name: "style",
propName: "style",
Expand All @@ -117,26 +66,26 @@ export const baseProperties: MappedAttribute[] = [
text: "string",
},
},
{
name: "title",
propName: "title",
description: "Specifies the tooltip text for the element.",
},
{
name: "translate",
propName: "translate",
description:
"Passing 'no' excludes the element content from being translated.",
type: {
text: "'yes' | 'no'",
},
},
];

export const baseEvents: GlobalEvent[] = [
{
event: "onClick",
description: "Triggered when a user clicks an element.",
type: "React.MouseEventHandler",
},
export const BASE_PROPS = [
"children",
"className",
"dir",
"exportparts",
"htmlFor",
"hidden",
"id",
"key",
"lang",
"part",
"ref",
"slot",
"style",
"tabIndex",
"title",
"translate",
"onClick",
"onFocus",
"onBlur",
];
6 changes: 5 additions & 1 deletion packages/react-wrappers/src/types.d.ts
Expand Up @@ -9,8 +9,12 @@ export interface Options extends BaseOptions {
defaultExport?: boolean;
/** Used to provide alternative property name to prevent name collisions with React */
attributeMapping?: { [key: string]: string };
/** Used to add global element props to all component types */
/** Used to add custom global props to all component types */
globalProps?: MappedAttribute[];
/** Used to add custom global events to all component types */
globalEvents?: GlobalEvent[];
/** Includes React props defined for HTML elements */
reactProps?: string[] | boolean;
}

export interface GlobalEvent {
Expand Down

0 comments on commit a700ce1

Please sign in to comment.