diff --git a/examples/react/basic/src/index.tsx b/examples/react/basic/src/index.tsx index 7fe7eeab..1153355a 100644 --- a/examples/react/basic/src/index.tsx +++ b/examples/react/basic/src/index.tsx @@ -1,5 +1,5 @@ import { createRoot } from 'react-dom/client' -import { createContext, useContext, useState } from 'react' +import { createContext, useContext, useEffect, useState } from 'react' import { createPortal } from 'react-dom' import { QueryClient, @@ -167,6 +167,17 @@ function App() { const [state, setState] = useState(1) const [win, setWin] = useState(null) const [postId, setPostId] = useState(-1) + const [value, setValue] = useState({ + initial: 'value', + should: 'change', + in: 2, + array: [1, 2, 3], + }) + useEffect(() => { + setTimeout(() => { + setValue({ title: 'Test Event', description: 'This is a test event.' }) + }, 2000) + }, []) return (
@@ -177,6 +188,45 @@ function App() { + + + console.log('Button clicked!')} + /> + + + Test Title + + Test Description + + 🔥 + + + + + test + + + {win && createPortal(, win.document.body)}

diff --git a/examples/react/start/src/components/client-plugin.tsx b/examples/react/start/src/components/client-plugin.tsx index 446a6d2a..53d79f85 100644 --- a/examples/react/start/src/components/client-plugin.tsx +++ b/examples/react/start/src/components/client-plugin.tsx @@ -17,6 +17,7 @@ export default function ClientPlugin() {

Client Plugin Initialized

Devtools Client is connected.

+
+ + console.log('Button clicked!')} + />
diff --git a/packages/devtools-ui/package.json b/packages/devtools-ui/package.json index a5dc7241..4afae3bb 100644 --- a/packages/devtools-ui/package.json +++ b/packages/devtools-ui/package.json @@ -56,9 +56,11 @@ "dependencies": { "clsx": "^2.1.1", "goober": "^2.1.16", + "solid-element": "^1.9.1", "solid-js": "^1.9.7" }, "peerDependencies": { + "@types/react": ">=17.0.0", "solid-js": ">=1.9.7" }, "devDependencies": { diff --git a/packages/devtools-ui/src/components/button.tsx b/packages/devtools-ui/src/components/button.tsx index e064455c..b6c47c9f 100644 --- a/packages/devtools-ui/src/components/button.tsx +++ b/packages/devtools-ui/src/components/button.tsx @@ -1,5 +1,6 @@ -import { splitProps } from 'solid-js' +import { Show, createEffect, createSignal, splitProps } from 'solid-js' import clsx from 'clsx' +import { customElement, noShadowDOM } from 'solid-element' import { useStyles } from '../styles/use-styles' import type { JSX } from 'solid-js' @@ -10,12 +11,14 @@ export type ButtonVariant = | 'success' | 'info' | 'warning' -type ButtonProps = JSX.ButtonHTMLAttributes & { + +export type ButtonProps = JSX.ButtonHTMLAttributes & { variant?: ButtonVariant outline?: boolean ghost?: boolean children?: any className?: string + text?: string } export function Button(props: ButtonProps) { @@ -40,3 +43,37 @@ export function Button(props: ButtonProps) { ) } + +export interface ButtonWebComponentProps + extends Exclude { + text: string +} + +export const registerButtonComponent = (elName: string = 'tsd-button') => + customElement( + elName, + { + variant: 'primary', + outline: false, + ghost: false, + text: '', + disabled: false, + autofocus: false, + }, + (props, { element }) => { + noShadowDOM() + const [buttonProps, setButtonProps] = createSignal(props) + + createEffect(() => { + element.addPropertyChangedCallback((name, value) => { + setButtonProps((prev) => ({ ...prev, [name]: value })) + }) + }) + + return ( + + + + ) + }, + ) diff --git a/packages/devtools-ui/src/components/checkbox.tsx b/packages/devtools-ui/src/components/checkbox.tsx index de5e761c..6d6fec8c 100644 --- a/packages/devtools-ui/src/components/checkbox.tsx +++ b/packages/devtools-ui/src/components/checkbox.tsx @@ -1,7 +1,8 @@ -import { createSignal } from 'solid-js' +import { Show, createEffect, createSignal } from 'solid-js' +import { customElement, noShadowDOM } from 'solid-element' import { useStyles } from '../styles/use-styles' -interface CheckboxProps { +export interface CheckboxProps { label?: string checked?: boolean onChange?: (checked: boolean) => void @@ -41,3 +42,29 @@ export function Checkbox(props: CheckboxProps) {
) } + +export const registerCheckboxComponent = (elName: string = 'tsd-checkbox') => + customElement( + elName, + { + checked: false, + label: '', + description: '', + }, + (props, { element }) => { + noShadowDOM() + const [checkboxProps, setCheckboxProps] = createSignal(props) + + createEffect(() => { + element.addPropertyChangedCallback((name, value) => { + setCheckboxProps((prev) => ({ ...prev, [name]: value })) + }) + }) + + return ( + + + + ) + }, + ) diff --git a/packages/devtools-ui/src/components/header.tsx b/packages/devtools-ui/src/components/header.tsx index 1bdb4332..b63d290e 100644 --- a/packages/devtools-ui/src/components/header.tsx +++ b/packages/devtools-ui/src/components/header.tsx @@ -1,16 +1,19 @@ import clsx from 'clsx' +import { customElement, noShadowDOM } from 'solid-element' +import { createEffect, createSignal } from 'solid-js' import { useStyles } from '../styles/use-styles' import type { JSX } from 'solid-js/jsx-runtime' -export function Header({ - children, - class: className, - ...rest -}: JSX.IntrinsicElements['header']) { +export type HeaderProps = Omit & { + className?: string + children?: any +} + +export function Header({ children, class: className, ...rest }: HeaderProps) { const styles = useStyles() return (
{children} @@ -18,16 +21,15 @@ export function Header({ ) } -export function HeaderLogo({ - children, - flavor, -}: { - children: JSX.Element +export type HeaderLogoProps = { + children?: any flavor: { light: string dark: string } -}) { +} + +export function HeaderLogo({ children, flavor }: HeaderLogoProps) { const styles = useStyles() return (
@@ -42,3 +44,37 @@ export function HeaderLogo({
) } + +export const registerHeaderComponent = (elName: string = 'tsd-header') => + customElement( + elName, + { className: '' }, + (props, { element }) => { + noShadowDOM() + const [headerProps, setHeaderProps] = createSignal(props) + createEffect(() => { + element.addPropertyChangedCallback((name, value) => { + setHeaderProps((prev) => ({ ...prev, [name]: value })) + }) + }) + return
{headerProps().children}
+ }, + ) + +export const registerHeaderLogoComponent = ( + elName: string = 'tsd-header-logo', +) => + customElement( + elName, + { flavor: { light: '', dark: '' } }, + (props, { element }) => { + noShadowDOM() + const [logoProps, setLogoProps] = createSignal(props) + createEffect(() => { + element.addPropertyChangedCallback((name, value) => { + setLogoProps((prev) => ({ ...prev, [name]: value })) + }) + }) + return {logoProps().children} + }, + ) diff --git a/packages/devtools-ui/src/components/input.tsx b/packages/devtools-ui/src/components/input.tsx index 8868d073..843859d2 100644 --- a/packages/devtools-ui/src/components/input.tsx +++ b/packages/devtools-ui/src/components/input.tsx @@ -1,7 +1,8 @@ import { createSignal } from 'solid-js' +import { customElement, noShadowDOM } from 'solid-element' import { useStyles } from '../styles/use-styles' -interface InputProps { +export interface InputProps { label?: string type?: 'text' | 'number' | 'password' | 'email' value?: string @@ -40,3 +41,20 @@ export function Input(props: InputProps) { ) } + +export const registerInputComponent = (elName: string = 'tsd-input') => + customElement( + elName, + { label: '', type: 'text', value: '', placeholder: '', description: '' }, + (props, { element }) => { + noShadowDOM() + const [inputProps, setInputProps] = createSignal(props) + createSignal(() => { + element.addPropertyChangedCallback((name, value) => { + setInputProps((prev) => ({ ...prev, [name]: value })) + }) + }) + + return + }, + ) diff --git a/packages/devtools-ui/src/components/main-panel.tsx b/packages/devtools-ui/src/components/main-panel.tsx index 64b97ffc..e8448b88 100644 --- a/packages/devtools-ui/src/components/main-panel.tsx +++ b/packages/devtools-ui/src/components/main-panel.tsx @@ -1,8 +1,10 @@ import clsx from 'clsx' +import { createEffect, createSignal } from 'solid-js' +import { customElement, noShadowDOM } from 'solid-element' import { useStyles } from '../styles/use-styles' import type { JSX } from 'solid-js/jsx-runtime' -type PanelProps = JSX.IntrinsicElements['div'] & { +export type PanelProps = Omit & { children?: any className?: string withPadding?: boolean @@ -28,3 +30,20 @@ export const MainPanel = ({ ) } + +export const registerMainPanelComponent = (elName: string = 'tsd-main-panel') => + customElement( + elName, + { className: '', withPadding: false }, + (props, { element }) => { + noShadowDOM() + const [panelProps, setPanelProps] = createSignal(props) + createEffect(() => { + element.addPropertyChangedCallback((name, value) => { + setPanelProps((prev) => ({ ...prev, [name]: value })) + }) + }) + + return {panelProps().children} + }, + ) diff --git a/packages/devtools-ui/src/components/section.tsx b/packages/devtools-ui/src/components/section.tsx index 38bc008f..c18f716d 100644 --- a/packages/devtools-ui/src/components/section.tsx +++ b/packages/devtools-ui/src/components/section.tsx @@ -1,11 +1,17 @@ import clsx from 'clsx' +import { customElement, noShadowDOM } from 'solid-element' +import { createEffect, createSignal } from 'solid-js' import { useStyles } from '../styles/use-styles' import type { JSX } from 'solid-js/jsx-runtime' -export const Section = ({ - children, - ...rest -}: JSX.IntrinsicElements['section']) => { +export type SectionProps = Omit< + JSX.IntrinsicElements['section'], + 'children' +> & { + children?: any +} + +export const Section = ({ children, ...rest }: SectionProps) => { const styles = useStyles() return (
@@ -14,10 +20,14 @@ export const Section = ({ ) } -export const SectionTitle = ({ - children, - ...rest -}: JSX.IntrinsicElements['h3']) => { +export type SectionTitleProps = Omit< + JSX.IntrinsicElements['h3'], + 'children' +> & { + children?: any +} + +export const SectionTitle = ({ children, ...rest }: SectionTitleProps) => { const styles = useStyles() return (

@@ -26,10 +36,17 @@ export const SectionTitle = ({ ) } +export type SectionDescriptionProps = Omit< + JSX.IntrinsicElements['p'], + 'children' +> & { + children?: any +} + export const SectionDescription = ({ children, ...rest -}: JSX.IntrinsicElements['p']) => { +}: SectionDescriptionProps) => { const styles = useStyles() return (

@@ -38,10 +55,14 @@ export const SectionDescription = ({ ) } -export const SectionIcon = ({ - children, - ...rest -}: JSX.IntrinsicElements['span']) => { +export type SectionIconProps = Omit< + JSX.IntrinsicElements['span'], + 'children' +> & { + children?: any +} + +export const SectionIcon = ({ children, ...rest }: SectionIconProps) => { const styles = useStyles() return ( @@ -49,3 +70,63 @@ export const SectionIcon = ({ ) } + +export const registerSectionComponent = (elName: string = 'tsd-section') => + customElement(elName, {}, (props, { element }) => { + noShadowDOM() + const [sectionProps, setSectionProps] = createSignal(props) + + createEffect(() => { + element.addPropertyChangedCallback((name, value) => { + setSectionProps((prev) => ({ ...prev, [name]: value })) + }) + }) + return

{sectionProps().children}
+ }) + +export const registerSectionTitleComponent = ( + elName: string = 'tsd-section-title', +) => + customElement(elName, {}, (props, { element }) => { + noShadowDOM() + const [titleProps, setTitleProps] = createSignal(props) + createEffect(() => { + element.addPropertyChangedCallback((name, value) => { + setTitleProps((prev) => ({ ...prev, [name]: value })) + }) + }) + return ( + {titleProps().children} + ) + }) + +export const registerSectionDescriptionComponent = ( + elName: string = 'tsd-section-description', +) => + customElement(elName, {}, (props, { element }) => { + noShadowDOM() + const [descriptionProps, setDescriptionProps] = createSignal(props) + createEffect(() => { + element.addPropertyChangedCallback((name, value) => { + setDescriptionProps((prev) => ({ ...prev, [name]: value })) + }) + }) + return ( + + {descriptionProps().children} + + ) + }) +export const registerSectionIconComponent = ( + elName: string = 'tsd-section-icon', +) => + customElement(elName, {}, (props, { element }) => { + noShadowDOM() + const [iconProps, setIconProps] = createSignal(props) + createEffect(() => { + element.addPropertyChangedCallback((name, value) => { + setIconProps((prev) => ({ ...prev, [name]: value })) + }) + }) + return {iconProps().children} + }) diff --git a/packages/devtools-ui/src/components/select.tsx b/packages/devtools-ui/src/components/select.tsx index a5aec5f9..7b95ba48 100644 --- a/packages/devtools-ui/src/components/select.tsx +++ b/packages/devtools-ui/src/components/select.tsx @@ -1,4 +1,5 @@ -import { createSignal } from 'solid-js' +import { Show, createEffect, createSignal } from 'solid-js' +import { customElement, noShadowDOM } from 'solid-element' import { useStyles } from '../styles/use-styles' interface SelectOption { @@ -6,7 +7,7 @@ interface SelectOption { label: string } -interface SelectProps { +export interface SelectProps { label?: string options: Array> value?: T @@ -48,3 +49,30 @@ export function Select(props: SelectProps) { ) } + +export const registerSelectComponent = (elName: string = 'tsd-select') => + customElement>( + elName, + { + label: '', + options: [], + value: undefined, + description: '', + }, + (props, { element }) => { + noShadowDOM() + const [selectProps, setSelectProps] = createSignal(props) + + createEffect(() => { + element.addPropertyChangedCallback((name, value) => { + setSelectProps((prev) => ({ ...prev, [name]: value })) + }) + }) + + return ( + +