diff --git a/.storybook-s2/docs/Icons.jsx b/.storybook-s2/docs/Icons.jsx index f5b9893fbae..006a2315b94 100644 --- a/.storybook-s2/docs/Icons.jsx +++ b/.storybook-s2/docs/Icons.jsx @@ -1,7 +1,7 @@ import icons from '@react-spectrum/s2/s2wf-icons/*.svg'; import { style } from '../../packages/@react-spectrum/s2/style/spectrum-theme' with {type: 'macro'}; import {ActionButton, Text} from '@react-spectrum/s2'; -import {P, Code, Pre} from './typography'; +import {H2, H3, P, Code, Pre, Link} from './typography'; import {highlight} from './highlight' with {type: 'macro'}; export function Icons() { @@ -29,6 +29,25 @@ export function Icons() { ); })} +
To use custom icons, you first need to convert your SVGs into compatible icon components. This depends on your bundler.
+If you are using Parcel, the @react-spectrum/parcel-transformer-s2-icon
plugin can be used to convert SVGs to icon components. First install it into your project as a dev dependency:
yarn add @react-spectrum/parcel-transformer-s2-icon --dev+
Then, add it to your .parcelrc
:
{highlight(`{ + "extends": "@parcel/config-default", + "transformers": { + "icon:*.svg": ["@react-spectrum/parcel-transformer-s2-icon"] + } +}`)}+
Now you can import icon SVGs using the icon:
pipeline:
{highlight(`import Icon from 'icon:./path/to/Icon.svg';`)}+
The @react-spectrum/s2-icon-builder
CLI tool can be used to pre-process a folder of SVG icons into TSX files.
npx @react-spectrum/s2-icon-builder -i 'path/to/icons/*.svg' -o 'path/to/destination'+
This outputs a folder of TSX files with names corresponding to the input SVG files. You may rename them as you wish. To use them in your application, import them like normal components.
+{highlight(`import Icon from './path/to/destination/Icon';`)}); diff --git a/.storybook-s2/docs/Illustrations.jsx b/.storybook-s2/docs/Illustrations.jsx index df9836b1945..ebf6fac8dc4 100644 --- a/.storybook-s2/docs/Illustrations.jsx +++ b/.storybook-s2/docs/Illustrations.jsx @@ -1,9 +1,9 @@ import linearIllustrations from '@react-spectrum/s2/spectrum-illustrations/linear/*.tsx'; -import gradientIllustrations from '@react-spectrum/s2/spectrum-illustrations/gradient/*.svg'; +import gradientIllustrations from 'illustration:@react-spectrum/s2/spectrum-illustrations/gradient/*.svg'; import Paste from '@react-spectrum/s2/s2wf-icons/S2_Icon_Paste_20_N.svg'; import { style } from '../../packages/@react-spectrum/s2/style/spectrum-theme' with {type: 'macro'}; import {ActionButton, Text} from '@react-spectrum/s2'; -import {H2, P, Code, Pre} from './typography'; +import {H2, H3, P, Code, Pre, Link} from './typography'; import {highlight} from './highlight' with {type: 'macro'}; import { Radio, RadioGroup } from '../../packages/@react-spectrum/s2/src'; import { useState } from 'react'; @@ -35,7 +35,7 @@ export function Illustrations() { return 'gradient/' + style + '/' + name; }); return ( -
To use custom illustrations, you first need to convert your SVGs into compatible illustration components. This depends on your bundler.
+If you are using Parcel, the @react-spectrum/parcel-transformer-s2-icon
plugin can be used to convert SVGs to illustration components. First install it into your project as a dev dependency:
yarn add @react-spectrum/parcel-transformer-s2-icon --dev+
Then, add it to your .parcelrc
:
{highlight(`{ + "extends": "@parcel/config-default", + "transformers": { + "illustration:*.svg": ["@react-spectrum/parcel-transformer-s2-icon"] + } +}`)}+
Now you can import illustration SVGs using the illustration:
pipeline:
{highlight(`import Illustration from 'illustration:./path/to/Illustration.svg';`)}+
The @react-spectrum/s2-icon-builder
CLI tool can be used to pre-process a folder of SVG illustrations into TSX files.
npx @react-spectrum/s2-icon-builder -i 'path/to/illustrations/*.svg' --type illustration -o 'path/to/destination'+
This outputs a folder of TSX files with names corresponding to the input SVG files. You may rename them as you wish. To use them in your application, import them like normal components.
+{highlight(`import Illustration from './path/to/destination/Illustration';`)}
By default, React Spectrum uses the browser/operating system language setting for localized strings, date and number formatting, and to determine the layout direction (left-to-right or right-to-left). This can be overridden by rendering a {'
component at the root of your app, and setting the locale
prop.
{highlight(`import {Provider} from '@react-spectrum/s2'; +{/* your app */} `)}
If you’re building an embedded section of a larger page using Spectrum 2, use the {'
component to set the background instead of importing page.css
. The background
prop should be set to the Spectrum background layer appropriate for your app, and the colorScheme
can be overridden as well.
{highlight(`import {Provider} from '@react-spectrum/s2'; +@@ -186,7 +188,7 @@ import {ActionButton} from '@react-spectrum/s2';{/* your app */} `)}
The styles
prop accepts a limited set of CSS properties, including layout, spacing, sizing, and positioning. Other styles such as colors and internal padding cannot be customized within Spectrum components.
insetEnd
We highly discourage overriding the styles of React Spectrum components because it may break at any time when we change our implementation, making it difficult for you to update in the future. Consider using React Aria Components with our style macro to build a custom component with Spectrum styles instead.
+We highly discourage overriding the styles of React Spectrum components because it may break at any time when we change our implementation, making it difficult for you to update in the future. Consider using React Aria Components with our style macro to build a custom component with Spectrum styles instead.
That said, just like in React Spectrum v3, the UNSAFE_className
and UNSAFE_style
props are supported on Spectrum 2 components as last-resort escape hatches. However, unlike in v3, UNSAFE_classNames must be placed in a special UNSAFE_overrides
CSS cascade layer. This guarentees that your overrides will always win over other styles on the page, no matter the order or specificity of the selector.
{highlight(`/* YourComponent.tsx */ import {Button} from '@react-spectrum/s2'; diff --git a/.storybook-s2/docs/MDXLayout.jsx b/.storybook-s2/docs/MDXLayout.jsx new file mode 100644 index 00000000000..a5e1842b688 --- /dev/null +++ b/.storybook-s2/docs/MDXLayout.jsx @@ -0,0 +1,30 @@ +import { style } from '../../packages/@react-spectrum/s2/style/spectrum-theme' with {type: 'macro'}; +import {highlight} from './highlight' with {type: 'macro'}; +import {H2, H3, H3, P, Pre, Code, Strong, H4, Link} from './typography'; +import {MDXProvider} from '@mdx-js/react'; + +const mdxComponents = { + h1: ({children}) =>{children}
, + h2: H2, + h3: H3, + h4: H4, + p: P, + pre: Pre, + code: Code, + strong: Strong, + ul: ({children}) =>
An automated upgrade assistant is available by running the following command in the project you want to upgrade:
@@ -19,9 +18,9 @@ export function Migrating() {The following arguments are also available:
--path
- Path to apply the upgrade changes to. Defaults to the current directory (.
)--dry
- Runs the upgrade assistant without making changes to components--ignore-pattern
- Ignore files that match the provided glob expression. Defaults to '**/node_modules/**'
--path
- Path to apply the upgrade changes to. Defaults to the current directory (.
)--dry
- Runs the upgrade assistant without making changes to components--ignore-pattern
- Ignore files that match the provided glob expression. Defaults to '**/node_modules/**'
For cases that the upgrade assistant doesn't handle automatically or where you'd rather upgrade some components manually, use the guide below.
@@ -31,8 +30,8 @@ export function Migrating() {@react-spectrum/s2
package instead of @adobe/react-spectrum
or individual packages like @react-spectrum/button
@react-spectrum/s2
package instead of @adobe/react-spectrum
or individual packages like @react-spectrum/button
closeOnSelect
(it has not been implemented yet)trigger
(it has not been implemented yet)Item
to be a MenuItem
closeOnSelect
(it has not been implemented yet)trigger
(it has not been implemented yet)Item
to be a MenuItem
isDisabled
(it has not been implemented yet)size
to be a pixel value if it currently matches 'avatar-size-*'
isDisabled
(it has not been implemented yet)size
to be a pixel value if it currently matches 'avatar-size-*'
showRoot
(it has not been implemented yet)isMultiline
(it has not been implemented yet)autoFocusCurrent
(it has not been implemented yet)size="S"
(Small is no longer a supported size in Spectrum 2)Item
to be a Breadcrumb
showRoot
(it has not been implemented yet)isMultiline
(it has not been implemented yet)autoFocusCurrent
(it has not been implemented yet)size="S"
(Small is no longer a supported size in Spectrum 2)Item
to be a Breadcrumb
variant="cta"
to variant="accent"
variant="overBackground"
to variant="primary" staticColor="white"
style
to fillStyle
isPending
(it has not been implemented yet)isQuiet
(it is no longer supported in Spectrum 2)href
is present, the Button
should be converted to a LinkButton
elementType
(it is no longer supported in Spectrum 2)variant="cta"
to variant="accent"
variant="overBackground"
to variant="primary" staticColor="white"
style
to fillStyle
isPending
(it has not been implemented yet)isQuiet
(it is no longer supported in Spectrum 2)href
is present, the Button
should be converted to a LinkButton
elementType
(it is no longer supported in Spectrum 2)showErrorIcon
(it has been removed due to accessibility issues)showErrorIcon
(it has been removed due to accessibility issues)size
and instead provide a size via the style macro (i.e. {`styles={style({size: 20})}`}
)size
and instead provide a size via the style macro (i.e. {`styles={style({size: 20})}`}
)isQuiet
(it is no longer supported in Spectrum 2)placeholder
(it has been removed due to accessibility issues)validationState="invalid"
to isInvalid
validationState="valid"
(it is no longer supported in Spectrum 2)isQuiet
(it is no longer supported in Spectrum 2)placeholder
(it has been removed due to accessibility issues)validationState="invalid"
to isInvalid
validationState="valid"
(it is no longer supported in Spectrum 2)showValueLabel
(it has been removed due to accessibility issues)showValueLabel
(it has been removed due to accessibility issues)size
and instead provide a size via the style macro (i.e. {`styles={style({size: 20})}`}
)size
and instead provide a size via the style macro (i.e. {`styles={style({size: 20})}`}
)menuWidth
value from a DimensionValue
to a pixel valueisQuiet
(it is no longer supported in Spectrum 2)loadingState
(it has not been implemented yet)placeholder
(it is no longer supported in Spectrum 2)validationState="invalid"
to isInvalid
validationState="valid"
(it is no longer supported in Spectrum 2)onLoadMore
(it has not been implemented yet)Item
to be a ComboBoxItem
menuWidth
value from a DimensionValue
to a pixel valueisQuiet
(it is no longer supported in Spectrum 2)loadingState
(it has not been implemented yet)placeholder
(it is no longer supported in Spectrum 2)validationState="invalid"
to isInvalid
validationState="valid"
(it is no longer supported in Spectrum 2)onLoadMore
(it has not been implemented yet)Item
to be a ComboBoxItem
DialogTrigger
to being a child of Dialog
onDismiss
and use onOpenChange
on the DialogTrigger
, or onDismiss
on the DialogContainer
insteadDialogTrigger
to being a child of Dialog
onDismiss
and use onOpenChange
on the DialogTrigger
, or onDismiss
on the DialogContainer
insteadtype="tray"
(Tray
has not been implemented yet)mobileType="tray"
(Tray
has not been implemented yet)targetRef
(it is no longer supported in Spectrum 2)children
to remove render props usage, and note that the close
function was moved from DialogTrigger
to Dialog
type="tray"
(Tray
has not been implemented yet)mobileType="tray"
(Tray
has not been implemented yet)targetRef
(it is no longer supported in Spectrum 2)children
to remove render props usage, and note that the close
function was moved from DialogTrigger
to Dialog
Flex
to be a div
and apply flex styles using the style macro (i.e. {``}
)Flex
to be a div
and apply flex styles using the style macro (i.e. {``}
)isQuiet
(it is no longer supported in Spectrum 2)isReadOnly
(it is no longer supported in Spectrum 2)validationState
(it is no longer supported in Spectrum 2)validationBehavior
(it is no longer supported in Spectrum 2)isQuiet
(it is no longer supported in Spectrum 2)isReadOnly
(it is no longer supported in Spectrum 2)validationState
(it is no longer supported in Spectrum 2)validationBehavior
(it is no longer supported in Spectrum 2)Grid
to be a div
and apply grid styles using the style macro (i.e. {``}
)Grid
to be a div
and apply grid styles using the style macro (i.e. {``}
)@react-spectrum/s2/illustrations
. See Illustrations@react-spectrum/s2/illustrations
. See Illustrationsvariant="info"
to variant="informative"
variant="info"
to variant="informative"
Menu
: Update Item
to be a MenuItem
ActionMenu
: Update Item
to be a MenuItem
TagGroup
: Update Item
to be a Tag
Breadcrumbs
: Update Item
to be a Breadcrumb
Picker
: Update Item
to be a PickerItem
ComboBox
: Update Item
to be a ComboBoxItem
ListBox
: Update Item
to be a ListBoxItem
TabList
: Update Item
to be a Tab
TabPanels
: Update Item
to be a TabPanel
and remove surrounding TabPanels
key
to be id
(and keep key
if rendered inside array.map
)Menu
: Update Item
to be a MenuItem
ActionMenu
: Update Item
to be a MenuItem
TagGroup
: Update Item
to be a Tag
Breadcrumbs
: Update Item
to be a Breadcrumb
Picker
: Update Item
to be a PickerItem
ComboBox
: Update Item
to be a ComboBoxItem
ListBox
: Update Item
to be a ListBoxItem
TabList
: Update Item
to be a Tab
TabPanels
: Update Item
to be a TabPanel
and remove surrounding TabPanels
key
to be id
(and keep key
if rendered inside array.map
)variant="overBackground"
to staticColor="white"
variant="overBackground"
to staticColor="white"
Item
to be a ListBoxItem
Item
to be a ListBoxItem
Item
to be a MenuItem
Item
to be a MenuItem
closeOnSelect
(it has not been implemented yet)closeOnSelect
(it has not been implemented yet)isQuiet
(it is no longer supported in Spectrum 2)validationState="invalid"
to isInvalid
validationState="valid"
(it is no longer supported in Spectrum 2)isQuiet
(it is no longer supported in Spectrum 2)validationState="invalid"
to isInvalid
validationState="valid"
(it is no longer supported in Spectrum 2)menuWidth
value from a DimensionValue
to a pixel valueisQuiet
(it is no longer supported in Spectrum 2)validationState="invalid"
to isInvalid
validationState="valid"
(it is no longer supported in Spectrum 2)isLoading
(it has not been implemented yet)onLoadMore
(it has not been implemented yet)Item
to be a PickerItem
menuWidth
value from a DimensionValue
to a pixel valueisQuiet
(it is no longer supported in Spectrum 2)validationState="invalid"
to isInvalid
validationState="valid"
(it is no longer supported in Spectrum 2)isLoading
(it has not been implemented yet)onLoadMore
(it has not been implemented yet)Item
to be a PickerItem
variant="overBackground"
to staticColor="white"
labelPosition
(it has not been implemented yet)showValueLabel
(it has not been implemented yet)variant="overBackground"
to staticColor="white"
labelPosition
(it has not been implemented yet)showValueLabel
(it has not been implemented yet)variant="overBackground"
to staticColor="white"
variant="overBackground"
to staticColor="white"
validationState="invalid"
to isInvalid
validationState="valid"
(it is no longer supported in Spectrum 2)showErrorIcon
(it has been removed due to accessibility issues)validationState="invalid"
to isInvalid
validationState="valid"
(it is no longer supported in Spectrum 2)showErrorIcon
(it has been removed due to accessibility issues)showValueLabel
(it has been removed due to accessibility issues)getValueLabel
(it has not been implemented yet)orientation
(it has not been implemented yet)showValueLabel
(it has been removed due to accessibility issues)getValueLabel
(it has not been implemented yet)orientation
(it has not been implemented yet)placeholder
(it has been removed due to accessibility issues)isQuiet
(it is no longer supported in Spectrum 2)validationState="invalid"
to isInvalid
validationState="valid"
(it is no longer supported in Spectrum 2)placeholder
(it has been removed due to accessibility issues)isQuiet
(it is no longer supported in Spectrum 2)validationState="invalid"
to isInvalid
validationState="valid"
(it is no longer supported in Spectrum 2)Menu
: Update Section
to be a MenuSection
Picker
: Update Section
to be a PickerSection
Menu
: Update Section
to be a MenuSection
Picker
: Update Section
to be a PickerSection
isFilled
(Slider is always filled in Spectrum 2)trackGradient
(Not supported in S2 design)showValueLabel
(it has been removed due to accessibility issues)getValueLabel
(it has not been implemented yet)orientation
(it has not been implemented yet)isFilled
(Slider is always filled in Spectrum 2)trackGradient
(Not supported in S2 design)showValueLabel
(it has been removed due to accessibility issues)getValueLabel
(it has not been implemented yet)orientation
(it has not been implemented yet)isDisabled
(it is no longer supported in Spectrum 2)variant="info"
to variant="informative"
isDisabled
(it is no longer supported in Spectrum 2)variant="info"
to variant="informative"
TabList
: Update Item
to be Tab
items
on Tabs
to be on TabList
TabPanels
: Update Item
to be a TabPanel
and remove the surrounding TabPanels
isEmphasized
(it is no longer supported in Spectrum 2)isQuiet
(it is no longer supported in Spectrum 2)TabList
: Update Item
to be Tab
items
on Tabs
to be on TabList
TabPanels
: Update Item
to be a TabPanel
and remove the surrounding TabPanels
isEmphasized
(it is no longer supported in Spectrum 2)isQuiet
(it is no longer supported in Spectrum 2)actionLabel
to groupActionLabel
onAction
to onGroupAction
validationState="invalid"
to isInvalid
Item
to be Tag
actionLabel
to groupActionLabel
onAction
to onGroupAction
validationState="invalid"
to isInvalid
Item
to be Tag
icon
(it has not been implemented yet)isQuiet
(it is no longer supported in Spectrum 2)placeholder
(it has been removed due to accessibility issues)validationState="invalid"
to isInvalid
validationState="valid"
(it is no longer supported in Spectrum 2)icon
(it has not been implemented yet)isQuiet
(it is no longer supported in Spectrum 2)placeholder
(it has been removed due to accessibility issues)validationState="invalid"
to isInvalid
validationState="valid"
(it is no longer supported in Spectrum 2)icon
(it has not been implemented yet)isQuiet
(it is no longer supported in Spectrum 2)placeholder
(it has been removed due to accessibility issues)validationState="invalid"
to isInvalid
validationState="valid"
(it is no longer supported in Spectrum 2)icon
(it has not been implemented yet)isQuiet
(it is no longer supported in Spectrum 2)placeholder
(it has been removed due to accessibility issues)validationState="invalid"
to isInvalid
validationState="valid"
(it is no longer supported in Spectrum 2)variant
(it is no longer supported in Spectrum 2)placement
and add to the parent TooltipTrigger
insteadshowIcon
(it is no longer supported in Spectrum 2)isOpen
and add to the parent TooltipTrigger
insteadvariant
(it is no longer supported in Spectrum 2)placement
and add to the parent TooltipTrigger
insteadshowIcon
(it is no longer supported in Spectrum 2)isOpen
and add to the parent TooltipTrigger
insteadplacement="bottom left"
to be placement="bottom"
)placement="bottom left"
to be placement="bottom"
)View
to be a div
and apply styles using the style macroView
to be a div
and apply styles using the style macroReact Spectrum v3 supported a limited set of style props for layout and positioning using Spectrum-defined values. Usage of these should be updated to instead use the style macro.
+React Spectrum v3 supported a limited set of style props for layout and positioning using Spectrum-defined values. Usage of these should be updated to instead use the style macro.
Example:
{`- import {ActionButton} from '@adobe/react-spectrum';`}@@ -366,30 +365,34 @@ export function Migrating() {
Border widths should be updated to use pixel values. Use the following mappings:
Spectrum 1 | -Spectrum 2 | -
---|---|
'none' |
- 0 |
-
'thin' |
- 1 |
-
'thick' |
- 2 |
-
'thicker' |
- 4 |
-
'thickest' |
- '[8px]' |
-
Spectrum 1 | +Spectrum 2 | +
'none' |
+ 0 |
+
'thin' |
+ 1 |
+
'thick' |
+ 2 |
+
'thicker' |
+ 4 |
+
'thickest' |
+ '[8px]' |
+
Border radius values should be updated to use pixel values. Use the following mappings:
Spectrum 1 | -Spectrum 2 | -
---|---|
'xsmall' |
- '[1px]' |
-
'small' |
- 'sm' |
-
'regular' |
- 'default' |
-
'medium' |
- 'lg' |
-
'large' |
- 'xl' |
-
Spectrum 1 | +Spectrum 2 | +
'xsmall' |
+ '[1px]' |
+
'small' |
+ 'sm' |
+
'regular' |
+ 'default' |
+
'medium' |
+ 'lg' |
+
'large' |
+ 'xl' |
+
Dimension values should be converted to pixel values. Use the following mappings:
-Spectrum 1 | -Spectrum 2 | -
---|---|
'size-0' |
- 0 |
-
'size-10' |
- 1 |
-
'size-25' |
- 2 |
-
'size-40' |
- 3 |
-
'size-50' |
- 4 |
-
'size-65' |
- 5 |
-
'size-75' |
- 6 |
-
'size-85' |
- 7 |
-
'size-100' |
- 8 |
-
'size-115' |
- 9 |
-
'size-125' |
- 10 |
-
'size-130' |
- 11 |
-
'size-150' |
- 12 |
-
'size-160' |
- 13 |
-
'size-175' |
- 14 |
-
'size-200' |
- 16 |
-
'size-225' |
- 18 |
-
'size-250' |
- 20 |
-
'size-275' |
- 22 |
-
'size-300' |
- 24 |
-
'size-325' |
- 26 |
-
'size-350' |
- 28 |
-
'size-400' |
- 32 |
-
'size-450' |
- 36 |
-
'size-500' |
- 40 |
-
'size-550' |
- 44 |
-
'size-600' |
- 48 |
-
'size-675' |
- 54 |
-
'size-700' |
- 56 |
-
'size-800' |
- 64 |
-
'size-900' |
- 72 |
-
'size-1000' |
- 80 |
-
'size-1200' |
- 96 |
-
'size-1250' |
- 100 |
-
'size-1600' |
- 128 |
-
'size-1700' |
- 136 |
-
'size-2000' |
- 160 |
-
'size-2400' |
- 192 |
-
'size-3000' |
- 240 |
-
'size-3400' |
- 272 |
-
'size-3600' |
- 288 |
-
'size-4600' |
- 368 |
-
'size-5000' |
- 400 |
-
'size-6000' |
- 480 |
-
'static-size-0' |
- 0 |
-
'static-size-10' |
- 1 |
-
'static-size-25' |
- 2 |
-
'static-size-40' |
- 3 |
-
'static-size-50' |
- 4 |
-
'static-size-65' |
- 5 |
-
'static-size-100' |
- 8 |
-
'static-size-115' |
- 9 |
-
'static-size-125' |
- 10 |
-
'static-size-130' |
- 11 |
-
'static-size-150' |
- 12 |
-
'static-size-160' |
- 13 |
-
'static-size-175' |
- 14 |
-
'static-size-200' |
- 16 |
-
'static-size-225' |
- 18 |
-
'static-size-250' |
- 20 |
-
'static-size-300' |
- 24 |
-
'static-size-400' |
- 32 |
-
'static-size-450' |
- 36 |
-
'static-size-500' |
- 40 |
-
'static-size-550' |
- 44 |
-
'static-size-600' |
- 48 |
-
'static-size-700' |
- 56 |
-
'static-size-800' |
- 64 |
-
'static-size-900' |
- 72 |
-
'static-size-1000' |
- 80 |
-
'static-size-1200' |
- 96 |
-
'static-size-1700' |
- 136 |
-
'static-size-2400' |
- 192 |
-
'static-size-2600' |
- 208 |
-
'static-size-3400' |
- 272 |
-
'static-size-3600' |
- 288 |
-
'static-size-4600' |
- 368 |
-
'static-size-5000' |
- 400 |
-
'static-size-6000' |
- 480 |
-
'single-line-height' |
- 32 |
-
'single-line-width' |
- 192 |
-
Spectrum 1 | +Spectrum 2 | +
---|---|
'size-0' |
+ 0 |
+
'size-10' |
+ 1 |
+
'size-25' |
+ 2 |
+
'size-40' |
+ 3 |
+
'size-50' |
+ 4 |
+
'size-65' |
+ 5 |
+
'size-75' |
+ 6 |
+
'size-85' |
+ 7 |
+
'size-100' |
+ 8 |
+
'size-115' |
+ 9 |
+
'size-125' |
+ 10 |
+
'size-130' |
+ 11 |
+
'size-150' |
+ 12 |
+
'size-160' |
+ 13 |
+
'size-175' |
+ 14 |
+
'size-200' |
+ 16 |
+
'size-225' |
+ 18 |
+
'size-250' |
+ 20 |
+
'size-275' |
+ 22 |
+
'size-300' |
+ 24 |
+
'size-325' |
+ 26 |
+
'size-350' |
+ 28 |
+
'size-400' |
+ 32 |
+
'size-450' |
+ 36 |
+
'size-500' |
+ 40 |
+
'size-550' |
+ 44 |
+
'size-600' |
+ 48 |
+
'size-675' |
+ 54 |
+
'size-700' |
+ 56 |
+
'size-800' |
+ 64 |
+
'size-900' |
+ 72 |
+
'size-1000' |
+ 80 |
+
'size-1200' |
+ 96 |
+
'size-1250' |
+ 100 |
+
'size-1600' |
+ 128 |
+
'size-1700' |
+ 136 |
+
'size-2000' |
+ 160 |
+
'size-2400' |
+ 192 |
+
'size-3000' |
+ 240 |
+
'size-3400' |
+ 272 |
+
'size-3600' |
+ 288 |
+
'size-4600' |
+ 368 |
+
'size-5000' |
+ 400 |
+
'size-6000' |
+ 480 |
+
'static-size-0' |
+ 0 |
+
'static-size-10' |
+ 1 |
+
'static-size-25' |
+ 2 |
+
'static-size-40' |
+ 3 |
+
'static-size-50' |
+ 4 |
+
'static-size-65' |
+ 5 |
+
'static-size-100' |
+ 8 |
+
'static-size-115' |
+ 9 |
+
'static-size-125' |
+ 10 |
+
'static-size-130' |
+ 11 |
+
'static-size-150' |
+ 12 |
+
'static-size-160' |
+ 13 |
+
'static-size-175' |
+ 14 |
+
'static-size-200' |
+ 16 |
+
'static-size-225' |
+ 18 |
+
'static-size-250' |
+ 20 |
+
'static-size-300' |
+ 24 |
+
'static-size-400' |
+ 32 |
+
'static-size-450' |
+ 36 |
+
'static-size-500' |
+ 40 |
+
'static-size-550' |
+ 44 |
+
'static-size-600' |
+ 48 |
+
'static-size-700' |
+ 56 |
+
'static-size-800' |
+ 64 |
+
'static-size-900' |
+ 72 |
+
'static-size-1000' |
+ 80 |
+
'static-size-1200' |
+ 96 |
+
'static-size-1700' |
+ 136 |
+
'static-size-2400' |
+ 192 |
+
'static-size-2600' |
+ 208 |
+
'static-size-3400' |
+ 272 |
+
'static-size-3600' |
+ 288 |
+
'static-size-4600' |
+ 368 |
+
'static-size-5000' |
+ 400 |
+
'static-size-6000' |
+ 480 |
+
'single-line-height' |
+ 32 |
+
'single-line-width' |
+ 192 |
+
Break points previously used in style props can be used in the style macro with updated keys. Use the following mappings:
Spectrum 1 | -Spectrum 2 | -
---|---|
base |
- default |
-
S |
- sm |
-
M |
- md |
-
L |
- lg |
-
Spectrum 1 | +Spectrum 2 | +
base |
+ default |
+
S |
+ sm |
+
M |
+ md |
+
L |
+ lg |
+
Example:
diff --git a/.storybook-s2/docs/Release Notes.mdx b/.storybook-s2/docs/Release Notes.mdx new file mode 100644 index 00000000000..93bd87426be --- /dev/null +++ b/.storybook-s2/docs/Release Notes.mdx @@ -0,0 +1,75 @@ +import {Release030Intro} from './Release030Intro.jsx'; +import {MDXLayout} from './MDXLayout'; +export default MDXLayout; + +# Release Notes + +## v0.3.0 + ++ +### New components + +* [NumberField](?path=/docs/numberfield--docs) +* [AlertDialog](?path=/docs/alertdialog--docs) +* [Linear and gradient illustrations](?path=/docs/illustrations--docs) +* [AvatarGroup](?path=/docs/avatargroup--docs) +* [Tabs](?path=/docs/tabs--docs) + +### Updates + +* Add collapse and action support to TagGroup +* Add support for new Adobe Clean variable font +* Updated [workflow icons](?path=/docs/workflow-icons--docs) – **PLEASE NOTE**: some icons changed names in this release. +* Add CLI and Parcel plugins to build custom icons and illustrations +* Add translations for all components +* Add slot contexts to all S2 components +* Fix menu z-index +* Fix overlay trigger press scaling and menu description color +* Fix ComboBox and NumberField custom width +* Fix padding on fields with no visible label +* Add ContextualHelp Storybook stories to components missing them + +## v0.2.0 + +### New components + +* [Breadcrumbs](?path=/docs/breadcrumbs--docs) +* [Contextual Help](?path=/docs/contextualhelp--docs) +* [ColorArea](?path=/docs/colorarea--docs) +* [ColorField](?path=/docs/colorfield--docs) +* [ColorSlider](?path=/docs/colorslider--docs) +* [ColorSwatch](?path=/docs/colorswatch--docs) +* [ColorSwatchPicker](?path=/docs/colorswatchpicker--docs) +* [ColorWheel](?path=/docs/colorwheel--docs) +* [RangeSlider](?path=/docs/rangeslider--docs) +* [Slider](?path=/docs/slider--docs) + +### Updates + +* [ESBuild starter](https://github.com/adobe/react-spectrum/tree/main/examples/s2-esbuild-starter-app) added +* InlineAlert iconography updated +* ContextualHelp added to all form field components +* Fixed custom widths for field components +* Spectrum tokens updated +* CSS processing updated so output size is smaller + +See the updated [API changelog](https://github.com/adobe/react-spectrum/blob/main/packages/@react-spectrum/s2/api-diff.md) for a full list of changes since RSP v3. + +## v0.1.0 + +### New components + +* [Badge](?path=/docs/badge--docs) +* [ComboBox](?path=/docs/combobox--docs) +* [Meter](?path=/docs/meter--docs) +* [Picker](?path=/docs/picker--docs) + +### Updates + +* [TagGroup](?path=/docs/taggroup--docs) now supports avatars, images, error message and description help text, and improved hover/focus styling +* Updated React Aria Components to v1.2.0 +* Fixed global styles such as CSS resets from applying to Spectrum 2 elements. Note that any CSS rule referenced from an `UNSAFE_className` prop must now be wrapped in `@layer UNSAFE_overrides`. See [the docs](?path=/docs/intro--docs#unsafe-style-overrides) for more details. +* The `style` macro will now error if it is called without importing `with {type: 'macro'}`. Previously it would fail to apply styles silently. This should help with debugging. + +See the updated [API changelog](https://github.com/adobe/react-spectrum/blob/main/packages/@react-spectrum/s2/api-diff.md) for a full list of changes since RSP v3. diff --git a/.storybook-s2/docs/Release030Intro.jsx b/.storybook-s2/docs/Release030Intro.jsx new file mode 100644 index 00000000000..b65b6837727 --- /dev/null +++ b/.storybook-s2/docs/Release030Intro.jsx @@ -0,0 +1,18 @@ +import {highlight} from './highlight' with {type: 'macro'}; +import {H3, P, Pre, Code, Link} from './typography'; + +export function Release030Intro() { + return ( + <> + + Spectrum 2 now lives in npm, please update your dependencies to
+@react-spectrum/s2@^0.3.0
if you were using a previous version. + You'll need to update your imports to the new package name: +{highlight(`import {...} from '@react-spectrum/s2';`)}+and in your package.json:
+{highlight(`"@react-spectrum/s2": "^0.3.0"`)}+ +To help teams kickstart their migrations from v3 to Spectrum 2, we've also added a migration wizard. Please read the migration documentation for more information.
+ > + ) +} diff --git a/.storybook-s2/docs/typography.js b/.storybook-s2/docs/typography.js index be02b53ebeb..58ac26d5c43 100644 --- a/.storybook-s2/docs/typography.js +++ b/.storybook-s2/docs/typography.js @@ -1,5 +1,5 @@ import { style } from '../../packages/@react-spectrum/s2/style/spectrum-theme' with {type: 'macro'}; -import {Link} from '@react-spectrum/s2'; +import {Link as S2Link} from '@react-spectrum/s2'; import {useFocusRing, useHover} from 'react-aria'; function AnchorLink({id, isHovered}) { @@ -7,7 +7,7 @@ function AnchorLink({id, isHovered}) { const url = `${location.origin}${location.pathname.replace('iframe', 'index')}${location.search.replace('viewMode=docs&id=', 'path=/docs/')}#${id}`; return ( - # +# ); } @@ -59,7 +59,7 @@ export function Strong({children}) { export function Pre({children}) { return ( -+); @@ -68,3 +68,12 @@ export function Pre({children}) { function anchorId(children) { return children.replace(/\s/g, '-').replace(/[^a-zA-Z0-9-_]/g, '').toLowerCase(); } + +export function Link(props) { + return ( +
+ ); +} diff --git a/.storybook-s2/preview.tsx b/.storybook-s2/preview.tsx index fd988359434..b9074b785f3 100644 --- a/.storybook-s2/preview.tsx +++ b/.storybook-s2/preview.tsx @@ -66,7 +66,7 @@ const preview = { }, options: { storySort: { - order: ['Intro', 'Style Macro', 'Workflow Icons', 'Illustrations', 'Release Notes'], + order: ['Intro', 'Style Macro', 'Workflow Icons', 'Illustrations', 'Migrating', 'Release Notes'], method: 'alphabetical' } } @@ -88,9 +88,6 @@ const preview = { }; export const parameters = { - options: { - storySort: (a: any, b: any) => a[1].kind === b[1].kind ? 0 : a[1].id.localeCompare(b[1].id, undefined, { numeric: true }), - }, a11y: { config: { rules: [ diff --git a/packages/@react-spectrum/picker/intl/en-US.json b/packages/@react-spectrum/picker/intl/en-US.json index 05ea63ada2e..2829e8a0db6 100644 --- a/packages/@react-spectrum/picker/intl/en-US.json +++ b/packages/@react-spectrum/picker/intl/en-US.json @@ -1,4 +1,4 @@ { - "placeholder": "Select…", + "placeholder": "Select an option…", "loading": "Loading…" } diff --git a/packages/@react-spectrum/picker/test/Picker.test.js b/packages/@react-spectrum/picker/test/Picker.test.js index 9595777562e..99c1a8cc651 100644 --- a/packages/@react-spectrum/picker/test/Picker.test.js +++ b/packages/@react-spectrum/picker/test/Picker.test.js @@ -70,7 +70,7 @@ describe('Picker', function () { expect(picker).toHaveAttribute('data-testid', 'test'); let label = getAllByText('Test')[0]; - let value = getByText('Select…'); + let value = getByText('Select an option…'); expect(label).toBeVisible(); expect(value).toBeVisible(); }); @@ -362,7 +362,7 @@ describe('Picker', function () { expect(listbox).toBeVisible(); expect(onOpenChange).not.toBeCalled(); - let picker = getByLabelText('Select…'); + let picker = getByLabelText('Select an option…'); expect(picker).toHaveAttribute('aria-expanded', 'true'); expect(picker).toHaveAttribute('aria-controls', listbox.id); @@ -393,7 +393,7 @@ describe('Picker', function () { expect(listbox).toBeVisible(); expect(onOpenChange).not.toBeCalled(); - let picker = getByLabelText('Select…'); + let picker = getByLabelText('Select an option…'); expect(picker).toHaveAttribute('aria-expanded', 'true'); expect(picker).toHaveAttribute('aria-controls', listbox.id); @@ -721,7 +721,7 @@ describe('Picker', function () { expect(listbox).toBeVisible(); expect(onOpenChange).not.toBeCalled(); - let picker = getByLabelText('Select…'); + let picker = getByLabelText('Select an option…'); expect(picker).toHaveAttribute('aria-expanded', 'true'); expect(picker).toHaveAttribute('aria-controls', listbox.id); @@ -751,7 +751,7 @@ describe('Picker', function () { expect(getByRole('listbox')).toBeVisible(); expect(onOpenChange).not.toBeCalled(); - let picker = getByLabelText('Select…'); + let picker = getByLabelText('Select an option…'); expect(picker).toHaveAttribute('aria-expanded', 'true'); let listbox = getByRole('listbox'); @@ -804,7 +804,7 @@ describe('Picker', function () { expect(picker).toHaveAttribute('aria-haspopup', 'listbox'); let label = getAllByText('Test')[0]; - let value = getByText('Select…'); + let value = getByText('Select an option…'); expect(label).toHaveAttribute('id'); expect(value).toHaveAttribute('id'); expect(picker).toHaveAttribute('aria-labelledby', `${value.id} ${label.id}`); @@ -829,7 +829,7 @@ describe('Picker', function () { ); let picker = getByRole('button'); - let value = getByText('Select…'); + let value = getByText('Select an option…'); expect(picker).toHaveAttribute('id'); expect(value).toHaveAttribute('id'); expect(picker).toHaveAttribute('aria-label', 'Test'); @@ -855,7 +855,7 @@ describe('Picker', function () { ); let picker = getByRole('button'); - let value = getByText('Select…'); + let value = getByText('Select an option…'); expect(picker).toHaveAttribute('id'); expect(value).toHaveAttribute('id'); expect(picker).toHaveAttribute('aria-labelledby', `${value.id} foo`); @@ -880,7 +880,7 @@ describe('Picker', function () { ); let picker = getByRole('button'); - let value = getByText('Select…'); + let value = getByText('Select an option…'); expect(picker).toHaveAttribute('id'); expect(value).toHaveAttribute('id'); expect(picker).toHaveAttribute('aria-label', 'Test'); @@ -914,7 +914,7 @@ describe('Picker', function () { expect(span).not.toHaveAttribute('aria-hidden'); let label = span.parentElement; - let value = getByText('Select…'); + let value = getByText('Select an option…'); expect(label).toHaveAttribute('id'); expect(value).toHaveAttribute('id'); expect(picker).toHaveAttribute('aria-labelledby', `${value.id} ${label.id}`); @@ -978,7 +978,7 @@ describe('Picker', function () { ); let picker = getByRole('button'); - expect(picker).toHaveTextContent('Select…'); + expect(picker).toHaveTextContent('Select an option…'); await user.click(picker); act(() => jest.runAllTimers()); @@ -1015,7 +1015,7 @@ describe('Picker', function () { ); let picker = getByRole('button'); - expect(picker).toHaveTextContent('Select…'); + expect(picker).toHaveTextContent('Select an option…'); await user.click(picker); act(() => jest.runAllTimers()); @@ -1086,7 +1086,7 @@ describe('Picker', function () { ); let picker = getByRole('button'); - expect(picker).toHaveTextContent('Select…'); + expect(picker).toHaveTextContent('Select an option…'); await user.click(picker); act(() => jest.runAllTimers()); @@ -1132,7 +1132,7 @@ describe('Picker', function () { ); let picker = getByRole('button'); - expect(picker).toHaveTextContent('Select…'); + expect(picker).toHaveTextContent('Select an option…'); act(() => {picker.focus();}); fireEvent.keyDown(picker, {key: 'ArrowUp'}); @@ -1177,7 +1177,7 @@ describe('Picker', function () { ); let picker = getByRole('button'); - expect(picker).toHaveTextContent('Select…'); + expect(picker).toHaveTextContent('Select an option…'); await user.click(picker); act(() => jest.runAllTimers()); @@ -1223,7 +1223,7 @@ describe('Picker', function () { ); let picker = getByRole('button'); - expect(picker).toHaveTextContent('Select…'); + expect(picker).toHaveTextContent('Select an option…'); expect(onOpenChangeSpy).toHaveBeenCalledTimes(0); await user.click(picker); act(() => jest.runAllTimers()); @@ -1370,7 +1370,7 @@ describe('Picker', function () { ); let picker = getByRole('button'); - expect(picker).toHaveTextContent('Select…'); + expect(picker).toHaveTextContent('Select an option…'); await user.click(picker); act(() => jest.runAllTimers()); @@ -1443,7 +1443,7 @@ describe('Picker', function () { ); let picker = getByRole('button'); - expect(picker).toHaveTextContent('Select…'); + expect(picker).toHaveTextContent('Select an option…'); await user.click(picker); act(() => jest.runAllTimers()); @@ -1545,7 +1545,7 @@ describe('Picker', function () { let picker = getByRole('button'); act(() => {picker.focus();}); - expect(picker).toHaveTextContent('Select…'); + expect(picker).toHaveTextContent('Select an option…'); fireEvent.keyDown(picker, {key: 'ArrowDown'}); act(() => jest.runAllTimers()); @@ -1641,7 +1641,7 @@ describe('Picker', function () { let picker = getByRole('button'); await user.tab(); - expect(picker).toHaveTextContent('Select…'); + expect(picker).toHaveTextContent('Select an option…'); await user.keyboard('{ArrowLeft}'); act(() => jest.runAllTimers()); expect(onSelectionChange).toHaveBeenCalledTimes(1); @@ -1687,7 +1687,7 @@ describe('Picker', function () { let picker = getByRole('button'); act(() => {picker.focus();}); - expect(picker).toHaveTextContent('Select…'); + expect(picker).toHaveTextContent('Select an option…'); fireEvent.keyDown(picker, {key: 't'}); fireEvent.keyUp(picker, {key: 't'}); @@ -1715,7 +1715,7 @@ describe('Picker', function () { let picker = getByRole('button'); act(() => {picker.focus();}); - expect(picker).toHaveTextContent('Select…'); + expect(picker).toHaveTextContent('Select an option…'); fireEvent.keyDown(picker, {key: 't'}); fireEvent.keyUp(picker, {key: 't'}); @@ -1744,7 +1744,7 @@ describe('Picker', function () { let picker = getByRole('button'); act(() => {picker.focus();}); - expect(picker).toHaveTextContent('Select…'); + expect(picker).toHaveTextContent('Select an option…'); fireEvent.keyDown(picker, {key: 't'}); fireEvent.keyUp(picker, {key: 't'}); @@ -1772,7 +1772,7 @@ describe('Picker', function () { ); let picker = getByRole('button'); - expect(picker).toHaveTextContent('Select…'); + expect(picker).toHaveTextContent('Select an option…'); let hiddenLabel = getByText('Test', {hidden: true, selector: 'label'}); expect(hiddenLabel.tagName).toBe('LABEL'); @@ -2500,7 +2500,7 @@ describe('Picker', function () { jest.runAllTimers(); }); - expect(button).toHaveTextContent('Select…'); + expect(button).toHaveTextContent('Select an option…'); expect(listbox).not.toBeInTheDocument(); expect(onClick.mock.calls[0][0].target).toBeInstanceOf(HTMLAnchorElement); expect(onClick.mock.calls[0][0].target.href).toBe('https://google.com/'); diff --git a/packages/@react-spectrum/s2/api-diff.md b/packages/@react-spectrum/s2/api-diff.md index c2d73f8a076..055bc3fc726 100644 --- a/packages/@react-spectrum/s2/api-diff.md +++ b/packages/@react-spectrum/s2/api-diff.md @@ -107,8 +107,9 @@ React Spectrum v3 [style props](https://react-spectrum.adobe.com/react-spectrum/ | Prop | Spectrum 2 | RSP v3 | Comments | |------|------------|--------|----------| +| size | 🟢 `16 \| 20 \| 24 \| 28 \| 32 \| 36 \| 40 \| 44 \| 48 \| 56 \| 64 \| 80 \| 96 \| 112 \| number` | 🔴 `'avatar-size-100' \| 'avatar-size-200' \| 'avatar-size-300' \| 'avatar-size-400' \| 'avatar-size-50' \| 'avatar-size-500' \| 'avatar-size-600' \| 'avatar-size-700' \| 'avatar-size-75' \| string \| number` | Named sizes have been replaced with pixel values. | +| isOverBackground | 🟢 `boolean` | – | | | isDisabled | – | 🔴 `boolean` | Focusable/interactive Avatars aren't supported in S2 yet. | -| size | – | 🔴 `'avatar-size-100' \| 'avatar-size-200' \| 'avatar-size-300' \| 'avatar-size-400' \| 'avatar-size-50' \| 'avatar-size-500' \| 'avatar-size-600' \| 'avatar-size-700' \| 'avatar-size-75' \| (string & {
}) \| number` | This prop has been removed in favor of providing a size via the `styles` prop. | ## Breadcrumbs | Prop | Spectrum 2 | RSP v3 | Comments | @@ -129,8 +130,7 @@ React Spectrum v3 [style props](https://react-spectrum.adobe.com/react-spectrum/ | Prop | Spectrum 2 | RSP v3 | Comments | |------|------------|--------|----------| -| inputRef | 🟢 `MutableRefObject` | – | | -| slot | 🟢 `null \| string` | – | | +| inputRef | 🟢 `RefObject ` | – | | | size | 🟢 `'L' \| 'M' \| 'S' \| 'XL'` | – | | ## CheckboxGroup @@ -274,6 +274,15 @@ React Spectrum v3 [style props](https://react-spectrum.adobe.com/react-spectrum/ | size | 🟢 `'L' \| 'M' \| 'S' \| 'XL'` | – | | | closeOnSelect | – | 🔴 `boolean` | Not yet implemented in S2. | | trigger | – | 🔴 `MenuTriggerType` | Not yet implemented in S2. | +## NumberField + +| Prop | Spectrum 2 | RSP v3 | Comments | +|------|------------|--------|----------| +| size | 🟢 `'L' \| 'M' \| 'S' \| 'XL'` | – | | +| isInvalid | 🟢 `boolean` | – | | +| slot | 🟢 `null \| string` | – | | +| isQuiet | – | 🔴 `boolean` | Not supported in S2 design. | +| validationState | – | 🔴 `ValidationState` | Use `isInvalid` instead. | ## Picker | Prop | Spectrum 2 | RSP v3 | Comments | @@ -304,7 +313,7 @@ React Spectrum v3 [style props](https://react-spectrum.adobe.com/react-spectrum/ | Prop | Spectrum 2 | RSP v3 | Comments | |------|------------|--------|----------| -| inputRef | 🟢 `MutableRefObject ` | – | | +| inputRef | 🟢 `RefObject ` | – | | | slot | 🟢 `null \| string` | – | | ## RadioGroup @@ -364,15 +373,43 @@ React Spectrum v3 [style props](https://react-spectrum.adobe.com/react-spectrum/ | Prop | Spectrum 2 | RSP v3 | Comments | |------|------------|--------|----------| -| inputRef | 🟢 `MutableRefObject ` | – | | +| inputRef | 🟢 `RefObject ` | – | | | slot | 🟢 `null \| string` | – | | | size | 🟢 `'L' \| 'M' \| 'S' \| 'XL'` | – | | +## TabList + +| Prop | Spectrum 2 | RSP v3 | Comments | +|------|------------|--------|----------| +| aria-label | 🟢 `string` | – | | +| aria-labelledby | 🟢 `string` | – | | +| aria-describedby | 🟢 `string` | – | | +| aria-details | 🟢 `string` | – | | +| dependencies | 🟢 `Array ` | – | | +| items | 🟢 `Iterable ` | – | | +| id | – | 🔴 `string` | | +## Tabs + +| Prop | Spectrum 2 | RSP v3 | Comments | +|------|------------|--------|----------| +| slot | 🟢 `null \| string` | – | | +| items | – | 🔴 `Iterable<{}>` | Pass items to `TabList` instead. | +| isQuiet | – | 🔴 `boolean` | Not supported in S2 design. | +| isEmphasized | – | 🔴 `boolean` | Not supported in S2 design. | +| disallowEmptySelection | – | 🔴 `boolean` | Tabs always disallow empty selection. | +## TabPanels + +This component has been removed in S2. Provide ` ` elements as direct children of ` ` instead. + ## TagGroup | Prop | Spectrum 2 | RSP v3 | Comments | |------|------------|--------|----------| | size | 🟢 `'L' \| 'M' \| 'S'` | – | | | isEmphasized | 🟢 `boolean` | – | | +| actionLabel | – | 🔴 `string` | Use `groupActionLabel` instead. | +| onAction | – | 🔴 `() => void` | Use `onGroupAction` instead. | +| groupActionLabel | 🟢 `string` | – | | +| onGroupAction | 🟢 `() => void` | – | | | selectionBehavior | 🟢 `SelectionBehavior` | – | | | disabledKeys | 🟢 `Iterable ` | – | | | selectionMode | 🟢 `SelectionMode` | – | | @@ -381,9 +418,6 @@ React Spectrum v3 [style props](https://react-spectrum.adobe.com/react-spectrum/ | defaultSelectedKeys | 🟢 `'all' \| Iterable ` | – | | | onSelectionChange | 🟢 `(Selection) => void` | – | | | slot | 🟢 `null \| string` | – | | -| actionLabel | – | 🔴 `string` | Not yet implemented in S2.| -| onAction | – | 🔴 `() => void` | Not yet implemented in S2. | -| maxRows | – | 🔴 `number` | Not yet implemented in S2. | | validationState | – | 🔴 `ValidationState` | Use `isInvalid` instead. | ## TextArea diff --git a/packages/@react-spectrum/s2/stories/Tabs.stories.tsx b/packages/@react-spectrum/s2/stories/Tabs.stories.tsx index 900907aedab..82b08c78d3f 100644 --- a/packages/@react-spectrum/s2/stories/Tabs.stories.tsx +++ b/packages/@react-spectrum/s2/stories/Tabs.stories.tsx @@ -21,7 +21,8 @@ const meta: Meta = { component: Tabs, parameters: { layout: 'centered' - } + }, + tags: ['autodocs'] }; export default meta; @@ -74,9 +75,9 @@ export const Disabled = (args: any) => ( export const Icons = (args: any) => ( - - - + + + Arma virumque cano, Troiae qui primus ab oris. diff --git a/packages/@react-spectrum/table/src/TableViewWrapper.tsx b/packages/@react-spectrum/table/src/TableViewWrapper.tsx index 1dda249c33b..5385a6488c2 100644 --- a/packages/@react-spectrum/table/src/TableViewWrapper.tsx +++ b/packages/@react-spectrum/table/src/TableViewWrapper.tsx @@ -10,7 +10,7 @@ * governing permissions and limitations under the License. */ -import type {AriaLabelingProps, DisabledBehavior, DOMProps, DOMRef, Key, SpectrumSelectionProps, StyleProps} from '@react-types/shared'; +import type {AriaLabelingProps, DOMProps, DOMRef, Key, SpectrumSelectionProps, StyleProps} from '@react-types/shared'; import type {ColumnSize, TableProps} from '@react-types/table'; import type {DragAndDropHooks} from '@react-spectrum/dnd'; import React, {JSX, ReactElement} from 'react'; @@ -33,11 +33,6 @@ export interface SpectrumTableProps extends TableProps , SpectrumSelectionP isQuiet?: boolean, /** Sets what the TableView should render when there is no content to display. */ renderEmptyState?: () => JSX.Element, - /** - * Whether `disabledKeys` applies to all interactions, or only selection. - * @default "selection" - */ - disabledBehavior?: DisabledBehavior, /** Handler that is called when a user performs an action on a row. */ onAction?: (key: Key) => void, /** diff --git a/packages/@react-spectrum/table/stories/Table.stories.tsx b/packages/@react-spectrum/table/stories/Table.stories.tsx index 33fc1db14f4..f3bdc80f13f 100644 --- a/packages/@react-spectrum/table/stories/Table.stories.tsx +++ b/packages/@react-spectrum/table/stories/Table.stories.tsx @@ -117,10 +117,6 @@ export default { }, disallowEmptySelection: { control: 'boolean' - }, - disabledBehavior: { - control: 'select', - options: ['all', 'selection'] } } } as ComponentMeta ; diff --git a/packages/@react-spectrum/tabs/test/Tabs.test.js b/packages/@react-spectrum/tabs/test/Tabs.test.js index e402a0995ad..4b839486b94 100644 --- a/packages/@react-spectrum/tabs/test/Tabs.test.js +++ b/packages/@react-spectrum/tabs/test/Tabs.test.js @@ -890,386 +890,4 @@ describe('Tabs', function () { fireEvent.keyDown(tabs[1], {key: 'ArrowRight'}); expect(tabs[2]).toHaveAttribute('aria-selected', 'true'); }); - - describe('when using fragments', function () { - it('renders fragment with children properly', function () { - let container = render( - - - ); - - let tablist = container.getByRole('tablist'); - expect(tablist).toBeTruthy(); - - expect(tablist).toHaveAttribute('aria-orientation', 'horizontal'); - - let tabs = within(tablist).getAllByRole('tab'); - expect(tabs.length).toBe(2); - - for (let tab of tabs) { - expect(tab).toHaveAttribute('tabindex'); - expect(tab).toHaveAttribute('aria-selected'); - let isSelected = tab.getAttribute('aria-selected') === 'true'; - if (isSelected) { - expect(tab).toHaveAttribute('aria-controls'); - let tabpanel = document.getElementById(tab.getAttribute('aria-controls')); - expect(tabpanel).toBeTruthy(); - expect(tabpanel).toHaveAttribute('aria-labelledby', tab.id); - expect(tabpanel).toHaveAttribute('role', 'tabpanel'); - expect(tabpanel).toHaveTextContent('Tab 1 content'); - } - } - }); - - it('renders beginning fragment sibling properly', function () { - let container = render( -- -- <> - -- Tab 1
-- Tab 2
- > -- <> - -- - Tab 1 content -
-- - Tab 2 content -
- > -- - ); - - let tablist = container.getByRole('tablist'); - expect(tablist).toBeTruthy(); - - expect(tablist).toHaveAttribute('aria-orientation', 'horizontal'); - - let tabs = within(tablist).getAllByRole('tab'); - expect(tabs.length).toBe(2); - - for (let tab of tabs) { - expect(tab).toHaveAttribute('tabindex'); - expect(tab).toHaveAttribute('aria-selected'); - let isSelected = tab.getAttribute('aria-selected') === 'true'; - if (isSelected) { - expect(tab).toHaveAttribute('aria-controls'); - let tabpanel = document.getElementById(tab.getAttribute('aria-controls')); - expect(tabpanel).toBeTruthy(); - expect(tabpanel).toHaveAttribute('aria-labelledby', tab.id); - expect(tabpanel).toHaveAttribute('role', 'tabpanel'); - expect(tabpanel).toHaveTextContent('Tab 1 content'); - } - } - }); - - it('renders middle fragment sibling properly', function () { - let container = render( -- -- <> - -- Tab 1
- > -- Tab 2
-- <> - -- - Tab 1 content -
- > -- - Tab 2 content -
-- - ); - - let tablist = container.getByRole('tablist'); - expect(tablist).toBeTruthy(); - - expect(tablist).toHaveAttribute('aria-orientation', 'horizontal'); - - let tabs = within(tablist).getAllByRole('tab'); - expect(tabs.length).toBe(3); - - for (let tab of tabs) { - expect(tab).toHaveAttribute('tabindex'); - expect(tab).toHaveAttribute('aria-selected'); - let isSelected = tab.getAttribute('aria-selected') === 'true'; - if (isSelected) { - expect(tab).toHaveAttribute('aria-controls'); - let tabpanel = document.getElementById(tab.getAttribute('aria-controls')); - expect(tabpanel).toBeTruthy(); - expect(tabpanel).toHaveAttribute('aria-labelledby', tab.id); - expect(tabpanel).toHaveAttribute('role', 'tabpanel'); - expect(tabpanel).toHaveTextContent('Tab 1 content'); - } - } - }); - - it('renders ending fragment sibling properly', function () { - let container = render( -- -- -- Tab 1
- <> -- Tab 2
- > -- Tab 3
-- -- - Tab 1 content -
- <> -- - Tab 2 content -
- > -- - Tab 3 content -
-- - ); - - let tablist = container.getByRole('tablist'); - expect(tablist).toBeTruthy(); - - expect(tablist).toHaveAttribute('aria-orientation', 'horizontal'); - - let tabs = within(tablist).getAllByRole('tab'); - expect(tabs.length).toBe(2); - - for (let tab of tabs) { - expect(tab).toHaveAttribute('tabindex'); - expect(tab).toHaveAttribute('aria-selected'); - let isSelected = tab.getAttribute('aria-selected') === 'true'; - if (isSelected) { - expect(tab).toHaveAttribute('aria-controls'); - let tabpanel = document.getElementById(tab.getAttribute('aria-controls')); - expect(tabpanel).toBeTruthy(); - expect(tabpanel).toHaveAttribute('aria-labelledby', tab.id); - expect(tabpanel).toHaveAttribute('role', 'tabpanel'); - expect(tabpanel).toHaveTextContent('Tab 1 content'); - } - } - }); - - it('renders list and panel fragment siblings in non-matching positions properly, list fragment first', function () { - let container = render( -- -- -- Tab 1
- <> -- Tab 2
- > -- -- - Tab 1 content -
- <> -- - Tab 2 content -
- > -- - ); - - let tablist = container.getByRole('tablist'); - expect(tablist).toBeTruthy(); - - expect(tablist).toHaveAttribute('aria-orientation', 'horizontal'); - - let tabs = within(tablist).getAllByRole('tab'); - expect(tabs.length).toBe(2); - - for (let tab of tabs) { - expect(tab).toHaveAttribute('tabindex'); - expect(tab).toHaveAttribute('aria-selected'); - let isSelected = tab.getAttribute('aria-selected') === 'true'; - if (isSelected) { - expect(tab).toHaveAttribute('aria-controls'); - let tabpanel = document.getElementById(tab.getAttribute('aria-controls')); - expect(tabpanel).toBeTruthy(); - expect(tabpanel).toHaveAttribute('aria-labelledby', tab.id); - expect(tabpanel).toHaveAttribute('role', 'tabpanel'); - expect(tabpanel).toHaveTextContent('Tab 1 content'); - } - } - }); - - it('renders list and panel fragment siblings in non-matching positions properly, panel fragment first', function () { - let container = render( -- -- <> - -- Tab 1
- > -- Tab 2
-- -- - Tab 1 content -
- <> -- - Tab 2 content -
- > -- - ); - - let tablist = container.getByRole('tablist'); - expect(tablist).toBeTruthy(); - - expect(tablist).toHaveAttribute('aria-orientation', 'horizontal'); - - let tabs = within(tablist).getAllByRole('tab'); - expect(tabs.length).toBe(2); - - for (let tab of tabs) { - expect(tab).toHaveAttribute('tabindex'); - expect(tab).toHaveAttribute('aria-selected'); - let isSelected = tab.getAttribute('aria-selected') === 'true'; - if (isSelected) { - expect(tab).toHaveAttribute('aria-controls'); - let tabpanel = document.getElementById(tab.getAttribute('aria-controls')); - expect(tabpanel).toBeTruthy(); - expect(tabpanel).toHaveAttribute('aria-labelledby', tab.id); - expect(tabpanel).toHaveAttribute('role', 'tabpanel'); - expect(tabpanel).toHaveTextContent('Tab 1 content'); - } - } - }); - - it('renders fragment with renderer properly', function () { - let container = render( -- -- -- Tab 1
- <> -- Tab 2
- > -- <> - -- - Tab 1 content -
- > -- - Tab 2 content -
-- - ); - - let tablist = container.getByRole('tablist'); - expect(tablist).toBeTruthy(); - - expect(tablist).toHaveAttribute('aria-orientation', 'horizontal'); - - let tabs = within(tablist).getAllByRole('tab'); - expect(tabs.length).toBe(3); - - for (let tab of tabs) { - expect(tab).toHaveAttribute('tabindex'); - expect(tab).toHaveAttribute('aria-selected'); - let isSelected = tab.getAttribute('aria-selected') === 'true'; - if (isSelected) { - expect(tab).toHaveAttribute('aria-controls'); - let tabpanel = document.getElementById(tab.getAttribute('aria-controls')); - expect(tabpanel).toBeTruthy(); - expect(tabpanel).toHaveAttribute('aria-labelledby', tab.id); - expect(tabpanel).toHaveAttribute('role', 'tabpanel'); - expect(tabpanel).toHaveTextContent(defaultItems[0].children); - } - } - }); - - it('renders fragment with mapper properly', function () { - let container = render( -- -- <> - {item => ( - -- - )} - > -
- <> - {item => ( - -- - {item.children} -
- )} - > -- - ); - - let tablist = container.getByRole('tablist'); - expect(tablist).toBeTruthy(); - - expect(tablist).toHaveAttribute('aria-orientation', 'horizontal'); - - let tabs = within(tablist).getAllByRole('tab'); - expect(tabs.length).toBe(3); - - for (let tab of tabs) { - expect(tab).toHaveAttribute('tabindex'); - expect(tab).toHaveAttribute('aria-selected'); - let isSelected = tab.getAttribute('aria-selected') === 'true'; - if (isSelected) { - expect(tab).toHaveAttribute('aria-controls'); - let tabpanel = document.getElementById(tab.getAttribute('aria-controls')); - expect(tabpanel).toBeTruthy(); - expect(tabpanel).toHaveAttribute('aria-labelledby', tab.id); - expect(tabpanel).toHaveAttribute('role', 'tabpanel'); - expect(tabpanel).toHaveTextContent(defaultItems[0].children); - } - } - }); - }); }); diff --git a/packages/@react-stately/collections/src/CollectionBuilder.ts b/packages/@react-stately/collections/src/CollectionBuilder.ts index 09f804818b4..3d7bae6c1e6 100644 --- a/packages/@react-stately/collections/src/CollectionBuilder.ts +++ b/packages/@react-stately/collections/src/CollectionBuilder.ts @@ -27,15 +27,10 @@ export class CollectionBuilder- -- <> - {defaultItems.map(item => ( - -- - ))} - > -
- <> - {defaultItems.map(item => ( - -- - {item.children} -
- ))} - > -{ return iterable(() => this.iterateCollection(props)); } - private *iterateCollection(props: CollectionBase ): Generator > { + private *iterateCollection(props: CollectionBase ) { let {children, items} = props; - if (React.isValidElement<{children: CollectionElement }>(children) && children.type === React.Fragment) { - yield* this.iterateCollection({ - children: children.props.children, - items - }); - } else if (typeof children === 'function') { + if (typeof children === 'function') { if (!items) { throw new Error('props.children was a function but props.items is missing'); } @@ -95,25 +90,6 @@ export class CollectionBuilder { } private *getFullNode(partialNode: PartialNode , state: CollectionBuilderState, parentKey?: Key, parentNode?: Node ): Generator > { - if (React.isValidElement<{children: CollectionElement }>(partialNode.element) && partialNode.element.type === React.Fragment) { - let children: CollectionElement [] = []; - - React.Children.forEach(partialNode.element.props.children, child => { - children.push(child); - }); - - let index = partialNode.index; - - for (const child of children) { - yield* this.getFullNode({ - element: child, - index: index++ - }, state, parentKey, parentNode); - } - - return; - } - // If there's a value instead of an element on the node, and a parent renderer function is available, // use it to render an element for the value. let element = partialNode.element; diff --git a/scripts/api-diff.js b/scripts/api-diff.js index 6ab0f1a3393..b5615236152 100644 --- a/scripts/api-diff.js +++ b/scripts/api-diff.js @@ -39,6 +39,7 @@ merge(require('../dist/branch-api/@react-spectrum/inlinealert/dist/api.json')); merge(require('../dist/branch-api/@react-spectrum/link/dist/api.json')); merge(require('../dist/branch-api/@react-spectrum/menu/dist/api.json')); merge(require('../dist/branch-api/@react-spectrum/meter/dist/api.json')); +merge(require('../dist/branch-api/@react-spectrum/numberfield/dist/api.json')); merge(require('../dist/branch-api/@react-spectrum/picker/dist/api.json')); merge(require('../dist/branch-api/@react-spectrum/progress/dist/api.json')); merge(require('../dist/branch-api/@react-spectrum/provider/dist/api.json')); @@ -47,6 +48,7 @@ merge(require('../dist/branch-api/@react-spectrum/searchfield/dist/api.json')); merge(require('../dist/branch-api/@react-spectrum/slider/dist/api.json')); merge(require('../dist/branch-api/@react-spectrum/statuslight/dist/api.json')); merge(require('../dist/branch-api/@react-spectrum/switch/dist/api.json')); +merge(require('../dist/branch-api/@react-spectrum/tabs/dist/api.json')); merge(require('../dist/branch-api/@react-spectrum/tag/dist/api.json')); merge(require('../dist/branch-api/@react-spectrum/textfield/dist/api.json')); merge(require('../dist/branch-api/@react-spectrum/tooltip/dist/api.json')); diff --git a/scripts/diff.js b/scripts/diff.js index 0b3a88b031e..268c840a3c2 100644 --- a/scripts/diff.js +++ b/scripts/diff.js @@ -2,8 +2,25 @@ const exec = require('child_process').execSync; const spawn = require('child_process').spawnSync; const fs = require('fs'); -let packages = JSON.parse(exec('yarn workspaces info --json').toString().split('\n').slice(1, -2).join('\n')); -let uuid = require('uuid')(); +let workspaceLookup = {}; +let packages = exec('yarn workspaces list --json -v').toString().split('\n') + .map(line => { + try { + let result = JSON.parse(line); + workspaceLookup[result.location] = result.name; + return result; + } catch (e) { + console.log(e) + // ignore empty lines + } + }) + .filter(Boolean) + .reduce((acc, item) => { + acc[item.name] = item; + acc[item.name].workspaceDependencies = item.workspaceDependencies.map(dep => workspaceLookup[dep]); + return acc; + }, {}); +let uuid = require('uuid').v4(); let ksdiff = process.argv.includes('--ksdiff'); let codeOnly = process.argv.includes('--code-only');