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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,5 +44,7 @@
"core-js",
"sharp"
]
}
},
"workspaces": ["packages/*"],
"packageManager": "pnpm@10.5.2+sha512.da9dc28cd3ff40d0592188235ab25d3202add8a207afbedc682220e4a0029ffbff4562102b9e6e46b4e3f9e8bd53e6d05de48544b0c57d4b0179e22c76d1199b"
}
4 changes: 4 additions & 0 deletions packages/react/src/container.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ export const Container: (props: ContainerProperties & RefAttributes<ContainerRef
propertySignals.default,
outerRef,
innerRef,
// @ts-expect-error
propertySignals.handlers,
propertySignals.hoverProps,
propertySignals.activeProps,
),
[parent, propertySignals],
)
Expand Down
4 changes: 4 additions & 0 deletions packages/react/src/content.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ export const Content: (props: ContentProperties & RefAttributes<ContentRef>) =>
propertySignals.default,
outerRef,
innerRef,
// @ts-expect-error
propertySignals.handlers,
propertySignals.hoverProps,
propertySignals.activeProps,
),
[parent, propertySignals],
)
Expand Down
4 changes: 4 additions & 0 deletions packages/react/src/custom.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ export const CustomContainer: (props: CustomContainerProperties & RefAttributes<
propertySignals.default,
outerRef,
innerRef,
// @ts-expect-error
propertySignals.handlers,
propertySignals.hoverProps,
propertySignals.activeProps,
),
[parent, propertySignals],
)
Expand Down
74 changes: 60 additions & 14 deletions packages/react/src/default.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { AllOptionalProperties } from '@pmndrs/uikit'
import { ReactNode, createContext, useContext } from 'react'
import { Signal } from '@preact/signals-core'
import { ReactNode, createContext, useContext, useMemo } from 'react'

const DefaultPropertiesContext = createContext<AllOptionalProperties | undefined>(undefined)

Expand All @@ -9,19 +10,64 @@ export function useDefaultProperties(): AllOptionalProperties | undefined {

export type DefaultPropertiesProperties = { children?: ReactNode } & AllOptionalProperties

export function DefaultProperties(properties: DefaultPropertiesProperties) {
const createDefaultPropertiesHash = (properties: AllOptionalProperties | undefined) => {
if (properties === undefined) {
return ''
}
return Array.from(Object.entries(properties))
.sort(([ka], [kb]) => (ka > kb ? 1 : ka < kb ? -1 : 0))
.map(([k, v]) => {
switch (typeof v) {
case 'function':
console.warn('no function in default props please', k)
return ''
case 'object':
if (Array.isArray(v)) {
return v.join(',')
}
if (v instanceof Signal) {
return `${k}=${v.peek()}`
}
for (let nk of Object.keys(v)) {
if (typeof v[nk] === 'object') {
console.warn('no deeply nested objects in default props please', k, v)
return ''
}
if (typeof v[nk] === 'function') {
console.warn('no functions nested in objects in default props please', k, v)
return ''
}
}
return `${k}=${JSON.stringify(v)}`
default:
if (v === undefined) return ''
return `${k}=${v}`
}
})
.join('&')
}

export function DefaultProperties({ children, ...properties }: DefaultPropertiesProperties) {
const existingDefaultProperties = useContext(DefaultPropertiesContext)
const result: any = { ...existingDefaultProperties }
for (const key in properties) {
if (key === 'children') {
continue
}
//TODO: this is not correctly merged but rather overwritten
const value = properties[key as keyof AllOptionalProperties]
if (value == null) {
continue
const existingDefaultPropertiesHash = createDefaultPropertiesHash(existingDefaultProperties)
const propertiesHash = createDefaultPropertiesHash(properties)

const result: any = useMemo(() => {
const result: any = { ...existingDefaultProperties }
for (const key in properties) {
if (key === 'children') {
continue
}
//TODO: this is not correctly merged but rather overwritten
const value = properties[key as keyof AllOptionalProperties]
if (value == null) {
continue
}
result[key] = value as any
}
result[key] = value as any
}
return <DefaultPropertiesContext.Provider value={result}>{properties.children}</DefaultPropertiesContext.Provider>
return result
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [existingDefaultPropertiesHash, propertiesHash])

return <DefaultPropertiesContext.Provider value={result}>{children}</DefaultPropertiesContext.Provider>
}
4 changes: 4 additions & 0 deletions packages/react/src/icon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ export const Icon: (props: IconProperties & RefAttributes<IconRef>) => ReactNode
propertySignals.properties,
propertySignals.default,
outerRef,
// @ts-expect-error
propertySignals.handlers,
propertySignals.hoverProps,
propertySignals.activeProps,
),
[parent, properties.svgHeight, properties.svgWidth, properties.text, propertySignals],
)
Expand Down
4 changes: 4 additions & 0 deletions packages/react/src/image.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ export const Image: (props: ImageProperties & RefAttributes<ImageRef>) => ReactN
propertySignals.default,
outerRef,
innerRef,
// @ts-expect-error
propertySignals.handlers,
propertySignals.hoverProps,
propertySignals.activeProps,
),
// eslint-disable-next-line react-hooks/exhaustive-deps
[],
Expand Down
4 changes: 4 additions & 0 deletions packages/react/src/input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ export const Input: (props: InputProperties & RefAttributes<InputRef>) => ReactN
propertySignals.properties,
propertySignals.default,
outerRef,
// @ts-expect-error
propertySignals.handlers,
propertySignals.hoverProps,
propertySignals.activeProps,
),
// eslint-disable-next-line react-hooks/exhaustive-deps
[],
Expand Down
4 changes: 4 additions & 0 deletions packages/react/src/root.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ export const Root: (props: RootProperties & RefAttributes<RootRef>) => ReactNode
},
//requestFrame = invalidate, because invalidate always causes another frame
invalidate,
// @ts-expect-error
propertySignals.handlers,
propertySignals.hoverProps,
propertySignals.activeProps,
),
// eslint-disable-next-line react-hooks/exhaustive-deps
[invalidate],
Expand Down
4 changes: 4 additions & 0 deletions packages/react/src/svg.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ export const Svg: (props: SvgProperties & RefAttributes<SvgRef>) => ReactNode =
propertySignals.default,
outerRef,
innerRef,
// @ts-expect-error
propertySignals.handlers,
propertySignals.hoverProps,
propertySignals.activeProps,
),
[parent, propertySignals],
)
Expand Down
4 changes: 4 additions & 0 deletions packages/react/src/text.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ export const Text: (props: TextProperties & RefAttributes<TextRef>) => ReactNode
propertySignals.properties,
propertySignals.default,
outerRef,
// @ts-expect-error
propertySignals.handlers,
propertySignals.hoverProps,
propertySignals.activeProps,
),
[fontFamilies, parent, propertySignals, textSignal],
)
Expand Down
59 changes: 56 additions & 3 deletions packages/react/src/utils.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { Signal, effect, signal } from '@preact/signals-core'
import { Signal, batch, effect, signal } from '@preact/signals-core'
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 } from '@pmndrs/uikit/internals'
import { Sign } from 'crypto'

