Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use @pmndrs/uikit/internals for creating components #9

Merged
merged 7 commits into from
Jun 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/three-nails-mix.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'threlte-uikit': minor
---

Use @pmndrs/uikit/internals for creating components
632 changes: 449 additions & 183 deletions package-lock.json

Large diffs are not rendered by default.

31 changes: 16 additions & 15 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,31 +37,32 @@
},
"devDependencies": {
"@changesets/cli": "^2.27.5",
"@preact/signals-core": "^1.6.0",
"@sveltejs/adapter-auto": "^3.2.1",
"@sveltejs/kit": "^2.5.10",
"@sveltejs/package": "^2.3.1",
"@preact/signals-core": "^1.6.1",
"@sveltejs/adapter-auto": "^3.2.2",
"@sveltejs/kit": "^2.5.17",
"@sveltejs/package": "^2.3.2",
"@sveltejs/vite-plugin-svelte": "^3.1.1",
"@threlte/core": "^7.3.0",
"@threlte/extras": "^8.11.2",
"@threlte/test": "^0.2.3",
"@threlte/extras": "^8.11.3",
"@threlte/test": "^0.2.4",
"@types/eslint": "^8.56.10",
"@types/three": "^0.165.0",
"eslint": "^9.4.0",
"eslint": "^9.5.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-svelte": "^2.39.2",
"globals": "^15.4.0",
"prettier": "^3.3.1",
"prettier-plugin-svelte": "^3.2.4",
"eslint-plugin-svelte": "^2.40.0",
"globals": "^15.6.0",
"prettier": "^3.3.2",
"prettier-plugin-svelte": "^3.2.5",
"publint": "^0.2.8",
"svelte": "^4.2.18",
"svelte-check": "^3.8.0",
"svelte-check": "^3.8.1",
"three": "^0.165.0",
"three-inspect": "^0.7.0",
"tslib": "^2.6.3",
"type-fest": "^4.20.0",
"typescript": "^5.4.5",
"type-fest": "^4.20.1",
"typescript": "^5.5.2",
"typescript-eslint": "^8.0.0-alpha.20",
"vite": "^5.2.13",
"vite": "^5.3.1",
"vitest": "^1.6.0",
"vitest-canvas-mock": "^0.3.3"
}
Expand Down
72 changes: 72 additions & 0 deletions src/lib/components/AddHandlers.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<script lang="ts">
import type { Object3D } from 'three'
import { T } from '@threlte/core'
import type { Signal } from '@preact/signals-core'
import { type EventHandlers, addHandler } from '@pmndrs/uikit/internals'

export let ref: Object3D
export let userHandlers: EventHandlers
export let handlers: Signal<EventHandlers> | undefined = undefined

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

const createHandlers = (userFns: EventHandlers, fns?: EventHandlers) => {
const result: EventHandlers = { ...fns }
const keysLength = eventHandlerKeys.length

for (let i = 0; i < keysLength; i += 1) {
const key = eventHandlerKeys[i]
addHandler(key, result, userFns[key])
}

if (Object.keys(result).length === 0) {
return undefined
}

return result
}

$: allHandlers = createHandlers(userHandlers, $handlers)
</script>

