diff --git a/packages/@react-aria/autocomplete/src/useAutocomplete.ts b/packages/@react-aria/autocomplete/src/useAutocomplete.ts index b9c1e6420ee..3abaafd6413 100644 --- a/packages/@react-aria/autocomplete/src/useAutocomplete.ts +++ b/packages/@react-aria/autocomplete/src/useAutocomplete.ts @@ -92,6 +92,7 @@ export function useAutocomplete(props: AriaAutocompleteOptions, state: Aut let timeout = useRef | undefined>(undefined); let delayNextActiveDescendant = useRef(false); let queuedActiveDescendant = useRef(null); + let lastPointerType = useRef(null); // 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 @@ -105,9 +106,23 @@ export function useAutocomplete(props: AriaAutocompleteOptions, state: Aut return () => clearTimeout(timeout.current); }, []); + useEffect(() => { + let handlePointerDown = (e: PointerEvent) => { + lastPointerType.current = e.pointerType; + }; + + if (typeof PointerEvent !== 'undefined') { + document.addEventListener('pointerdown', handlePointerDown, true); + return () => { + document.removeEventListener('pointerdown', handlePointerDown, true); + }; + } + }, []); + let updateActiveDescendantEvent = useEffectEvent((e: Event) => { // Ensure input is focused if the user clicks on the collection directly. - if (!e.isTrusted && shouldUseVirtualFocus && inputRef.current && getActiveElement(getOwnerDocument(inputRef.current)) !== inputRef.current) { + // don't trigger on touch so that mobile keyboard doesnt appear when tapping on options + if (!e.isTrusted && shouldUseVirtualFocus && inputRef.current && getActiveElement(getOwnerDocument(inputRef.current)) !== inputRef.current && lastPointerType.current !== 'touch') { inputRef.current.focus(); } diff --git a/packages/@react-aria/interactions/src/useFocusVisible.ts b/packages/@react-aria/interactions/src/useFocusVisible.ts index 1ffd18463cb..45a93b86deb 100644 --- a/packages/@react-aria/interactions/src/useFocusVisible.ts +++ b/packages/@react-aria/interactions/src/useFocusVisible.ts @@ -15,7 +15,7 @@ // NOTICE file in the root directory of this source tree. // See https://github.com/facebook/react/tree/cc7c1aece46a6b69b41958d731e0fd27c94bfc6c/packages/react-interactions -import {getOwnerDocument, getOwnerWindow, isMac, isVirtualClick} from '@react-aria/utils'; +import {getOwnerDocument, getOwnerWindow, isMac, isVirtualClick, openLink} from '@react-aria/utils'; import {ignoreFocusEvent} from './utils'; import {useEffect, useState} from 'react'; import {useIsSSR} from '@react-aria/ssr'; @@ -68,7 +68,7 @@ function isValidKey(e: KeyboardEvent) { function handleKeyboardEvent(e: KeyboardEvent) { hasEventBeforeFocus = true; - if (isValidKey(e)) { + if (!(openLink as any).isOpening && isValidKey(e)) { currentModality = 'keyboard'; triggerChangeHandlers('keyboard', e); } @@ -83,7 +83,7 @@ function handlePointerEvent(e: PointerEvent | MouseEvent) { } function handleClickEvent(e: MouseEvent) { - if (isVirtualClick(e)) { + if (!(openLink as any).isOpening && isVirtualClick(e)) { hasEventBeforeFocus = true; currentModality = 'virtual'; } diff --git a/packages/@react-aria/utils/src/openLink.tsx b/packages/@react-aria/utils/src/openLink.tsx index e3c4823f998..25836692576 100644 --- a/packages/@react-aria/utils/src/openLink.tsx +++ b/packages/@react-aria/utils/src/openLink.tsx @@ -106,7 +106,7 @@ export function openLink(target: HTMLAnchorElement, modifiers: Modifiers, setOpe let event = isWebKit() && isMac() && !isIPad() && process.env.NODE_ENV !== 'test' // @ts-ignore - keyIdentifier is a non-standard property, but it's what webkit expects ? new KeyboardEvent('keydown', {keyIdentifier: 'Enter', metaKey, ctrlKey, altKey, shiftKey}) - : new MouseEvent('click', {metaKey, ctrlKey, altKey, shiftKey, bubbles: true, cancelable: true}); + : new MouseEvent('click', {metaKey, ctrlKey, altKey, shiftKey, detail: 1, bubbles: true, cancelable: true}); (openLink as any).isOpening = setOpening; focusWithoutScrolling(target); target.dispatchEvent(event); diff --git a/packages/@react-spectrum/s2/chromatic/TreeView.stories.tsx b/packages/@react-spectrum/s2/chromatic/TreeView.stories.tsx index d297c5e911c..7e4aaed9e7a 100644 --- a/packages/@react-spectrum/s2/chromatic/TreeView.stories.tsx +++ b/packages/@react-spectrum/s2/chromatic/TreeView.stories.tsx @@ -152,43 +152,6 @@ export const TreeSelection: StoryObj = { } }; -export const TreeIsDetached: StoryObj = { - ...TreeStatic, - args: { - isDetached: true, - selectionMode: 'multiple', - defaultSelectedKeys: ['projects-2', 'projects-3'] - } -}; - -export const TreeIsEmphasized: StoryObj = { - ...TreeStatic, - args: { - isEmphasized: true, - selectionMode: 'multiple', - defaultSelectedKeys: ['projects-2', 'projects-3'] - } -}; - -export const TreeIsDetachedIsEmphasized: StoryObj = { - ...TreeStatic, - args: { - isDetached: true, - isEmphasized: true, - selectionMode: 'multiple', - defaultSelectedKeys: ['projects-2', 'projects-3'] - } -}; - -export const TreeIsDetachedMobile: StoryObj = { - ...TreeStatic, - args: { - isDetached: true, - selectionMode: 'multiple', - defaultSelectedKeys: ['projects-2', 'projects-3'] - } -}; - interface TreeViewItemType { id: string, name: string, diff --git a/packages/@react-spectrum/s2/src/Calendar.tsx b/packages/@react-spectrum/s2/src/Calendar.tsx index b9bfa24cecc..a83692a8004 100644 --- a/packages/@react-spectrum/s2/src/Calendar.tsx +++ b/packages/@react-spectrum/s2/src/Calendar.tsx @@ -141,7 +141,8 @@ const cellStyles = style({ isOutsideMonth: 'none' }, alignItems: 'center', - justifyContent: 'center' + justifyContent: 'center', + disableTapHighlight: true }); const cellInnerStyles = style({ diff --git a/packages/@react-spectrum/s2/src/CloseButton.tsx b/packages/@react-spectrum/s2/src/CloseButton.tsx index ec981959ef2..abd796e779e 100644 --- a/packages/@react-spectrum/s2/src/CloseButton.tsx +++ b/packages/@react-spectrum/s2/src/CloseButton.tsx @@ -76,7 +76,8 @@ const styles = style, FocusableRefValue>>(null); diff --git a/packages/@react-spectrum/s2/src/ColorSwatchPicker.tsx b/packages/@react-spectrum/s2/src/ColorSwatchPicker.tsx index 9028a4f65e4..c0f095e8545 100644 --- a/packages/@react-spectrum/s2/src/ColorSwatchPicker.tsx +++ b/packages/@react-spectrum/s2/src/ColorSwatchPicker.tsx @@ -90,7 +90,8 @@ function useWrapper(swatch: ReactElement, color: Color, rounding: ColorSwatchPro default: 'sm', full: 'full' } - } + }, + disableTapHighlight: true })({...renderProps, rounding})}> {({isSelected}) => (<> {swatch} diff --git a/packages/@react-spectrum/s2/src/ComboBox.tsx b/packages/@react-spectrum/s2/src/ComboBox.tsx index 18a4c541182..9f5ea1cfb9d 100644 --- a/packages/@react-spectrum/s2/src/ComboBox.tsx +++ b/packages/@react-spectrum/s2/src/ComboBox.tsx @@ -601,7 +601,6 @@ const ComboboxInner = forwardRef(function ComboboxInner(props: ComboBoxProps ({ isFocusVisible: 'blue-800' }, borderRadius: 'lg', - padding: 24 + padding: 24, + boxSizing: 'border-box' }, getAllowedOverrides({height: true})); const banner = style({ diff --git a/packages/@react-spectrum/s2/src/Field.tsx b/packages/@react-spectrum/s2/src/Field.tsx index 40a753d605c..ad806490465 100644 --- a/packages/@react-spectrum/s2/src/Field.tsx +++ b/packages/@react-spectrum/s2/src/Field.tsx @@ -112,7 +112,8 @@ export const FieldLabel = forwardRef(function FieldLabel(props: FieldLabelProps, value: 'currentColor' } })} - aria-label={includeNecessityIndicatorInAccessibilityName ? stringFormatter.format('label.(required)') : undefined} /> + aria-label={includeNecessityIndicatorInAccessibilityName ? stringFormatter.format('label.(required)') : undefined} + aria-hidden={!includeNecessityIndicatorInAccessibilityName} /> } {necessityIndicator === 'label' && /* The necessity label is hidden to screen readers if the field is required because diff --git a/packages/@react-spectrum/s2/src/SelectBoxGroup.tsx b/packages/@react-spectrum/s2/src/SelectBoxGroup.tsx index 685d8f07061..4944a228f1f 100644 --- a/packages/@react-spectrum/s2/src/SelectBoxGroup.tsx +++ b/packages/@react-spectrum/s2/src/SelectBoxGroup.tsx @@ -368,7 +368,7 @@ export function SelectBox(props: SelectBoxProps): ReactNode { ); } -/* +/** * SelectBoxGroup allows users to select one or more options from a list. */ export const SelectBoxGroup = /*#__PURE__*/ forwardRef(function SelectBoxGroup(props: SelectBoxGroupProps, ref: DOMRef) { diff --git a/packages/@react-spectrum/s2/src/TableView.tsx b/packages/@react-spectrum/s2/src/TableView.tsx index b7af9870fc1..4d4e9fd494e 100644 --- a/packages/@react-spectrum/s2/src/TableView.tsx +++ b/packages/@react-spectrum/s2/src/TableView.tsx @@ -908,7 +908,7 @@ export const TableHeader = /*#__PURE__*/ (forwardRef as forwardRefType)(function } {selectionMode === 'multiple' && - + } )} @@ -1362,8 +1362,8 @@ function EditableCellInner(props: EditableCellProps & {isFocusVisible: boolean, }; // Use color-mix instead of transparency so sticky cells work correctly. -const selectedBackground = lightDark(colorMix('gray-25', 'informative-900', 10), colorMix('gray-25', 'informative-700', 10)); -const selectedActiveBackground = lightDark(colorMix('gray-25', 'informative-900', 15), colorMix('gray-25', 'informative-700', 15)); +const selectedBackground = colorMix('gray-25', 'gray-900', 7); +const selectedActiveBackground = colorMix('gray-25', 'gray-900', 10); const rowBackgroundColor = { default: { default: 'gray-25', @@ -1462,7 +1462,7 @@ export const Row = /*#__PURE__*/ (forwardRef as forwardRefType)(function Row - + )} diff --git a/packages/@react-spectrum/s2/src/TreeView.tsx b/packages/@react-spectrum/s2/src/TreeView.tsx index 5d1f0c26e5d..b2801ba08c1 100644 --- a/packages/@react-spectrum/s2/src/TreeView.tsx +++ b/packages/@react-spectrum/s2/src/TreeView.tsx @@ -31,7 +31,7 @@ import { import {centerBaseline} from './CenterBaseline'; import {Checkbox} from './Checkbox'; import Chevron from '../ui-icons/Chevron'; -import {colorMix, focusRing, fontRelative, lightDark, style} from '../style' with {type: 'macro'}; +import {colorMix, focusRing, fontRelative, style} from '../style' with {type: 'macro'}; import {DOMRef, forwardRefType, GlobalDOMAttributes, Key, LoadingState} from '@react-types/shared'; import {getAllowedOverrides, StylesPropWithHeight, UnsafeStyles} from './style-utils' with {type: 'macro'}; import {IconContext} from './Icon'; @@ -39,21 +39,15 @@ import {IconContext} from './Icon'; import intlMessages from '../intl/*.json'; import {ProgressCircle} from './ProgressCircle'; import {raw} from '../style/style-macro' with {type: 'macro'}; -import React, {createContext, forwardRef, JSXElementConstructor, ReactElement, ReactNode, useContext, useRef} from 'react'; +import React, {createContext, forwardRef, JSXElementConstructor, ReactElement, ReactNode, useRef} from 'react'; import {Text, TextContext} from './Content'; import {useDOMRef} from '@react-spectrum/utils'; import {useLocale, useLocalizedStringFormatter} from 'react-aria'; import {useScale} from './utils'; interface S2TreeProps { - // Only detatched is supported right now with the current styles from Spectrum - // See https://github.com/adobe/react-spectrum/pull/7343 for what remaining combinations are left - /** Whether the tree should be displayed with a [detached style](https://spectrum.adobe.com/page/tree-view/#Detached). */ - isDetached?: boolean, /** Handler that is called when a user performs an action on a row. */ - onAction?: (key: Key) => void, - /** Whether the tree should be displayed with a [emphasized style](https://spectrum.adobe.com/page/tree-view/#Emphasis). */ - isEmphasized?: boolean + onAction?: (key: Key) => void } export interface TreeViewProps extends Omit, 'style' | 'className' | 'onRowAction' | 'selectionBehavior' | 'onScroll' | 'onCellAction' | 'dragAndDropHooks' | keyof GlobalDOMAttributes>, UnsafeStyles, S2TreeProps { @@ -77,8 +71,6 @@ interface TreeRendererContextValue { const TreeRendererContext = createContext({}); -let InternalTreeContext = createContext<{isDetached?: boolean, isEmphasized?: boolean}>({}); - // TODO: the below is needed so the borders of the top and bottom row isn't cut off if the TreeView is wrapped within a container by always reserving the 2px needed for the // keyboard focus ring. Perhaps find a different way of rendering the outlines since the top of the item doesn't // scroll into view due to how the ring is offset. Alternatively, have the tree render the top/bottom outline like it does in Listview @@ -108,7 +100,7 @@ const tree = style({ * A tree view provides users with a way to navigate nested hierarchical information. */ export const TreeView = /*#__PURE__*/ (forwardRef as forwardRefType)(function TreeView(props: TreeViewProps, ref: DOMRef) { - let {children, isDetached, isEmphasized, UNSAFE_className, UNSAFE_style} = props; + let {children, UNSAFE_className, UNSAFE_style} = props; let scale = useScale(); let renderer; @@ -122,28 +114,22 @@ export const TreeView = /*#__PURE__*/ (forwardRef as forwardRefType)(function Tr - - (UNSAFE_className ?? '') + tree({isDetached, ...renderProps}, props.styles)} - selectionBehavior="toggle" - ref={domRef}> - {props.children} - - + (UNSAFE_className ?? '') + tree({...renderProps}, props.styles)} + selectionBehavior="toggle" + ref={domRef}> + {props.children} + ); }); -const selectedBackground = lightDark(colorMix('gray-25', 'informative-900', 10), colorMix('gray-25', 'informative-700', 10)); -const selectedActiveBackground = lightDark(colorMix('gray-25', 'informative-900', 15), colorMix('gray-25', 'informative-700', 15)); - const rowBackgroundColor = { default: '--s2-container-bg', isFocusVisibleWithin: colorMix('gray-25', 'gray-900', 7), @@ -151,19 +137,9 @@ const rowBackgroundColor = { isPressed: colorMix('gray-25', 'gray-900', 10), isSelected: { default: colorMix('gray-25', 'gray-900', 7), - isEmphasized: selectedBackground, - isFocusVisibleWithin: { - default: colorMix('gray-25', 'gray-900', 10), - isEmphasized: selectedActiveBackground - }, - isHovered: { - default: colorMix('gray-25', 'gray-900', 10), - isEmphasized: selectedActiveBackground - }, - isPressed: { - default: colorMix('gray-25', 'gray-900', 10), - isEmphasized: selectedActiveBackground - } + isFocusVisibleWithin: colorMix('gray-25', 'gray-900', 10), + isHovered: colorMix('gray-25', 'gray-900', 10), + isPressed: colorMix('gray-25', 'gray-900', 10) }, forcedColors: { default: 'Background' @@ -230,21 +206,6 @@ const treeCellGrid = style({ default: 'focus-ring', forcedColors: 'Highlight' } - }, - borderColor: { - isDetached: { - default: 'transparent', - isSelected: '--rowSelectedBorderColor' - } - }, - borderWidth: { - isDetached: 1 - }, - borderRadius: { - isDetached: 'default' - }, - borderStyle: { - isDetached: 'solid' } }); @@ -282,17 +243,6 @@ const treeActionMenu = style({ gridArea: 'actionmenu' }); -const cellFocus = { - outlineStyle: { - default: 'none', - isFocusVisible: 'solid' - }, - outlineOffset: -2, - outlineWidth: 2, - outlineColor: 'focus-ring', - borderRadius: '[6px]' -} as const; - const treeRowFocusIndicator = raw(` &:before { content: ""; @@ -312,15 +262,14 @@ export const TreeViewItem = (props: TreeViewItemProps): ReactNode => { let { href } = props; - let {isDetached, isEmphasized} = useContext(InternalTreeContext); return ( treeRow({ ...renderProps, - isLink: !!href, isEmphasized - }) + (renderProps.isFocusVisible && !isDetached ? ' ' + treeRowFocusIndicator : '')} /> + isLink: !!href + }) + (renderProps.isFocusVisible ? ' ' + treeRowFocusIndicator : '')} /> ); }; @@ -333,12 +282,11 @@ export const TreeViewItemContent = (props: TreeViewItemContentProps): ReactNode let { children } = props; - let {isDetached, isEmphasized} = useContext(InternalTreeContext); let scale = useScale(); return ( - {({isExpanded, hasChildItems, selectionMode, selectionBehavior, isDisabled, isFocusVisible, isSelected, id, state}) => { + {({isExpanded, hasChildItems, selectionMode, selectionBehavior, isDisabled, isSelected, id, state}) => { let isNextSelected = false; let isNextFocused = false; let keyAfter = state.collection.getKeyAfter(id); @@ -347,13 +295,11 @@ export const TreeViewItemContent = (props: TreeViewItemContentProps): ReactNode } let isFirst = state.collection.getFirstKey() === id; return ( -
+
{selectionMode !== 'none' && selectionBehavior === 'toggle' && ( // TODO: add transition?
- +
)}
{typeof children === 'string' ? {children} : children} - {isFocusVisible && isDetached &&
}
); }} diff --git a/packages/dev/s2-docs/pages/react-aria/Checkbox.mdx b/packages/dev/s2-docs/pages/react-aria/Checkbox.mdx index 65c9f9d3404..108df8d31ad 100644 --- a/packages/dev/s2-docs/pages/react-aria/Checkbox.mdx +++ b/packages/dev/s2-docs/pages/react-aria/Checkbox.mdx @@ -66,7 +66,7 @@ function Example(props) { ## Forms -Use the `name` and `value` props to submit the checkbox to the server. Set the `isRequired` prop to validate the user selects the checkbox, or implement custom client or server-side validation. See the Forms guide to learn more. +Use the `name` and `value` props to submit the checkbox to the server. Set the `isRequired` prop to validate the user selects the checkbox, or implement custom client or server-side validation. See the [Forms](forms) guide to learn more. ```tsx render "use client"; diff --git a/packages/dev/s2-docs/pages/react-aria/CheckboxGroup.mdx b/packages/dev/s2-docs/pages/react-aria/CheckboxGroup.mdx index dac36265096..962d178a8ab 100644 --- a/packages/dev/s2-docs/pages/react-aria/CheckboxGroup.mdx +++ b/packages/dev/s2-docs/pages/react-aria/CheckboxGroup.mdx @@ -76,7 +76,7 @@ function Example() { ## Forms -Use the `name` prop to submit the selected checkboxes to the server. Set the `isRequired` prop on the `` to validate the user selects at least one checkbox, or on individual checkboxes. See the Forms guide to learn more. +Use the `name` prop to submit the selected checkboxes to the server. Set the `isRequired` prop on the `` to validate the user selects at least one checkbox, or on individual checkboxes. See the [Forms](forms) guide to learn more. ```tsx render "use client"; diff --git a/packages/dev/s2-docs/pages/react-aria/ColorField.mdx b/packages/dev/s2-docs/pages/react-aria/ColorField.mdx index 36a76d68ef9..6cb641bfe07 100644 --- a/packages/dev/s2-docs/pages/react-aria/ColorField.mdx +++ b/packages/dev/s2-docs/pages/react-aria/ColorField.mdx @@ -105,7 +105,7 @@ function Example() { ## Forms -Use the `name` prop to submit the text value to the server. Set the `isRequired` prop to validate the value, or implement custom client or server-side validation. See the Forms guide to learn more. +Use the `name` prop to submit the text value to the server. Set the `isRequired` prop to validate the value, or implement custom client or server-side validation. See the [Forms](forms) guide to learn more. ```tsx render "use client"; diff --git a/packages/dev/s2-docs/pages/react-aria/ComboBox.mdx b/packages/dev/s2-docs/pages/react-aria/ComboBox.mdx index 50b51c801d2..3d6723170d2 100644 --- a/packages/dev/s2-docs/pages/react-aria/ComboBox.mdx +++ b/packages/dev/s2-docs/pages/react-aria/ComboBox.mdx @@ -287,7 +287,7 @@ function Example() { ## Forms -Use the `name` prop to submit the `id` of the selected item to the server. Set the `isRequired` prop to validate that the user selects a value, or implement custom client or server-side validation. See the Forms guide to learn more. +Use the `name` prop to submit the `id` of the selected item to the server. Set the `isRequired` prop to validate that the user selects a value, or implement custom client or server-side validation. See the [Forms](forms) guide to learn more. ```tsx render "use client"; diff --git a/packages/dev/s2-docs/pages/react-aria/DateField.mdx b/packages/dev/s2-docs/pages/react-aria/DateField.mdx index d7b06f3ec13..ee0623e14c0 100644 --- a/packages/dev/s2-docs/pages/react-aria/DateField.mdx +++ b/packages/dev/s2-docs/pages/react-aria/DateField.mdx @@ -94,7 +94,7 @@ import {DateField} from 'vanilla-starter/DateField'; ## Forms -Use the `name` prop to submit the selected date to the server as an [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) string. Set the `isRequired`, `minValue`, or `maxValue` props to validate the value, or implement custom client or server-side validation. See the Forms guide to learn more. +Use the `name` prop to submit the selected date to the server as an [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) string. Set the `isRequired`, `minValue`, or `maxValue` props to validate the value, or implement custom client or server-side validation. See the [Forms](forms) guide to learn more. ```tsx render "use client"; diff --git a/packages/dev/s2-docs/pages/react-aria/DatePicker.mdx b/packages/dev/s2-docs/pages/react-aria/DatePicker.mdx index 5ad97caa44b..a7882d113f8 100644 --- a/packages/dev/s2-docs/pages/react-aria/DatePicker.mdx +++ b/packages/dev/s2-docs/pages/react-aria/DatePicker.mdx @@ -94,7 +94,7 @@ import {DatePicker} from 'vanilla-starter/DatePicker'; ## Forms -Use the `name` prop to submit the selected date to the server as an [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) string. Set the `isRequired`, `minValue`, or `maxValue` props to validate the value, or implement custom client or server-side validation. The `isDateUnavailable` callback prevents certain dates from being selected. See the Forms guide to learn more. +Use the `name` prop to submit the selected date to the server as an [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) string. Set the `isRequired`, `minValue`, or `maxValue` props to validate the value, or implement custom client or server-side validation. The `isDateUnavailable` callback prevents certain dates from being selected. See the [Forms](forms) guide to learn more. ```tsx render "use client"; diff --git a/packages/dev/s2-docs/pages/react-aria/DateRangePicker.mdx b/packages/dev/s2-docs/pages/react-aria/DateRangePicker.mdx index 5770094921c..7650bdcace5 100644 --- a/packages/dev/s2-docs/pages/react-aria/DateRangePicker.mdx +++ b/packages/dev/s2-docs/pages/react-aria/DateRangePicker.mdx @@ -107,7 +107,7 @@ import {DateRangePicker} from 'vanilla-starter/DateRangePicker'; ## Forms -Use the `name` prop to submit the selected date to the server as an [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) string. Set the `isRequired`, `minValue`, or `maxValue` props to validate the value, or implement custom client or server-side validation. The `isDateUnavailable` callback prevents certain dates from being selected. Use `allowsNonContiguousRanges` to allow selecting ranges containing unavailable dates. See the Forms guide to learn more. +Use the `name` prop to submit the selected date to the server as an [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) string. Set the `isRequired`, `minValue`, or `maxValue` props to validate the value, or implement custom client or server-side validation. The `isDateUnavailable` callback prevents certain dates from being selected. Use `allowsNonContiguousRanges` to allow selecting ranges containing unavailable dates. See the [Forms](forms) guide to learn more. ```tsx render docs={vanillaDocs.exports.DateRangePicker} links={docs.links} props={['allowsNonContiguousRanges']} wide "use client"; diff --git a/packages/dev/s2-docs/pages/react-aria/FocusScope.mdx b/packages/dev/s2-docs/pages/react-aria/FocusScope.mdx index 06c989004dd..8139fcd68e1 100644 --- a/packages/dev/s2-docs/pages/react-aria/FocusScope.mdx +++ b/packages/dev/s2-docs/pages/react-aria/FocusScope.mdx @@ -42,8 +42,7 @@ button mounts a FocusScope, which auto focuses the first input inside it. Once o press the Tab key to move within the scope, but focus is contained inside. Clicking the "Close" button unmounts the focus scope, which restores focus back to the button. -{/* Not implemented yet */} -{/* For a full example of building a modal dialog, see [useDialog](useDialog). */} +For a full example of building a modal dialog, see [useDialog](https://react-spectrum.adobe.com/react-aria/useDialog.html). ```tsx render 'use client'; diff --git a/packages/dev/s2-docs/pages/react-aria/NumberField.mdx b/packages/dev/s2-docs/pages/react-aria/NumberField.mdx index 5731e462f46..e2a9361eda6 100644 --- a/packages/dev/s2-docs/pages/react-aria/NumberField.mdx +++ b/packages/dev/s2-docs/pages/react-aria/NumberField.mdx @@ -112,7 +112,7 @@ import {NumberField} from 'vanilla-starter/NumberField'; ## Forms -Use the `name` prop to submit the raw number value (not a formatted string) to the server. Set the `isRequired` prop to validate that the user enters a value, or implement custom client or server-side validation. See the Forms guide to learn more. +Use the `name` prop to submit the raw number value (not a formatted string) to the server. Set the `isRequired` prop to validate that the user enters a value, or implement custom client or server-side validation. See the [Forms](forms) guide to learn more. ```tsx render "use client"; diff --git a/packages/dev/s2-docs/pages/react-aria/RadioGroup.mdx b/packages/dev/s2-docs/pages/react-aria/RadioGroup.mdx index 25241736f4c..318e93ef4c5 100644 --- a/packages/dev/s2-docs/pages/react-aria/RadioGroup.mdx +++ b/packages/dev/s2-docs/pages/react-aria/RadioGroup.mdx @@ -74,7 +74,7 @@ function Example() { ## Forms -Use the `name` prop to submit the selected radio to the server. Set the `isRequired` prop to validate that the user selects an option, or implement custom client or server-side validation. See the Forms guide to learn more. +Use the `name` prop to submit the selected radio to the server. Set the `isRequired` prop to validate that the user selects an option, or implement custom client or server-side validation. See the [Forms](forms) guide to learn more. ```tsx render "use client"; diff --git a/packages/dev/s2-docs/pages/react-aria/SearchField.mdx b/packages/dev/s2-docs/pages/react-aria/SearchField.mdx index 49902104e3f..6d271888943 100644 --- a/packages/dev/s2-docs/pages/react-aria/SearchField.mdx +++ b/packages/dev/s2-docs/pages/react-aria/SearchField.mdx @@ -69,7 +69,7 @@ function Example() { ## Forms -Use the `name` prop to submit the text value to the server. Set the `isRequired`, `minLength`, `maxLength`, `pattern`, or `type` props to validate the value, or implement custom client or server-side validation. See the Forms guide to learn more. +Use the `name` prop to submit the text value to the server. Set the `isRequired`, `minLength`, `maxLength`, `pattern`, or `type` props to validate the value, or implement custom client or server-side validation. See the [Forms](forms) guide to learn more. ```tsx render docs={docs.exports.SearchField} links={docs.links} props={['isRequired', 'type', 'pattern', 'minLength', 'maxLength']} initialProps={{isRequired: true}} "use client"; diff --git a/packages/dev/s2-docs/pages/react-aria/Select.mdx b/packages/dev/s2-docs/pages/react-aria/Select.mdx index 2ee14e6513b..8724009d5d8 100644 --- a/packages/dev/s2-docs/pages/react-aria/Select.mdx +++ b/packages/dev/s2-docs/pages/react-aria/Select.mdx @@ -304,7 +304,7 @@ function Example(props) { ## Forms -Use the `name` prop to submit the `id` of the selected item to the server. Set the `isRequired` prop to validate that the user selects an option, or implement custom client or server-side validation. See the Forms guide to learn more. +Use the `name` prop to submit the `id` of the selected item to the server. Set the `isRequired` prop to validate that the user selects an option, or implement custom client or server-side validation. See the [Forms](forms) guide to learn more. ```tsx render "use client"; diff --git a/packages/dev/s2-docs/pages/react-aria/Switch.mdx b/packages/dev/s2-docs/pages/react-aria/Switch.mdx index f5b16d51f6a..220449b2622 100644 --- a/packages/dev/s2-docs/pages/react-aria/Switch.mdx +++ b/packages/dev/s2-docs/pages/react-aria/Switch.mdx @@ -65,7 +65,7 @@ function Example(props) { ## Forms -Use the `name` and `value` props to submit the switch to the server. See the Forms guide to learn more. +Use the `name` and `value` props to submit the switch to the server. See the [Forms](forms) guide to learn more. ```tsx render "use client"; diff --git a/packages/dev/s2-docs/pages/react-aria/TextField.mdx b/packages/dev/s2-docs/pages/react-aria/TextField.mdx index 2a263fa4b11..539568fb21a 100644 --- a/packages/dev/s2-docs/pages/react-aria/TextField.mdx +++ b/packages/dev/s2-docs/pages/react-aria/TextField.mdx @@ -64,7 +64,7 @@ function Example() { ## Forms -Use the `name` prop to submit the text value to the server. Set the `isRequired`, `minLength`, `maxLength`, `pattern`, or `type` props to validate the value, or implement custom client or server-side validation. See the Forms guide to learn more. +Use the `name` prop to submit the text value to the server. Set the `isRequired`, `minLength`, `maxLength`, `pattern`, or `type` props to validate the value, or implement custom client or server-side validation. See the [Forms](forms) guide to learn more. ```tsx render docs={docs.exports.TextField} links={docs.links} props={['isRequired', 'type', 'pattern', 'minLength', 'maxLength']} initialProps={{isRequired: true, type: 'email'}} "use client"; diff --git a/packages/dev/s2-docs/pages/react-aria/TimeField.mdx b/packages/dev/s2-docs/pages/react-aria/TimeField.mdx index 1c0b5900201..a7aeb9263ca 100644 --- a/packages/dev/s2-docs/pages/react-aria/TimeField.mdx +++ b/packages/dev/s2-docs/pages/react-aria/TimeField.mdx @@ -77,7 +77,7 @@ import {TimeField} from 'vanilla-starter/TimeField'; ## Forms -Use the `name` prop to submit the selected date to the server as an [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) string. Set the `isRequired`, `minValue`, or `maxValue` props to validate the value, or implement custom client or server-side validation. See the Forms guide to learn more. +Use the `name` prop to submit the selected date to the server as an [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) string. Set the `isRequired`, `minValue`, or `maxValue` props to validate the value, or implement custom client or server-side validation. See the [Forms](forms) guide to learn more. ```tsx render "use client"; diff --git a/packages/dev/s2-docs/pages/react-aria/Toast.mdx b/packages/dev/s2-docs/pages/react-aria/Toast.mdx index 6cc74517677..41f8bf88aa2 100644 --- a/packages/dev/s2-docs/pages/react-aria/Toast.mdx +++ b/packages/dev/s2-docs/pages/react-aria/Toast.mdx @@ -33,7 +33,7 @@ export const description = 'Displays brief, temporary notifications of actions, }, props.timeout ? {timeout: props.timeout} : undefined )}> - Upload files + Show Toast
); @@ -56,7 +56,7 @@ export const description = 'Displays brief, temporary notifications of actions, }, props.timeout ? {timeout: props.timeout} : undefined )}> - Upload files + Show Toast
); @@ -71,26 +71,50 @@ export const description = 'Displays brief, temporary notifications of actions, Use the `"title"` and `"description"` slots within `` to provide structured content for the toast. The title is required, and description is optional. -```tsx render hideImports -"use client"; -import {queue} from 'vanilla-starter/Toast'; -import {Button} from 'vanilla-starter/Button'; - -function Example() { - return ( - - ); -} -``` + + ```tsx render hideImports type="vanilla" + "use client"; + import {queue} from 'vanilla-starter/Toast'; + import {Button} from 'vanilla-starter/Button'; + + function Example() { + return ( + + ); + } + ``` + + ```tsx render hideImports type="tailwind" + "use client"; + import {queue} from 'tailwind-starter/Toast'; + import {Button} from 'tailwind-starter/Button'; + + function Example() { + return ( + + ); + } + ``` + + ### Close button @@ -105,26 +129,50 @@ Include a ` - ); -} -``` + + ```tsx render hideImports type="vanilla" + "use client"; + import {queue} from 'vanilla-starter/Toast'; + import {Button} from 'vanilla-starter/Button'; + + function Example() { + return ( + + ); + } + ``` + + ```tsx render hideImports type="tailwind" + "use client"; + import {queue} from 'tailwind-starter/Toast'; + import {Button} from 'tailwind-starter/Button'; + + function Example() { + return ( + + ); + } + ``` + + Accessibility @@ -135,35 +183,68 @@ function Example() { Toasts can be programmatically dismissed using the key returned from `queue.add()`. This is useful when a toast becomes irrelevant before the user manually closes it. -```tsx render hideImports -"use client"; -import {queue} from 'vanilla-starter/Toast'; -import {Button} from 'vanilla-starter/Button'; -import {useState} from 'react'; - -function Example() { - let [toastKey, setToastKey] = useState(null); - - return ( - - ); -} -``` + + ```tsx render hideImports type="vanilla" + "use client"; + import {queue} from 'vanilla-starter/Toast'; + import {Button} from 'vanilla-starter/Button'; + import {useState} from 'react'; + + function Example() { + let [toastKey, setToastKey] = useState(null); + + return ( + + ); + } + ``` + + ```tsx render hideImports type="tailwind" + "use client"; + import {queue} from 'tailwind-starter/Toast'; + import {Button} from 'tailwind-starter/Button'; + import {useState} from 'react'; + + function Example() { + let [toastKey, setToastKey] = useState(null); + + return ( + + ); + } + ``` + + ## Accessibility diff --git a/packages/dev/s2-docs/pages/react-aria/VisuallyHidden.mdx b/packages/dev/s2-docs/pages/react-aria/VisuallyHidden.mdx index 206b805449a..8a01162bfb2 100644 --- a/packages/dev/s2-docs/pages/react-aria/VisuallyHidden.mdx +++ b/packages/dev/s2-docs/pages/react-aria/VisuallyHidden.mdx @@ -56,8 +56,7 @@ let {visuallyHiddenProps} = useVisuallyHidden(); -{/* not implemented yet */} -{/* ## Example +## Example -See [useRadioGroup](useRadioGroup#styling) and [useCheckbox](useCheckbox#styling) -for examples of using `VisuallyHidden` to hide native form elements visually. */} +See [useRadioGroup](https://react-spectrum.adobe.com/react-aria/useRadioGroup.html#styling) and [useCheckbox](https://react-spectrum.adobe.com/react-aria/useCheckbox.html#styling) +for examples of using `VisuallyHidden` to hide native form elements visually. diff --git a/packages/dev/s2-docs/pages/react-aria/useField.mdx b/packages/dev/s2-docs/pages/react-aria/useField.mdx index f5835a47200..f1789da0469 100644 --- a/packages/dev/s2-docs/pages/react-aria/useField.mdx +++ b/packages/dev/s2-docs/pages/react-aria/useField.mdx @@ -26,8 +26,7 @@ The `useField` hook associates a form control with a label, and an optional desc By default, `useField` assumes that the label is a native HTML `