Skip to content
This repository was archived by the owner on Mar 4, 2020. It is now read-only.
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm

### Fixes
- Fix `Menu` and `Submenu` to use correct indicator icon and have correct width behavior [redlines] @bcalvery ([#1831](https://github.com/stardust-ui/react/pull/1831))
- Fix order of applying unhandled props and key handlers @jurokapsiar ([#1901](https://github.com/stardust-ui/react/pull/1901))
- Fix handling of `onMouseEnter` prop in `ChatMessage` @layershifter ([#1903](https://github.com/stardust-ui/react/pull/1903))
- Fix `CreateShorthandOptions` should be typed @lucivpav ([#1886](https://github.com/stardust-ui/react/pull/1886))

Expand Down
2 changes: 1 addition & 1 deletion packages/react/src/components/Button/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -142,9 +142,9 @@ class Button extends UIComponent<WithAsProp<ButtonProps>> {
onClick={this.handleClick}
onFocus={this.handleFocus}
{...accessibility.attributes.root}
{...applyAccessibilityKeyHandlers(accessibility.keyHandlers.root, unhandledProps)}
{...rtlTextContainer.getAttributes({ forElements: [children] })}
{...unhandledProps}
{...applyAccessibilityKeyHandlers(accessibility.keyHandlers.root, unhandledProps)}
>
{hasChildren && children}
{!hasChildren && loading && this.renderLoader(variables, styles)}
Expand Down
2 changes: 1 addition & 1 deletion packages/react/src/components/Embed/Embed.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -131,8 +131,8 @@ class Embed extends AutoControlledComponent<WithAsProp<EmbedProps>, EmbedState>
className={classes.root}
onClick={this.handleClick}
{...accessibility.attributes.root}
{...applyAccessibilityKeyHandlers(accessibility.keyHandlers.root, unhandledProps)}
{...unhandledProps}
{...applyAccessibilityKeyHandlers(accessibility.keyHandlers.root, unhandledProps)}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is correct applyAccessibilityKeyHandlers should always be spread after the unhandledProps, as it will invoke the key events provided by the behavior.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, there's now even a test verifying that for all compoennts (that have the actions defined)

>
{active ? (
<>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -198,8 +198,8 @@ class HierarchicalTreeItem extends UIComponent<WithAsProp<HierarchicalTreeItemPr
className={classes.root}
{...accessibility.attributes.root}
{...rtlTextContainer.getAttributes({ forElements: [children] })}
{...applyAccessibilityKeyHandlers(accessibility.keyHandlers.root, unhandledProps)}
{...unhandledProps}
{...applyAccessibilityKeyHandlers(accessibility.keyHandlers.root, unhandledProps)}
>
{childrenExist(children) ? children : this.renderContent()}
</ElementType>
Expand Down
7 changes: 1 addition & 6 deletions packages/react/src/components/Slider/Slider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -179,12 +179,7 @@ class Slider extends AutoControlledComponent<WithAsProp<SliderProps>, SliderStat

// we need 2 wrappers around the slider rail, track, input and thumb slots to achieve correct component sizes
return (
<ElementType
className={classes.root}
{...accessibility.attributes.root}
{...restProps}
{...applyAccessibilityKeyHandlers(accessibility.keyHandlers.root, unhandledProps)}
>
<ElementType className={classes.root} {...accessibility.attributes.root} {...restProps}>
<div className={cx(Slider.slotClassNames.inputWrapper, classes.inputWrapper)}>
<span className={cx(Slider.slotClassNames.rail, classes.rail)} />
<span
Expand Down
2 changes: 1 addition & 1 deletion packages/react/src/components/Tree/TreeItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -213,8 +213,8 @@ class TreeItem extends UIComponent<WithAsProp<TreeItemProps>, TreeItemState> {
className={classes.root}
{...accessibility.attributes.root}
{...rtlTextContainer.getAttributes({ forElements: [children] })}
{...applyAccessibilityKeyHandlers(accessibility.keyHandlers.root, unhandledProps)}
{...unhandledProps}
{...applyAccessibilityKeyHandlers(accessibility.keyHandlers.root, unhandledProps)}
>
{childrenExist(children) ? children : this.renderContent()}
</ElementType>
Expand Down
28 changes: 28 additions & 0 deletions packages/react/test/specs/commonTests/eventTarget.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { ReactWrapper } from 'enzyme'

export const EVENT_TARGET_ATTRIBUTE = 'data-simulate-event-here'

export const getEventTargetComponent = (
wrapper: ReactWrapper,
listenerName: string,
eventTargets?: object = {},
) => {
const eventTarget = eventTargets[listenerName]
? wrapper
.find(eventTargets[listenerName])
.hostNodes()
.first()
: wrapper
.find(`[${EVENT_TARGET_ATTRIBUTE}]`)
.hostNodes()
.first()

// if (eventTarget.length === 0) {
// throw new Error(
// 'The event prop was not delegated to the children. You probably ' +
// 'forgot to use `getUnhandledProps` util to spread the `unhandledProps` props.',
// )
// }

return eventTarget
}
45 changes: 44 additions & 1 deletion packages/react/test/specs/commonTests/handlesAccessibility.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import * as React from 'react'
import * as keyboardKey from 'keyboard-key'

import { mountWithProviderAndGetComponent } from 'test/utils'
import { mountWithProviderAndGetComponent, mountWithProvider } from 'test/utils'
import { Accessibility, AriaRole, FocusZoneMode } from 'src/lib/accessibility/types'
import { FocusZone } from 'src/lib/accessibility/FocusZone'
import { FOCUSZONE_WRAP_ATTRIBUTE } from 'src/lib/accessibility/FocusZone/focusUtilities'
import { UIComponent } from 'src/lib'
import { EVENT_TARGET_ATTRIBUTE, getEventTargetComponent } from './eventTarget'

export const getRenderedAttribute = (renderedComponent, propName, partSelector) => {
const target = partSelector
Expand Down Expand Up @@ -106,6 +109,46 @@ export default (
const role = getRenderedAttribute(rendered, 'role', partSelector)
expect(role).toBe(testRole)
})

test(`handles "onKeyDown" overrides`, () => {
const actionHandler = jest.fn()
const eventHandler = jest.fn()

const actionBehavior: Accessibility = () => ({
keyActions: {
root: {
mockAction: {
keyCombinations: [{ keyCode: keyboardKey.Enter }],
},
},
},
})

const wrapperProps = {
...requiredProps,
accessibility: actionBehavior,
[EVENT_TARGET_ATTRIBUTE]: true,
onKeyDown: eventHandler,
}

const wrapper = mountWithProvider(<Component {...wrapperProps} />)
const component = wrapper.find(Component)
const instance = component.instance() as UIComponent<any, any>
if (instance.actionHandlers) {
instance.actionHandlers.mockAction = actionHandler
}
// Force render component to apply updated key handlers
wrapper.setProps({})

getEventTargetComponent(component, 'onKeyDown').simulate('keydown', {
keyCode: keyboardKey.Enter,
})

if (instance.actionHandlers) {
expect(actionHandler).toBeCalledTimes(1)
}
expect(eventHandler).toBeCalledTimes(1)
})
}

if (focusZoneDefinition) {
Expand Down
30 changes: 5 additions & 25 deletions packages/react/test/specs/commonTests/isConformant.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import * as stardust from 'src/index'
import { Accessibility, AriaRole } from 'src/lib/accessibility/types'
import { FocusZone, IS_FOCUSABLE_ATTRIBUTE } from 'src/lib/accessibility/FocusZone'
import { FOCUSZONE_WRAP_ATTRIBUTE } from 'src/lib/accessibility/FocusZone/focusUtilities'
import { getEventTargetComponent, EVENT_TARGET_ATTRIBUTE } from './eventTarget'

export interface Conformant {
eventTargets?: object
Expand Down Expand Up @@ -85,27 +86,6 @@ export default (Component, options: Conformant = {}) => {
return wrapperComponent ? toNextNonTrivialChild(componentElement) : componentElement
}

const getEventTargetComponent = (wrapper: ReactWrapper, listenerName: string) => {
const eventTarget = eventTargets[listenerName]
? wrapper
.find(eventTargets[listenerName])
.hostNodes()
.first()
: wrapper
.find('[data-simulate-event-here]')
.hostNodes()
.first()

// if (eventTarget.length === 0) {
// throw new Error(
// 'The event prop was not delegated to the children. You probably ' +
// 'forgot to use `getUnhandledProps` util to spread the `unhandledProps` props.',
// )
// }

return eventTarget
}

// make sure components are properly exported
if (componentType !== 'function') {
throwError(`Components should export a class or function, got: ${componentType}.`)
Expand Down Expand Up @@ -365,12 +345,12 @@ export default (Component, options: Conformant = {}) => {

const wrapperProps = {
...requiredProps,
'data-simulate-event-here': true,
[EVENT_TARGET_ATTRIBUTE]: true,
[listenerName]: handler,
}
const wrapper = mount(<Component {...wrapperProps} />)

getEventTargetComponent(wrapper, listenerName).simulate(eventName)
getEventTargetComponent(wrapper, listenerName, eventTargets).simulate(eventName)
expect(handler).toBeCalledTimes(1)
})
})
Expand Down Expand Up @@ -398,11 +378,11 @@ export default (Component, options: Conformant = {}) => {
const props = {
...requiredProps,
[listenerName]: handlerSpy,
'data-simulate-event-here': true,
[EVENT_TARGET_ATTRIBUTE]: true,
}

const component = mount(<Component {...props} />)
const eventTarget = getEventTargetComponent(component, listenerName)
const eventTarget = getEventTargetComponent(component, listenerName, eventTargets)
const customHandler: Function = eventTarget.prop(listenerName)

if (customHandler) {
Expand Down
6 changes: 5 additions & 1 deletion packages/react/test/specs/components/Embed/Embed-test.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import * as React from 'react'
import Embed from 'src/components/Embed/Embed'
import { isConformant } from 'test/specs/commonTests'
import { isConformant, handlesAccessibility } from 'test/specs/commonTests'
import { mountWithProviderAndGetComponent } from 'test/utils'

describe('Embed', () => {
isConformant(Embed)

describe('accessibility', () => {
handlesAccessibility(Embed, { defaultRootRole: 'presentation' })
})

describe('onClick', () => {
test('is called with (e, props) on a click', () => {
const onClick = jest.fn()
Expand Down