Skip to content

Commit

Permalink
Merge pull request #38 from borisbelmar/feature/update-handlers
Browse files Browse the repository at this point in the history
Update Handlers
  • Loading branch information
borisbelmar committed Jun 7, 2023
2 parents 970a31a + f85d428 commit 8f60f1e
Show file tree
Hide file tree
Showing 8 changed files with 193 additions and 2 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@arrow-navigation/core",
"version": "2.0.1",
"version": "2.1.0",
"description": "Zero-dependency library to navigate through UI elements using the keyboard arrow keys built with Typescript",
"main": "./lib/index.js",
"module": "./lib/index.mjs",
Expand Down
12 changes: 11 additions & 1 deletion src/arrowNavigation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ import {
registerGroupHandler,
resetGroupStateHandler,
setFocusHandler,
unregisterElementHandler
unregisterElementHandler,
updateElementHandler,
updateGroupHandler
} from './handlers'
import changeFocusEventHandler from './handlers/changeFocusEventHandler'
import createEventEmitter from './utils/createEventEmitter'
Expand Down Expand Up @@ -114,10 +116,18 @@ export function initArrowNavigation ({
state,
emit: emitter.emit
}),
updateGroup: updateGroupHandler({
state,
emit: emitter.emit
}),
registerElement: registerElementHandler({
state,
emit: emitter.emit
}),
updateElement: updateElementHandler({
state,
emit: emitter.emit
}),
unregisterElement: unregisterElementHandler({
state,
emit: emitter.emit
Expand Down
3 changes: 3 additions & 0 deletions src/handlers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,6 @@ export { default as getNextGroupHandler } from './getNextGroupHandler'
export { default as globalFocusHandler } from './globalFocusHandler'
export { default as directionPressHandler } from './directionPressHandler'
export { default as resetGroupStateHandler } from './resetGroupStateHandler'
export { default as changeFocusEventHandler } from './changeFocusEventHandler'
export { default as updateElementHandler } from './updateElementHandler'
export { default as updateGroupHandler } from './updateGroupHandler'
55 changes: 55 additions & 0 deletions src/handlers/updateElementHandler.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import getViewNavigationStateMock from '@/__mocks__/viewNavigationState.mock'
import { ArrowNavigationState } from '@/types'
import createEventEmitter, { EventEmitter } from '@/utils/createEventEmitter'
import updateElementHandler from './updateElementHandler'

describe('updateElementHandler', () => {
let state: ArrowNavigationState
let emitter: EventEmitter

beforeEach(() => {
state = getViewNavigationStateMock()
emitter = createEventEmitter()
})

it('should update the element', () => {
const updateElement = updateElementHandler({
state,
emit: emitter.emit
})

const element00 = state.elements.get('element-0-0')

expect(element00).toBeDefined()
expect(element00?.id).toBe('element-0-0')

const handlerFocus = jest.fn()

updateElement('element-0-0', { onFocus: handlerFocus })

const updatedElement00 = state.elements.get('element-0-0')

expect(updatedElement00).toBeDefined()
expect(updatedElement00?.id).toBe('element-0-0')
expect(updatedElement00?.onFocus).toBe(handlerFocus)
})

it('should not update the element if it does not exist', () => {
const updateElement = updateElementHandler({
state,
emit: emitter.emit
})

const nonExistentElement = state.elements.get('non-existent-element')

expect(nonExistentElement).toBeUndefined()

const handlerFocus = jest.fn()

updateElement('non-existent-element', { onFocus: handlerFocus })

const updatedNonExistentElement = state.elements.get('non-existent-element')

expect(updatedNonExistentElement).toBeUndefined()
})
})
33 changes: 33 additions & 0 deletions src/handlers/updateElementHandler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/* eslint-disable no-param-reassign */
import EVENTS from '@/config/events'
import type { ArrowNavigationState, FocusableElement, FocusableElementOptions } from '@/types'
import type { EventEmitter } from '@/utils/createEventEmitter'

interface UpdateElementHandlerProps {
state: ArrowNavigationState
emit: EventEmitter['emit']
}

export default function updateElementHandler ({
state,
emit
}: UpdateElementHandlerProps) {
return (
id: string,
options: FocusableElementOptions
) => {
const existentElement = state.elements.get(id)

if (!existentElement) {
return
}

const updatedFocusableElement: FocusableElement = {
...existentElement,
...options
}

state.elements.set(id, updatedFocusableElement)
emit(EVENTS.ELEMENTS_CHANGED, state.elements)
}
}
55 changes: 55 additions & 0 deletions src/handlers/updateGroupHandler.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import getViewNavigationStateMock from '@/__mocks__/viewNavigationState.mock'
import { ArrowNavigationState } from '@/types'
import createEventEmitter, { EventEmitter } from '@/utils/createEventEmitter'
import updateGroupHandler from './updateGroupHandler'

describe('updateGroupHandler', () => {
let state: ArrowNavigationState
let emitter: EventEmitter

beforeEach(() => {
state = getViewNavigationStateMock()
emitter = createEventEmitter()
})

it('should update the group', () => {
const updateGroup = updateGroupHandler({
state,
emit: emitter.emit
})

const group0 = state.groupsConfig.get('group-0')

expect(group0).toBeDefined()
expect(group0?.id).toBe('group-0')

const handlerFocus = jest.fn()

updateGroup('group-0', { onFocus: handlerFocus })

const updatedGroup0 = state.groupsConfig.get('group-0')

expect(updatedGroup0).toBeDefined()
expect(updatedGroup0?.id).toBe('group-0')
expect(updatedGroup0?.onFocus).toBe(handlerFocus)
})

it('should not update the group if it does not exist', () => {
const updateGroup = updateGroupHandler({
state,
emit: emitter.emit
})

const nonExistentGroup = state.groups.get('non-existent-group')

expect(nonExistentGroup).toBeUndefined()

const handlerFocus = jest.fn()

updateGroup('non-existent-group', { onFocus: handlerFocus })

const updatedNonExistentGroup = state.groups.get('non-existent-group')

expect(updatedNonExistentGroup).toBeUndefined()
})
})
33 changes: 33 additions & 0 deletions src/handlers/updateGroupHandler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/* eslint-disable no-param-reassign */
import EVENTS from '@/config/events'
import type { ArrowNavigationState, FocusableGroupConfig } from '@/types'
import type { EventEmitter } from '@/utils/createEventEmitter'

interface UpdateElementHandlerProps {
state: ArrowNavigationState
emit: EventEmitter['emit']
}

export default function updateElementHandler ({
state,
emit
}: UpdateElementHandlerProps) {
return (
id: string,
config: Omit<FocusableGroupConfig, 'id'>
) => {
const existentGroupConfig = state.groupsConfig.get(id)

if (!existentGroupConfig) {
return
}

const updatedFocusableGroup: FocusableGroupConfig = {
...existentGroupConfig,
...config
}

state.groupsConfig.set(id, updatedFocusableGroup)
emit(EVENTS.GROUPS_CHANGED, state.elements)
}
}
2 changes: 2 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,9 @@ export type ArrowNavigationInstance = {
setFocusElement: (id: string) => void
setInitialFocusElement: (id: string) => void
registerGroup: (id: string, options?: FocusableGroupOptions) => void
updateGroup: (id: string, options: Omit<FocusableGroupConfig, 'id'>) => void
registerElement: (id: string, groupId: string, options?: FocusableElementOptions) => void
updateElement: (id: string, options: FocusableElementOptions) => void
unregisterElement: (id: string) => void
resetGroupState: (id: string) => void
destroy: () => void
Expand Down

0 comments on commit 8f60f1e

Please sign in to comment.