Skip to content
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: 0 additions & 5 deletions .storybook-s2/docs/Migrating.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,6 @@ export function Migrating() {
<H3>ColorField</H3>
<ul className="sb-unstyled">
<li className={style({font: 'body', marginY: 8})}>Remove <Code>isQuiet</Code> (it is no longer supported in Spectrum 2)</li>
<li className={style({font: 'body', marginY: 8})}>Remove <Code>placeholder</Code> (it has been removed due to accessibility issues)</li>
<li className={style({font: 'body', marginY: 8})}>Change <Code>validationState="invalid"</Code> to <Code>isInvalid</Code></li>
<li className={style({font: 'body', marginY: 8})}>Remove <Code>validationState="valid"</Code> (it is no longer supported in Spectrum 2)</li>
</ul>
Expand All @@ -155,7 +154,6 @@ export function Migrating() {
<ul className="sb-unstyled">
<li className={style({font: 'body', marginY: 8})}>Change <Code>menuWidth</Code> value from a <Code>DimensionValue</Code> to a pixel value</li>
<li className={style({font: 'body', marginY: 8})}>Remove <Code>isQuiet</Code> (it is no longer supported in Spectrum 2)</li>
<li className={style({font: 'body', marginY: 8})}>Remove <Code>placeholder</Code> (it is no longer supported in Spectrum 2)</li>
<li className={style({font: 'body', marginY: 8})}>Change <Code>validationState="invalid"</Code> to <Code>isInvalid</Code></li>
<li className={style({font: 'body', marginY: 8})}>Remove <Code>validationState="valid"</Code> (it is no longer supported in Spectrum 2)</li>
<li className={style({font: 'body', marginY: 8})}>Update <Code>Item</Code> to be a <Code>ComboBoxItem</Code></li>
Expand Down Expand Up @@ -338,7 +336,6 @@ export function Migrating() {

<H3>SearchField</H3>
<ul className="sb-unstyled">
<li className={style({font: 'body', marginY: 8})}>Remove <Code>placeholder</Code> (it has been removed due to accessibility issues)</li>
<li className={style({font: 'body', marginY: 8})}>[PENDING] Comment out icon (it has not been implemented yet)</li>
<li className={style({font: 'body', marginY: 8})}>Remove <Code>isQuiet</Code> (it is no longer supported in Spectrum 2)</li>
<li className={style({font: 'body', marginY: 8})}>Change <Code>validationState="invalid"</Code> to <Code>isInvalid</Code></li>
Expand Down Expand Up @@ -405,7 +402,6 @@ export function Migrating() {
<ul className="sb-unstyled">
<li className={style({font: 'body', marginY: 8})}>[PENDING] Comment out <Code>icon</Code> (it has not been implemented yet)</li>
<li className={style({font: 'body', marginY: 8})}>Remove <Code>isQuiet</Code> (it is no longer supported in Spectrum 2)</li>
<li className={style({font: 'body', marginY: 8})}>Remove <Code>placeholder</Code> (it has been removed due to accessibility issues)</li>
<li className={style({font: 'body', marginY: 8})}>Change <Code>validationState="invalid"</Code> to <Code>isInvalid</Code></li>
<li className={style({font: 'body', marginY: 8})}>Remove <Code>validationState="valid"</Code> (it is no longer supported in Spectrum 2)</li>
</ul>
Expand All @@ -414,7 +410,6 @@ export function Migrating() {
<ul className="sb-unstyled">
<li className={style({font: 'body', marginY: 8})}>[PENDING] Comment out <Code>icon</Code> (it has not been implemented yet)</li>
<li className={style({font: 'body', marginY: 8})}>Remove <Code>isQuiet</Code> (it is no longer supported in Spectrum 2)</li>
<li className={style({font: 'body', marginY: 8})}>Remove <Code>placeholder</Code> (it has been removed due to accessibility issues)</li>
<li className={style({font: 'body', marginY: 8})}>Change <Code>validationState="invalid"</Code> to <Code>isInvalid</Code></li>
<li className={style({font: 'body', marginY: 8})}>Remove <Code>validationState="valid"</Code> (it is no longer supported in Spectrum 2)</li>
</ul>
Expand Down
24 changes: 18 additions & 6 deletions packages/@react-aria/autocomplete/src/useAutocomplete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@
import {AriaLabelingProps, BaseEvent, DOMProps, FocusableElement, FocusEvents, KeyboardEvents, Node, RefObject, ValueBase} from '@react-types/shared';
import {AriaTextFieldProps} from '@react-aria/textfield';
import {AutocompleteProps, AutocompleteState} from '@react-stately/autocomplete';
import {CLEAR_FOCUS_EVENT, FOCUS_EVENT, getActiveElement, getOwnerDocument, isAndroid, isCtrlKeyPressed, isIOS, mergeProps, mergeRefs, useEffectEvent, useEvent, useLabels, useObjectRef, useSlotId} from '@react-aria/utils';
import {CLEAR_FOCUS_EVENT, FOCUS_EVENT, getActiveElement, getOwnerDocument, isAndroid, isCtrlKeyPressed, isIOS, mergeProps, mergeRefs, useEffectEvent, useEvent, useId, useLabels, useObjectRef} from '@react-aria/utils';
import {dispatchVirtualBlur, dispatchVirtualFocus, getVirtuallyFocusedElement, moveVirtualFocus} from '@react-aria/focus';
import {getInteractionModality} from '@react-aria/interactions';
// @ts-ignore
import intlMessages from '../intl/*.json';
import {FocusEvent as ReactFocusEvent, KeyboardEvent as ReactKeyboardEvent, useCallback, useEffect, useMemo, useRef} from 'react';
import {FocusEvent as ReactFocusEvent, KeyboardEvent as ReactKeyboardEvent, useCallback, useEffect, useMemo, useRef, useState} from 'react';
import {useLocalizedStringFormatter} from '@react-aria/i18n';

export interface CollectionOptions extends DOMProps, AriaLabelingProps {
Expand Down Expand Up @@ -88,7 +88,7 @@ export function useAutocomplete<T>(props: AriaAutocompleteOptions<T>, state: Aut
disableVirtualFocus = false
} = props;

let collectionId = useSlotId();
let collectionId = useId();
let timeout = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);
let delayNextActiveDescendant = useRef(false);
let queuedActiveDescendant = useRef<string | null>(null);
Expand All @@ -97,7 +97,11 @@ export function useAutocomplete<T>(props: AriaAutocompleteOptions<T>, state: Aut
// For mobile screen readers, we don't want virtual focus, instead opting to disable FocusScope's restoreFocus and manually
// moving focus back to the subtriggers
let isMobileScreenReader = getInteractionModality() === 'virtual' && (isIOS() || isAndroid());
let shouldUseVirtualFocus = !isMobileScreenReader && !disableVirtualFocus;
let [shouldUseVirtualFocus, setShouldUseVirtualFocus] = useState(!isMobileScreenReader && !disableVirtualFocus);
// Tracks if a collection has been connected to the autocomplete. If false, we don't want to add various attributes to the autocomplete input
// since it isn't attached to a filterable collection (e.g. Tabs)
let [hasCollection, setHasCollection] = useState(false);

useEffect(() => {
return () => clearTimeout(timeout.current);
}, []);
Expand Down Expand Up @@ -145,8 +149,16 @@ export function useAutocomplete<T>(props: AriaAutocompleteOptions<T>, state: Aut
lastCollectionNode.current?.removeEventListener('focusin', updateActiveDescendant);
lastCollectionNode.current = collectionNode;
collectionNode.addEventListener('focusin', updateActiveDescendant);
// If useSelectableCollection isn't passed shouldUseVirtualFocus even when useAutocomplete provides it
// that means the collection doesn't support it (e.g. Table). If that is the case, we need to disable it here regardless
// of what the user's provided so that the input doesn't recieve the onKeyDown and autocomplete props.
if (collectionNode.getAttribute('tabindex') != null) {
setShouldUseVirtualFocus(false);
}
setHasCollection(true);
} else {
lastCollectionNode.current?.removeEventListener('focusin', updateActiveDescendant);
setHasCollection(false);
}
}, [updateActiveDescendant]);

Expand Down Expand Up @@ -393,7 +405,7 @@ export function useAutocomplete<T>(props: AriaAutocompleteOptions<T>, state: Aut
onFocus
};

if (collectionId) {
if (hasCollection) {
inputProps = {
...inputProps,
...(shouldUseVirtualFocus && virtualFocusProps),
Expand All @@ -413,7 +425,7 @@ export function useAutocomplete<T>(props: AriaAutocompleteOptions<T>, state: Aut
inputProps,
collectionProps: mergeProps(collectionProps, {
shouldUseVirtualFocus,
disallowTypeAhead: true
disallowTypeAhead: shouldUseVirtualFocus
}),
collectionRef: mergedCollectionRef,
filter: filter != null ? filterFn : undefined
Expand Down
25 changes: 12 additions & 13 deletions packages/@react-aria/virtualizer/src/ScrollView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -86,15 +86,6 @@ export function useScrollView(props: ScrollViewProps, ref: RefObject<HTMLElement

let [isScrolling, setScrolling] = useState(false);

let onScrollTimeout = useCallback(() => {
state.isScrolling = false;
setScrolling(false);
state.scrollTimeout = null;

window.dispatchEvent(new Event('tk.connect-observer'));
onScrollEnd?.();
}, [state, onScrollEnd]);

let onScroll = useCallback((e) => {
if (e.target !== e.currentTarget) {
return;
Expand Down Expand Up @@ -128,21 +119,29 @@ export function useScrollView(props: ScrollViewProps, ref: RefObject<HTMLElement
// keep track of the current timeout time and only reschedule
// the timer when it is getting close.
let now = Date.now();
if (!('onscrollend' in window) && state.scrollEndTime <= now + 50) {
if (state.scrollEndTime <= now + 50) {
state.scrollEndTime = now + 300;

if (state.scrollTimeout != null) {
clearTimeout(state.scrollTimeout);
}

state.scrollTimeout = setTimeout(onScrollTimeout, 300);
state.scrollTimeout = setTimeout(() => {
state.isScrolling = false;
setScrolling(false);
state.scrollTimeout = null;

window.dispatchEvent(new Event('tk.connect-observer'));
if (onScrollEnd) {
onScrollEnd();
}
}, 300);
}
});
}, [props, direction, state, contentSize, onVisibleRectChange, onScrollStart, onScrollTimeout]);
}, [props, direction, state, contentSize, onVisibleRectChange, onScrollStart, onScrollEnd]);

// Attach event directly to ref so RAC Virtualizer doesn't need to send props upward.
useEvent(ref, 'scroll', onScroll);
useEvent(ref, 'scrollend', onScrollTimeout);

useEffect(() => {
return () => {
Expand Down
6 changes: 3 additions & 3 deletions packages/@react-spectrum/s2/chromatic/Accordion.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export const Example: Story = {
People
</DisclosureTitle>
<DisclosurePanel>
<TextField label="Name" styles={style({maxWidth: 176})} />
<TextField label="Name" styles={style({maxWidth: 176})} placeholder="Enter your name" />
</DisclosurePanel>
</Disclosure>
</Accordion>
Expand Down Expand Up @@ -107,7 +107,7 @@ export const WithDisabledDisclosure: Story = {
People
</DisclosureTitle>
<DisclosurePanel>
<TextField label="Name" />
<TextField label="Name" placeholder="Enter your name" />
</DisclosurePanel>
</Disclosure>
</Accordion>
Expand Down Expand Up @@ -152,7 +152,7 @@ export const WithActionButton: Story = {
<ActionButton><NewIcon aria-label="new icon" /></ActionButton>
</DisclosureHeader>
<DisclosurePanel>
<TextField label="Name" styles={style({maxWidth: 176})} />
<TextField label="Name" styles={style({maxWidth: 176})} placeholder="Enter your name" />
</DisclosurePanel>
</Disclosure>
</Accordion>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ const Template = ({combos, ...args}: ColorFieldProps & {combos: any[]}): ReactEl
key = 'default';
}
return (
<ColorField data-testid={fullComboName} defaultValue="#e21" label={key} description="test description" errorMessage="test error" {...c} {...args} />
<ColorField data-testid={fullComboName} defaultValue="#e21" label={key} description="test description" errorMessage="test error" placeholder="######" {...c} {...args} />
);
})}
</div>
Expand Down
22 changes: 11 additions & 11 deletions packages/@react-spectrum/s2/chromatic/Forms.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,9 @@ type Story = StoryObj<typeof Form>;
export const Example: Story = {
render: (args) => (
<Form {...args}>
<TextField label="First Name" name="firstName" />
<TextField label="Last Name" name="firstName" />
<TextField label="Email" name="email" type="email" description="Enter an email" />
<TextField label="First Name" name="firstName" placeholder="John" />
<TextField label="Last Name" name="lastName" placeholder="Doe" />
<TextField label="Email" name="email" type="email" description="Enter an email" placeholder="abc@123.com" />
<CheckboxGroup label="Favorite sports">
<Checkbox value="soccer">Soccer</Checkbox>
<Checkbox value="baseball">Baseball</Checkbox>
Expand All @@ -75,10 +75,10 @@ export const Example: Story = {
<Radio value="dog">Dog</Radio>
<Radio value="plant" isDisabled>Plant</Radio>
</RadioGroup>
<TextField label="City" name="city" description="A long description to test help text wrapping." />
<TextField label="A long label to test wrapping behavior" name="long" />
<TextField label="City" name="city" description="A long description to test help text wrapping." placeholder="Some city" />
<TextField label="A long label to test wrapping behavior" name="long" placeholder="looooooooooong" />
<SearchField label="Search" name="search" />
<TextArea label="Comment" name="comment" />
<TextArea label="Comment" name="comment" placeholder="Enter your comment here" />
<Switch>Wi-Fi</Switch>
<Checkbox>I agree to the terms</Checkbox>
<Slider label="Cookies" defaultValue={30} />
Expand All @@ -91,9 +91,9 @@ export const Example: Story = {
export const MixedForm: Story = {
render: (args) => (
<Form {...args}>
<TextField label="First Name" name="firstName" />
<TextField label="Last Name" name="firstName" />
<TextField label="Email" name="email" type="email" description="Enter an email" />
<TextField label="First Name" name="firstName" placeholder="John" />
<TextField label="Last Name" name="lastName" placeholder="Doe" />
<TextField label="Email" name="email" type="email" description="Enter an email" placeholder="abc@123.com" />
<CheckboxGroup aria-label="Favorite sports">
<Checkbox value="soccer">Soccer</Checkbox>
<Checkbox value="baseball">Baseball</Checkbox>
Expand Down Expand Up @@ -143,7 +143,7 @@ const CustomLabelsExampleRender = (args: FormProps): ReactElement => {
<ToggleButton>
Enable color
</ToggleButton>
<ColorField aria-label="Fill color" styles={style({width: 144})} />
<ColorField aria-label="Fill color" styles={style({width: 144})} placeholder="######" />
<ColorSlider channel="alpha" defaultValue="#000" />
</div>
<Divider size="S" />
Expand All @@ -152,7 +152,7 @@ const CustomLabelsExampleRender = (args: FormProps): ReactElement => {
<ToggleButton>
Enable search
</ToggleButton>
<TextField aria-label="Query" styles={style({width: 144})} />
<TextField aria-label="Query" styles={style({width: 144})} placeholder="Search here" />
<ComboBox aria-label="Search terms" styles={style({width: 144})}>
<ComboBoxItem>search term 1</ComboBoxItem>
<ComboBoxItem>search term 2</ComboBoxItem>
Expand Down
16 changes: 11 additions & 5 deletions packages/@react-spectrum/s2/chromatic/TextField.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ type Story = StoryObj<typeof TextField>;
export const Example: Story = {
render: (args) => <TextField {...args} />,
args: {
label: 'Name'
label: 'Name',
placeholder: 'Enter your name'
}
};

Expand All @@ -57,6 +58,7 @@ export const ContextualHelpExample: Story = {
),
args: {
label: 'Segment',
placeholder: 'Enter your name',
contextualHelp: (
<ContextualHelp>
<Heading>What is a segment?</Heading>
Expand All @@ -80,14 +82,16 @@ export const ContextualHelpExample: Story = {
export const TextAreaExample: StoryObj<typeof TextArea> = {
render: (args) => <TextArea {...args} />,
args: {
label: 'Comment'
label: 'Comment',
placeholder: 'Enter your name'
}
};

export const CustomWidth: Story = {
render: (args) => <TextField {...args} styles={style({width: 384})} />,
args: {
label: 'Name'
label: 'Name',
placeholder: 'Enter your name'
},
parameters: {
docs: {
Expand All @@ -99,7 +103,8 @@ export const CustomWidth: Story = {
export const SmallWidth: Story = {
render: (args) => <TextField {...args} styles={style({width: 48})} />,
args: {
label: 'Name'
label: 'Name',
placeholder: 'Enter your name'
},
parameters: {
docs: {
Expand All @@ -111,7 +116,8 @@ export const SmallWidth: Story = {
export const UNSAFEWidth: Story = {
render: (args) => <TextField {...args} UNSAFE_style={{width: 384}} />,
args: {
label: 'Name'
label: 'Name',
placeholder: 'Enter your name'
},
parameters: {
docs: {
Expand Down
5 changes: 3 additions & 2 deletions packages/@react-spectrum/s2/src/ColorField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
import {
ColorField as AriaColorField,
ColorFieldProps as AriaColorFieldProps,
ContextValue
ContextValue,
InputProps
} from 'react-aria-components';
import {createContext, forwardRef, Ref, useContext, useImperativeHandle, useRef} from 'react';
import {createFocusableRef} from '@react-spectrum/utils';
Expand All @@ -25,7 +26,7 @@ import {style} from '../style' with {type: 'macro'};
import {TextFieldRef} from '@react-types/textfield';
import {useSpectrumContextProps} from './useSpectrumContextProps';

export interface ColorFieldProps extends Omit<AriaColorFieldProps, 'children' | 'className' | 'style' | keyof GlobalDOMAttributes>, StyleProps, SpectrumLabelableProps, HelpTextProps {
export interface ColorFieldProps extends Omit<AriaColorFieldProps, 'children' | 'className' | 'style' | keyof GlobalDOMAttributes>, StyleProps, SpectrumLabelableProps, HelpTextProps, Pick<InputProps, 'placeholder'> {
/**
* The size of the color field.
*
Expand Down
Loading
Loading