export type R3FEventMap = {
mouse: ThreeEvent<MouseEvent>
Expand Down Expand Up @@ -35,16 +36,68 @@ export const AddHandlers = forwardRef<
)
})

const eventHandlerKeys: Array<keyof EventHandlers> = [
'onClick',
'onContextMenu',
'onDoubleClick',
'onPointerCancel',
'onPointerDown',
'onPointerEnter',
'onPointerLeave',
'onPointerMove',
'onPointerOut',
'onPointerOver',
'onPointerUp',
'onWheel',
]

export function usePropertySignals<T>(properties: T) {
const propertySignals = useMemo(
() => ({
style: signal<T | undefined>(undefined),
properties: signal<T | undefined>(undefined as any),
default: signal<AllOptionalProperties | undefined>(undefined),
handlers: (() => {
const hashmap = {} as Record<keyof EventHandlers, Signal<EventHandlers[keyof EventHandlers]>>
for (const key of eventHandlerKeys) {
hashmap[key] = signal(undefined)
}
return hashmap
})(),
hoverProps: signal(undefined),
activeProps: signal(undefined),
}),
[],
)
propertySignals.properties.value = properties
propertySignals.default.value = useDefaultProperties()
const defaultProperties = useDefaultProperties()
batch(() => {
propertySignals.properties.value = properties
propertySignals.default.value = defaultProperties
for (const key of eventHandlerKeys) {
// @ts-expect-error
const handler = properties[key]
propertySignals.handlers[key].value = handler
}
// @ts-expect-error
propertySignals.hoverProps.value = {
// @ts-expect-error
hover: properties.hover,
// @ts-expect-error
cursor: properties.cursor,
// @ts-expect-error
onHoverChange: properties.onHoverChange,
// @ts-expect-error
classes: properties.classes,
}
// @ts-expect-error
propertySignals.activeProps.value = {
// @ts-expect-error
active: properties.active,
// @ts-expect-error
onActiveChange: properties.onActiveChange,
// @ts-expect-error
classes: properties.classes,
}
})
return propertySignals
}
14 changes: 13 additions & 1 deletion packages/uikit/src/components/container.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ export function createContainer<EM extends ThreeEventMap = ThreeEventMap>(
defaultProperties: Signal<AllOptionalProperties | undefined>,
object: Object3DRef,
childrenContainer: Object3DRef,
handlersSignal: Record<keyof EventHandlers, Signal<EventHandlers[keyof EventHandlers]>>,
hoverPropsSingnal: Signal<unknown | undefined>,
activePropsSingnal: Signal<unknown | undefined>,
) {
const node = signal<FlexNode | undefined>(undefined)
const flexState = createFlexNodeState()
Expand Down Expand Up @@ -152,7 +155,16 @@ export function createContainer<EM extends ThreeEventMap = ThreeEventMap>(
initializers,
)

const handlers = computedHandlers(style, properties, defaultProperties, hoveredSignal, activeSignal, scrollHandlers)
const handlers = computedHandlers(
style,
defaultProperties,
hoveredSignal,
activeSignal,
handlersSignal,
hoverPropsSingnal,
activePropsSingnal,
scrollHandlers,
)
const ancestorsHaveListeners = computeAncestorsHaveListeners(parentCtx, handlers)

const interactionPanel = createInteractionPanel(
Expand Down
13 changes: 12 additions & 1 deletion packages/uikit/src/components/content.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ export function createContent<EM extends ThreeEventMap = ThreeEventMap>(
defaultProperties: Signal<AllOptionalProperties | undefined>,
object: Object3DRef,
contentContainerRef: Object3DRef,
handlersSignal: Record<keyof EventHandlers, Signal<EventHandlers[keyof EventHandlers]>>,
hoverPropsSingnal: Signal<unknown | undefined>,
activePropsSingnal: Signal<unknown | undefined>,
) {
const hoveredSignal = signal<Array<number>>([])
const activeSignal = signal<Array<number>>([])
Expand Down Expand Up @@ -145,7 +148,15 @@ export function createContent<EM extends ThreeEventMap = ThreeEventMap>(

setupMatrixWorldUpdate(true, true, object, parentCtx.root, globalMatrix, initializers, false)

const handlers = computedHandlers(style, properties, defaultProperties, hoveredSignal, activeSignal)
const handlers = computedHandlers(
style,
defaultProperties,
hoveredSignal,
activeSignal,
handlersSignal,
hoverPropsSingnal,
activePropsSingnal,
)
const ancestorsHaveListeners = computeAncestorsHaveListeners(parentCtx, handlers)
setupPointerEvents(mergedProperties, ancestorsHaveListeners, parentCtx.root, object, initializers, true)

Expand Down
13 changes: 12 additions & 1 deletion packages/uikit/src/components/custom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ export function createCustomContainer<EM extends ThreeEventMap = ThreeEventMap>(
defaultProperties: Signal<AllOptionalProperties | undefined>,
object: Object3DRef,
meshRef: { current?: Mesh | null },
handlersSignal: Record<keyof EventHandlers, Signal<EventHandlers[keyof EventHandlers]>>,
hoverPropsSingnal: Signal<unknown | undefined>,
activePropsSingnal: Signal<unknown | undefined>,
) {
const hoveredSignal = signal<Array<number>>([])
const activeSignal = signal<Array<number>>([])
Expand Down Expand Up @@ -150,7 +153,15 @@ export function createCustomContainer<EM extends ThreeEventMap = ThreeEventMap>(

setupMatrixWorldUpdate(true, true, object, parentCtx.root, globalMatrix, initializers, false)

const handlers = computedHandlers(style, properties, defaultProperties, hoveredSignal, activeSignal)
const handlers = computedHandlers(
style,
defaultProperties,
hoveredSignal,
activeSignal,
handlersSignal,
hoverPropsSingnal,
activePropsSingnal,
)
const ancestorsHaveListeners = computeAncestorsHaveListeners(parentCtx, handlers)
setupPointerEvents(mergedProperties, ancestorsHaveListeners, parentCtx.root, object, initializers, true)

Expand Down
13 changes: 12 additions & 1 deletion packages/uikit/src/components/icon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ export function createIcon<EM extends ThreeEventMap = ThreeEventMap>(
properties: Signal<IconProperties<EM> | undefined>,
defaultProperties: Signal<AllOptionalProperties | undefined>,
object: Object3DRef,
handlersSignal: Record<keyof EventHandlers, Signal<EventHandlers[keyof EventHandlers]>>,
hoverPropsSingnal: Signal<unknown | undefined>,
activePropsSingnal: Signal<unknown | undefined>,
) {
const initializers: Initializers = []
const hoveredSignal = signal<Array<number>>([])
Expand Down Expand Up @@ -141,7 +144,15 @@ export function createIcon<EM extends ThreeEventMap = ThreeEventMap>(

setupMatrixWorldUpdate(true, true, object, parentCtx.root, globalMatrix, initializers, false)

const handlers = computedHandlers(style, properties, defaultProperties, hoveredSignal, activeSignal)
const handlers = computedHandlers(
style,
defaultProperties,
hoveredSignal,
activeSignal,
handlersSignal,
hoverPropsSingnal,
activePropsSingnal,
)
const ancestorsHaveListeners = computeAncestorsHaveListeners(parentCtx, handlers)
setupPointerEvents(mergedProperties, ancestorsHaveListeners, parentCtx.root, object, initializers, false)

Expand Down
Loading