{#if allHandlers === undefined}
<T
is={ref}
matrixAutoUpdate={false}
>
<slot />
</T>
{:else}
<T
is={ref}
matrixAutoUpdate={false}
on:click={allHandlers.onClick}
on:contextmenu={allHandlers.onContextMenu}
on:dblclick={allHandlers.onDoubleClick}
on:pointerdown={allHandlers.onPointerDown}
on:pointerenter={allHandlers.onPointerEnter}
on:pointerleave={allHandlers.onPointerLeave}
on:pointermissed={allHandlers.onPointerMissed}
on:pointermove={allHandlers.onPointerMove}
on:pointerout={allHandlers.onPointerOut}
on:pointerover={allHandlers.onPointerOver}
on:pointerup={allHandlers.onPointerUp}
on:wheel={allHandlers.onWheel}
>
<slot />
</T>
{/if}
86 changes: 47 additions & 39 deletions src/lib/components/Container.svelte
Original file line number Diff line number Diff line change
@@ -1,50 +1,58 @@
<script lang="ts">
import { Container } from '@pmndrs/uikit'
import Base from './Shared/Base.svelte'
import type { EventHandlers, InheritableContainerProperties } from '@pmndrs/uikit/internals'
import { useDefaultProperties } from '$lib/useDefaultProperties'
import { eventPropNames } from './Shared/events'
import type { Writable } from 'type-fest'
import { Group } from 'three'
import { T, currentWritable } from '@threlte/core'
import {
type ContainerProperties,
createContainer,
type EventHandlers,
} from '@pmndrs/uikit/internals'
import { createParent, useParent } from '$lib/useParent'
import { usePropertySignals } from '$lib/usePropSignals'
import { useInternals, type ContainerRef } from '$lib/useInternals'
import AddHandlers from './AddHandlers.svelte'

type Properties = Writable<InheritableContainerProperties>
type $$Props = {
type $$Props = ContainerProperties & {
ref?: ContainerRef
name?: string
ref?: Container
} & Properties &
EventHandlers
} & EventHandlers

export let name: string | undefined = undefined
export let active: Properties['active'] = undefined
export let hover: Properties['hover'] = undefined
export let name: $$Props['name'] = undefined

const defaultProps = useDefaultProperties()
const events: EventHandlers = {}
const parent = useParent()
const outerRef = currentWritable(new Group())
const innerRef = currentWritable(new Group())
const propertySignals = usePropertySignals($$restProps)
$: propertySignals.properties.value = $$restProps

let props: Properties = {}
const internals = createContainer(
parent,
propertySignals.style,
propertySignals.properties,
propertySignals.default,
outerRef,
innerRef
)
$: internals.interactionPanel.name = name ?? ''

$: {
props = {}
for (const key of Object.keys($$restProps)) {
if (eventPropNames.includes(key as keyof EventHandlers)) {
events[key as keyof EventHandlers] = $$restProps[key]
} else {
props[key as keyof Properties] = $$restProps[key]
}
}
if (active) props.active = active
if (hover) props.hover = hover
}
export const ref = useInternals<ContainerProperties>(
internals,
propertySignals.style,
parent.root.pixelSize
)

export const ref = new Container(undefined, defaultProps)
$: ref.setProperties(props)
$: if (name) ref.name = name
createParent(internals)
</script>

<Base
is={ref}
{events}
active={active !== undefined}
hover={hover !== undefined}
<AddHandlers
userHandlers={$$restProps}
handlers={internals.handlers}
ref={$outerRef}
>
<slot />
</Base>
<T is={internals.interactionPanel} />
<T
matrixAutoUpdate={false}
is={$innerRef}
>
<slot />
</T>
</AddHandlers>
86 changes: 47 additions & 39 deletions src/lib/components/Content.svelte
Original file line number Diff line number Diff line change
@@ -1,50 +1,58 @@
<script lang="ts">
import { Content } from '@pmndrs/uikit'
import Base from './Shared/Base.svelte'
import type { EventHandlers, InheritableContentProperties } from '@pmndrs/uikit/internals'
import { useDefaultProperties } from '$lib/useDefaultProperties'
import { eventPropNames } from './Shared/events'
import type { Writable } from 'type-fest'
import { Object3D } from 'three'
import { T, currentWritable } from '@threlte/core'
import {
type ContentProperties,
type EventHandlers,
createContent,
} from '@pmndrs/uikit/internals'
import { createParent, useParent } from '$lib/useParent'
import { usePropertySignals } from '$lib/usePropSignals'
import { useInternals, type ContentRef } from '$lib/useInternals'
import AddHandlers from './AddHandlers.svelte'

type Properties = Writable<InheritableContentProperties>
type $$Props = {
type $$Props = ContentProperties & {
ref?: ContentRef
name?: string
ref?: Content
} & Properties &
EventHandlers
} & EventHandlers

export let name: string | undefined = undefined
export let active: Properties['active'] = undefined
export let hover: Properties['hover'] = undefined
export let name: $$Props['name'] = undefined

const defaultProps = useDefaultProperties()
const events: EventHandlers = {}
const parent = useParent()
const outerRef = currentWritable(new Object3D())
const innerRef = currentWritable(new Object3D())
const propertySignals = usePropertySignals($$restProps)
$: propertySignals.properties.value = $$restProps

let props: Properties = {}
const internals = createContent(
parent,
propertySignals.style,
propertySignals.properties,
propertySignals.default,
outerRef,
innerRef
)
$: internals.interactionPanel.name = name ?? ''

$: {
props = {}
for (const key of Object.keys($$restProps)) {
if (eventPropNames.includes(key as keyof EventHandlers)) {
events[key as keyof EventHandlers] = $$restProps[key]
} else {
props[key as keyof Properties] = $$restProps[key]
}
}
if (active) props.active = active
if (hover) props.hover = hover
}
export const ref = useInternals<ContentProperties>(
internals,
propertySignals.style,
parent.root.pixelSize
)

export const ref = new Content(undefined, defaultProps)
$: ref.setProperties(props)
$: if (name) ref.name = name
createParent(undefined!)
</script>

<Base
is={ref}
{events}
active={active !== undefined}
hover={hover !== undefined}
<AddHandlers
userHandlers={$$restProps}
handlers={internals.handlers}
ref={$outerRef}
>
<slot />
</Base>
<T is={internals.interactionPanel} />
<T
is={$innerRef}
matrixAutoUpdate={false}
>
<slot />
</T>
</AddHandlers>
Loading