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

feat: add enter/leave helpers and UI map #1040

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
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
2 changes: 1 addition & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"--async-stack-traces"
],
"args": [
"${fileBasename}",
"${file}",
"--verbose",
"--no-cache",
"-i"
Expand Down
81 changes: 78 additions & 3 deletions packages/@dcl/ecs/src/systems/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,20 @@ export interface PointerEventsSystem {
*/
removeOnPointerUp(entity: Entity): void

/**
* @public
* Remove the callback for onPointerHoverEnter event
* @param entity - Entity where the callback was attached
*/
removeOnPointerHoverEnter(entity: Entity): void

/**
* @public
* Remove the callback for onPointerHoverLeave event
* @param entity - Entity where the callback was attached
*/
removeOnPointerHoverLeave(entity: Entity): void

/**
* @internal
* Execute callback when the user clicks the entity.
Expand Down Expand Up @@ -88,6 +102,28 @@ export interface PointerEventsSystem {
* @param opts - Opts to trigger Feedback and Button
*/
onPointerUp(entity: Entity, cb: EventSystemCallback, opts?: Partial<EventSystemOptions>): void

/**
* @public
* Execute callback when the user place the pointer over the entity
* @param pointerData - Entity to attach the callback - Opts to trigger Feedback and Button
* @param cb - Function to execute when click fires
*/
onPointerHoverEnter(
pointerData: { entity: Entity; opts?: Partial<EventSystemOptions> },
cb: EventSystemCallback
): void

/**
* @public
* Execute callback when the user take the pointer out of the entity
* @param pointerData - Entity to attach the callback - Opts to trigger Feedback and Button
* @param cb - Function to execute when click fires
*/
onPointerHoverLeave(
pointerData: { entity: Entity; opts?: Partial<EventSystemOptions> },
cb: EventSystemCallback
): void
}

/**
Expand All @@ -100,7 +136,9 @@ export function createPointerEventsSystem(engine: IEngine, inputSystem: IInputSy
enum EventType {
Click,
Down,
Up
Up,
HoverEnter,
HoverLeave
}
type EventMapType = Map<EventType, { cb: EventSystemCallback; opts: EventSystemOptions }>

Expand Down Expand Up @@ -135,6 +173,10 @@ export function createPointerEventsSystem(engine: IEngine, inputSystem: IInputSy
function getPointerEvent(eventType: EventType) {
if (eventType === EventType.Up) {
return PointerEventType.PET_UP
} else if (eventType === EventType.HoverLeave) {
return PointerEventType.PET_HOVER_LEAVE
} else if (eventType === EventType.HoverEnter) {
return PointerEventType.PET_HOVER_ENTER
}
return PointerEventType.PET_DOWN
}
Expand Down Expand Up @@ -164,7 +206,12 @@ export function createPointerEventsSystem(engine: IEngine, inputSystem: IInputSy
checkNotThenable(cb(command.up), 'Click event returned a thenable. Only synchronous functions are allowed')
}

if (eventType === EventType.Down || eventType === EventType.Up) {
if (
eventType === EventType.Down ||
eventType === EventType.Up ||
eventType === EventType.HoverEnter ||
eventType === EventType.HoverLeave
) {
const command = inputSystem.getInputCommand(opts.button, getPointerEvent(eventType), entity)
if (command) {
checkNotThenable(cb(command), 'Event handler returned a thenable. Only synchronous functions are allowed')
Expand Down Expand Up @@ -198,6 +245,24 @@ export function createPointerEventsSystem(engine: IEngine, inputSystem: IInputSy
setPointerEvent(entity, PointerEventType.PET_UP, options)
}

const onPointerHoverEnter: PointerEventsSystem['onPointerHoverEnter'] = (...args) => {
const [data, cb] = args
const { entity, opts } = data
const options = getDefaultOpts(opts)
removeEvent(entity, EventType.HoverEnter)
getEvent(entity).set(EventType.HoverEnter, { cb, opts: options })
setPointerEvent(entity, PointerEventType.PET_HOVER_ENTER, options)
}

const onPointerHoverLeave: PointerEventsSystem['onPointerHoverLeave'] = (...args) => {
const [data, cb] = args
const { entity, opts } = data
const options = getDefaultOpts(opts)
removeEvent(entity, EventType.HoverLeave)
getEvent(entity).set(EventType.HoverLeave, { cb, opts: options })
setPointerEvent(entity, PointerEventType.PET_HOVER_LEAVE, options)
}

return {
removeOnClick(entity: Entity) {
removeEvent(entity, EventType.Click)
Expand All @@ -211,6 +276,14 @@ export function createPointerEventsSystem(engine: IEngine, inputSystem: IInputSy
removeEvent(entity, EventType.Up)
},

removeOnPointerHoverEnter(entity: Entity) {
removeEvent(entity, EventType.HoverEnter)
},

removeOnPointerHoverLeave(entity: Entity) {
removeEvent(entity, EventType.HoverLeave)
},

onClick(value, cb) {
const { entity } = value
const options = getDefaultOpts(value.opts)
Expand All @@ -223,6 +296,8 @@ export function createPointerEventsSystem(engine: IEngine, inputSystem: IInputSy
},

onPointerDown,
onPointerUp
onPointerUp,
onPointerHoverEnter,
onPointerHoverLeave
}
}
14 changes: 14 additions & 0 deletions packages/@dcl/playground-assets/etc/playground-assets.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -1082,6 +1082,8 @@ export type EntityComponents = {
uiDropdown: PBUiDropdown;
onMouseDown: Callback;
onMouseUp: Callback;
onMouseEnter: Callback;
onMouseLeave: Callback;
};

// @public (undocumented)
Expand Down Expand Up @@ -1558,6 +1560,8 @@ export interface LastWriteWinElementSetComponentDefinition<T> extends BaseCompon
export type Listeners = {
onMouseDown?: Callback;
onMouseUp?: Callback;
onMouseEnter?: Callback;
onMouseLeave?: Callback;
};

// @public (undocumented)
Expand Down Expand Up @@ -3313,13 +3317,23 @@ export interface PointerEventsSystem {
}, cb: EventSystemCallback): void;
// @deprecated (undocumented)
onPointerDown(entity: Entity, cb: EventSystemCallback, opts?: Partial<EventSystemOptions>): void;
onPointerHoverEnter(pointerData: {
entity: Entity;
opts?: Partial<EventSystemOptions>;
}, cb: EventSystemCallback): void;
onPointerHoverLeave(pointerData: {
entity: Entity;
opts?: Partial<EventSystemOptions>;
}, cb: EventSystemCallback): void;
onPointerUp(pointerData: {
entity: Entity;
opts?: Partial<EventSystemOptions>;
}, cb: EventSystemCallback): void;
// @deprecated (undocumented)
onPointerUp(entity: Entity, cb: EventSystemCallback, opts?: Partial<EventSystemOptions>): void;
removeOnPointerDown(entity: Entity): void;
removeOnPointerHoverEnter(entity: Entity): void;
removeOnPointerHoverLeave(entity: Entity): void;
removeOnPointerUp(entity: Entity): void;
}

Expand Down
4 changes: 3 additions & 1 deletion packages/@dcl/react-ecs/src/components/Button/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ function getButtonProps(props: UiButtonProps) {
*/
/* @__PURE__ */
export function Button(props: UiButtonProps) {
const { uiTransform, uiBackground, onMouseDown, onMouseUp, ...otherProps } = props
const { uiTransform, uiBackground, onMouseDown, onMouseUp, onMouseEnter, onMouseLeave, ...otherProps } = props
const buttonProps = getButtonProps(props)
const uiBackgroundProps = parseUiBackground({
...buttonProps.uiBackground,
Expand Down Expand Up @@ -64,6 +64,8 @@ export function Button(props: UiButtonProps) {
<entity
onMouseDown={!!props.disabled ? undefined : onMouseDown}
onMouseUp={!!props.disabled ? undefined : onMouseUp}
onMouseEnter={!!props.disabled ? undefined : onMouseEnter}
onMouseLeave={!!props.disabled ? undefined : onMouseLeave}
uiTransform={uiTransformProps}
uiText={textProps}
uiBackground={uiBackgroundProps}
Expand Down
6 changes: 4 additions & 2 deletions packages/@dcl/react-ecs/src/components/Dropdown/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,15 @@ function parseUiDropdown(props: UiDropdownProps): PBUiDropdown {
*/
/* @__PURE__ */
export function Dropdown(props: UiDropdownProps) {
const { uiTransform, uiBackground, onMouseDown, onMouseUp, ...otherProps } = props
const { uiTransform, uiBackground, onMouseDown, onMouseUp, onMouseEnter, onMouseLeave, ...otherProps } = props
const dropdownProps = parseUiDropdown(otherProps)
const commonProps = parseProps({
uiTransform,
uiBackground,
onMouseDown,
onMouseUp
onMouseUp,
onMouseEnter,
onMouseLeave
})
return <entity {...commonProps} uiDropdown={dropdownProps} />
}
6 changes: 4 additions & 2 deletions packages/@dcl/react-ecs/src/components/Input/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,15 @@ function parseUiInput(props: Partial<UiInputProps>): PBUiInput {
* @category Component
*/ /* @__PURE__ */
export function Input(props: EntityPropTypes & Partial<UiInputProps>) {
const { uiTransform, uiBackground, onMouseDown, onMouseUp, ...otherProps } = props
const { uiTransform, uiBackground, onMouseDown, onMouseUp, onMouseEnter, onMouseLeave, ...otherProps } = props
const inputProps = parseUiInput(otherProps)
const commonProps = parseProps({
uiTransform,
uiBackground,
onMouseDown,
onMouseUp
onMouseUp,
onMouseEnter,
onMouseLeave
})
return <entity {...commonProps} uiInput={inputProps} />
}
6 changes: 4 additions & 2 deletions packages/@dcl/react-ecs/src/components/Label/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,15 @@ export { scaleFontSize } from './utils'

/* @__PURE__ */
export function Label(props: EntityPropTypes & UiLabelProps) {
const { uiTransform, uiBackground, onMouseDown, onMouseUp, ...uiTextProps } = props
const { uiTransform, uiBackground, onMouseDown, onMouseUp, onMouseEnter, onMouseLeave, ...uiTextProps } = props

const commonProps = parseProps({
uiTransform,
uiBackground,
onMouseDown,
onMouseUp
onMouseUp,
onMouseEnter,
onMouseLeave
})
const { font, textAlign, fontSize, textWrap, ...textProps } = uiTextProps
const uiText: PBUiText = {
Expand Down
8 changes: 7 additions & 1 deletion packages/@dcl/react-ecs/src/components/listeners/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,17 @@ export type Listeners = {
onMouseDown?: Callback
/** triggered on mouse up event */
onMouseUp?: Callback
/** triggered on mouse hover event */
onMouseEnter?: Callback
/** triggered on mouse leave event */
onMouseLeave?: Callback
}

const listeners: Listeners = {
onMouseDown: undefined,
onMouseUp: undefined
onMouseUp: undefined,
onMouseEnter: undefined,
onMouseLeave: undefined
}
const listenersKey = Object.keys(listeners)

Expand Down
2 changes: 2 additions & 0 deletions packages/@dcl/react-ecs/src/react-ecs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ export type EntityComponents = {
uiDropdown: PBUiDropdown
onMouseDown: Callback
onMouseUp: Callback
onMouseEnter: Callback
onMouseLeave: Callback
}

/**
Expand Down
44 changes: 35 additions & 9 deletions packages/@dcl/react-ecs/src/reconciler/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@ import { componentKeys, isNotUndefined, noopConfig, propsChanged } from './utils
function getPointerEnum(pointerKey: keyof Listeners): PointerEventType {
const pointers: { [key in keyof Required<Listeners>]: PointerEventType } = {
onMouseDown: PointerEventType.PET_DOWN,
onMouseUp: PointerEventType.PET_UP
onMouseUp: PointerEventType.PET_UP,
onMouseEnter: PointerEventType.PET_HOVER_ENTER,
onMouseLeave: PointerEventType.PET_HOVER_LEAVE
}
return pointers[pointerKey]
}
Expand Down Expand Up @@ -80,13 +82,20 @@ export function createReconciler(
upsertComponent(instance, props as { rightOf: number; parent: number }, 'uiTransform')
}

function upsertListener(instance: Instance, update: Changes<keyof Pick<Listeners, 'onMouseDown' | 'onMouseUp'>>) {
function upsertListener(
instance: Instance,
update: Changes<keyof Pick<Listeners, 'onMouseDown' | 'onMouseUp' | 'onMouseEnter' | 'onMouseLeave'>>
) {
if (update.type === 'delete' || !update.props) {
clickEvents.get(instance.entity)?.delete(getPointerEnum(update.component))
if (update.component === 'onMouseDown') {
pointerEvents.removeOnPointerDown(instance.entity)
} else if (update.component === 'onMouseUp') {
pointerEvents.removeOnPointerUp(instance.entity)
} else if (update.component === 'onMouseEnter') {
pointerEvents.removeOnPointerHoverEnter(instance.entity)
} else if (update.component === 'onMouseLeave') {
pointerEvents.removeOnPointerHoverLeave(instance.entity)
}
return
}
Expand All @@ -101,13 +110,30 @@ export function createReconciler(
if (alreadyHasPointerEvent) return

const pointerEventSystem =
update.component === 'onMouseDown' ? pointerEvents.onPointerDown : pointerEvents.onPointerUp
pointerEventSystem(instance.entity, () => pointerEventCallback(instance.entity, pointerEvent), {
button: InputAction.IA_POINTER,
// We add this showFeedBack so the pointerEventSystem creates a PointerEvent component with our entity
// This is needed for the renderer to know which entities are clickeables
showFeedback: true
})
update.component === 'onMouseDown'
? pointerEvents.onPointerDown
: update.component === 'onMouseUp'
? pointerEvents.onPointerUp
: update.component === 'onMouseEnter'
? pointerEvents.onPointerHoverEnter
: update.component === 'onMouseLeave'
? pointerEvents.onPointerHoverLeave
: undefined

if (pointerEventSystem !== undefined) {
pointerEventSystem(
{
entity: instance.entity,
opts: {
button: InputAction.IA_POINTER,
// We add this showFeedBack so the pointerEventSystem creates a PointerEvent component with our entity
// This is needed for the renderer to know which entities are clickeables
showFeedback: true
}
},
() => pointerEventCallback(instance.entity, pointerEvent)
)
}
}
}

Expand Down
2 changes: 2 additions & 0 deletions packages/@dcl/react-ecs/src/reconciler/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ const entityComponent: EntityComponents = {
uiTransform: undefined as any,
onMouseDown: undefined as any,
onMouseUp: undefined as any,
onMouseEnter: undefined as any,
onMouseLeave: undefined as any,
uiInput: undefined as any,
uiDropdown: undefined as any
}
Expand Down
Loading
Loading