Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 16 additions & 24 deletions packages/components/_templates/mitosis/new/component/tsx.ejs.t
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,22 @@ import { onMount, Show, useMetadata, useStore } from "@builder.io/mitosis";
import { DB<%= h.changeCase.pascal(name) %>State, DB<%= h.changeCase.pascal(name) %>Props } from "./model";
import { cls, uuid } from "../../utils";
import {DEFAULT_ID} from "../../shared/constants";
<% if(formValue!=="no"){ -%>
import {ChangeEvent, InteractionEvent} from "../../shared/model";
<% } -%>

useMetadata({
isAttachedToShadowDom: true,
component: {
// MS Power Apps
includeIcon: false,
properties: [],
},
isAttachedToShadowDom: true
});

export default function DB<%= h.changeCase.pascal(name) %>(props: DB<%= h.changeCase.pascal(name) %>Props) {
// This is used as forwardRef
let component: any;
const ref = useRef<HTMLDivElement>(null);
// jscpd:ignore-start
const state = useStore<DB<%= h.changeCase.pascal(name) %>State>({
_id: DEFAULT_ID,
<% if(formValue!=="no"){ -%>
_isValid: undefined,
handleChange: (event: any) => {
handleChange: (event: ChangeEvent<HTMLInputElement>) => {
if (props.onChange) {
props.onChange(event);
}
Expand All @@ -32,21 +29,16 @@ export default function DB<%= h.changeCase.pascal(name) %>(props: DB<%= h.change
props.change(event);
}

if (event.target?.validity?.valid != state._isValid) {
state._isValid = event.target?.validity?.valid;
if (props.validityChange) {
props.validityChange(!!event.target?.validity?.valid);
}
}
const target = event.target as HTMLInputElement;

// TODO: Replace this with the solution out of https://github.com/BuilderIO/mitosis/issues/833 after this has been "solved"
// VUE:this.$emit("update:<%= formValue %>", event.target.<%= formValue %>);
// VUE:this.$emit("update:<%= formValue %>", target.<%= formValue %>);

// Change event to work with reactive and template driven forms
// ANGULAR: this.propagateChange(event.target.<%= formValue %>);
// ANGULAR: this.writeValue(event.target.<%= formValue %>);
// ANGULAR: this.propagateChange(target.<%= formValue %>);
// ANGULAR: this.writeValue(target.<%= formValue %>);
},
handleBlur: (event: any) => {
handleBlur: (event: InteractionEvent<HTMLInputElement>) => {
if (props.onBlur) {
props.onBlur(event);
}
Expand All @@ -55,7 +47,7 @@ export default function DB<%= h.changeCase.pascal(name) %>(props: DB<%= h.change
props.blur(event);
}
},
handleFocus: (event: any) => {
handleFocus: (event: InteractionEvent<HTMLInputElement>) => {
if (props.onFocus) {
props.onFocus(event);
}
Expand All @@ -77,13 +69,13 @@ export default function DB<%= h.changeCase.pascal(name) %>(props: DB<%= h.change

return (
<div
ref={component}
ref={ref}
id={state._id}
class={cls('db-<%= name %>', props.className)}
<% if(formValue!=="no"){ -%>
onChange={(event) => state.handleChange(event)}
onBlur={(event) => state.handleBlur(event)}
onFocus={(event) => state.handleFocus(event)}
onChange={(event: ChangeEvent<HTMLInputElement>) => state.handleChange(event)}
onBlur={(event: InteractionEvent<HTMLInputElement>) => state.handleBlur(event)}
onFocus={(event: InteractionEvent<HTMLInputElement>) => state.handleFocus(event)}
<% } -%>
>
<Show when={state.stylePath}>
Expand Down
4 changes: 2 additions & 2 deletions packages/components/scripts/post-build/angular.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,8 @@ const setControlValueAccessorReplacements = (
writeValue(value: any) {
this.${valueAccessor} = value;

if (this.component?.nativeElement) {
this.renderer.setProperty(this.component?.nativeElement, '${valueAccessor}', value);
if (this.ref?.nativeElement) {
this.renderer.setProperty(this.ref?.nativeElement, '${valueAccessor}', value);
}
}

Expand Down
29 changes: 3 additions & 26 deletions packages/components/scripts/post-build/components.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,6 @@ const getComponents = () => [
overwrites: {
angular: [
{ from: 'openItems = []', to: 'openItems: string[] = []' }
],
react: [
{
from: 'const ref = useRef<HTMLDivElement>(null);',
to: 'const ref = useRef<HTMLDivElement>(component);'
}
]
}
},
Expand All @@ -56,22 +50,11 @@ const getComponents = () => [
angular: {
controlValueAccessor: 'value'
}
},
overwrites: {
},overwrites: {
angular: [
{
from: '[attr.defaultValue]="defaultValue ?? children"',
to: ''
},
{
from: '</textarea>',
to: '{{value || defaultValue}}</textarea>'
}
],
vue: [
{
from: ':defaultValue="defaultValue || $slots.default"',
to: ''
to: '{{value}}</textarea>'
}
]
}
Expand Down Expand Up @@ -106,12 +89,6 @@ const getComponents = () => [
{
name: 'drawer',
overwrites: {
react: [
{
from: 'const dialogRef = useRef<HTMLDialogElement>(null);',
to: 'const dialogRef = useRef<HTMLDialogElement>(component);'
}
],
webComponents: [{ from: '__prev.find', to: '!!__prev.find' }]
}
},
Expand Down Expand Up @@ -142,7 +119,7 @@ const getComponents = () => [
vModel: [{ modelValue: 'checked', binding: ':checked' }]
},
angular: {
controlValueAccessor: false
controlValueAccessor: 'checked'
}
}
},
Expand Down
64 changes: 57 additions & 7 deletions packages/components/scripts/post-build/react.js
Original file line number Diff line number Diff line change
@@ -1,28 +1,62 @@
const { components } = require('./components');
const FS = require('node:fs');
const { getComponentName, runReplacements } = require('../utils');

const overwriteEvents = (tmp) => {
const modelFilePath = `../../${
tmp ? 'output/tmp' : 'output'
}/react/src/shared/model.ts`;
let modelFileContent = FS.readFileSync(modelFilePath).toString('utf-8');
modelFileContent = 'import * as React from "react";\n' + modelFileContent;
modelFileContent = modelFileContent.replace(
'export type ClickEvent<T> = MouseEvent;',
'export type ClickEvent<T> = React.MouseEvent<T, MouseEvent>;'
);
modelFileContent = modelFileContent.replace(
'export type ChangeEvent<T> = Event;',
'export type ChangeEvent<T> = React.ChangeEvent<T>;'
);
modelFileContent = modelFileContent.replace(
'export type InteractionEvent<T> = FocusEvent;',
'export type InteractionEvent<T> = React.FocusEvent<T>;'
);
FS.writeFileSync(modelFilePath, modelFileContent);
};

module.exports = (tmp) => {
for (const component of components) {
try {
try {
overwriteEvents(tmp);

for (const component of components) {
const upperComponentName = getComponentName(component.name);

const tsxFile = `../../${
tmp ? 'output/tmp' : 'output'
}/react/src/components/${component.name}/${component.name}.tsx`;

const tsxFileContent = FS.readFileSync(tsxFile).toString('utf-8');
const htmlElements = tsxFileContent.match('(?<=useRef<)(.*?)(?=>)');
let htmlElement = 'HTMLDivElement';
if (htmlElements.length > 0) {
htmlElement = htmlElements[0];
}

let replacements = [
{
from: /= useState/g,
to: '= useState<any>'
},
{ from: ` } from "react"`, to: `, forwardRef } from "react"` },
{
from: ` } from "react"`,
to: `, forwardRef, HTMLProps } from "react"`
},
{
from: `function DB${upperComponentName}(props: DB${upperComponentName}Props) {`,
to: `function DB${upperComponentName}Fn(props: DB${upperComponentName}Props, component: any) {`
to: `function DB${upperComponentName}Fn(props: Omit<HTMLProps<${htmlElement}>, keyof DB${upperComponentName}Props> & DB${upperComponentName}Props, component: any) {`
},
{
from: `export default DB${upperComponentName};`,
to: `const DB${upperComponentName} = forwardRef(DB${upperComponentName}Fn);\nexport default DB${upperComponentName};`
to: `const DB${upperComponentName} = forwardRef<${htmlElement}, Omit<HTMLProps<${htmlElement}>, keyof DB${upperComponentName}Props> & DB${upperComponentName}Props>(DB${upperComponentName}Fn);\nexport default DB${upperComponentName};`
},
{
from: 'if (ref.current)',
Expand All @@ -31,12 +65,28 @@ module.exports = (tmp) => {
{
from: '[ref.current]',
to: '[ref]'
},
{
from: '>(null);',
to: '>(component);'
},
{
from: '={true}',
to: ''
},
{
from: '} from "../../utils"',
to: ', filterPassingProps } from "../../utils"'
},
{
from: 'ref={ref}',
to: 'ref={ref}\n' + '{...filterPassingProps(props)}'
}
];

runReplacements(replacements, component, 'react', tsxFile);
} catch (error) {
console.error('Error occurred:', error);
}
} catch (error) {
console.error('Error occurred:', error);
}
};
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ import {
Show,
Slot,
useMetadata,
useRef,
useStore
} from '@builder.io/mitosis';
import { DBAccordionItemState, DBAccordionItemProps } from './model';
import { cls, uuid } from '../../utils';
import { DEFAULT_ID } from '../../shared/constants';
import { ClickEvent } from '../../shared/model';

useMetadata({
isAttachedToShadowDom: true,
Expand All @@ -20,12 +22,11 @@ useMetadata({
});

export default function DBAccordionItem(props: DBAccordionItemProps) {
// This is used as forwardRef
let component: any;
const ref = useRef<HTMLDetailsElement>(null);
// jscpd:ignore-start
const state = useStore<DBAccordionItemState>({
_id: DEFAULT_ID,
toggle: (event: any) => {
toggle: (event: ClickEvent<HTMLElement>) => {
// We need this for react https://github.com/facebook/react/issues/15486#issuecomment-488028431
event?.preventDefault();
if (props.onToggle) {
Expand All @@ -44,15 +45,18 @@ export default function DBAccordionItem(props: DBAccordionItemProps) {

return (
<details
ref={component}
ref={ref}
id={state._id}
class={cls('db-accordion-item', props.className)}
aria-disabled={props.disabled}
open={props.open}>
<Show when={state.stylePath}>
<link rel="stylesheet" href={state.stylePath} />
</Show>
<summary onClick={(event) => state.toggle(event)}>
<summary
onClick={(event: ClickEvent<HTMLElement>) =>
state.toggle(event)
}>
<Show when={props.title}>{props.title}</Show>
<Show when={!props.title}>
<Slot name="title" />
Expand Down
2 changes: 1 addition & 1 deletion packages/components/src/components/accordion-item/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,4 @@ export interface DBAccordionItemDefaultState {}

export type DBAccordionItemState = DBAccordionItemDefaultState &
GlobalState &
ToggleEventState;
ToggleEventState<HTMLElement>;
Loading