Skip to content

Commit

Permalink
fix(future/Select): stop propagation on touch devices (#5113)
Browse files Browse the repository at this point in the history
  • Loading branch information
HeartSquared authored Oct 2, 2024
1 parent e155adc commit 54dd006
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 4 deletions.
5 changes: 5 additions & 0 deletions .changeset/nasty-toys-raise.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@kaizen/components": patch
---

Future Select - stop propagation when selecting an option using a touch device.
47 changes: 47 additions & 0 deletions packages/components/src/__future__/Select/_docs/Select.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React from "react"
import { Meta, StoryObj } from "@storybook/react"
import { RadioField, RadioGroup } from "~components/Radio"
import { Select } from "../Select"
import { SelectOption } from "../types"
import {
Expand All @@ -26,6 +27,10 @@ const meta = {
args: {
label: "Label",
items: singleMockItems,
onFocus: undefined,
onFocusChange: undefined,
onOpenChange: undefined,
onSelectionChange: undefined,
},
parameters: {
actions: {
Expand Down Expand Up @@ -190,3 +195,45 @@ export const PortalContainer: Story = {
},
parameters: { docs: { source: { type: "code" } } },
}

export const TouchDeviceTest: Story = {
name: "Touch Device Pointer Event (Manual Test)",
render: args => {
const [selected, setSelected] = React.useState("radio-1")
return (
<div>
<p>
On touch devices, the radios below were changing when selecting an
option sitting above it.
<br />
At this time, we could not automate this test, so this story exists
for manual testing.
</p>
<Select {...args} />
<RadioGroup labelText="Radio group">
<RadioField
labelText="Label 1"
name="radio-group"
value="radio-value-1"
onChange={() => setSelected("radio-1")}
selectedStatus={selected === "radio-1"}
/>
<RadioField
labelText="Label 2"
name="radio-group"
value="radio-value-2"
onChange={() => setSelected("radio-2")}
selectedStatus={selected === "radio-2"}
/>
<RadioField
labelText="Label 3"
name="radio-group"
value="radio-value-3"
onChange={() => setSelected("radio-3")}
selectedStatus={selected === "radio-3"}
/>
</RadioGroup>
</div>
)
},
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import React, { HTMLAttributes } from "react"
import { useFocusRing } from "@react-aria/focus"
import { useOption } from "@react-aria/listbox"
import { mergeProps } from "@react-aria/utils"
import { FocusableElement } from "@react-types/shared"
import classnames from "classnames"
import { mergeProps, useFocusRing, useOption } from "react-aria"
import { CheckIcon } from "~components/Icon"
import { OverrideClassName } from "~components/types/OverrideClassName"
import { useSelectContext } from "../../context"
Expand All @@ -26,11 +25,23 @@ export const Option = <Option extends SelectOption = SelectOption>({
ref
)

const { onPointerUp, ...restOptionProps } = optionProps

const { isFocusVisible, focusProps } = useFocusRing()

return (
<li
{...mergeProps(optionProps, focusProps, props)}
{...mergeProps(restOptionProps, focusProps, props, {
onPointerUp: (e: React.PointerEvent<FocusableElement>) => {
if (e.pointerType === "touch") {
// On touch devices, the listbox closes too quickly so below elements will trigger their pointer events.
// Slow it down a bit to prevent the appearance of propagation.
setTimeout(() => state.setSelectedKey(item.key), 250)
} else {
onPointerUp?.(e)
}
},
})}
ref={ref}
className={classnames(
styles.option,
Expand Down

0 comments on commit 54dd006

Please sign in to comment.