From b5fe6bd2b9c01cb1a976d6e7b4f85e3bc566cc87 Mon Sep 17 00:00:00 2001 From: Bela Bohlender Date: Tue, 5 Nov 2024 14:23:19 +0100 Subject: [PATCH] fix: route onClick, ... event handlers through uikit so uikit is aware of them and can compute the ancestorsHaveListeners flag correctly --- .../components-and-properties.md | 2 +- examples/uikit/src/App.tsx | 5 +- examples/vanilla/index.ts | 2 +- packages/icons/lucide/react/generate.ts | 4 +- packages/kits/apfel/src/button.tsx | 4 +- packages/kits/apfel/src/card.tsx | 4 +- packages/kits/apfel/src/checkbox.tsx | 4 +- packages/kits/apfel/src/input.tsx | 4 +- packages/kits/apfel/src/list.tsx | 6 +- packages/kits/apfel/src/loading.tsx | 4 +- packages/kits/apfel/src/progress.tsx | 4 +- packages/kits/apfel/src/slider.tsx | 6 +- packages/kits/apfel/src/tab-bar.tsx | 6 +- packages/kits/apfel/src/tabs.tsx | 6 +- packages/kits/default/src/accordion.tsx | 13 +- packages/kits/default/src/alert-dialog.tsx | 83 ++++---- packages/kits/default/src/alert.tsx | 42 ++-- packages/kits/default/src/avatar.tsx | 31 ++- packages/kits/default/src/badge.tsx | 4 +- packages/kits/default/src/button.tsx | 4 +- packages/kits/default/src/card.tsx | 10 +- packages/kits/default/src/checkbox.tsx | 4 +- packages/kits/default/src/dialog.tsx | 37 ++-- packages/kits/default/src/input.tsx | 4 +- packages/kits/default/src/label.tsx | 4 +- packages/kits/default/src/menubar.tsx | 13 +- packages/kits/default/src/pagination.tsx | 76 ++++--- packages/kits/default/src/progress.tsx | 4 +- packages/kits/default/src/radio-group.tsx | 11 +- packages/kits/default/src/separator.tsx | 4 +- packages/kits/default/src/skeleton.tsx | 4 +- packages/kits/default/src/slider.tsx | 6 +- packages/kits/default/src/switch.tsx | 4 +- packages/kits/default/src/tabs.tsx | 10 +- packages/kits/default/src/textarea.tsx | 4 +- packages/kits/default/src/toggle-group.tsx | 6 +- packages/kits/default/src/toggle.tsx | 4 +- packages/kits/default/src/tooltip.tsx | 18 +- packages/kits/default/src/video.tsx | 194 +++++++++--------- packages/react/src/container.tsx | 84 ++++---- packages/react/src/content.tsx | 87 ++++---- packages/react/src/custom.tsx | 101 +++++---- packages/react/src/fullscreen.tsx | 106 +++++----- packages/react/src/icon.tsx | 29 ++- packages/react/src/image.tsx | 23 +-- packages/react/src/index.ts | 1 + packages/react/src/input.tsx | 115 +++++------ packages/react/src/portal.tsx | 18 +- packages/react/src/root.tsx | 19 +- packages/react/src/suspending.tsx | 17 +- packages/react/src/svg.tsx | 30 +-- packages/react/src/text.tsx | 18 +- packages/react/src/{utilts.tsx => utils.tsx} | 40 +--- packages/react/src/video.tsx | 17 +- packages/uikit/src/active.ts | 4 +- packages/uikit/src/components/container.ts | 21 +- packages/uikit/src/components/content.ts | 20 +- packages/uikit/src/components/custom.ts | 20 +- packages/uikit/src/components/fullscreen.ts | 6 +- packages/uikit/src/components/icon.ts | 22 +- packages/uikit/src/components/image.ts | 22 +- packages/uikit/src/components/input.ts | 27 +-- packages/uikit/src/components/root.ts | 16 +- packages/uikit/src/components/svg.ts | 21 +- packages/uikit/src/components/text.ts | 21 +- packages/uikit/src/components/utils.ts | 39 +++- packages/uikit/src/components/video.ts | 4 +- packages/uikit/src/events.ts | 43 ++-- packages/uikit/src/index.ts | 2 +- packages/uikit/src/listeners.ts | 4 +- packages/uikit/src/scroll.ts | 49 +++-- packages/uikit/src/vanilla/container.ts | 21 +- packages/uikit/src/vanilla/content.ts | 21 +- packages/uikit/src/vanilla/custom.ts | 23 ++- packages/uikit/src/vanilla/fullscreen.ts | 11 +- packages/uikit/src/vanilla/icon.ts | 22 +- packages/uikit/src/vanilla/image.ts | 22 +- packages/uikit/src/vanilla/input.ts | 20 +- packages/uikit/src/vanilla/root.ts | 21 +- packages/uikit/src/vanilla/svg.ts | 21 +- packages/uikit/src/vanilla/text.ts | 22 +- packages/uikit/src/vanilla/video.ts | 7 +- 82 files changed, 986 insertions(+), 926 deletions(-) rename packages/react/src/{utilts.tsx => utils.tsx} (50%) diff --git a/docs/getting-started/components-and-properties.md b/docs/getting-started/components-and-properties.md index 4562011c..48f3477f 100644 --- a/docs/getting-started/components-and-properties.md +++ b/docs/getting-started/components-and-properties.md @@ -529,7 +529,7 @@ All Components support [all R3F event handlers](https://docs.pmnd.rs/react-three ## Ref -Each component exposes the `ComponentInternals` when using a `ref`. The component internals provide you with access to +Each component exposes internal information when using a `ref`. For instance, the container component exposes internals of the type `ContainerRef`. The component internals provide you with access to | Property | Explanation | | ------------------- | --------------------------------------------------------------------------------------------------------------- | diff --git a/examples/uikit/src/App.tsx b/examples/uikit/src/App.tsx index 2e3fda3a..6bc0976f 100644 --- a/examples/uikit/src/App.tsx +++ b/examples/uikit/src/App.tsx @@ -14,11 +14,10 @@ import { SuspendingImage, Input, FontFamilyProvider, - ComponentInternals, - ImageProperties, Video, useMeasureText, InputInternals, + ImageRef, } from '@react-three/uikit' import { Texture } from 'three' import { Skeleton } from '../../../packages/kits/default/src/skeleton.js' @@ -31,7 +30,7 @@ export default function App() { const s = useMemo(() => signal(5), []) const x = useMemo(() => signal('red'), []) const t = useMemo(() => signal('X X\nX X'), []) - const ref = useRef>(null) + const ref = useRef(null) const [input, setInput] = useState(null) const videoRef = useRef() const [videoel, setVideoEl] = useState() diff --git a/examples/vanilla/index.ts b/examples/vanilla/index.ts index 4e63b1e9..86940e05 100644 --- a/examples/vanilla/index.ts +++ b/examples/vanilla/index.ts @@ -68,7 +68,7 @@ setTimeout(() => { const c = new Content({ flexShrink: 0, height: 100, backgroundColor: 'black' }) const loader = new GLTFLoader() loader.load('example.glb', (gltf) => c.add(gltf.scene)) -const del = new Delete({ width: 100, flexShrink: 0 }) +const del = new Delete({ onClick: () => {}, width: 100, flexShrink: 0 }) const svg = new Svg({ src: 'example.svg', width: 100, height: 100, flexShrink: 0 }) const text = new Text('Hello World', { fontSize: 40, flexShrink: 0 }) const a = new Container({ flexShrink: 0, alignSelf: 'stretch', flexGrow: 1, backgroundColor: 'blue' }) diff --git a/packages/icons/lucide/react/generate.ts b/packages/icons/lucide/react/generate.ts index 2730f6bb..f3748623 100644 --- a/packages/icons/lucide/react/generate.ts +++ b/packages/icons/lucide/react/generate.ts @@ -15,10 +15,10 @@ async function main() { const svg = raw.toString() const code = ` /* eslint-disable no-shadow-restricted-names */ - import { Icon, ComponentInternals, IconProperties } from "@react-three/uikit"; + import { Icon, IconRef, IconProperties } from "@react-three/uikit"; import { forwardRef } from "react"; const text = \`${svg}\`; - export const ${name}Icon = /*@__PURE__*/ forwardRef, Omit>((props, ref) => { + export const ${name}Icon = /*@__PURE__*/ forwardRef>((props, ref) => { return }) export const ${name} = ${name}Icon diff --git a/packages/kits/apfel/src/button.tsx b/packages/kits/apfel/src/button.tsx index 9bdb4264..f3a4fbf3 100644 --- a/packages/kits/apfel/src/button.tsx +++ b/packages/kits/apfel/src/button.tsx @@ -1,4 +1,4 @@ -import { ComponentInternals, Container, ContainerProperties, DefaultProperties } from '@react-three/uikit' +import { Container, ContainerProperties, ContainerRef, DefaultProperties } from '@react-three/uikit' import React, { ReactNode, RefAttributes, forwardRef } from 'react' import { colors } from './theme.js' @@ -61,7 +61,7 @@ export type ButtonProperties = ContainerProperties & { disabled?: boolean } -export const Button: (props: ButtonProperties & RefAttributes) => ReactNode = forwardRef( +export const Button: (props: ButtonProperties & RefAttributes) => ReactNode = forwardRef( ({ children, size = 'md', variant = 'rect', platter, selected, disabled, ...props }, ref) => { const { borderRadius, fontSize, height, padding, iconSize } = typeof size === 'number' ? getAribtrarySize(size) : sizes[size] diff --git a/packages/kits/apfel/src/card.tsx b/packages/kits/apfel/src/card.tsx index b5137288..da637298 100644 --- a/packages/kits/apfel/src/card.tsx +++ b/packages/kits/apfel/src/card.tsx @@ -1,10 +1,10 @@ -import { ComponentInternals, Container, ContainerProperties, DefaultProperties } from '@react-three/uikit' +import { ContainerRef, Container, ContainerProperties, DefaultProperties } from '@react-three/uikit' import React, { ReactNode, RefAttributes, forwardRef } from 'react' import { GlassMaterial, colors } from './theme.js' export type CardProperties = ContainerProperties -export const Card: (props: CardProperties & RefAttributes) => ReactNode = forwardRef( +export const Card: (props: CardProperties & RefAttributes) => ReactNode = forwardRef( ({ children, ...props }, ref) => { return ( ) => ReactNode = forwardRef( +export const Checkbox: (props: CheckboxProperties & RefAttributes) => ReactNode = forwardRef( ({ selected, disabled = false, defaultSelected, onSelectedChange, ...props }, ref) => { const [internalValue, setInternalValue] = useState(defaultSelected ?? false) const value = selected != null ? selected : internalValue diff --git a/packages/kits/apfel/src/input.tsx b/packages/kits/apfel/src/input.tsx index 09251dcb..c7e51bc5 100644 --- a/packages/kits/apfel/src/input.tsx +++ b/packages/kits/apfel/src/input.tsx @@ -7,7 +7,7 @@ import { Text, InputInternals, InputProperties as BaseInputProperties, - ComponentInternals, + ContainerRef, } from '@react-three/uikit' import React, { ReactNode, RefAttributes, forwardRef, useMemo, useState } from 'react' @@ -16,7 +16,7 @@ export type InputProperties = BaseInputProperties & { placeholder?: string; vari //TODO: increase hitbox size (by increasing the size of the InputImpl) -export const Input: (props: InputProperties & RefAttributes) => ReactNode = forwardRef( +export const Input: (props: InputProperties & RefAttributes) => ReactNode = forwardRef( ( { variant = 'rect', diff --git a/packages/kits/apfel/src/list.tsx b/packages/kits/apfel/src/list.tsx index 7788fd3f..d58cea69 100644 --- a/packages/kits/apfel/src/list.tsx +++ b/packages/kits/apfel/src/list.tsx @@ -1,4 +1,4 @@ -import { ComponentInternals, Container, ContainerProperties, DefaultProperties } from '@react-three/uikit' +import { ContainerRef, Container, ContainerProperties, DefaultProperties } from '@react-three/uikit' import React, { ReactNode, RefAttributes, createContext, forwardRef, useContext } from 'react' import { colors } from './theme.js' @@ -10,7 +10,7 @@ type ListProperties = ContainerProperties & { type?: Type } -export const List: (props: ListProperties & RefAttributes) => ReactNode = forwardRef( +export const List: (props: ListProperties & RefAttributes) => ReactNode = forwardRef( ({ type = 'plain', ...props }, ref) => { return ( @@ -29,7 +29,7 @@ export type ListItemProperties = ContainerProperties & { isLast?: boolean } -export const ListItem: (props: ListItemProperties & RefAttributes) => ReactNode = forwardRef( +export const ListItem: (props: ListItemProperties & RefAttributes) => ReactNode = forwardRef( ({ children, subtitle, selected, leadingAccessory, trailingAccessory, isFirst, isLast, ...props }, ref) => { const type = useContext(ListContext) diff --git a/packages/kits/apfel/src/loading.tsx b/packages/kits/apfel/src/loading.tsx index a885c486..c4795d1c 100644 --- a/packages/kits/apfel/src/loading.tsx +++ b/packages/kits/apfel/src/loading.tsx @@ -1,4 +1,4 @@ -import { ComponentInternals, Container, ContainerProperties } from '@react-three/uikit' +import { ContainerRef, Container, ContainerProperties } from '@react-three/uikit' import { useFrame } from '@react-three/fiber' import React, { ReactNode, RefAttributes, forwardRef, useMemo } from 'react' import { signal } from '@preact/signals-core' @@ -18,7 +18,7 @@ export type LoadingProperties = ContainerProperties & { size?: Size } -export const Loading: (props: LoadingProperties & RefAttributes) => ReactNode = forwardRef( +export const Loading: (props: LoadingProperties & RefAttributes) => ReactNode = forwardRef( ({ size = 'md', ...props }, ref) => { const pillOpacities = useMemo(() => new Array(PILL_AMOUNT).fill(undefined).map(() => signal(0)), []) diff --git a/packages/kits/apfel/src/progress.tsx b/packages/kits/apfel/src/progress.tsx index b0cea8db..f4a3bcbf 100644 --- a/packages/kits/apfel/src/progress.tsx +++ b/packages/kits/apfel/src/progress.tsx @@ -1,4 +1,4 @@ -import { ComponentInternals, Container, ContainerProperties } from '@react-three/uikit' +import { ContainerRef, Container, ContainerProperties } from '@react-three/uikit' import React, { ReactNode, RefAttributes, forwardRef } from 'react' import { colors } from './theme.js' @@ -6,7 +6,7 @@ export type ProgressProperties = ContainerProperties & { value?: number } -export const Progress: (props: ProgressProperties & RefAttributes) => ReactNode = forwardRef( +export const Progress: (props: ProgressProperties & RefAttributes) => ReactNode = forwardRef( ({ value = 0, ...props }, ref) => { return ( ) => ReactNode = forwardRef( +export const Slider: (props: SliderProperties & RefAttributes) => ReactNode = forwardRef( ( { value: providedValue, @@ -47,7 +47,7 @@ export const Slider: (props: SliderProperties & RefAttributes { const [uncontrolled, setUncontrolled] = useState(defaultValue) const value = providedValue ?? uncontrolled ?? 50 - const internalRef = useRef>(null) + const internalRef = useRef(null) const onChange = useRef(onValueChange) onChange.current = onValueChange const hasProvidedValue = providedValue != null diff --git a/packages/kits/apfel/src/tab-bar.tsx b/packages/kits/apfel/src/tab-bar.tsx index 4e756e17..6204b769 100644 --- a/packages/kits/apfel/src/tab-bar.tsx +++ b/packages/kits/apfel/src/tab-bar.tsx @@ -1,4 +1,4 @@ -import { ComponentInternals, Container, ContainerProperties, DefaultProperties } from '@react-three/uikit' +import { ContainerRef, Container, ContainerProperties, DefaultProperties } from '@react-three/uikit' import React, { ReactNode, RefAttributes, @@ -28,7 +28,7 @@ export type TabBarProperties = ContainerProperties & { onValueChange?(value: string): void } -export const TabBar: (props: TabBarProperties & RefAttributes) => ReactNode = forwardRef( +export const TabBar: (props: TabBarProperties & RefAttributes) => ReactNode = forwardRef( ({ value: valueProp, defaultValue, onValueChange, ...props }, ref) => { const [internalValue, setInternalValue] = useState(defaultValue) const value = valueProp !== undefined ? valueProp : internalValue @@ -82,7 +82,7 @@ export type TabBarItemProperties = ContainerProperties & { icon: ReactNode } -export const TabBarItem: (props: TabBarItemProperties & RefAttributes) => ReactNode = forwardRef( +export const TabBarItem: (props: TabBarItemProperties & RefAttributes) => ReactNode = forwardRef( ({ value: tabValue, children, icon, ...props }, ref) => { const { isExpanded, value, setValue } = useContext(TabBarContext)! const isSelected = value === tabValue diff --git a/packages/kits/apfel/src/tabs.tsx b/packages/kits/apfel/src/tabs.tsx index e7c77454..37b5260c 100644 --- a/packages/kits/apfel/src/tabs.tsx +++ b/packages/kits/apfel/src/tabs.tsx @@ -1,4 +1,4 @@ -import { ComponentInternals, Container, ContainerProperties, DefaultProperties } from '@react-three/uikit' +import { Container, ContainerProperties, ContainerRef, DefaultProperties } from '@react-three/uikit' import React, { ReactNode, RefAttributes, @@ -26,7 +26,7 @@ export type TabsProperties = ContainerProperties & { disabled?: boolean } -export const Tabs: (props: TabsProperties & RefAttributes) => ReactNode = forwardRef( +export const Tabs: (props: TabsProperties & RefAttributes) => ReactNode = forwardRef( ({ value, defaultValue, onValueChange, disabled, ...props }, ref) => { const [internalValue, setInternalValue] = useState(defaultValue) const currentValue = value != null ? value : internalValue @@ -74,7 +74,7 @@ type TabsButtonProperties = ContainerProperties & { disabled?: boolean } -export const TabsButton: (props: TabsButtonProperties & RefAttributes) => ReactNode = forwardRef( +export const TabsButton: (props: TabsButtonProperties & RefAttributes) => ReactNode = forwardRef( ({ children, value, disabled, ...props }, ref) => { const { value: currentValue, onValueChange, disabled: tabsDisabled } = useContext(TabsContext) as TabsContext diff --git a/packages/kits/default/src/accordion.tsx b/packages/kits/default/src/accordion.tsx index 371ec0d4..3548f841 100644 --- a/packages/kits/default/src/accordion.tsx +++ b/packages/kits/default/src/accordion.tsx @@ -1,5 +1,5 @@ import React, { ReactNode, RefAttributes, createContext, forwardRef, useContext, useState } from 'react' -import { ComponentInternals, Container, ContainerProperties, DefaultProperties } from '@react-three/uikit' +import { ContainerRef, Container, ContainerProperties, DefaultProperties } from '@react-three/uikit' import { ChevronDown } from '@react-three/uikit-lucide' const AccordionContext = createContext<[string | undefined, (value: string | undefined) => void]>(null as any) @@ -18,8 +18,8 @@ const AccordionItemContext = createContext('') export type AccordionItemProperties = ContainerProperties & { value: string } -export const AccordionItem: (props: RefAttributes & AccordionItemProperties) => ReactNode = - forwardRef(({ children, ...props }, ref) => { +export const AccordionItem: (props: RefAttributes & AccordionItemProperties) => ReactNode = forwardRef( + ({ children, ...props }, ref) => { const [value, setValue] = useContext(AccordionContext) const isSelected = props.value === value return ( @@ -34,11 +34,12 @@ export const AccordionItem: (props: RefAttributes & Accordio {children} ) - }) + }, +) export type AccordionTriggerProperties = ContainerProperties -export const AccordionTrigger: (props: RefAttributes & AccordionTriggerProperties) => ReactNode = +export const AccordionTrigger: (props: RefAttributes & AccordionTriggerProperties) => ReactNode = forwardRef(({ children, ...props }, ref) => { const itemValue = useContext(AccordionItemContext) const [value] = useContext(AccordionContext) @@ -62,7 +63,7 @@ export const AccordionTrigger: (props: RefAttributes & Accor export type AccordionContentProperties = ContainerProperties -export const AccordionContent: (props: RefAttributes & AccordionContentProperties) => ReactNode = +export const AccordionContent: (props: RefAttributes & AccordionContentProperties) => ReactNode = forwardRef(({ children, ...props }, ref) => { const itemValue = useContext(AccordionItemContext) const [value] = useContext(AccordionContext) diff --git a/packages/kits/default/src/alert-dialog.tsx b/packages/kits/default/src/alert-dialog.tsx index 330c7bf3..1ebcd368 100644 --- a/packages/kits/default/src/alert-dialog.tsx +++ b/packages/kits/default/src/alert-dialog.tsx @@ -15,13 +15,12 @@ import { DialogTriggerProperties, useCloseDialog, } from './dialog.js' -import { ComponentInternals, Container, ContainerProperties, DefaultProperties } from '@react-three/uikit' +import { ContainerRef, Container, ContainerProperties, DefaultProperties } from '@react-three/uikit' import { borderRadius, colors } from './theme.js' export type AlertDialogOverlayProperties = DialogOverlayProperties -export const AlertDialogOverlay: ( - props: AlertDialogOverlayProperties & RefAttributes, -) => ReactNode = DialogOverlay +export const AlertDialogOverlay: (props: AlertDialogOverlayProperties & RefAttributes) => ReactNode = + DialogOverlay export type AlertDialogProperties = DialogProperties @@ -29,56 +28,54 @@ export const AlertDialog = Dialog export type AlertDialogTriggerProperties = DialogTriggerProperties -export const AlertDialogTrigger: ( - props: AlertDialogTriggerProperties & RefAttributes, -) => ReactNode = DialogTrigger +export const AlertDialogTrigger: (props: AlertDialogTriggerProperties & RefAttributes) => ReactNode = + DialogTrigger export type AlertDialogContentProperties = ContainerProperties -export const AlertDialogContent: ( - props: AlertDialogContentProperties & RefAttributes, -) => ReactNode = forwardRef(({ onClick, sm, ...props }, ref) => { - const close = useCloseDialog() - return ( - - { - close() - e.stopPropagation() - }} - alignItems="center" - justifyContent="center" - > - ) => ReactNode = + forwardRef(({ onClick, sm, ...props }, ref) => { + const close = useCloseDialog() + return ( + + { + close() e.stopPropagation() - onClick?.(e) }} - positionType="relative" - flexDirection="column" - maxWidth={512} - width="100%" - gap={16} - borderWidth={1} - backgroundColor={colors.background} - padding={24} - sm={{ borderRadius: borderRadius.lg, ...sm }} - ref={ref} - {...props} - > - - - ) -}) + alignItems="center" + justifyContent="center" + > + { + e.stopPropagation() + onClick?.(e) + }} + positionType="relative" + flexDirection="column" + maxWidth={512} + width="100%" + gap={16} + borderWidth={1} + backgroundColor={colors.background} + padding={24} + sm={{ borderRadius: borderRadius.lg, ...sm }} + ref={ref} + {...props} + > + + + ) + }) export type AlertDialogHeaderProperties = DialogHeaderProperties -export const AlertDialogHeader: (props: AlertDialogHeaderProperties & RefAttributes) => ReactNode = +export const AlertDialogHeader: (props: AlertDialogHeaderProperties & RefAttributes) => ReactNode = DialogHeader export type AlertDialogFooterProperties = DialogFooterProperties -export const AlertDialogFooter: (props: AlertDialogFooterProperties & RefAttributes) => ReactNode = +export const AlertDialogFooter: (props: AlertDialogFooterProperties & RefAttributes) => ReactNode = DialogFooter export type AlertDialogTitleProperties = { children?: ReactNode } @@ -93,7 +90,7 @@ export const AlertDialogDescription = DialogDescription export type AlertDialogActionProperties = ContainerProperties -export const AlertDialogAction: (props: AlertDialogActionProperties & RefAttributes) => ReactNode = +export const AlertDialogAction: (props: AlertDialogActionProperties & RefAttributes) => ReactNode = forwardRef(({ children, onClick, ...props }, ref) => { const close = useCloseDialog() return ( @@ -135,7 +132,7 @@ export const AlertDialogAction: (props: AlertDialogActionProperties & RefAttribu export type AlertDialogCancelProperties = ContainerProperties -export const AlertDialogCancel: (props: AlertDialogCancelProperties & RefAttributes) => ReactNode = +export const AlertDialogCancel: (props: AlertDialogCancelProperties & RefAttributes) => ReactNode = forwardRef(({ children, onClick, ...props }, ref) => { const close = useCloseDialog() return ( diff --git a/packages/kits/default/src/alert.tsx b/packages/kits/default/src/alert.tsx index 83e52298..c9d8e7fe 100644 --- a/packages/kits/default/src/alert.tsx +++ b/packages/kits/default/src/alert.tsx @@ -1,9 +1,9 @@ import { AllOptionalProperties, - ComponentInternals, Container, ContainerProperties, DefaultProperties, + ContainerRef, } from '@react-three/uikit' import React, { ReactNode, RefAttributes, forwardRef } from 'react' import { borderRadius, colors } from './theme.js' @@ -19,28 +19,26 @@ const alertVariants = { export type AlertProperties = ContainerProperties & { variant?: keyof typeof alertVariants } -export const Alert: (props: AlertProperties & RefAttributes) => ReactNode = forwardRef( - (props, ref) => { - return ( - - - - ) - }, -) +export const Alert: (props: AlertProperties & RefAttributes) => ReactNode = forwardRef((props, ref) => { + return ( + + + + ) +}) export type AlertIconProperties = ContainerProperties -export const AlertIcon: (props: AlertIconProperties & RefAttributes) => ReactNode = forwardRef( +export const AlertIcon: (props: AlertIconProperties & RefAttributes) => ReactNode = forwardRef( (props, ref) => { return }, @@ -48,7 +46,7 @@ export const AlertIcon: (props: AlertIconProperties & RefAttributes) => ReactNode = forwardRef( +export const AlertTitle: (props: AlertTitleProperties & RefAttributes) => ReactNode = forwardRef( ({ children, ...props }, ref) => { return ( @@ -62,7 +60,7 @@ export const AlertTitle: (props: AlertTitleProperties & RefAttributes) => ReactNode = +export const AlertDescription: (props: AlertDescriptionProperties & RefAttributes) => ReactNode = forwardRef(({ children, ...props }, ref) => { return ( diff --git a/packages/kits/default/src/avatar.tsx b/packages/kits/default/src/avatar.tsx index 44c8463e..0b4d72ac 100644 --- a/packages/kits/default/src/avatar.tsx +++ b/packages/kits/default/src/avatar.tsx @@ -1,20 +1,19 @@ -import { ComponentInternals, Image, ImageProperties } from '@react-three/uikit' +import { Image, ImageProperties, ImageRef } from '@react-three/uikit' import React, { ReactNode, RefAttributes, forwardRef } from 'react' export type AvatarProperties = ImageProperties -export const Avatar: (props: AvatarProperties & RefAttributes>) => ReactNode = - forwardRef((props, ref) => { - return ( - - ) - }) +export const Avatar: (props: AvatarProperties & RefAttributes) => ReactNode = forwardRef((props, ref) => { + return ( + + ) +}) diff --git a/packages/kits/default/src/badge.tsx b/packages/kits/default/src/badge.tsx index 05a89d76..bff74fdb 100644 --- a/packages/kits/default/src/badge.tsx +++ b/packages/kits/default/src/badge.tsx @@ -1,7 +1,7 @@ import { - ComponentInternals, Container, ContainerProperties, + ContainerRef, DefaultProperties, DefaultPropertiesProperties, } from '@react-three/uikit' @@ -47,7 +47,7 @@ const badgeVariants = { export type BadgeProperties = ContainerProperties & { variant?: keyof typeof badgeVariants } -export const Badge: (props: BadgeProperties & RefAttributes) => ReactNode = forwardRef( +export const Badge: (props: BadgeProperties & RefAttributes) => ReactNode = forwardRef( ({ children, variant = 'default', hover, ...props }, ref) => { const { containerProps, diff --git a/packages/kits/default/src/button.tsx b/packages/kits/default/src/button.tsx index 570d7088..ec6ed02a 100644 --- a/packages/kits/default/src/button.tsx +++ b/packages/kits/default/src/button.tsx @@ -1,8 +1,8 @@ import { AllOptionalProperties, - ComponentInternals, Container, ContainerProperties, + ContainerRef, DefaultProperties, } from '@react-three/uikit' import React, { ReactNode, RefAttributes, forwardRef } from 'react' @@ -79,7 +79,7 @@ export type ButtonProperties = ContainerProperties & { disabled?: boolean } -export const Button: (props: ButtonProperties & RefAttributes) => ReactNode = forwardRef( +export const Button: (props: ButtonProperties & RefAttributes) => ReactNode = forwardRef( ({ children, variant = 'default', size = 'default', disabled = false, hover, ...props }, ref) => { const { containerProps, diff --git a/packages/kits/default/src/card.tsx b/packages/kits/default/src/card.tsx index fb52ebf9..645bcf7e 100644 --- a/packages/kits/default/src/card.tsx +++ b/packages/kits/default/src/card.tsx @@ -1,10 +1,10 @@ -import { ComponentInternals, Container, ContainerProperties, DefaultProperties } from '@react-three/uikit' +import { ContainerRef, Container, ContainerProperties, DefaultProperties } from '@react-three/uikit' import React, { ReactNode, RefAttributes, forwardRef } from 'react' import { borderRadius, colors } from './theme.js' export type CardProperties = ContainerProperties -export const Card: (props: CardProperties & RefAttributes) => ReactNode = forwardRef( +export const Card: (props: CardProperties & RefAttributes) => ReactNode = forwardRef( ({ children, ...props }, ref) => { return ( ) = export type CardHeaderProperties = ContainerProperties -export const CardHeader: (props: CardHeaderProperties & RefAttributes) => ReactNode = forwardRef( +export const CardHeader: (props: CardHeaderProperties & RefAttributes) => ReactNode = forwardRef( (props, ref) => { return }, @@ -43,7 +43,7 @@ export function CardDescription(props: CardDescriptionProperties) { export type CardContentProperties = ContainerProperties -export const CardContent: (props: CardContentProperties & RefAttributes) => ReactNode = forwardRef( +export const CardContent: (props: CardContentProperties & RefAttributes) => ReactNode = forwardRef( (props, ref) => { return }, @@ -51,7 +51,7 @@ export const CardContent: (props: CardContentProperties & RefAttributes) => ReactNode = forwardRef( +export const CardFooter: (props: CardFooterProperties & RefAttributes) => ReactNode = forwardRef( (props, ref) => { return }, diff --git a/packages/kits/default/src/checkbox.tsx b/packages/kits/default/src/checkbox.tsx index 3a312457..5831c712 100644 --- a/packages/kits/default/src/checkbox.tsx +++ b/packages/kits/default/src/checkbox.tsx @@ -1,4 +1,4 @@ -import { ComponentInternals, Container, ContainerProperties } from '@react-three/uikit' +import { ContainerRef, Container, ContainerProperties } from '@react-three/uikit' import { Check } from '@react-three/uikit-lucide' import React, { ReactNode, RefAttributes, forwardRef, useState } from 'react' import { borderRadius, colors } from './theme.js' @@ -10,7 +10,7 @@ export type CheckboxProperties = Omit & { onCheckedChange?(checked: boolean): void } -export const Checkbox: (props: CheckboxProperties & RefAttributes) => ReactNode = forwardRef( +export const Checkbox: (props: CheckboxProperties & RefAttributes) => ReactNode = forwardRef( ({ defaultChecked, checked: providedChecked, disabled = false, onCheckedChange, ...props }, ref) => { const [uncontrolled, setUncontrolled] = useState(defaultChecked ?? false) const checked = providedChecked ?? uncontrolled diff --git a/packages/kits/default/src/dialog.tsx b/packages/kits/default/src/dialog.tsx index dd7e3405..e24c646b 100644 --- a/packages/kits/default/src/dialog.tsx +++ b/packages/kits/default/src/dialog.tsx @@ -1,4 +1,4 @@ -import { ComponentInternals, Container, ContainerProperties, DefaultProperties } from '@react-three/uikit' +import { Container, ContainerProperties, ContainerRef, DefaultProperties } from '@react-three/uikit' import { borderRadius, colors } from './theme.js' import React, { ReactNode, @@ -109,8 +109,8 @@ export function Dialog({ children, open: providedOpen, onOpenChange, defaultOpen export type DialogTriggerProperties = ContainerProperties -export const DialogTrigger: (props: DialogTriggerProperties & RefAttributes) => ReactNode = - forwardRef(({ onClick, ...props }, ref) => { +export const DialogTrigger: (props: DialogTriggerProperties & RefAttributes) => ReactNode = forwardRef( + ({ onClick, ...props }, ref) => { const { setOpen } = useDialogContext() return ( ) - }) + }, +) export type DialogOverlayProperties = ContainerProperties -export const DialogOverlay: (props: DialogOverlayProperties & RefAttributes) => ReactNode = - forwardRef((props, ref) => { +export const DialogOverlay: (props: DialogOverlayProperties & RefAttributes) => ReactNode = forwardRef( + (props, ref) => { return ( e.stopPropagation()} @@ -143,7 +144,8 @@ export const DialogOverlay: (props: DialogOverlayProperties & RefAttributes ) - }) + }, +) export function useCloseDialog() { const { setOpen } = useDialogContext() @@ -163,8 +165,8 @@ export function DialogContentPrimitive({ children }: DialogContentPrimitivePrope export type DialogContentProperties = ContainerProperties -export const DialogContent: (props: DialogContentProperties & RefAttributes) => ReactNode = - forwardRef(({ children, sm, ...props }, ref) => { +export const DialogContent: (props: DialogContentProperties & RefAttributes) => ReactNode = forwardRef( + ({ children, sm, ...props }, ref) => { const close = useCloseDialog() return ( @@ -209,12 +211,13 @@ export const DialogContent: (props: DialogContentProperties & RefAttributes ) - }) + }, +) export type DialogHeaderProperties = ContainerProperties -export const DialogHeader: (props: DialogHeaderProperties & RefAttributes) => ReactNode = - forwardRef(({ children, ...props }, ref) => { +export const DialogHeader: (props: DialogHeaderProperties & RefAttributes) => ReactNode = forwardRef( + ({ children, ...props }, ref) => { return ( @@ -222,12 +225,13 @@ export const DialogHeader: (props: DialogHeaderProperties & RefAttributes ) - }) + }, +) export type DialogFooterProperties = ContainerProperties -export const DialogFooter: (props: DialogFooterProperties & RefAttributes) => ReactNode = - forwardRef(({ sm, ...props }, ref) => { +export const DialogFooter: (props: DialogFooterProperties & RefAttributes) => ReactNode = forwardRef( + ({ sm, ...props }, ref) => { return ( ) - }) + }, +) export type DialogTitleProperties = { children?: ReactNode } diff --git a/packages/kits/default/src/input.tsx b/packages/kits/default/src/input.tsx index b102f1ed..33cb8662 100644 --- a/packages/kits/default/src/input.tsx +++ b/packages/kits/default/src/input.tsx @@ -5,7 +5,7 @@ import { Text, InputInternals, InputProperties as BaseInputProperties, - ComponentInternals, + ContainerRef, } from '@react-three/uikit' import React, { ReactNode, RefAttributes, forwardRef, useMemo, useState } from 'react' import { borderRadius, colors } from './theme.js' @@ -16,7 +16,7 @@ export type InputProperties = Omit & { placeho //for getting the correct types for conversion type _InputProperties = InputProperties -export const Input: (props: InputProperties & RefAttributes) => ReactNode = forwardRef( +export const Input: (props: InputProperties & RefAttributes) => ReactNode = forwardRef( ( { panelMaterialClass, value, defaultValue, onValueChange, tabIndex, disabled, placeholder, type, ...props }, ref, diff --git a/packages/kits/default/src/label.tsx b/packages/kits/default/src/label.tsx index c87533a5..e6a6aa20 100644 --- a/packages/kits/default/src/label.tsx +++ b/packages/kits/default/src/label.tsx @@ -1,9 +1,9 @@ -import { ComponentInternals, DefaultProperties } from '@react-three/uikit' +import { ContainerRef, DefaultProperties } from '@react-three/uikit' import React, { ReactNode, RefAttributes, forwardRef } from 'react' export type LabelProperties = { children?: ReactNode; disabled?: boolean } -export const Label: (props: LabelProperties & RefAttributes) => ReactNode = forwardRef( +export const Label: (props: LabelProperties & RefAttributes) => ReactNode = forwardRef( ({ disabled, ...props }, ref) => { return ( ) => ReactNode = forwardRef( +export const Menubar: (props: MenubarProperties & RefAttributes) => ReactNode = forwardRef( (props, ref) => { return ( ) => ReactNode = - forwardRef(({ children, ...props }, ref) => { +export const MenubarTrigger: (props: MenubarTriggerProperties & RefAttributes) => ReactNode = forwardRef( + ({ children, ...props }, ref) => { //TODO: data-[state=open]:bg-accent data-[state=open]:text-accent-foreground return ( ) - }) + }, +) /* const MenubarGroup = MenubarPrimitive.Group diff --git a/packages/kits/default/src/pagination.tsx b/packages/kits/default/src/pagination.tsx index 33df6033..895b8302 100644 --- a/packages/kits/default/src/pagination.tsx +++ b/packages/kits/default/src/pagination.tsx @@ -1,11 +1,11 @@ -import { ComponentInternals, Container, ContainerProperties, Text } from '@react-three/uikit' +import { ContainerRef, Container, ContainerProperties, Text } from '@react-three/uikit' import { ChevronLeft, ChevronRight, Ellipsis } from '@react-three/uikit-lucide' import React, { ReactNode, RefAttributes, forwardRef } from 'react' import { borderRadius, colors } from './theme.js' export type PaginationProperties = ContainerProperties -export const Pagination: (props: PaginationProperties & RefAttributes) => ReactNode = forwardRef( +export const Pagination: (props: PaginationProperties & RefAttributes) => ReactNode = forwardRef( (props, ref) => { return }, @@ -13,16 +13,14 @@ export const Pagination: (props: PaginationProperties & RefAttributes) => ReactNode = +export const PaginationContent: (props: PaginationContentProperties & RefAttributes) => ReactNode = forwardRef((props, ref) => { return }) export type PaginationItemProperties = ContainerProperties -export const PaginationItem: ( - props: ContainerProperties & RefAttributes>, -) => ReactNode = Container +export const PaginationItem: (props: ContainerProperties & RefAttributes) => ReactNode = Container const paginationVariants: { [Key in string]: { @@ -59,8 +57,8 @@ export type PaginationLinkProperties = ContainerProperties & { isActive?: boolean } -export const PaginationLink: (props: PaginationLinkProperties & RefAttributes) => ReactNode = - forwardRef(({ isActive = false, size = 'icon', hover, ...props }, ref) => { +export const PaginationLink: (props: PaginationLinkProperties & RefAttributes) => ReactNode = forwardRef( + ({ isActive = false, size = 'icon', hover, ...props }, ref) => { const { containerProps, containerHoverProps } = paginationVariants[isActive ? 'outline' : 'ghost'] const sizeProps = paginationSizes[size] return ( @@ -76,50 +74,50 @@ export const PaginationLink: (props: PaginationLinkProperties & RefAttributes ) - }) + }, +) export type PaginationPreviousProperties = Omit -export const PaginationPrevious: ( - props: PaginationPreviousProperties & RefAttributes, -) => ReactNode = forwardRef((props, ref) => { - return ( - - - Previous - - ) -}) +export const PaginationPrevious: (props: PaginationPreviousProperties & RefAttributes) => ReactNode = + forwardRef((props, ref) => { + return ( + + + Previous + + ) + }) export type PaginationNextProperties = Omit -export const PaginationNext: (props: PaginationNextProperties & RefAttributes) => ReactNode = - forwardRef((props, ref) => { +export const PaginationNext: (props: PaginationNextProperties & RefAttributes) => ReactNode = forwardRef( + (props, ref) => { return ( Next ) - }) + }, +) export type PaginationEllipsisProperties = Omit -export const PaginationEllipsis: ( - props: PaginationEllipsisProperties & RefAttributes, -) => ReactNode = forwardRef((props, ref) => { - return ( - - - - ) -}) +export const PaginationEllipsis: (props: PaginationEllipsisProperties & RefAttributes) => ReactNode = + forwardRef((props, ref) => { + return ( + + + + ) + }) //More pages diff --git a/packages/kits/default/src/progress.tsx b/packages/kits/default/src/progress.tsx index e85e8637..0dc2649b 100644 --- a/packages/kits/default/src/progress.tsx +++ b/packages/kits/default/src/progress.tsx @@ -1,11 +1,11 @@ -import { ComponentInternals, Container, ContainerProperties } from '@react-three/uikit' +import { ContainerRef, Container, ContainerProperties } from '@react-three/uikit' import React, { ReactNode, RefAttributes, forwardRef, useMemo } from 'react' import { colors } from './theme.js' import { Signal, computed } from '@preact/signals-core' export type ProgressProperties = { value?: Signal | number } & Omit -export const Progress: (props: ProgressProperties & RefAttributes) => ReactNode = forwardRef( +export const Progress: (props: ProgressProperties & RefAttributes) => ReactNode = forwardRef( ({ value, ...props }, ref) => { const width = useMemo(() => computed(() => `${(value ?? 0) as number}%` as const), [value]) return ( diff --git a/packages/kits/default/src/radio-group.tsx b/packages/kits/default/src/radio-group.tsx index b4cf0acd..cc7fd7e4 100644 --- a/packages/kits/default/src/radio-group.tsx +++ b/packages/kits/default/src/radio-group.tsx @@ -1,4 +1,4 @@ -import { ComponentInternals, Container, ContainerProperties } from '@react-three/uikit' +import { ContainerRef, Container, ContainerProperties } from '@react-three/uikit' import React, { ReactNode, RefAttributes, createContext, forwardRef, useContext, useMemo, useState } from 'react' import { colors } from './theme.js' @@ -13,7 +13,7 @@ export type RadioGroupProperties = { defaultValue?: string } & ContainerProperties -export const RadioGroup: (props: RadioGroupProperties & RefAttributes) => ReactNode = forwardRef( +export const RadioGroup: (props: RadioGroupProperties & RefAttributes) => ReactNode = forwardRef( ({ defaultValue, value: providedValue, onValueChange, children, ...props }, ref) => { const [uncontrolled, setUncontrolled] = useState(defaultValue) const contextValue = useMemo(() => { @@ -41,8 +41,8 @@ export const RadioGroup: (props: RadioGroupProperties & RefAttributes) => ReactNode = - forwardRef(({ disabled = false, value, children, ...props }, ref) => { +export const RadioGroupItem: (props: RadioGroupItemProperties & RefAttributes) => ReactNode = forwardRef( + ({ disabled = false, value, children, ...props }, ref) => { const { value: current, setValue } = useContext(RadioGroupContext) return ( ) - }) + }, +) diff --git a/packages/kits/default/src/separator.tsx b/packages/kits/default/src/separator.tsx index b49a9ac0..424c9516 100644 --- a/packages/kits/default/src/separator.tsx +++ b/packages/kits/default/src/separator.tsx @@ -1,10 +1,10 @@ -import { ComponentInternals, Container, ContainerProperties } from '@react-three/uikit' +import { ContainerRef, Container, ContainerProperties } from '@react-three/uikit' import React, { ReactNode, RefAttributes, forwardRef } from 'react' import { colors } from './theme.js' export type SeparatorProperties = Omit & { orientation?: 'horizontal' | 'vertical' } -export const Separator: (props: SeparatorProperties & RefAttributes) => ReactNode = forwardRef( +export const Separator: (props: SeparatorProperties & RefAttributes) => ReactNode = forwardRef( ({ orientation = 'horizontal', ...props }, ref) => { return ( -export const Skeleton: (props: SkeletonProperties & RefAttributes) => ReactNode = forwardRef( +export const Skeleton: (props: SkeletonProperties & RefAttributes) => ReactNode = forwardRef( (props, ref) => { const opacity = useMemo(() => signal(1), []) const time = useRef(0) diff --git a/packages/kits/default/src/slider.tsx b/packages/kits/default/src/slider.tsx index 4a6cfd01..8e4c0f6f 100644 --- a/packages/kits/default/src/slider.tsx +++ b/packages/kits/default/src/slider.tsx @@ -1,4 +1,4 @@ -import { Container, ComponentInternals, ContainerProperties } from '@react-three/uikit' +import { Container, ContainerRef, ContainerProperties } from '@react-three/uikit' import { colors } from './theme.js' import React, { ReactNode, RefAttributes, forwardRef, useImperativeHandle, useMemo, useRef, useState } from 'react' import { EventHandlers, ThreeEvent } from '@react-three/fiber/dist/declarations/src/core/events.js' @@ -17,7 +17,7 @@ export type SliderProperties = { step?: number } & Omit -export const Slider: (props: SliderProperties & RefAttributes) => ReactNode = forwardRef( +export const Slider: (props: SliderProperties & RefAttributes) => ReactNode = forwardRef( ( { disabled = false, value: providedValue, defaultValue, onValueChange, min = 0, max = 100, step = 1, ...props }, ref, @@ -32,7 +32,7 @@ export const Slider: (props: SliderProperties & RefAttributes>(null) + const internalRef = useRef(null) const onChange = useRef(onValueChange) onChange.current = onValueChange const hasProvidedValue = providedValue != null diff --git a/packages/kits/default/src/switch.tsx b/packages/kits/default/src/switch.tsx index 96e6251e..15db7968 100644 --- a/packages/kits/default/src/switch.tsx +++ b/packages/kits/default/src/switch.tsx @@ -1,4 +1,4 @@ -import { ComponentInternals, Container, ContainerProperties } from '@react-three/uikit' +import { ContainerRef, Container, ContainerProperties } from '@react-three/uikit' import React, { ReactNode, RefAttributes, forwardRef, useState } from 'react' import { colors } from './theme.js' @@ -9,7 +9,7 @@ export type SwitchProperties = Omit & { onCheckedChange?(checked: boolean): void } -export const Switch: (props: SwitchProperties & RefAttributes) => ReactNode = forwardRef( +export const Switch: (props: SwitchProperties & RefAttributes) => ReactNode = forwardRef( ({ defaultChecked, checked: providedChecked, disabled = false, onCheckedChange, ...props }, ref) => { const [uncontrolled, setUncontrolled] = useState(defaultChecked ?? false) const checked = providedChecked ?? uncontrolled diff --git a/packages/kits/default/src/tabs.tsx b/packages/kits/default/src/tabs.tsx index 9eb13dda..b3f0670b 100644 --- a/packages/kits/default/src/tabs.tsx +++ b/packages/kits/default/src/tabs.tsx @@ -1,4 +1,4 @@ -import { ComponentInternals, Container, ContainerProperties, DefaultProperties } from '@react-three/uikit' +import { ContainerRef, Container, ContainerProperties, DefaultProperties } from '@react-three/uikit' import React, { ReactNode, RefAttributes, createContext, forwardRef, useContext, useMemo, useState } from 'react' import { borderRadius, colors } from './theme.js' @@ -14,7 +14,7 @@ export type TabsProperties = { children?: ReactNode } & ContainerProperties -export const Tabs: (props: TabsProperties & RefAttributes) => ReactNode = forwardRef( +export const Tabs: (props: TabsProperties & RefAttributes) => ReactNode = forwardRef( ({ value: providedValue, onValueChange, defaultValue, children, ...props }, ref) => { const [uncontrolled, setUncontrolled] = useState(defaultValue) const contextValue = useMemo(() => { @@ -42,7 +42,7 @@ export const Tabs: (props: TabsProperties & RefAttributes) = export type TabsListProperties = ContainerProperties -export const TabsList: (props: TabsListProperties & RefAttributes) => ReactNode = forwardRef( +export const TabsList: (props: TabsListProperties & RefAttributes) => ReactNode = forwardRef( ({ children, ...props }, ref) => { return ( ) => ReactNode = forwardRef( +export const TabsTrigger: (props: TabsTriggerProperties & RefAttributes) => ReactNode = forwardRef( ({ children, value, disabled = false, ...props }, ref) => { const { setValue, value: current } = useContext(TabsContext) const active = value === current @@ -100,7 +100,7 @@ export const TabsTrigger: (props: TabsTriggerProperties & RefAttributes) => ReactNode = forwardRef( +export const TabsContent: (props: TabsContentProperties & RefAttributes) => ReactNode = forwardRef( ({ value, ...props }, ref) => { const { value: current } = useContext(TabsContext) if (value != current) { diff --git a/packages/kits/default/src/textarea.tsx b/packages/kits/default/src/textarea.tsx index a10d336c..9c75a576 100644 --- a/packages/kits/default/src/textarea.tsx +++ b/packages/kits/default/src/textarea.tsx @@ -5,7 +5,7 @@ import { Text, InputInternals, InputProperties as BaseInputProperties, - ComponentInternals, + ContainerRef, } from '@react-three/uikit' import React, { ReactNode, RefAttributes, forwardRef, useMemo, useState } from 'react' import { borderRadius, colors } from './theme.js' @@ -13,7 +13,7 @@ import { computed } from '@preact/signals-core' export type TextareaProperties = Omit & { placeholder?: string } -export const Textarea: (props: TextareaProperties & RefAttributes) => ReactNode = forwardRef( +export const Textarea: (props: TextareaProperties & RefAttributes) => ReactNode = forwardRef( ( { panelMaterialClass, value, defaultValue, onValueChange, tabIndex, disabled, placeholder, type, ...props }, ref, diff --git a/packages/kits/default/src/toggle-group.tsx b/packages/kits/default/src/toggle-group.tsx index e3cd0926..e9eebfc5 100644 --- a/packages/kits/default/src/toggle-group.tsx +++ b/packages/kits/default/src/toggle-group.tsx @@ -1,4 +1,4 @@ -import { ComponentInternals, Container, ContainerProperties, DefaultProperties } from '@react-three/uikit' +import { ContainerRef, Container, ContainerProperties, DefaultProperties } from '@react-three/uikit' import React, { ReactNode, RefAttributes, createContext, forwardRef, useContext, useState } from 'react' import { borderRadius, colors } from './theme.js' @@ -32,7 +32,7 @@ export type ToggleGroupProperties = ContainerProperties & { size?: keyof typeof toggleSizes } -export const ToggleGroup: (props: ToggleGroupProperties & RefAttributes) => ReactNode = forwardRef( +export const ToggleGroup: (props: ToggleGroupProperties & RefAttributes) => ReactNode = forwardRef( ({ children, size = 'default', variant = 'default', ...props }, ref) => { return ( @@ -49,7 +49,7 @@ export type ToggleGroupItemProperties = ContainerProperties & { onCheckedChange?(checked: boolean): void } -export const ToggleGroupItem: (props: ToggleGroupItemProperties & RefAttributes) => ReactNode = +export const ToggleGroupItem: (props: ToggleGroupItemProperties & RefAttributes) => ReactNode = forwardRef( ( { children, defaultChecked, checked: providedChecked, disabled = false, onCheckedChange, hover, ...props }, diff --git a/packages/kits/default/src/toggle.tsx b/packages/kits/default/src/toggle.tsx index 4471ce05..57635eb2 100644 --- a/packages/kits/default/src/toggle.tsx +++ b/packages/kits/default/src/toggle.tsx @@ -1,4 +1,4 @@ -import { ComponentInternals, Container, ContainerProperties, DefaultProperties } from '@react-three/uikit' +import { ContainerRef, Container, ContainerProperties, DefaultProperties } from '@react-three/uikit' import React, { ReactNode, RefAttributes, forwardRef, useState } from 'react' import { borderRadius, colors } from './theme.js' @@ -30,7 +30,7 @@ export type ToggleProperties = ContainerProperties & { size?: keyof typeof toggleSizes } -export const Toggle: (props: ToggleProperties & RefAttributes) => ReactNode = forwardRef( +export const Toggle: (props: ToggleProperties & RefAttributes) => ReactNode = forwardRef( ( { children, diff --git a/packages/kits/default/src/tooltip.tsx b/packages/kits/default/src/tooltip.tsx index 9378dd89..42b9b8a2 100644 --- a/packages/kits/default/src/tooltip.tsx +++ b/packages/kits/default/src/tooltip.tsx @@ -1,4 +1,4 @@ -import { ComponentInternals, Container, ContainerProperties, DefaultProperties } from '@react-three/uikit' +import { ContainerRef, Container, ContainerProperties, DefaultProperties } from '@react-three/uikit' import React, { ReactNode, RefAttributes, @@ -15,7 +15,7 @@ const TooltipContext = createContext(null as any) export type TooltipProperties = ContainerProperties -export const Tooltip: (props: TooltipProperties & RefAttributes) => ReactNode = forwardRef( +export const Tooltip: (props: TooltipProperties & RefAttributes) => ReactNode = forwardRef( ({ children, ...props }, ref) => { const [open, setOpen] = useState(false) const timeoutRef = useRef(undefined) @@ -61,15 +61,16 @@ export const Tooltip: (props: TooltipProperties & RefAttributes) => ReactNode = - forwardRef((props, ref) => { +export const TooltipTrigger: (props: TooltipTriggerProperties & RefAttributes) => ReactNode = forwardRef( + (props, ref) => { return - }) + }, +) export type TooltipContentProperties = ContainerProperties & { sideOffset?: number } -export const TooltipContent: (props: TooltipContentProperties & RefAttributes) => ReactNode = - forwardRef(({ children, sideOffset = 4, ...props }, ref) => { +export const TooltipContent: (props: TooltipContentProperties & RefAttributes) => ReactNode = forwardRef( + ({ children, sideOffset = 4, ...props }, ref) => { const open = useContext(TooltipContext) if (!open) { return null @@ -94,4 +95,5 @@ export const TooltipContent: (props: TooltipContentProperties & RefAttributes ) - }) + }, +) diff --git a/packages/kits/default/src/video.tsx b/packages/kits/default/src/video.tsx index 286e434b..16562b1e 100644 --- a/packages/kits/default/src/video.tsx +++ b/packages/kits/default/src/video.tsx @@ -18,7 +18,7 @@ import { VideoInternals, ContainerProperties, useVideoElement, - ComponentInternals, + ContainerRef, } from '@react-three/uikit' import { Play, Pause, VolumeX, Volume2 } from '@react-three/uikit-lucide' import { Slider } from './slider.js' @@ -61,110 +61,110 @@ export const Video: (props: VideoProperties & RefAttributes) => export type VideoControlsProperties = Omit -export const VideoControls: ( - props: VideoControlsProperties & RefAttributes>, -) => ReactNode = forwardRef((props: VideoControlsProperties, ref) => { - const videoElement = useVideoElement() - const [paused, setPaused] = useState(videoElement.paused) - useEffect(() => { - const listener = () => setPaused(videoElement.paused) - videoElement.addEventListener('pause', listener) - videoElement.addEventListener('play', listener) - return () => { - videoElement.removeEventListener('pause', listener) - videoElement.removeEventListener('play', listener) - } - }, [videoElement]) - - const [muted, setMuted] = useState(videoElement.muted) - useEffect(() => { - const listener = () => setMuted(videoElement.muted) - videoElement.addEventListener('volumechange', listener) - return () => videoElement.removeEventListener('volumechange', listener) - }, [videoElement]) +export const VideoControls: (props: VideoControlsProperties & RefAttributes) => ReactNode = forwardRef( + (props: VideoControlsProperties, ref) => { + const videoElement = useVideoElement() + const [paused, setPaused] = useState(videoElement.paused) + useEffect(() => { + const listener = () => setPaused(videoElement.paused) + videoElement.addEventListener('pause', listener) + videoElement.addEventListener('play', listener) + return () => { + videoElement.removeEventListener('pause', listener) + videoElement.removeEventListener('play', listener) + } + }, [videoElement]) - const durationSignal = useMemo(() => signal(1), []) - const timeSignal = useMemo(() => signal(0), []) + const [muted, setMuted] = useState(videoElement.muted) + useEffect(() => { + const listener = () => setMuted(videoElement.muted) + videoElement.addEventListener('volumechange', listener) + return () => videoElement.removeEventListener('volumechange', listener) + }, [videoElement]) - const moving = useContext(movingContext) - if (moving == null) { - throw new Error(`VideoControls form the default kit can only be used inside a Video from the default kit`) - } - const displaySignal = useMemo(() => computed(() => (moving.value ? 'flex' : 'none')), [moving]) + const durationSignal = useMemo(() => signal(1), []) + const timeSignal = useMemo(() => signal(0), []) - useEffect(() => { - const metadataListener = () => (durationSignal.value = videoElement.duration) - const timeUpdateListener = () => (timeSignal.value = videoElement.currentTime) - if (!isNaN(videoElement.duration)) { - metadataListener() + const moving = useContext(movingContext) + if (moving == null) { + throw new Error(`VideoControls form the default kit can only be used inside a Video from the default kit`) } - videoElement.addEventListener('loadedmetadata', metadataListener) - videoElement.addEventListener('timeupdate', timeUpdateListener) - return () => { - videoElement.removeEventListener('loadedmetadata', metadataListener) - videoElement.removeEventListener('timeupdate', timeUpdateListener) - } - }, [durationSignal, timeSignal, videoElement]) + const displaySignal = useMemo(() => computed(() => (moving.value ? 'flex' : 'none')), [moving]) + + useEffect(() => { + const metadataListener = () => (durationSignal.value = videoElement.duration) + const timeUpdateListener = () => (timeSignal.value = videoElement.currentTime) + if (!isNaN(videoElement.duration)) { + metadataListener() + } + videoElement.addEventListener('loadedmetadata', metadataListener) + videoElement.addEventListener('timeupdate', timeUpdateListener) + return () => { + videoElement.removeEventListener('loadedmetadata', metadataListener) + videoElement.removeEventListener('timeupdate', timeUpdateListener) + } + }, [durationSignal, timeSignal, videoElement]) - const timeTextSignal = useMemo( - () => computed(() => `${formatDuration(timeSignal.value)} / ${formatDuration(durationSignal.value)}`), - [durationSignal, timeSignal], - ) + const timeTextSignal = useMemo( + () => computed(() => `${formatDuration(timeSignal.value)} / ${formatDuration(durationSignal.value)}`), + [durationSignal, timeSignal], + ) - const setTime = useCallback((t: number) => (videoElement.currentTime = t), [videoElement]) + const setTime = useCallback((t: number) => (videoElement.currentTime = t), [videoElement]) - return ( - - - - - - - {timeTextSignal} - + return ( + + + + + + + {timeTextSignal} + + + - - - ) -}) + ) + }, +) function formatDuration(seconds: number) { const hour = Math.floor(seconds / 3600) diff --git a/packages/react/src/container.tsx b/packages/react/src/container.tsx index 7aac7afb..73c8c667 100644 --- a/packages/react/src/container.tsx +++ b/packages/react/src/container.tsx @@ -1,15 +1,13 @@ -import { EventHandlers } from '@react-three/fiber/dist/declarations/src/core/events' import { forwardRef, ReactNode, RefAttributes, useEffect, useMemo, useRef } from 'react' import { Object3D } from 'three' import { ParentProvider, useParent } from './context.js' -import { AddHandlers, usePropertySignals } from './utilts.js' +import { AddHandlers, R3FEventMap, usePropertySignals } from './utils.js' import { ContainerProperties as BaseContainerProperties, createContainer, unsubscribeSubscriptions, Subscriptions, initialize, - PointerEventsProperties, } from '@pmndrs/uikit/internals' import { ComponentInternals, useComponentInternals } from './ref.js' import { DefaultProperties } from './default.js' @@ -17,48 +15,48 @@ import { DefaultProperties } from './default.js' export type ContainerProperties = { name?: string children?: ReactNode -} & BaseContainerProperties & - EventHandlers & - PointerEventsProperties +} & BaseContainerProperties -export const Container: ( - props: ContainerProperties & RefAttributes>, -) => ReactNode = forwardRef((properties, ref) => { - const parent = useParent() - const outerRef = useRef(null) - const innerRef = useRef(null) - const propertySignals = usePropertySignals(properties) - const internals = useMemo( - () => - createContainer( - parent, - propertySignals.style, - propertySignals.properties, - propertySignals.default, - outerRef, - innerRef, - ), - [parent, propertySignals], - ) +export type ContainerRef = ComponentInternals> - internals.interactionPanel.name = properties.name ?? '' +export const Container: (props: ContainerProperties & RefAttributes) => ReactNode = forwardRef( + (properties, ref) => { + const parent = useParent() + const outerRef = useRef(null) + const innerRef = useRef(null) + const propertySignals = usePropertySignals(properties) + const internals = useMemo( + () => + createContainer( + parent, + propertySignals.style, + propertySignals.properties, + propertySignals.default, + outerRef, + innerRef, + ), + [parent, propertySignals], + ) - useEffect(() => { - const subscriptions: Subscriptions = [] - initialize(internals.initializers, subscriptions) - return () => unsubscribeSubscriptions(subscriptions) - }, [parent, propertySignals, internals]) + internals.interactionPanel.name = properties.name ?? '' - useComponentInternals(ref, parent.root.pixelSize, propertySignals.style, internals, internals.interactionPanel) + useEffect(() => { + const subscriptions: Subscriptions = [] + initialize(internals.initializers, subscriptions) + return () => unsubscribeSubscriptions(subscriptions) + }, [parent, propertySignals, internals]) - return ( - - - - - {properties.children} - - - - ) -}) + useComponentInternals(ref, parent.root.pixelSize, propertySignals.style, internals, internals.interactionPanel) + + return ( + + + + + {properties.children} + + + + ) + }, +) diff --git a/packages/react/src/content.tsx b/packages/react/src/content.tsx index 1f8354c5..925e936d 100644 --- a/packages/react/src/content.tsx +++ b/packages/react/src/content.tsx @@ -1,61 +1,54 @@ -import { EventHandlers } from '@react-three/fiber/dist/declarations/src/core/events' import { forwardRef, ReactNode, RefAttributes, useEffect, useMemo, useRef } from 'react' import { Object3D } from 'three' import { ParentProvider, useParent } from './context.js' -import { AddHandlers, usePropertySignals } from './utilts.js' -import { - createContent, - initialize, - PointerEventsProperties, - Subscriptions, - unsubscribeSubscriptions, -} from '@pmndrs/uikit/internals' +import { AddHandlers, R3FEventMap, usePropertySignals } from './utils.js' +import { createContent, initialize, Subscriptions, unsubscribeSubscriptions } from '@pmndrs/uikit/internals' import { ComponentInternals, useComponentInternals } from './ref.js' import { ContentProperties as BaseContentProperties } from '../../uikit/dist/components/content.js' export type ContentProperties = { name?: string children?: ReactNode -} & BaseContentProperties & - EventHandlers & - PointerEventsProperties +} & BaseContentProperties -export const Content: ( - props: ContentProperties & RefAttributes>, -) => ReactNode = forwardRef((properties, ref) => { - const parent = useParent() - const outerRef = useRef(null) - const innerRef = useRef(null) - const propertySignals = usePropertySignals(properties) - const internals = useMemo( - () => - createContent( - parent, - propertySignals.style, - propertySignals.properties, - propertySignals.default, - outerRef, - innerRef, - ), - [parent, propertySignals], - ) +export type ContentRef = ComponentInternals> - internals.interactionPanel.name = properties.name ?? '' +export const Content: (props: ContentProperties & RefAttributes) => ReactNode = forwardRef( + (properties, ref) => { + const parent = useParent() + const outerRef = useRef(null) + const innerRef = useRef(null) + const propertySignals = usePropertySignals(properties) + const internals = useMemo( + () => + createContent( + parent, + propertySignals.style, + propertySignals.properties, + propertySignals.default, + outerRef, + innerRef, + ), + [parent, propertySignals], + ) - useEffect(() => { - const subscriptions: Subscriptions = [] - initialize(internals.initializers, subscriptions) - return () => unsubscribeSubscriptions(subscriptions) - }, [internals]) + internals.interactionPanel.name = properties.name ?? '' - useComponentInternals(ref, parent.root.pixelSize, propertySignals.style, internals, internals.interactionPanel) + useEffect(() => { + const subscriptions: Subscriptions = [] + initialize(internals.initializers, subscriptions) + return () => unsubscribeSubscriptions(subscriptions) + }, [internals]) - return ( - - - - {properties.children} - - - ) -}) + useComponentInternals(ref, parent.root.pixelSize, propertySignals.style, internals, internals.interactionPanel) + + return ( + + + + {properties.children} + + + ) + }, +) diff --git a/packages/react/src/custom.tsx b/packages/react/src/custom.tsx index e8d3b909..e3032519 100644 --- a/packages/react/src/custom.tsx +++ b/packages/react/src/custom.tsx @@ -1,8 +1,7 @@ -import { EventHandlers } from '@react-three/fiber/dist/declarations/src/core/events' import { forwardRef, ReactNode, RefAttributes, useEffect, useMemo, useRef } from 'react' import { Material, Mesh, Object3D } from 'three' import { ParentProvider, useParent } from './context.js' -import { AddHandlers, usePropertySignals } from './utilts.js' +import { AddHandlers, R3FEventMap, usePropertySignals } from './utils.js' import { createCustomContainer, CustomContainerProperties as BaseCustomContainerProperties, @@ -10,7 +9,6 @@ import { panelGeometry, Subscriptions, unsubscribeSubscriptions, - PointerEventsProperties, } from '@pmndrs/uikit/internals' import { ComponentInternals, useComponentInternals } from './ref.js' @@ -19,56 +17,55 @@ export type CustomContainerProperties = { children?: ReactNode customDepthMaterial?: Material customDistanceMaterial?: Material -} & BaseCustomContainerProperties & - EventHandlers & - PointerEventsProperties +} & BaseCustomContainerProperties -export const CustomContainer: ( - props: CustomContainerProperties & RefAttributes>, -) => ReactNode = forwardRef((properties, ref) => { - const parent = useParent() - const outerRef = useRef(null) - const innerRef = useRef(null) - const propertySignals = usePropertySignals(properties) - const internals = useMemo( - () => - createCustomContainer( - parent, - propertySignals.style, - propertySignals.properties, - propertySignals.default, - outerRef, - innerRef, - ), - [parent, propertySignals], - ) - useEffect(() => { - const subscriptions: Subscriptions = [] - initialize(internals.initializers, subscriptions) - return () => unsubscribeSubscriptions(subscriptions) - }, [internals]) +export type CustomContainerRef = ComponentInternals> - useComponentInternals(ref, parent.root.pixelSize, propertySignals.style, internals, innerRef) +export const CustomContainer: (props: CustomContainerProperties & RefAttributes) => ReactNode = + forwardRef((properties, ref) => { + const parent = useParent() + const outerRef = useRef(null) + const innerRef = useRef(null) + const propertySignals = usePropertySignals(properties) + const internals = useMemo( + () => + createCustomContainer( + parent, + propertySignals.style, + propertySignals.properties, + propertySignals.default, + outerRef, + innerRef, + ), + [parent, propertySignals], + ) + useEffect(() => { + const subscriptions: Subscriptions = [] + initialize(internals.initializers, subscriptions) + return () => unsubscribeSubscriptions(subscriptions) + }, [internals]) - useEffect(() => { - if (innerRef.current && properties.name) { - innerRef.current.name = properties.name - } - }, [properties.name]) + useComponentInternals(ref, parent.root.pixelSize, propertySignals.style, internals, innerRef) - return ( - - - - {properties.children} - - - - ) -}) + useEffect(() => { + if (innerRef.current && properties.name) { + innerRef.current.name = properties.name + } + }, [properties.name]) + + return ( + + + + {properties.children} + + + + ) + }) diff --git a/packages/react/src/fullscreen.tsx b/packages/react/src/fullscreen.tsx index 96d478bf..0f7b8634 100644 --- a/packages/react/src/fullscreen.tsx +++ b/packages/react/src/fullscreen.tsx @@ -2,65 +2,61 @@ import { ReactNode, RefAttributes, forwardRef, useEffect, useMemo, useRef } from import { Root } from './root.js' import { batch, signal } from '@preact/signals-core' import { createPortal, useFrame, useStore, useThree } from '@react-three/fiber' -import { EventHandlers } from '@react-three/fiber/dist/declarations/src/core/events.js' -import { - FullscreenProperties as BaseFullscreenProperties, - PointerEventsProperties, - RootProperties, - updateSizeFullscreen, -} from '@pmndrs/uikit/internals' +import { FullscreenProperties as BaseFullscreenProperties, updateSizeFullscreen } from '@pmndrs/uikit/internals' import { ComponentInternals } from './ref.js' +import { R3FEventMap } from './utils.js' -export type FullscreenProperties = BaseFullscreenProperties & { +export type FullscreenProperties = BaseFullscreenProperties & { children?: ReactNode attachCamera?: boolean distanceToCamera?: number -} & EventHandlers & - PointerEventsProperties +} -export const Fullscreen: ( - props: FullscreenProperties & RefAttributes>, -) => ReactNode = forwardRef((properties, ref) => { - const store = useStore() - const camera = useThree((s) => s.camera) - const distanceToCamera = properties.distanceToCamera ?? camera.near + 0.1 - const [sizeX, sizeY, pixelSize] = useMemo(() => { - const sizeX = signal(1) - const sizeY = signal(1) - const pixelSize = signal(1) - updateSizeFullscreen(sizeX, sizeY, pixelSize, distanceToCamera, camera, store.getState().size.height) - return [sizeX, sizeY, pixelSize] - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []) - const hasAttached = useRef(false) - useFrame(({ camera, scene, size: { height } }) => { - batch(() => updateSizeFullscreen(sizeX, sizeY, pixelSize, distanceToCamera, camera, height)) - //attach camera to something so we can see the camera - if (camera.parent == null && (properties.attachCamera ?? true)) { - scene.add(camera) - hasAttached.current = true - } - }) - //cleanup attaching the camera - useEffect( - () => () => { - if (!hasAttached.current) { - return - } - const { camera, scene } = store.getState() - if (camera.parent != scene) { - return +export type FullscreenRef = ComponentInternals> + +export const Fullscreen: (props: FullscreenProperties & RefAttributes) => ReactNode = forwardRef( + (properties, ref) => { + const store = useStore() + const camera = useThree((s) => s.camera) + const distanceToCamera = properties.distanceToCamera ?? camera.near + 0.1 + const [sizeX, sizeY, pixelSize] = useMemo(() => { + const sizeX = signal(1) + const sizeY = signal(1) + const pixelSize = signal(1) + updateSizeFullscreen(sizeX, sizeY, pixelSize, distanceToCamera, camera, store.getState().size.height) + return [sizeX, sizeY, pixelSize] + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []) + const hasAttached = useRef(false) + useFrame(({ camera, scene, size: { height } }) => { + batch(() => updateSizeFullscreen(sizeX, sizeY, pixelSize, distanceToCamera, camera, height)) + //attach camera to something so we can see the camera + if (camera.parent == null && (properties.attachCamera ?? true)) { + scene.add(camera) + hasAttached.current = true } - scene.remove(camera) - }, - [store], - ) - return createPortal( - - - {properties.children} - - , - camera, - ) -}) + }) + //cleanup attaching the camera + useEffect( + () => () => { + if (!hasAttached.current) { + return + } + const { camera, scene } = store.getState() + if (camera.parent != scene) { + return + } + scene.remove(camera) + }, + [store], + ) + return createPortal( + + + {properties.children} + + , + camera, + ) + }, +) diff --git a/packages/react/src/icon.tsx b/packages/react/src/icon.tsx index 4b7a1437..924d5b65 100644 --- a/packages/react/src/icon.tsx +++ b/packages/react/src/icon.tsx @@ -1,6 +1,5 @@ import { IconProperties as BaseIconProperties, - PointerEventsProperties, Subscriptions, createIcon, initialize, @@ -8,29 +7,27 @@ import { } from '@pmndrs/uikit/internals' import { ReactNode, RefAttributes, forwardRef, useEffect, useMemo, useRef } from 'react' import { Object3D } from 'three' -import { AddHandlers, usePropertySignals } from './utilts.js' +import { AddHandlers, R3FEventMap, usePropertySignals } from './utils.js' import { useParent } from './context.js' import { ComponentInternals, useComponentInternals } from './ref.js' -import type { EventHandlers } from '@react-three/fiber/dist/declarations/src/core/events.js' -export type IconProperties = BaseIconProperties & - EventHandlers & { - text: string - svgWidth: number - svgHeight: number - children?: ReactNode - name?: string - } & PointerEventsProperties +export type IconProperties = BaseIconProperties & { + text: string + svgWidth: number + svgHeight: number + children?: ReactNode + name?: string +} -export const Icon: ( - props: IconProperties & RefAttributes>>, -) => ReactNode = forwardRef((properties, ref) => { +export type IconRef = ComponentInternals>> + +export const Icon: (props: IconProperties & RefAttributes) => ReactNode = forwardRef((properties, ref) => { const parent = useParent() const outerRef = useRef(null) const propertySignals = usePropertySignals(properties) const internals = useMemo( () => - createIcon( + createIcon( parent, properties.text, properties.svgWidth, @@ -54,7 +51,7 @@ export const Icon: ( useComponentInternals(ref, parent.root.pixelSize, propertySignals.style, internals, internals.interactionPanel) return ( - + diff --git a/packages/react/src/image.tsx b/packages/react/src/image.tsx index 8ca8162a..7ddcef74 100644 --- a/packages/react/src/image.tsx +++ b/packages/react/src/image.tsx @@ -4,32 +4,29 @@ import { initialize, Subscriptions, unsubscribeSubscriptions, - PointerEventsProperties, } from '@pmndrs/uikit/internals' import { ReactNode, RefAttributes, forwardRef, useEffect, useMemo, useRef } from 'react' import { Object3D } from 'three' -import { AddHandlers, usePropertySignals } from './utilts.js' +import { AddHandlers, R3FEventMap, usePropertySignals } from './utils.js' import { ParentProvider, useParent } from './context.js' import { ComponentInternals, useComponentInternals } from './ref.js' -import type { EventHandlers } from '@react-three/fiber/dist/declarations/src/core/events.js' import { DefaultProperties } from './default.js' -export type ImageProperties = BaseImageProperties & - EventHandlers & { - children?: ReactNode - name?: string - } & PointerEventsProperties +export type ImageProperties = BaseImageProperties & { + children?: ReactNode + name?: string +} -export const Image: ( - props: ImageProperties & RefAttributes>, -) => ReactNode = forwardRef((properties, ref) => { +export type ImageRef = ComponentInternals> + +export const Image: (props: ImageProperties & RefAttributes) => ReactNode = forwardRef((properties, ref) => { const parent = useParent() const outerRef = useRef(null) const innerRef = useRef(null) const propertySignals = usePropertySignals(properties) const internals = useMemo( () => - createImage( + createImage( parent, propertySignals.style, propertySignals.properties, @@ -52,7 +49,7 @@ export const Image: ( useComponentInternals(ref, parent.root.pixelSize, propertySignals.style, internals, internals.interactionPanel) return ( - + diff --git a/packages/react/src/index.ts b/packages/react/src/index.ts index 8ab8cf08..570dfc92 100644 --- a/packages/react/src/index.ts +++ b/packages/react/src/index.ts @@ -1,5 +1,6 @@ export { FontFamilyProvider, useMeasureText } from './font.js' export { useRootSize } from './responsive.js' +export type { R3FEventMap } from './utils.js' export { isInteractionPanel, basedOnPreferredColorScheme, diff --git a/packages/react/src/input.tsx b/packages/react/src/input.tsx index 126118ed..98cbefe6 100644 --- a/packages/react/src/input.tsx +++ b/packages/react/src/input.tsx @@ -1,8 +1,7 @@ -import { EventHandlers } from '@react-three/fiber/dist/declarations/src/core/events' import { forwardRef, ReactNode, RefAttributes, useEffect, useMemo, useRef } from 'react' import { Object3D } from 'three' import { useParent } from './context.js' -import { AddHandlers, usePropertySignals } from './utilts.js' +import { AddHandlers, R3FEventMap, usePropertySignals } from './utils.js' import { FontFamilies, InputProperties as BaseInputProperties, @@ -10,75 +9,73 @@ import { createInput, initialize, unsubscribeSubscriptions, - PointerEventsProperties, } from '@pmndrs/uikit/internals' import { ComponentInternals, useComponentInternals } from './ref.js' import { ReadonlySignal, signal } from '@preact/signals-core' import { useFontFamilies } from './font.js' -export type InputInternals = ComponentInternals & { +export type InputRef = InputInternals + +export type InputInternals = ComponentInternals> & { current: ReadonlySignal focus: () => void blur: () => void element: ReadonlySignal -} & PointerEventsProperties +} -export type InputProperties = BaseInputProperties & - EventHandlers & { - name?: string - } +export type InputProperties = BaseInputProperties & { + name?: string +} -export const Input: (props: InputProperties & RefAttributes) => ReactNode = forwardRef( - (properties, ref) => { - const parent = useParent() - const outerRef = useRef(null) - const propertySignals = usePropertySignals(properties) - const fontFamilies = useMemo(() => signal(undefined as any), []) - fontFamilies.value = useFontFamilies() - //allows to not get a eslint error because of dependencies (we deliberatly never update this ref) - const internals = useMemo( - () => - createInput( - parent, - fontFamilies, - propertySignals.style, - propertySignals.properties, - propertySignals.default, - outerRef, - ), - // eslint-disable-next-line react-hooks/exhaustive-deps - [], - ) +export const Input: (props: InputProperties & RefAttributes) => ReactNode = forwardRef((properties, ref) => { + const parent = useParent() + const outerRef = useRef(null) + const propertySignals = usePropertySignals(properties) + const fontFamilies = useMemo(() => signal(undefined as any), []) + fontFamilies.value = useFontFamilies() + //allows to not get a eslint error because of dependencies (we deliberatly never update this ref) + const internals = useMemo( + () => + createInput( + parent, + fontFamilies, + propertySignals.style, + propertySignals.properties, + propertySignals.default, + outerRef, + ), + // eslint-disable-next-line react-hooks/exhaustive-deps + [], + ) - internals.interactionPanel.name = properties.name ?? '' + internals.interactionPanel.name = properties.name ?? '' - useEffect(() => { - const subscriptions: Subscriptions = [] - initialize(internals.initializers, subscriptions) - return () => unsubscribeSubscriptions(subscriptions) - }, [internals]) + useEffect(() => { + const subscriptions: Subscriptions = [] + initialize(internals.initializers, subscriptions) + return () => unsubscribeSubscriptions(subscriptions) + }, [internals]) - useComponentInternals( - ref, - parent.root.pixelSize, - propertySignals.style, - internals, - internals.interactionPanel, - useMemo( - () => ({ - focus: internals.focus, - blur: internals.blur, - current: internals.valueSignal, - element: internals.element, - }), - [internals.focus, internals.blur, internals.valueSignal, internals.element], - ), - ) + useComponentInternals( + ref, + parent.root.pixelSize, + propertySignals.style, + internals, + internals.interactionPanel, + useMemo( + () => ({ + focus: internals.focus, + blur: internals.blur, + current: internals.valueSignal, + element: internals.element, + }), + [internals.focus, internals.blur, internals.valueSignal, internals.element], + ), + ) - return ( - - - - ) - }, -) + return ( + + + + ) +}) diff --git a/packages/react/src/portal.tsx b/packages/react/src/portal.tsx index 11010aae..9d6459fc 100644 --- a/packages/react/src/portal.tsx +++ b/packages/react/src/portal.tsx @@ -12,10 +12,11 @@ import { } from 'three' import { Image } from './image.js' import { InjectState, RootState, reconciler, useFrame, useStore, context } from '@react-three/fiber' -import type { DomEvent, EventHandlers, EventManager } from '@react-three/fiber/dist/declarations/src/core/events.js' -import type { ImageProperties, PointerEventsProperties } from '@pmndrs/uikit/internals' +import type { DomEvent, EventManager } from '@react-three/fiber/dist/declarations/src/core/events.js' +import type { ImageProperties } from '@pmndrs/uikit/internals' import type { ComponentInternals } from './ref.js' import { create } from 'zustand' +import { R3FEventMap } from './utils.js' // Keys that shouldn't be copied between R3F stores export const privateKeys = [ @@ -35,7 +36,7 @@ type Camera = THREE.OrthographicCamera | THREE.PerspectiveCamera const isOrthographicCamera = (def: Camera): def is THREE.OrthographicCamera => def && (def as THREE.OrthographicCamera).isOrthographicCamera -type BasePortalProperties = Omit +type BasePortalProperties = Omit, 'src' | 'objectFit'> export type PortalProperties = { frames?: number @@ -47,14 +48,13 @@ export type PortalProperties = { */ dpr?: number children?: ReactNode -} & BasePortalProperties & - EventHandlers & { +} & BasePortalProperties & { children?: ReactNode - } & PointerEventsProperties + } + +export type PortalRef = ComponentInternals -export const Portal: ( - props: PortalProperties & RefAttributes>, -) => ReactNode = forwardRef( +export const Portal: (props: PortalProperties & RefAttributes) => ReactNode = forwardRef( ({ children, dpr, frames = Infinity, renderPriority = 0, eventPriority = 0, ...props }, ref) => { const fbo = useMemo(() => new Signal(undefined), []) const imageRef = useRef>(null) diff --git a/packages/react/src/root.tsx b/packages/react/src/root.tsx index d53fa4f7..3cedb1e3 100644 --- a/packages/react/src/root.tsx +++ b/packages/react/src/root.tsx @@ -1,8 +1,7 @@ import { useFrame, useStore, useThree } from '@react-three/fiber' -import { EventHandlers } from '@react-three/fiber/dist/declarations/src/core/events' import { forwardRef, ReactNode, RefAttributes, useEffect, useMemo, useRef } from 'react' import { ParentProvider } from './context.js' -import { AddHandlers, usePropertySignals } from './utilts.js' +import { AddHandlers, R3FEventMap, usePropertySignals } from './utils.js' import { DEFAULT_PIXEL_SIZE, RootProperties as BaseRootProperties, @@ -13,23 +12,21 @@ import { readReactive, reversePainterSortStable, unsubscribeSubscriptions, - PointerEventsProperties, } from '@pmndrs/uikit/internals' import { Object3D } from 'three' import { ComponentInternals, useComponentInternals } from './ref.js' import { Signal, computed, signal } from '@preact/signals-core' import { DefaultProperties } from './default.js' -export type RootProperties = BaseRootProperties & +export type RootProperties = BaseRootProperties & WithReactive<{ pixelSize?: number }> & { children?: ReactNode name?: string - } & EventHandlers & - PointerEventsProperties + } -export const Root: ( - props: RootProperties & RefAttributes>, -) => ReactNode = forwardRef((properties, ref) => { +export type RootRef = ComponentInternals> + +export const Root: (props: RootProperties & RefAttributes) => ReactNode = forwardRef((properties, ref) => { const renderer = useThree((state) => state.gl) renderer.setTransparentSort(reversePainterSortStable) const store = useStore() @@ -43,7 +40,7 @@ export const Root: ( const invalidate = useThree((s) => s.invalidate) const internals = useMemo( () => - createRoot( + createRoot( computed(() => readReactive(pixelSizeSignal.value) ?? DEFAULT_PIXEL_SIZE), propertySignals.style, propertySignals.properties, @@ -88,7 +85,7 @@ export const Root: ( useComponentInternals(ref, internals.root.pixelSize, propertySignals.style, internals, internals.interactionPanel) return ( - + diff --git a/packages/react/src/suspending.tsx b/packages/react/src/suspending.tsx index b994a463..82fd073e 100644 --- a/packages/react/src/suspending.tsx +++ b/packages/react/src/suspending.tsx @@ -9,14 +9,15 @@ export type SuspendingImageProperties = ImageProperties & { children?: ReactNode } +export type SuspendingImageRef = ComponentInternals> + /** * be aware that this component does not dispose the loaded texture */ -export const SuspendingImage: ( - props: SuspendingImageProperties & RefAttributes>>, -) => ReactNode = forwardRef(({ src, ...props }, ref) => { - const texture = useLoader(TextureLoader, src) - texture.colorSpace = SRGBColorSpace - texture.matrixAutoUpdate = false - return -}) +export const SuspendingImage: (props: SuspendingImageProperties & RefAttributes) => ReactNode = + forwardRef(({ src, ...props }, ref) => { + const texture = useLoader(TextureLoader, src) + texture.colorSpace = SRGBColorSpace + texture.matrixAutoUpdate = false + return + }) diff --git a/packages/react/src/svg.tsx b/packages/react/src/svg.tsx index a7c82e6a..4ff01c5c 100644 --- a/packages/react/src/svg.tsx +++ b/packages/react/src/svg.tsx @@ -4,32 +4,36 @@ import { createSvg, initialize, unsubscribeSubscriptions, - PointerEventsProperties, } from '@pmndrs/uikit/internals' import { ReactNode, RefAttributes, forwardRef, useEffect, useMemo, useRef } from 'react' import { Object3D } from 'three' -import { AddHandlers, usePropertySignals } from './utilts.js' +import { AddHandlers, R3FEventMap, usePropertySignals } from './utils.js' import { ParentProvider, useParent } from './context.js' import { ComponentInternals, useComponentInternals } from './ref.js' -import type { EventHandlers } from '@react-three/fiber/dist/declarations/src/core/events.js' import { DefaultProperties } from './default.js' -export type SvgProperties = BaseSvgProperties & - EventHandlers & { - children?: ReactNode - name?: string - } & PointerEventsProperties +export type SvgProperties = BaseSvgProperties & { + children?: ReactNode + name?: string +} -export const Svg: ( - props: SvgProperties & RefAttributes>, -) => ReactNode = forwardRef((properties, ref) => { +export type SvgRef = ComponentInternals> + +export const Svg: (props: SvgProperties & RefAttributes) => ReactNode = forwardRef((properties, ref) => { const parent = useParent() const outerRef = useRef(null) const innerRef = useRef(null) const propertySignals = usePropertySignals(properties) const internals = useMemo( () => - createSvg(parent, propertySignals.style, propertySignals.properties, propertySignals.default, outerRef, innerRef), + createSvg( + parent, + propertySignals.style, + propertySignals.properties, + propertySignals.default, + outerRef, + innerRef, + ), [parent, propertySignals], ) @@ -44,7 +48,7 @@ export const Svg: ( useComponentInternals(ref, parent.root.pixelSize, propertySignals.style, internals, internals.interactionPanel) return ( - + diff --git a/packages/react/src/text.tsx b/packages/react/src/text.tsx index 5a02e580..e2c10cf7 100644 --- a/packages/react/src/text.tsx +++ b/packages/react/src/text.tsx @@ -1,8 +1,7 @@ -import { EventHandlers } from '@react-three/fiber/dist/declarations/src/core/events' import { forwardRef, ReactNode, RefAttributes, useEffect, useMemo, useRef } from 'react' import { Object3D } from 'three' import { useParent } from './context.js' -import { AddHandlers, usePropertySignals } from './utilts.js' +import { AddHandlers, R3FEventMap, usePropertySignals } from './utils.js' import { createText, FontFamilies, @@ -10,7 +9,6 @@ import { Subscriptions, TextProperties as BaseTextProperties, unsubscribeSubscriptions, - PointerEventsProperties, } from '@pmndrs/uikit/internals' import { ComponentInternals, useComponentInternals } from './ref.js' import { Signal, signal } from '@preact/signals-core' @@ -19,13 +17,11 @@ import { useFontFamilies } from './font.js' export type TextProperties = { children: string | Array> | Signal name?: string -} & BaseTextProperties & - EventHandlers & - PointerEventsProperties +} & BaseTextProperties -export const Text: ( - props: TextProperties & RefAttributes>>, -) => ReactNode = forwardRef((properties, ref) => { +export type TextRef = ComponentInternals>> + +export const Text: (props: TextProperties & RefAttributes) => ReactNode = forwardRef((properties, ref) => { const parent = useParent() const outerRef = useRef(null) const propertySignals = usePropertySignals(properties) @@ -38,7 +34,7 @@ export const Text: ( fontFamilies.value = useFontFamilies() const internals = useMemo( () => - createText( + createText( parent, textSignal, fontFamilies, @@ -61,7 +57,7 @@ export const Text: ( useComponentInternals(ref, parent.root.pixelSize, propertySignals.style, internals, internals.interactionPanel) return ( - + ) diff --git a/packages/react/src/utilts.tsx b/packages/react/src/utils.tsx similarity index 50% rename from packages/react/src/utilts.tsx rename to packages/react/src/utils.tsx index 87c38210..c26254c8 100644 --- a/packages/react/src/utilts.tsx +++ b/packages/react/src/utils.tsx @@ -1,53 +1,33 @@ import { Signal, effect, signal } from '@preact/signals-core' -import { EventHandlers } from '@react-three/fiber/dist/declarations/src/core/events' +import { EventHandlers, ThreeEvent } from '@react-three/fiber/dist/declarations/src/core/events' import { ReactNode, forwardRef, useEffect, useMemo, useState } from 'react' import { Object3D } from 'three' import { useDefaultProperties } from './default.js' -import { AllOptionalProperties, addHandler } from '@pmndrs/uikit/internals' +import { AllOptionalProperties } from '@pmndrs/uikit/internals' -const eventHandlerKeys: Array = [ - 'onClick', - 'onContextMenu', - 'onDoubleClick', - 'onPointerCancel', - 'onPointerDown', - 'onPointerEnter', - 'onPointerLeave', - 'onPointerMissed', - 'onPointerMove', - 'onPointerOut', - 'onPointerOver', - 'onPointerUp', - 'onWheel', -] +export type R3FEventMap = { + mouse: ThreeEvent + wheel: ThreeEvent + pointer: ThreeEvent +} export const AddHandlers = forwardRef< Object3D, { - properties: EventHandlers handlers: Signal children?: ReactNode } ->(({ handlers: handlersSignal, properties, children }, ref) => { - const [systemHandlers, setSystemHandlers] = useState(() => handlersSignal.peek()) +>(({ handlers: handlersSignal, children }, ref) => { + const [handlers, setHandlers] = useState(() => handlersSignal.peek()) useEffect( () => effect(() => { const handlers = handlersSignal.value - const ref = void setTimeout(() => setSystemHandlers(handlers), 0) + const ref = void setTimeout(() => setHandlers(handlers), 0) return () => clearTimeout(ref) }), [handlersSignal], ) - const handlers = useMemo(() => { - const result: EventHandlers = { ...systemHandlers } - const keysLength = eventHandlerKeys.length - for (let i = 0; i < keysLength; i++) { - const key = eventHandlerKeys[i] - addHandler(key, result, properties[key]) - } - return result - }, [systemHandlers, properties]) return ( {children} diff --git a/packages/react/src/video.tsx b/packages/react/src/video.tsx index 2a674357..bdf2b8a8 100644 --- a/packages/react/src/video.tsx +++ b/packages/react/src/video.tsx @@ -13,10 +13,10 @@ import { Image } from './image.js' import { SRGBColorSpace, Texture, VideoTexture } from 'three' import { signal } from '@preact/signals-core' import { VideoProperties as BaseVideoProperties, ImageProperties } from '@pmndrs/uikit' -import { PointerEventsProperties, setupVideoElementInvalidation, updateVideoElement } from '@pmndrs/uikit/internals' -import { EventHandlers } from '@react-three/fiber/dist/declarations/src/core/events.js' +import { setupVideoElementInvalidation, updateVideoElement } from '@pmndrs/uikit/internals' import { ComponentInternals } from './ref.js' import { useThree } from '@react-three/fiber' +import { R3FEventMap } from './utils.js' const VideoContext = createContext(undefined) @@ -28,16 +28,17 @@ export function useVideoElement(): HTMLVideoElement { return element } -export type VideoInternals = ComponentInternals & EventHandlers> & { +export type VideoInternals = ComponentInternals, 'src'>> & { element: HTMLVideoElement } -export type VideoProperties = BaseVideoProperties & - EventHandlers & { - children?: ReactNode - } & PointerEventsProperties +export type VideoRef = VideoInternals -export const Video: (props: VideoProperties & RefAttributes) => ReactNode = forwardRef( +export type VideoProperties = BaseVideoProperties & { + children?: ReactNode +} + +export const Video: (props: VideoProperties & RefAttributes) => ReactNode = forwardRef( (props: VideoProperties, ref) => { const texture = useMemo(() => signal(undefined), []) const aspectRatio = useMemo(() => signal(1), []) diff --git a/packages/uikit/src/active.ts b/packages/uikit/src/active.ts index 71643b1d..5c38892d 100644 --- a/packages/uikit/src/active.ts +++ b/packages/uikit/src/active.ts @@ -1,7 +1,7 @@ import { Signal } from '@preact/signals-core' import { AllOptionalProperties, Properties, WithClasses, traverseProperties } from './properties/default.js' import { createConditionalPropertyTranslator } from './utils.js' -import { EventHandlers, ThreeEvent } from './events.js' +import { EventHandlers, ThreePointerEvent } from './events.js' import { addHandler } from './components/index.js' export type WithActive = T & { @@ -31,7 +31,7 @@ export function addActiveHandlers( activeSignal.value.length = 0 return } - const onLeave = ({ pointerId }: ThreeEvent) => { + const onLeave = ({ pointerId }: ThreePointerEvent) => { activeSignal.value = activeSignal.value.filter((id) => id != pointerId) if (activeSignal.value.length > 0) { return diff --git a/packages/uikit/src/components/container.ts b/packages/uikit/src/components/container.ts index dfb0f291..c937a32a 100644 --- a/packages/uikit/src/components/container.ts +++ b/packages/uikit/src/components/container.ts @@ -34,13 +34,15 @@ import { PanelGroupProperties, computedPanelGroupDependencies } from '../panel/i import { createInteractionPanel } from '../panel/instanced-panel-mesh.js' import { Initializers } from '../utils.js' import { darkPropertyTransformers } from '../dark.js' -import { getDefaultPanelMaterialConfig } from '../panel/index.js' +import { getDefaultPanelMaterialConfig, PointerEventsProperties } from '../panel/index.js' import { - computeAnyAncestorsHaveListeners, + computeAncestorsHaveListeners, computedInheritableProperty, computeDefaultProperties, setupPointerEvents, UpdateMatrixWorldProperties, + EventHandlers, + ThreeEventMap, } from '../internals.js' export type InheritableContainerProperties = WithClasses< @@ -54,18 +56,21 @@ export type InheritableContainerProperties = WithClasses< ScrollbarProperties & PanelGroupProperties & VisibilityProperties & - UpdateMatrixWorldProperties + UpdateMatrixWorldProperties & + PointerEventsProperties > > > > -export type ContainerProperties = InheritableContainerProperties & Listeners +export type ContainerProperties = InheritableContainerProperties & + Listeners & + EventHandlers -export function createContainer( +export function createContainer( parentCtx: ParentContext, - style: Signal, - properties: Signal, + style: Signal | undefined>, + properties: Signal | undefined>, defaultProperties: Signal, object: Object3DRef, childrenContainer: Object3DRef, @@ -148,7 +153,7 @@ export function createContainer( ) const handlers = computedHandlers(style, properties, defaultProperties, hoveredSignal, activeSignal, scrollHandlers) - const ancestorsHaveListeners = computeAnyAncestorsHaveListeners(parentCtx, handlers) + const ancestorsHaveListeners = computeAncestorsHaveListeners(parentCtx, handlers) const interactionPanel = createInteractionPanel( orderInfo, diff --git a/packages/uikit/src/components/content.ts b/packages/uikit/src/components/content.ts index 8053a49c..61a89ba1 100644 --- a/packages/uikit/src/components/content.ts +++ b/packages/uikit/src/components/content.ts @@ -13,7 +13,7 @@ import { Signal, computed, effect, signal, untracked } from '@preact/signals-cor import { VisibilityProperties, WithConditionals, - computeAnyAncestorsHaveListeners, + computeAncestorsHaveListeners, computedGlobalMatrix, computedHandlers, computedIsVisible, @@ -34,9 +34,10 @@ import { import { createInteractionPanel } from '../panel/instanced-panel-mesh.js' import { Box3, Material, Mesh, Object3D, Vector3 } from 'three' import { darkPropertyTransformers } from '../dark.js' -import { getDefaultPanelMaterialConfig, makeClippedCast } from '../panel/index.js' +import { getDefaultPanelMaterialConfig, makeClippedCast, PointerEventsProperties } from '../panel/index.js' import { MergedProperties, computedInheritableProperty } from '../properties/index.js' import { KeepAspectRatioProperties } from './image.js' +import { EventHandlers, ThreeEventMap } from '../events.js' export type InheritableContentProperties = WithClasses< WithConditionals< @@ -51,7 +52,8 @@ export type InheritableContentProperties = WithClasses< DepthAlignProperties & KeepAspectRatioProperties & VisibilityProperties & - RenderProperties + RenderProperties & + PointerEventsProperties > > > @@ -61,12 +63,14 @@ export type DepthAlignProperties = { depthAlign?: keyof typeof alignmentZMap } -export type ContentProperties = InheritableContentProperties & Listeners +export type ContentProperties = InheritableContentProperties & + Listeners & + EventHandlers -export function createContent( +export function createContent( parentCtx: ParentContext, - style: Signal, - properties: Signal, + style: Signal | undefined>, + properties: Signal | undefined>, defaultProperties: Signal, object: Object3DRef, contentContainerRef: Object3DRef, @@ -142,7 +146,7 @@ export function createContent( setupMatrixWorldUpdate(true, true, object, parentCtx.root, globalMatrix, initializers, false) const handlers = computedHandlers(style, properties, defaultProperties, hoveredSignal, activeSignal) - const ancestorsHaveListeners = computeAnyAncestorsHaveListeners(parentCtx, handlers) + const ancestorsHaveListeners = computeAncestorsHaveListeners(parentCtx, handlers) setupPointerEvents(mergedProperties, ancestorsHaveListeners, parentCtx.root, object, initializers, true) setupLayoutListeners(style, properties, flexState.size, initializers) diff --git a/packages/uikit/src/components/custom.ts b/packages/uikit/src/components/custom.ts index 12c444aa..ccf5a0a8 100644 --- a/packages/uikit/src/components/custom.ts +++ b/packages/uikit/src/components/custom.ts @@ -13,7 +13,7 @@ import { Signal, effect, signal } from '@preact/signals-core' import { VisibilityProperties, WithConditionals, - computeAnyAncestorsHaveListeners, + computeAncestorsHaveListeners, computedGlobalMatrix, computedHandlers, computedIsVisible, @@ -27,7 +27,8 @@ import { Listeners, setupLayoutListeners, setupClippedListeners } from '../liste import { Object3DRef, ParentContext } from '../context.js' import { FrontSide, Material, Mesh } from 'three' import { darkPropertyTransformers } from '../dark.js' -import { RenderProperties, ShadowProperties, makeClippedCast } from '../panel/index.js' +import { PointerEventsProperties, RenderProperties, ShadowProperties, makeClippedCast } from '../panel/index.js' +import { EventHandlers, ThreeEventMap } from '../events.js' export type InheritableCustomContainerProperties = WithClasses< WithConditionals< @@ -40,18 +41,21 @@ export type InheritableCustomContainerProperties = WithClasses< ScrollbarProperties & ShadowProperties & VisibilityProperties & - RenderProperties + RenderProperties & + PointerEventsProperties > > > > -export type CustomContainerProperties = InheritableCustomContainerProperties & Listeners +export type CustomContainerProperties = InheritableCustomContainerProperties & + Listeners & + EventHandlers -export function createCustomContainer( +export function createCustomContainer( parentCtx: ParentContext, - style: Signal, - properties: Signal, + style: Signal | undefined>, + properties: Signal | undefined>, defaultProperties: Signal, object: Object3DRef, meshRef: { current?: Mesh | null }, @@ -147,7 +151,7 @@ export function createCustomContainer( setupMatrixWorldUpdate(true, true, object, parentCtx.root, globalMatrix, initializers, false) const handlers = computedHandlers(style, properties, defaultProperties, hoveredSignal, activeSignal) - const ancestorsHaveListeners = computeAnyAncestorsHaveListeners(parentCtx, handlers) + const ancestorsHaveListeners = computeAncestorsHaveListeners(parentCtx, handlers) setupPointerEvents(mergedProperties, ancestorsHaveListeners, parentCtx.root, object, initializers, true) setupLayoutListeners(style, properties, flexState.size, initializers) diff --git a/packages/uikit/src/components/fullscreen.ts b/packages/uikit/src/components/fullscreen.ts index b51cafe3..ff986508 100644 --- a/packages/uikit/src/components/fullscreen.ts +++ b/packages/uikit/src/components/fullscreen.ts @@ -1,8 +1,12 @@ import type { Signal } from '@preact/signals-core' import { Camera, OrthographicCamera, PerspectiveCamera } from 'three' import type { RootProperties } from './root.js' +import { ThreeEventMap } from '../events.js' -export type FullscreenProperties = Omit +export type FullscreenProperties = Omit< + RootProperties, + 'sizeX' | 'sizeY' | 'pixelSize' | 'anchorX' | 'anchorY' +> /** * must be called when camera.fov, camera.top, camera.bottom, camera.right, camera.left, camera.zoom, camera.aspect changes diff --git a/packages/uikit/src/components/icon.ts b/packages/uikit/src/components/icon.ts index aa3f79cb..72c76874 100644 --- a/packages/uikit/src/components/icon.ts +++ b/packages/uikit/src/components/icon.ts @@ -1,6 +1,6 @@ import { Signal, effect, signal } from '@preact/signals-core' import { BufferGeometry, Group, Material, Mesh, MeshBasicMaterial, Plane, ShapeGeometry } from 'three' -import { Listeners } from '../index.js' +import { EventHandlers, Listeners } from '../index.js' import { Object3DRef, ParentContext } from '../context.js' import { FlexNodeState, YogaProperties, createFlexNodeState } from '../flex/index.js' import { ElementType, OrderInfo, ZIndexProperties, computedOrderInfo, setupRenderOrder } from '../order.js' @@ -13,7 +13,7 @@ import { VisibilityProperties, WithConditionals, applyAppearancePropertiesToGroup, - computeAnyAncestorsHaveListeners, + computeAncestorsHaveListeners, computedGlobalMatrix, computedHandlers, computedIsVisible, @@ -24,7 +24,7 @@ import { setupPointerEvents, } from './utils.js' import { Initializers, fitNormalizedContentInside } from '../utils.js' -import { makeClippedCast } from '../panel/interaction-panel-mesh.js' +import { makeClippedCast, PointerEventsProperties } from '../panel/interaction-panel-mesh.js' import { computedIsClipped, createGlobalClippingPlanes } from '../clipping.js' import { setupLayoutListeners, setupClippedListeners } from '../listeners.js' import { createActivePropertyTransfomers } from '../active.js' @@ -36,6 +36,7 @@ import { AppearanceProperties } from './svg.js' import { PanelGroupProperties, computedPanelGroupDependencies, getDefaultPanelMaterialConfig } from '../panel/index.js' import { darkPropertyTransformers } from '../dark.js' import { MergedProperties } from '../properties/index.js' +import { ThreeEventMap } from '../events.js' export type InheritableIconProperties = WithClasses< WithConditionals< @@ -48,21 +49,24 @@ export type InheritableIconProperties = WithClasses< TransformProperties & PanelGroupProperties & ScrollbarProperties & - VisibilityProperties + VisibilityProperties & + PointerEventsProperties > > > > -export type IconProperties = InheritableIconProperties & Listeners +export type IconProperties = InheritableIconProperties & + Listeners & + EventHandlers -export function createIcon( +export function createIcon( parentCtx: ParentContext, text: string, svgWidth: number, svgHeight: number, - style: Signal, - properties: Signal, + style: Signal | undefined>, + properties: Signal | undefined>, defaultProperties: Signal, object: Object3DRef, ) { @@ -138,7 +142,7 @@ export function createIcon( setupMatrixWorldUpdate(true, true, object, parentCtx.root, globalMatrix, initializers, false) const handlers = computedHandlers(style, properties, defaultProperties, hoveredSignal, activeSignal) - const ancestorsHaveListeners = computeAnyAncestorsHaveListeners(parentCtx, handlers) + const ancestorsHaveListeners = computeAncestorsHaveListeners(parentCtx, handlers) setupPointerEvents(mergedProperties, ancestorsHaveListeners, parentCtx.root, object, initializers, false) setupLayoutListeners(style, properties, flexState.size, initializers) diff --git a/packages/uikit/src/components/image.ts b/packages/uikit/src/components/image.ts index 226642bc..e0d50c74 100644 --- a/packages/uikit/src/components/image.ts +++ b/packages/uikit/src/components/image.ts @@ -10,7 +10,7 @@ import { TextureLoader, Vector2Tuple, } from 'three' -import { Listeners } from '../index.js' +import { EventHandlers, Listeners } from '../index.js' import { Object3DRef, ParentContext, RootContext } from '../context.js' import { FlexNode, FlexNodeState, Inset, YogaProperties, createFlexNodeState } from '../flex/index.js' import { ElementType, OrderInfo, ZIndexProperties, computedOrderInfo, setupRenderOrder } from '../order.js' @@ -41,7 +41,7 @@ import { UpdateMatrixWorldProperties, VisibilityProperties, WithConditionals, - computeAnyAncestorsHaveListeners, + computeAncestorsHaveListeners, computeDefaultProperties, computedGlobalMatrix, computedHandlers, @@ -61,6 +61,7 @@ import { makeClippedCast, makePanelRaycast, makePanelSpherecast, + PointerEventsProperties, } from '../panel/interaction-panel-mesh.js' import { computedIsClipped, computedClippingRect, createGlobalClippingPlanes } from '../clipping.js' import { setupLayoutListeners, setupClippedListeners } from '../listeners.js' @@ -70,6 +71,7 @@ import { createHoverPropertyTransformers, setupCursorCleanup } from '../hover.js import { createResponsivePropertyTransformers } from '../responsive.js' import { AppearanceProperties } from './svg.js' import { darkPropertyTransformers } from '../dark.js' +import { ThreeEventMap } from '../events.js' export type ImageFit = 'cover' | 'fill' const defaultImageFit: ImageFit = 'fill' @@ -88,7 +90,8 @@ export type InheritableImageProperties = WithClasses< KeepAspectRatioProperties & ImageFitProperties & VisibilityProperties & - UpdateMatrixWorldProperties + UpdateMatrixWorldProperties & + PointerEventsProperties > > > @@ -102,12 +105,15 @@ export type KeepAspectRatioProperties = { keepAspectRatio?: boolean } -export type ImageProperties = InheritableImageProperties & Listeners & WithReactive<{ src?: string | Texture }> +export type ImageProperties = InheritableImageProperties & + Listeners & + WithReactive<{ src?: string | Texture }> & + EventHandlers -export function createImage( +export function createImage( parentCtx: ParentContext, - style: Signal, - properties: Signal, + style: Signal | undefined>, + properties: Signal | undefined>, defaultProperties: Signal, object: Object3DRef, childrenContainer: Object3DRef, @@ -200,7 +206,7 @@ export function createImage( ) const handlers = computedHandlers(style, properties, defaultProperties, hoveredSignal, activeSignal, scrollHandlers) - const ancestorsHaveListeners = computeAnyAncestorsHaveListeners(parentCtx, handlers) + const ancestorsHaveListeners = computeAncestorsHaveListeners(parentCtx, handlers) setupPointerEvents(mergedProperties, ancestorsHaveListeners, parentCtx.root, imageMesh, initializers, false) const updateMatrixWorld = computedInheritableProperty(mergedProperties, 'updateMatrixWorld', false) diff --git a/packages/uikit/src/components/input.ts b/packages/uikit/src/components/input.ts index 16c5b7e7..a575d85d 100644 --- a/packages/uikit/src/components/input.ts +++ b/packages/uikit/src/components/input.ts @@ -21,7 +21,7 @@ import { UpdateMatrixWorldProperties, VisibilityProperties, WithConditionals, - computeAnyAncestorsHaveListeners, + computeAncestorsHaveListeners, computedGlobalMatrix, computedHandlers, computedIsVisible, @@ -35,7 +35,7 @@ import { Listeners, setupLayoutListeners, setupClippedListeners } from '../liste import { Object3DRef, ParentContext } from '../context.js' import { PanelGroupProperties, computedPanelGroupDependencies } from '../panel/instanced-panel-group.js' import { createInteractionPanel } from '../panel/instanced-panel-mesh.js' -import { EventHandlers, ThreeEvent } from '../events.js' +import { EventHandlers, ThreeEventMap, ThreePointerEvent } from '../events.js' import { Vector2Tuple, Vector2, Vector3Tuple } from 'three' import { CaretProperties, createCaret } from '../caret.js' import { SelectionBoxes, SelectionProperties, createSelection } from '../selection.js' @@ -49,7 +49,7 @@ import { createInstancedText, } from '../text/index.js' import { darkPropertyTransformers } from '../dark.js' -import { getDefaultPanelMaterialConfig } from '../panel/index.js' +import { getDefaultPanelMaterialConfig, PointerEventsProperties } from '../panel/index.js' export type InheritableInputProperties = WithClasses< WithFocus< @@ -67,7 +67,8 @@ export type InheritableInputProperties = WithClasses< InstancedTextProperties & DisabledProperties & VisibilityProperties & - UpdateMatrixWorldProperties + UpdateMatrixWorldProperties & + PointerEventsProperties > > > @@ -78,9 +79,9 @@ export type DisabledProperties = { disabled?: boolean } -const cancelSet = new Set() +const cancelSet = new Set() -function cancelBlur(event: PointerEvent) { +function cancelBlur(event: unknown) { cancelSet.add(event) } @@ -99,7 +100,7 @@ export const canvasInputProps = { export type InputType = 'text' | 'password' -export type InputProperties = InheritableInputProperties & +export type InputProperties = InheritableInputProperties & Listeners & { onValueChange?: (value: string) => void } & WithReactive<{ @@ -110,13 +111,13 @@ export type InputProperties = InheritableInputProperties & }> & { multiline?: boolean defaultValue?: string - } + } & EventHandlers -export function createInput( +export function createInput( parentCtx: ParentContext, fontFamilies: Signal, - style: Signal, - properties: Signal, + style: Signal | undefined>, + properties: Signal | undefined>, defaultProperties: Signal, object: Object3DRef, ) { @@ -310,7 +311,7 @@ export function createInput( selectionHandlers, 'text', ) - const ancestorsHaveListeners = computeAnyAncestorsHaveListeners(parentCtx, handlers) + const ancestorsHaveListeners = computeAncestorsHaveListeners(parentCtx, handlers) setupPointerEvents(mergedProperties, ancestorsHaveListeners, parentCtx.root, interactionPanel, initializers, false) return Object.assign(flexState, { @@ -345,7 +346,7 @@ export function computedSelectionHandlers( return undefined } let dragState: { startCharIndex: number; pointerId: number } | undefined - const onPointerFinish = (e: ThreeEvent) => { + const onPointerFinish = (e: ThreePointerEvent) => { if (dragState == null || dragState.pointerId != e.pointerId) { return } diff --git a/packages/uikit/src/components/root.ts b/packages/uikit/src/components/root.ts index 1ddb25f6..45942e3b 100644 --- a/packages/uikit/src/components/root.ts +++ b/packages/uikit/src/components/root.ts @@ -25,7 +25,7 @@ import { UpdateMatrixWorldProperties, VisibilityProperties, WithConditionals, - computeAnyAncestorsHaveListeners, + computeAncestorsHaveListeners, computeDefaultProperties, computedHandlers, computedIsVisible, @@ -44,6 +44,7 @@ import { createResponsivePropertyTransformers } from '../responsive.js' import { darkPropertyTransformers } from '../dark.js' import { computedInheritableProperty } from '../properties/index.js' import { getDefaultPanelMaterialConfig, PointerEventsProperties } from '../panel/index.js' +import { EventHandlers, ThreeEventMap } from '../events.js' export type InheritableRootProperties = WithClasses< WithConditionals< @@ -66,7 +67,10 @@ export type InheritableRootProperties = WithClasses< > > -export type RootProperties = InheritableRootProperties & LayoutListeners & ScrollListeners +export type RootProperties = InheritableRootProperties & + LayoutListeners & + ScrollListeners & + EventHandlers export const DEFAULT_PIXEL_SIZE = 0.01 @@ -75,10 +79,10 @@ const planeHelper = new Plane() const identityMatrix = signal(new Matrix4()) -export function createRoot( +export function createRoot( pixelSize: Signal, - style: Signal, - properties: Signal, + style: Signal | undefined>, + properties: Signal | undefined>, defaultProperties: Signal, object: Object3DRef, childrenContainer: Object3DRef, @@ -259,7 +263,7 @@ export function createRoot( ) const handlers = computedHandlers(style, properties, defaultProperties, hoveredSignal, activeSignal, scrollHandlers) - const ancestorsHaveListeners = computeAnyAncestorsHaveListeners(undefined, handlers) + const ancestorsHaveListeners = computeAncestorsHaveListeners(undefined, handlers) setupPointerEvents(mergedProperties, ancestorsHaveListeners, rootCtx, interactionPanel, initializers, false) return Object.assign(flexState, { diff --git a/packages/uikit/src/components/svg.ts b/packages/uikit/src/components/svg.ts index 0df3be9e..7a755fad 100644 --- a/packages/uikit/src/components/svg.ts +++ b/packages/uikit/src/components/svg.ts @@ -42,7 +42,7 @@ import { loadResourceWithParams, } from './utils.js' import { ColorRepresentation, Initializers, fitNormalizedContentInside, readReactive } from '../utils.js' -import { makeClippedCast } from '../panel/interaction-panel-mesh.js' +import { makeClippedCast, PointerEventsProperties } from '../panel/interaction-panel-mesh.js' import { computedIsClipped, computedClippingRect, ClippingRect, createGlobalClippingPlanes } from '../clipping.js' import { setupLayoutListeners, setupClippedListeners } from '../listeners.js' import { createActivePropertyTransfomers } from '../active.js' @@ -58,7 +58,9 @@ import { computeDefaultProperties, setupMatrixWorldUpdate, setupPointerEvents, - computeAnyAncestorsHaveListeners, + computeAncestorsHaveListeners, + EventHandlers, + ThreeEventMap, } from '../internals.js' export type InheritableSvgProperties = WithClasses< @@ -73,7 +75,8 @@ export type InheritableSvgProperties = WithClasses< TransformProperties & PanelGroupProperties & ScrollbarProperties & - VisibilityProperties + VisibilityProperties & + PointerEventsProperties > > > @@ -83,16 +86,16 @@ export type AppearanceProperties = { color?: ColorRepresentation } -export type SvgProperties = InheritableSvgProperties & +export type SvgProperties = InheritableSvgProperties & Listeners & { src?: Signal | string keepAspectRatio?: boolean - } + } & EventHandlers -export function createSvg( +export function createSvg( parentCtx: ParentContext, - style: Signal, - properties: Signal, + style: Signal | undefined>, + properties: Signal | undefined>, defaultProperties: Signal, object: Object3DRef, childrenContainer: Object3DRef, @@ -210,7 +213,7 @@ export function createSvg( ) const handlers = computedHandlers(style, properties, defaultProperties, hoveredSignal, activeSignal, scrollHandlers) - const ancestorsHaveListeners = computeAnyAncestorsHaveListeners(undefined, handlers) + const ancestorsHaveListeners = computeAncestorsHaveListeners(undefined, handlers) setupPointerEvents(mergedProperties, ancestorsHaveListeners, parentCtx.root, centerGroup, initializers, false) setupPointerEvents(mergedProperties, ancestorsHaveListeners, parentCtx.root, interactionPanel, initializers, false) diff --git a/packages/uikit/src/components/text.ts b/packages/uikit/src/components/text.ts index a1a16e1c..5c7a7805 100644 --- a/packages/uikit/src/components/text.ts +++ b/packages/uikit/src/components/text.ts @@ -25,7 +25,7 @@ import { Initializers } from '../utils.js' import { Listeners, setupLayoutListeners, setupClippedListeners } from '../listeners.js' import { Object3DRef, ParentContext } from '../context.js' import { PanelGroupProperties, computedPanelGroupDependencies } from '../panel/instanced-panel-group.js' -import { createInteractionPanel, getDefaultPanelMaterialConfig } from '../panel/index.js' +import { createInteractionPanel, getDefaultPanelMaterialConfig, PointerEventsProperties } from '../panel/index.js' import { FontFamilies, InstancedTextProperties, @@ -35,8 +35,10 @@ import { } from '../text/index.js' import { darkPropertyTransformers } from '../dark.js' import { - computeAnyAncestorsHaveListeners, + computeAncestorsHaveListeners, computedInheritableProperty, + EventHandlers, + ThreeEventMap, UpdateMatrixWorldProperties, } from '../internals.js' @@ -52,20 +54,23 @@ export type InheritableTextProperties = WithClasses< PanelGroupProperties & InstancedTextProperties & VisibilityProperties & - UpdateMatrixWorldProperties + UpdateMatrixWorldProperties & + PointerEventsProperties > > > > -export type TextProperties = InheritableTextProperties & Listeners +export type TextProperties = InheritableTextProperties & + Listeners & + EventHandlers -export function createText( +export function createText( parentCtx: ParentContext, textSignal: Signal | Array>>, fontFamilies: Signal | undefined, - style: Signal, - properties: Signal, + style: Signal | undefined>, + properties: Signal | undefined>, defaultProperties: Signal, object: Object3DRef, ) { @@ -150,7 +155,7 @@ export function createText( ) const handlers = computedHandlers(style, properties, defaultProperties, hoveredSignal, activeSignal) - const ancestorsHaveListeners = computeAnyAncestorsHaveListeners(undefined, handlers) + const ancestorsHaveListeners = computeAncestorsHaveListeners(undefined, handlers) setupPointerEvents(mergedProperties, ancestorsHaveListeners, parentCtx.root, interactionPanel, initializers, false) const updateMatrixWorld = computedInheritableProperty(mergedProperties, 'updateMatrixWorld', false) diff --git a/packages/uikit/src/components/utils.ts b/packages/uikit/src/components/utils.ts index dabc0130..06ff2178 100644 --- a/packages/uikit/src/components/utils.ts +++ b/packages/uikit/src/components/utils.ts @@ -150,9 +150,24 @@ export const keepAspectRatioPropertyTransformer: PropertyTransformers = { }, } +const eventHandlerKeys: Array = [ + 'onClick', + 'onContextMenu', + 'onDoubleClick', + 'onPointerCancel', + 'onPointerDown', + 'onPointerEnter', + 'onPointerLeave', + 'onPointerMove', + 'onPointerOut', + 'onPointerOver', + 'onPointerUp', + 'onWheel', +] + export function computedHandlers( style: Signal, - properties: Signal, + propertiesSignal: Signal, defaultProperties: Signal, hoveredSignal: Signal>, activeSignal: Signal>, @@ -161,14 +176,30 @@ export function computedHandlers( ) { return computed(() => { const handlers: EventHandlers = {} + const properties = propertiesSignal.value + if (properties != null) { + for (const key of eventHandlerKeys) { + const handler = properties[key] + if (handler != null) { + handlers[key] = handler as any + } + } + } addHandlers(handlers, dynamicHandlers?.value) - addHoverHandlers(handlers, style.value, properties.value, defaultProperties.value, hoveredSignal, defaultCursor) - addActiveHandlers(handlers, style.value, properties.value, defaultProperties.value, activeSignal) + addHoverHandlers( + handlers, + style.value, + propertiesSignal.value, + defaultProperties.value, + hoveredSignal, + defaultCursor, + ) + addActiveHandlers(handlers, style.value, propertiesSignal.value, defaultProperties.value, activeSignal) return handlers }) } -export function computeAnyAncestorsHaveListeners( +export function computeAncestorsHaveListeners( parentContext: ParentContext | undefined, handlers: ReadonlySignal, ) { diff --git a/packages/uikit/src/components/video.ts b/packages/uikit/src/components/video.ts index 51f582bb..f9c61f65 100644 --- a/packages/uikit/src/components/video.ts +++ b/packages/uikit/src/components/video.ts @@ -1,6 +1,8 @@ +import { EventHandlers, ThreeEventMap } from '../events.js' import { ImageProperties } from './image.js' -export type VideoProperties = Omit & InternalVideoProperties +export type VideoProperties = Omit, 'src'> & + InternalVideoProperties type InternalVideoProperties = { /** diff --git a/packages/uikit/src/events.ts b/packages/uikit/src/events.ts index 3187307b..d716fc44 100644 --- a/packages/uikit/src/events.ts +++ b/packages/uikit/src/events.ts @@ -1,25 +1,32 @@ import { Intersection } from 'three' -export type ThreeEvent = Intersection & { - nativeEvent: TSourceEvent +export type ThreeMouseEvent = Intersection & { + nativeEvent: unknown stopPropagation?: () => void stopImmediatePropagation?: () => void -} & (TSourceEvent extends { pointerId: number } ? { pointerId: number } : {}) +} + +export type ThreePointerEvent = ThreeMouseEvent & { pointerId: number } + +export type ThreeEventMap = { + mouse: ThreeMouseEvent + wheel: ThreeMouseEvent + pointer: ThreePointerEvent +} + +export type EventHandlers = { + onClick?: (event: EM['mouse']) => void + onContextMenu?: (event: EM['mouse']) => void + onDoubleClick?: (event: EM['mouse']) => void -export type KeyToEvent = Parameters[K]>[0] + onWheel?: (event: EM['wheel']) => void -export type EventHandlers = { - onClick?: (event: ThreeEvent) => void - onContextMenu?: (event: ThreeEvent) => void - onDoubleClick?: (event: ThreeEvent) => void - onPointerUp?: (event: ThreeEvent) => void - onPointerDown?: (event: ThreeEvent) => void - onPointerOver?: (event: ThreeEvent) => void - onPointerOut?: (event: ThreeEvent) => void - onPointerEnter?: (event: ThreeEvent) => void - onPointerLeave?: (event: ThreeEvent) => void - onPointerMove?: (event: ThreeEvent) => void - onPointerMissed?: (event: MouseEvent) => void - onPointerCancel?: (event: ThreeEvent) => void - onWheel?: (event: ThreeEvent) => void + onPointerUp?: (event: EM['pointer']) => void + onPointerDown?: (event: EM['pointer']) => void + onPointerOver?: (event: EM['pointer']) => void + onPointerOut?: (event: EM['pointer']) => void + onPointerEnter?: (event: EM['pointer']) => void + onPointerLeave?: (event: EM['pointer']) => void + onPointerMove?: (event: EM['pointer']) => void + onPointerCancel?: (event: EM['pointer']) => void } diff --git a/packages/uikit/src/index.ts b/packages/uikit/src/index.ts index c17fc5e2..75cfeeca 100644 --- a/packages/uikit/src/index.ts +++ b/packages/uikit/src/index.ts @@ -1,5 +1,5 @@ export { canvasInputProps } from './components/input.js' -export type { EventHandlers, ThreeEvent } from './events.js' +export type { EventHandlers, ThreePointerEvent as ThreeEvent } from './events.js' export { reversePainterSortStable } from './order.js' export { basedOnPreferredColorScheme, diff --git a/packages/uikit/src/listeners.ts b/packages/uikit/src/listeners.ts index 9c6eedfc..62abd99c 100644 --- a/packages/uikit/src/listeners.ts +++ b/packages/uikit/src/listeners.ts @@ -1,7 +1,7 @@ import { Signal, effect } from '@preact/signals-core' import { Vector2Tuple } from 'three' import { Initializers } from './utils.js' -import { ThreeEvent } from './events.js' +import { ThreeMouseEvent, ThreePointerEvent } from './events.js' export type Listeners = ScrollListeners & LayoutListeners & ClippedListeners @@ -18,7 +18,7 @@ export type ScrollListeners = { scrollX: number, scrollY: number, scrollPosition: Signal, - event?: ThreeEvent, + event?: ThreePointerEvent | ThreeMouseEvent, ) => boolean | void } diff --git a/packages/uikit/src/scroll.ts b/packages/uikit/src/scroll.ts index 784b2ae2..5afc4ccb 100644 --- a/packages/uikit/src/scroll.ts +++ b/packages/uikit/src/scroll.ts @@ -11,7 +11,7 @@ import { PanelMaterialConfig, createPanelMaterialConfig } from './panel/panel-ma import { PanelGroupManager, defaultPanelDependencies } from './panel/instanced-panel-group.js' import { Object3DRef, RootContext } from './context.js' import { ScrollListeners } from './listeners.js' -import { EventHandlers, ThreeEvent } from './events.js' +import { EventHandlers, ThreeMouseEvent, ThreePointerEvent } from './events.js' const distanceHelper = new Vector3() const localPointHelper = new Vector3() @@ -88,7 +88,7 @@ export function computedScrollHandlers( const scrollVelocity = new Vector2() const scroll = ( - event: ThreeEvent | undefined, + event: ThreePointerEvent | ThreeMouseEvent | undefined, deltaX: number, deltaY: number, deltaTime: number | undefined, @@ -186,7 +186,7 @@ export function computedScrollHandlers( if (!isScrollable.value) { return undefined } - const onPointerFinish = (event: ThreeEvent) => { + const onPointerFinish = (event: ThreePointerEvent) => { if ('releasePointerCapture' in object && typeof object.releasePointerCapture === 'function') { object.releasePointerCapture(event.pointerId) } @@ -205,20 +205,25 @@ export function computedScrollHandlers( event.stopImmediatePropagation?.() const localPoint = object.current!.worldToLocal(event.point.clone()) - const scrollbarAxisIndex = - event.nativeEvent.pointerType != 'mouse' - ? undefined - : getIntersectedScrollbarIndex( - localPoint, - root.pixelSize.peek(), - scrollbarWidth.peek(), - nodeState.size.peek(), - nodeState.maxScrollPosition.peek(), - nodeState.borderInset.peek(), - scrollPosition.peek(), - ) - - if (event.nativeEvent.pointerType === 'mouse' && scrollbarAxisIndex == null) { + const ponterIsMouse = + event.nativeEvent != null && + typeof event.nativeEvent === 'object' && + 'pointerType' in event.nativeEvent && + event.nativeEvent.pointerType === 'mouse' + + const scrollbarAxisIndex = ponterIsMouse + ? undefined + : getIntersectedScrollbarIndex( + localPoint, + root.pixelSize.peek(), + scrollbarWidth.peek(), + nodeState.size.peek(), + nodeState.maxScrollPosition.peek(), + nodeState.borderInset.peek(), + scrollPosition.peek(), + ) + + if (ponterIsMouse && scrollbarAxisIndex == null) { return } @@ -279,6 +284,16 @@ export function computedScrollHandlers( }, onWheel: (event) => { const { nativeEvent } = event + if ( + nativeEvent == null || + typeof nativeEvent != 'object' || + !('deltaX' in nativeEvent) || + typeof nativeEvent.deltaX != 'number' || + !('deltaY' in nativeEvent) || + typeof nativeEvent.deltaY != 'number' + ) { + return + } scroll(event, nativeEvent.deltaX, nativeEvent.deltaY, undefined, false) }, } diff --git a/packages/uikit/src/vanilla/container.ts b/packages/uikit/src/vanilla/container.ts index 5da00b18..199a1a27 100644 --- a/packages/uikit/src/vanilla/container.ts +++ b/packages/uikit/src/vanilla/container.ts @@ -4,18 +4,19 @@ import { ReadonlySignal, Signal, effect, signal, untracked } from '@preact/signa import { Subscriptions, initialize, unsubscribeSubscriptions } from '../utils.js' import { Parent, createParentContextSignal, setupParentContextSignal, bindHandlers } from './utils.js' import { MergedProperties } from '../properties/index.js' +import { ThreeEventMap } from '../events.js' -export class Container extends Parent { +export class Container extends Parent { private mergedProperties?: ReadonlySignal - private readonly styleSignal: Signal = signal(undefined) - private readonly propertiesSignal: Signal + private readonly styleSignal: Signal | undefined> = signal(undefined) + private readonly propertiesSignal: Signal | undefined> private readonly defaultPropertiesSignal: Signal private readonly parentContextSignal = createParentContextSignal() private readonly unsubscribe: () => void public internals!: ReturnType - constructor(properties?: ContainerProperties, defaultProperties?: AllOptionalProperties) { + constructor(properties?: ContainerProperties, defaultProperties?: AllOptionalProperties) { super() this.matrixAutoUpdate = false setupParentContextSignal(this.parentContextSignal, this) @@ -50,19 +51,19 @@ export class Container extends Parent { }) } - getComputedProperty(key: K): ContainerProperties[K] | undefined { - return untracked(() => this.mergedProperties?.value.read(key, undefined)) + getComputedProperty>(key: K): ContainerProperties[K] | undefined { + return untracked(() => this.mergedProperties?.value.read(key as string, undefined)) } - getStyle(): undefined | Readonly { + getStyle(): undefined | Readonly> { return this.styleSignal.peek() } - setStyle(style: ContainerProperties | undefined, replace?: boolean) { - this.styleSignal.value = replace ? style : { ...this.styleSignal.value, ...style } + setStyle(style: ContainerProperties | undefined, replace?: boolean) { + this.styleSignal.value = replace ? style : ({ ...this.styleSignal.value, ...style } as any) } - setProperties(properties: ContainerProperties | undefined) { + setProperties(properties: ContainerProperties | undefined) { this.propertiesSignal.value = properties } diff --git a/packages/uikit/src/vanilla/content.ts b/packages/uikit/src/vanilla/content.ts index 45bf339c..f7ffb793 100644 --- a/packages/uikit/src/vanilla/content.ts +++ b/packages/uikit/src/vanilla/content.ts @@ -5,12 +5,13 @@ import { ReadonlySignal, Signal, effect, signal, untracked } from '@preact/signa import { Subscriptions, initialize, unsubscribeSubscriptions } from '../utils.js' import { ContentProperties, createContent } from '../components/index.js' import { MergedProperties } from '../properties/index.js' +import { ThreeEventMap } from '../events.js' -export class Content extends Component { +export class Content extends Component { private mergedProperties?: ReadonlySignal private readonly contentContainer: Object3D - private readonly styleSignal: Signal = signal(undefined) - private readonly propertiesSignal: Signal + private readonly styleSignal: Signal | undefined> = signal(undefined) + private readonly propertiesSignal: Signal | undefined> private readonly defaultPropertiesSignal: Signal private readonly contentSubscriptions: Subscriptions = [] private readonly parentContextSignal = createParentContextSignal() @@ -18,7 +19,7 @@ export class Content extends Component { public internals!: ReturnType - constructor(properties?: ContentProperties, defaultProperties?: AllOptionalProperties) { + constructor(properties?: ContentProperties, defaultProperties?: AllOptionalProperties) { super() this.matrixAutoUpdate = false setupParentContextSignal(this.parentContextSignal, this) @@ -82,19 +83,19 @@ export class Content extends Component { return this } - getComputedProperty(key: K): ContentProperties[K] | undefined { - return untracked(() => this.mergedProperties?.value.read(key, undefined)) + getComputedProperty>(key: K): ContentProperties[K] | undefined { + return untracked(() => this.mergedProperties?.value.read(key as string, undefined)) } - getStyle(): undefined | Readonly { + getStyle(): undefined | Readonly> { return this.styleSignal.peek() } - setStyle(style: ContentProperties | undefined, replace?: boolean) { - this.styleSignal.value = replace ? style : { ...this.styleSignal.value, ...style } + setStyle(style: ContentProperties | undefined, replace?: boolean) { + this.styleSignal.value = replace ? style : ({ ...this.styleSignal.value, ...style } as any) } - setProperties(properties: ContentProperties | undefined) { + setProperties(properties: ContentProperties | undefined) { this.propertiesSignal.value = properties } diff --git a/packages/uikit/src/vanilla/custom.ts b/packages/uikit/src/vanilla/custom.ts index 67c75b58..3ef77430 100644 --- a/packages/uikit/src/vanilla/custom.ts +++ b/packages/uikit/src/vanilla/custom.ts @@ -6,17 +6,18 @@ import { Subscriptions, initialize, unsubscribeSubscriptions } from '../utils.js import { CustomContainerProperties, createCustomContainer } from '../components/index.js' import { panelGeometry } from '../panel/index.js' import { MergedProperties } from '../properties/index.js' +import { ThreeEventMap } from '../events.js' -export class CustomContainer extends Component { +export class CustomContainer extends Component { private mergedProperties?: ReadonlySignal - private readonly styleSignal: Signal = signal(undefined) - private readonly propertiesSignal: Signal + private readonly styleSignal: Signal | undefined> = signal(undefined) + private readonly propertiesSignal: Signal | undefined> private readonly defaultPropertiesSignal: Signal private readonly parentContextSignal = createParentContextSignal() private readonly unsubscribe: () => void private readonly material = new MeshBasicMaterial() - constructor(properties?: CustomContainerProperties, defaultProperties?: AllOptionalProperties) { + constructor(properties?: CustomContainerProperties, defaultProperties?: AllOptionalProperties) { super() this.matrixAutoUpdate = false setupParentContextSignal(this.parentContextSignal, this) @@ -57,19 +58,21 @@ export class CustomContainer extends Component { }) } - getComputedProperty(key: K): CustomContainerProperties[K] | undefined { - return untracked(() => this.mergedProperties?.value.read(key, undefined)) + getComputedProperty>( + key: K, + ): CustomContainerProperties[K] | undefined { + return untracked(() => this.mergedProperties?.value.read(key as string, undefined)) } - getStyle(): undefined | Readonly { + getStyle(): undefined | Readonly> { return this.styleSignal.peek() } - setStyle(style: CustomContainerProperties | undefined, replace?: boolean) { - this.styleSignal.value = replace ? style : { ...this.styleSignal.value, ...style } + setStyle(style: CustomContainerProperties | undefined, replace?: boolean) { + this.styleSignal.value = replace ? style : ({ ...this.styleSignal.value, ...style } as any) } - setProperties(properties: CustomContainerProperties | undefined) { + setProperties(properties: CustomContainerProperties | undefined) { this.propertiesSignal.value = properties } diff --git a/packages/uikit/src/vanilla/fullscreen.ts b/packages/uikit/src/vanilla/fullscreen.ts index 7d14ca2e..a5c3d4d6 100644 --- a/packages/uikit/src/vanilla/fullscreen.ts +++ b/packages/uikit/src/vanilla/fullscreen.ts @@ -4,10 +4,11 @@ import { Signal, batch, signal } from '@preact/signals-core' import { FullscreenProperties, updateSizeFullscreen } from '../components/index.js' import { AllOptionalProperties } from '../properties/index.js' import { FontFamilies } from '../text/index.js' +import { ThreeEventMap } from '../events.js' const vectorHelper = new Vector2() -export class Fullscreen extends Root { +export class Fullscreen extends Root { private parentCameraSignal: Signal private readonly sizeX: Signal private readonly sizeY: Signal @@ -17,7 +18,7 @@ export class Fullscreen extends Root { constructor( private renderer: WebGLRenderer, private distanceToCamera?: number, - properties?: FullscreenProperties, + properties?: FullscreenProperties, defaultProperties?: AllOptionalProperties, fontFamilies?: FontFamilies, requestRender?: () => void, @@ -73,15 +74,15 @@ export class Fullscreen extends Root { }) } - getStyle(): undefined | Readonly { + getStyle(): undefined | Readonly> { return this.styleSignal.peek() } - setStyle(style: FullscreenProperties | undefined, replace?: boolean): void { + setStyle(style: FullscreenProperties | undefined, replace?: boolean): void { super.setStyle(style, replace) } - setProperties(properties: FullscreenProperties | undefined): void { + setProperties(properties: FullscreenProperties | undefined): void { super.setProperties({ ...properties, sizeX: this.sizeX, diff --git a/packages/uikit/src/vanilla/icon.ts b/packages/uikit/src/vanilla/icon.ts index 0a95a35a..d58d2d35 100644 --- a/packages/uikit/src/vanilla/icon.ts +++ b/packages/uikit/src/vanilla/icon.ts @@ -1,15 +1,15 @@ -import { Object3D } from 'three' import { AllOptionalProperties } from '../properties/default.js' import { createParentContextSignal, setupParentContextSignal, bindHandlers, Component } from './utils.js' import { ReadonlySignal, Signal, effect, signal, untracked } from '@preact/signals-core' import { Subscriptions, initialize, unsubscribeSubscriptions } from '../utils.js' import { IconProperties, createIcon } from '../components/icon.js' import { MergedProperties } from '../properties/index.js' +import { ThreeEventMap } from '../events.js' -export class Icon extends Component { +export class Icon extends Component { private mergedProperties?: ReadonlySignal - private readonly styleSignal: Signal = signal(undefined) - private readonly propertiesSignal: Signal + private readonly styleSignal: Signal | undefined> = signal(undefined) + private readonly propertiesSignal: Signal | undefined> private readonly defaultPropertiesSignal: Signal private readonly parentContextSignal = createParentContextSignal() private readonly unsubscribe: () => void @@ -20,7 +20,7 @@ export class Icon extends Component { text: string, svgWidth: number, svgHeight: number, - properties?: IconProperties, + properties?: IconProperties, defaultProperties?: AllOptionalProperties, ) { super() @@ -58,19 +58,19 @@ export class Icon extends Component { }) } - getComputedProperty(key: K): IconProperties[K] | undefined { - return untracked(() => this.mergedProperties?.value.read(key, undefined)) + getComputedProperty>(key: K): IconProperties[K] | undefined { + return untracked(() => this.mergedProperties?.value.read(key as string, undefined)) } - getStyle(): undefined | Readonly { + getStyle(): undefined | Readonly> { return this.styleSignal.peek() } - setStyle(style: IconProperties | undefined, replace?: boolean) { - this.styleSignal.value = replace ? style : { ...this.styleSignal.value, ...style } + setStyle(style: IconProperties | undefined, replace?: boolean) { + this.styleSignal.value = replace ? style : ({ ...this.styleSignal.value, ...style } as any) } - setProperties(properties: IconProperties | undefined) { + setProperties(properties: IconProperties | undefined) { this.propertiesSignal.value = properties } diff --git a/packages/uikit/src/vanilla/image.ts b/packages/uikit/src/vanilla/image.ts index c9ca59f3..f1a49f68 100644 --- a/packages/uikit/src/vanilla/image.ts +++ b/packages/uikit/src/vanilla/image.ts @@ -1,22 +1,22 @@ -import { Texture } from 'three' import { ImageProperties, createImage } from '../components/image.js' import { AllOptionalProperties } from '../properties/default.js' import { Parent, createParentContextSignal, setupParentContextSignal, bindHandlers } from './utils.js' import { ReadonlySignal, Signal, effect, signal, untracked } from '@preact/signals-core' import { Subscriptions, initialize, unsubscribeSubscriptions } from '../utils.js' import { MergedProperties } from '../properties/index.js' +import { ThreeEventMap } from '../events.js' -export class Image extends Parent { +export class Image extends Parent { private mergedProperties?: ReadonlySignal - private readonly styleSignal: Signal = signal(undefined) - private readonly propertiesSignal: Signal + private readonly styleSignal: Signal | undefined> = signal(undefined) + private readonly propertiesSignal: Signal | undefined> private readonly defaultPropertiesSignal: Signal protected readonly parentContextSignal = createParentContextSignal() private readonly unsubscribe: () => void public internals!: ReturnType - constructor(properties?: ImageProperties, defaultProperties?: AllOptionalProperties) { + constructor(properties?: ImageProperties, defaultProperties?: AllOptionalProperties) { super() setupParentContextSignal(this.parentContextSignal, this) this.matrixAutoUpdate = false @@ -49,19 +49,19 @@ export class Image extends Parent { }) } - getComputedProperty(key: K): ImageProperties[K] | undefined { - return untracked(() => this.mergedProperties?.value.read(key, undefined)) + getComputedProperty>(key: K): ImageProperties[K] | undefined { + return untracked(() => this.mergedProperties?.value.read(key as string, undefined)) } - getStyle(): undefined | Readonly { + getStyle(): undefined | Readonly> { return this.styleSignal.peek() } - setStyle(style: ImageProperties | undefined, replace?: boolean) { - this.styleSignal.value = replace ? style : { ...this.styleSignal.value, ...style } + setStyle(style: ImageProperties | undefined, replace?: boolean) { + this.styleSignal.value = replace ? style : ({ ...this.styleSignal.value, ...style } as any) } - setProperties(properties: ImageProperties | undefined) { + setProperties(properties: ImageProperties | undefined) { this.propertiesSignal.value = properties } diff --git a/packages/uikit/src/vanilla/input.ts b/packages/uikit/src/vanilla/input.ts index 0c11ccb0..1344c693 100644 --- a/packages/uikit/src/vanilla/input.ts +++ b/packages/uikit/src/vanilla/input.ts @@ -1,22 +1,22 @@ -import { Object3D } from 'three' import { AllOptionalProperties } from '../properties/default.js' import { createParentContextSignal, setupParentContextSignal, bindHandlers, Component } from './utils.js' import { ReadonlySignal, Signal, effect, signal, untracked } from '@preact/signals-core' import { InputProperties, createInput } from '../components/input.js' import { Subscriptions, initialize, unsubscribeSubscriptions } from '../utils.js' import { MergedProperties } from '../properties/index.js' +import { ThreeEventMap } from '../events.js' -export class Input extends Component { +export class Input extends Component { private mergedProperties?: ReadonlySignal - private readonly styleSignal: Signal = signal(undefined) - private readonly propertiesSignal: Signal + private readonly styleSignal: Signal | undefined> = signal(undefined) + private readonly propertiesSignal: Signal | undefined> private readonly defaultPropertiesSignal: Signal private readonly parentContextSignal = createParentContextSignal() private readonly unsubscribe: () => void public internals!: ReturnType - constructor(properties?: InputProperties, defaultProperties?: AllOptionalProperties) { + constructor(properties?: InputProperties, defaultProperties?: AllOptionalProperties) { super() this.matrixAutoUpdate = false setupParentContextSignal(this.parentContextSignal, this) @@ -50,19 +50,19 @@ export class Input extends Component { }) } - getComputedProperty(key: K): InputProperties[K] | undefined { - return untracked(() => this.mergedProperties?.value.read(key, undefined)) + getComputedProperty>(key: K): InputProperties[K] | undefined { + return untracked(() => this.mergedProperties?.value.read(key as string, undefined)) } getStyle(): undefined | Readonly { return this.styleSignal.peek() } - setStyle(style: InputProperties | undefined, replace?: boolean) { - this.styleSignal.value = replace ? style : { ...this.styleSignal.value, ...style } + setStyle(style: InputProperties | undefined, replace?: boolean) { + this.styleSignal.value = replace ? style : ({ ...this.styleSignal.value, ...style } as any) } - setProperties(properties: InputProperties | undefined) { + setProperties(properties: InputProperties | undefined) { this.propertiesSignal.value = properties } diff --git a/packages/uikit/src/vanilla/root.ts b/packages/uikit/src/vanilla/root.ts index 73cceb50..28a4fddb 100644 --- a/packages/uikit/src/vanilla/root.ts +++ b/packages/uikit/src/vanilla/root.ts @@ -5,11 +5,12 @@ import { createRoot, DEFAULT_PIXEL_SIZE, RootProperties } from '../components/ro import { Parent, bindHandlers } from './utils.js' import { Subscriptions, initialize, readReactive, unsubscribeSubscriptions } from '../utils.js' import { FontFamilies } from '../text/index.js' +import { ThreeEventMap } from '../events.js' -export class Root extends Parent { +export class Root extends Parent { private mergedProperties?: ReadonlySignal - protected readonly styleSignal: Signal = signal(undefined) - private readonly propertiesSignal: Signal + protected readonly styleSignal: Signal | undefined> = signal(undefined) + private readonly propertiesSignal: Signal | undefined> private readonly defaultPropertiesSignal: Signal private readonly unsubscribe: () => void private readonly onFrameSet = new Set<(delta: number) => void>() @@ -20,7 +21,7 @@ export class Root extends Parent { constructor( camera: Signal | (() => Camera) | Camera, renderer: WebGLRenderer, - properties?: RootProperties & WithReactive<{ pixelSize?: number }>, + properties?: RootProperties & WithReactive<{ pixelSize?: number }>, defaultProperties?: AllOptionalProperties, fontFamilies?: FontFamilies, requestRender?: () => void, @@ -81,19 +82,19 @@ export class Root extends Parent { this.fontFamiliesSignal.value = fontFamilies } - getComputedProperty(key: K): RootProperties[K] | undefined { - return untracked(() => this.mergedProperties?.value.read(key, undefined)) + getComputedProperty>(key: K): RootProperties[K] | undefined { + return untracked(() => this.mergedProperties?.value.read(key as string, undefined)) } - getStyle(): undefined | Readonly { + getStyle(): undefined | Readonly> { return this.styleSignal.peek() } - setStyle(style: RootProperties | undefined, replace?: boolean) { - this.styleSignal.value = replace ? style : { ...this.styleSignal.value, ...style } + setStyle(style: RootProperties | undefined, replace?: boolean) { + this.styleSignal.value = replace ? style : ({ ...this.styleSignal.value, ...style } as any) } - setProperties(properties: (RootProperties & WithReactive<{ pixelSize?: number }>) | undefined) { + setProperties(properties: (RootProperties & WithReactive<{ pixelSize?: number }>) | undefined) { this.pixelSizeSignal.value = properties?.pixelSize ?? DEFAULT_PIXEL_SIZE this.propertiesSignal.value = properties } diff --git a/packages/uikit/src/vanilla/svg.ts b/packages/uikit/src/vanilla/svg.ts index f01d758b..52e50346 100644 --- a/packages/uikit/src/vanilla/svg.ts +++ b/packages/uikit/src/vanilla/svg.ts @@ -4,18 +4,19 @@ import { ReadonlySignal, Signal, effect, signal, untracked } from '@preact/signa import { Subscriptions, initialize, unsubscribeSubscriptions } from '../utils.js' import { SvgProperties, createSvg } from '../components/svg.js' import { MergedProperties } from '../properties/index.js' +import { ThreeEventMap } from '../events.js' -export class Svg extends Parent { +export class Svg extends Parent { private mergedProperties?: ReadonlySignal - private readonly styleSignal: Signal = signal(undefined) - private readonly propertiesSignal: Signal + private readonly styleSignal: Signal | undefined> = signal(undefined) + private readonly propertiesSignal: Signal | undefined> private readonly defaultPropertiesSignal: Signal private readonly parentContextSignal = createParentContextSignal() private readonly unsubscribe: () => void public internals!: ReturnType - constructor(properties?: SvgProperties, defaultProperties?: AllOptionalProperties) { + constructor(properties?: SvgProperties, defaultProperties?: AllOptionalProperties) { super() this.matrixAutoUpdate = false setupParentContextSignal(this.parentContextSignal, this) @@ -52,19 +53,19 @@ export class Svg extends Parent { }) } - getComputedProperty(key: K): SvgProperties[K] | undefined { - return untracked(() => this.mergedProperties?.value.read(key, undefined)) + getComputedProperty>(key: K): SvgProperties[K] | undefined { + return untracked(() => this.mergedProperties?.value.read(key as string, undefined)) } - getStyle(): undefined | Readonly { + getStyle(): undefined | Readonly> { return this.styleSignal.peek() } - setStyle(style: SvgProperties | undefined, replace?: boolean) { - this.styleSignal.value = replace ? style : { ...this.styleSignal.value, ...style } + setStyle(style: SvgProperties | undefined, replace?: boolean) { + this.styleSignal.value = replace ? style : ({ ...this.styleSignal.value, ...style } as any) } - setProperties(properties: SvgProperties | undefined) { + setProperties(properties: SvgProperties | undefined) { this.propertiesSignal.value = properties } diff --git a/packages/uikit/src/vanilla/text.ts b/packages/uikit/src/vanilla/text.ts index 4a7a3822..78d87c8e 100644 --- a/packages/uikit/src/vanilla/text.ts +++ b/packages/uikit/src/vanilla/text.ts @@ -1,15 +1,15 @@ -import { Object3D } from 'three' import { AllOptionalProperties } from '../properties/default.js' import { createParentContextSignal, setupParentContextSignal, bindHandlers, Component } from './utils.js' import { ReadonlySignal, Signal, effect, signal, untracked } from '@preact/signals-core' import { TextProperties, createText } from '../components/text.js' import { Subscriptions, initialize, unsubscribeSubscriptions } from '../utils.js' import { MergedProperties } from '../properties/index.js' +import { ThreeEventMap } from '../events.js' -export class Text extends Component { +export class Text extends Component { private mergedProperties?: ReadonlySignal - private readonly styleSignal: Signal = signal(undefined) - private readonly propertiesSignal: Signal + private readonly styleSignal: Signal | undefined> = signal(undefined) + private readonly propertiesSignal: Signal | undefined> private readonly defaultPropertiesSignal: Signal private readonly textSignal: Signal | Array>> private readonly parentContextSignal = createParentContextSignal() @@ -19,7 +19,7 @@ export class Text extends Component { constructor( text: string | Signal | Array> = '', - properties?: TextProperties, + properties?: TextProperties, defaultProperties?: AllOptionalProperties, ) { super() @@ -60,19 +60,19 @@ export class Text extends Component { this.textSignal.value = text } - getComputedProperty(key: K): TextProperties[K] | undefined { - return untracked(() => this.mergedProperties?.value.read(key, undefined)) + getComputedProperty>(key: K): TextProperties[K] | undefined { + return untracked(() => this.mergedProperties?.value.read(key as string, undefined)) } - getStyle(): undefined | Readonly { + getStyle(): undefined | Readonly> { return this.styleSignal.peek() } - setStyle(style: TextProperties | undefined, replace?: boolean) { - this.styleSignal.value = replace ? style : { ...this.styleSignal.value, ...style } + setStyle(style: TextProperties | undefined, replace?: boolean) { + this.styleSignal.value = replace ? style : ({ ...this.styleSignal.value, ...style } as any) } - setProperties(properties: TextProperties | undefined) { + setProperties(properties: TextProperties | undefined) { this.propertiesSignal.value = properties } diff --git a/packages/uikit/src/vanilla/video.ts b/packages/uikit/src/vanilla/video.ts index 87e45823..ef435094 100644 --- a/packages/uikit/src/vanilla/video.ts +++ b/packages/uikit/src/vanilla/video.ts @@ -8,15 +8,16 @@ import { updateVideoElement, } from '../components/index.js' import { AllOptionalProperties } from '../properties/index.js' +import { ThreeEventMap } from '../events.js' -export class Video extends Image { +export class Video extends Image { public element: HTMLVideoElement private readonly texture: VideoTexture private readonly aspectRatio: Signal private readonly updateAspectRatio: () => void private unsubscribeInvalidate: () => void - constructor(props: VideoProperties = {}, defaultProperties?: AllOptionalProperties) { + constructor(props: VideoProperties, defaultProperties?: AllOptionalProperties) { const element = props.src instanceof HTMLVideoElement ? props.src : document.createElement('video') updateVideoElement(element, props) const texture = new VideoTexture(element) @@ -40,7 +41,7 @@ export class Video extends Image { this.element.addEventListener('resize', this.updateAspectRatio) } - setProperties(props: VideoProperties & ImageProperties): void { + setProperties(props: VideoProperties & ImageProperties): void { updateVideoElement(this.element, props) super.setProperties({ aspectRatio: this.aspectRatio,