diff --git a/packages/@react-spectrum/s2/src/ActionBar.tsx b/packages/@react-spectrum/s2/src/ActionBar.tsx index e7b65502b36..3bb7745b12f 100644 --- a/packages/@react-spectrum/s2/src/ActionBar.tsx +++ b/packages/@react-spectrum/s2/src/ActionBar.tsx @@ -12,6 +12,7 @@ import {ActionButtonGroup} from './ActionButtonGroup'; import {announce} from 'react-aria/private/live-announcer/LiveAnnouncer'; +import {banner, StyleProps} from './style-utils' with {type: 'macro'}; import {CloseButton} from './CloseButton'; import {ContextValue, SlotProps} from 'react-aria-components/slots'; import { @@ -31,7 +32,6 @@ import {DOMProps, DOMRef, DOMRefValue, Key} from '@react-types/shared'; import {FocusScope} from 'react-aria/FocusScope'; import intlMessages from '../intl/*.json'; import {lightDark, style} from '../style' with {type: 'macro'}; -import {StyleProps} from './style-utils' with {type: 'macro'}; import {useControlledState} from 'react-stately/useControlledState'; import {useDOMRef} from './useDOMRef'; import {useEnterAnimation, useExitAnimation} from 'react-aria/private/utils/animation'; @@ -42,6 +42,7 @@ import {useResizeObserver} from 'react-aria/private/utils/useResizeObserver'; import {useSpectrumContextProps} from './useSpectrumContextProps'; const actionBarStyles = style({ + ...banner(), borderRadius: 'lg', '--s2-container-bg': { type: 'backgroundColor', @@ -60,10 +61,7 @@ const actionBarStyles = style({ isEmphasized: 'transparent', forcedColors: 'ButtonBorder' }, - paddingX: 8, - paddingY: 12, display: 'flex', - gap: 16, alignItems: 'center', position: { isInContainer: 'absolute' @@ -194,7 +192,14 @@ const ActionBarInner = forwardRef(function ActionBarInner( {...keyboardProps} className={ (props.UNSAFE_className || '') + - actionBarStyles({isEmphasized, isInContainer: !!scrollRef, isEntering, isExiting}) + actionBarStyles({ + isEmphasized, + isInContainer: !!scrollRef, + isEntering, + isExiting, + orientation: 'horizontal', + density: 'compact' + }) } style={{ insetInlineEnd: `calc(var(--insetEnd) + ${scrollbarWidth}px)`, diff --git a/packages/@react-spectrum/s2/src/ActionButtonGroup.tsx b/packages/@react-spectrum/s2/src/ActionButtonGroup.tsx index 7530098a6d5..fa43e823ce5 100644 --- a/packages/@react-spectrum/s2/src/ActionButtonGroup.tsx +++ b/packages/@react-spectrum/s2/src/ActionButtonGroup.tsx @@ -15,6 +15,7 @@ import {ContextValue, SlotProps} from 'react-aria-components/slots'; import {createContext, ForwardedRef, forwardRef, ReactNode} from 'react'; import { getAllowedOverrides, + groupGap, StylesPropWithHeight, UnsafeStyles } from './style-utils' with {type: 'macro'}; @@ -70,20 +71,7 @@ export const actionGroupStyle = style( vertical: 'column' } }, - gap: { - density: { - compact: 2, - regular: { - size: { - XS: 4, - S: 4, - M: 8, - L: 8, - XL: 8 - } - } - } - } + gap: groupGap() }, getAllowedOverrides({height: true}) ); diff --git a/packages/@react-spectrum/s2/src/Breadcrumbs.tsx b/packages/@react-spectrum/s2/src/Breadcrumbs.tsx index 4c1c45e7829..ca0bf9d68e8 100644 --- a/packages/@react-spectrum/s2/src/Breadcrumbs.tsx +++ b/packages/@react-spectrum/s2/src/Breadcrumbs.tsx @@ -35,6 +35,7 @@ import { import {ContextValue, Provider} from 'react-aria-components/slots'; import { controlFont, + controlGap, controlSize, getAllowedOverrides, StyleProps @@ -112,13 +113,7 @@ const wrapper = style( flexGrow: 1, flexShrink: 0, flexBasis: 0, - gap: { - size: { - // TODO: why do these scale but other spacings don't? - M: size(6), // breadcrumbs-text-to-separator-medium - L: size(9) // breadcrumbs-text-to-separator-large - } - }, + gap: controlGap(), padding: 0, transition: 'default', marginTop: 0, diff --git a/packages/@react-spectrum/s2/src/ButtonGroup.tsx b/packages/@react-spectrum/s2/src/ButtonGroup.tsx index 07e86094ce2..7eb562b91a5 100644 --- a/packages/@react-spectrum/s2/src/ButtonGroup.tsx +++ b/packages/@react-spectrum/s2/src/ButtonGroup.tsx @@ -15,7 +15,7 @@ import {ContextValue, Provider, SlotProps} from 'react-aria-components/slots'; import {createContext, forwardRef, ReactNode, useCallback, useRef} from 'react'; import {DOMProps, DOMRef, DOMRefValue} from '@react-types/shared'; import {filterDOMProps} from 'react-aria/filterDOMProps'; -import {getAllowedOverrides, StyleProps} from './style-utils' with {type: 'macro'}; +import {getAllowedOverrides, groupGap, StyleProps} from './style-utils' with {type: 'macro'}; import {style} from '../style' with {type: 'macro'}; import {useDOMRef} from './useDOMRef'; import {useLayoutEffect} from 'react-aria/private/utils/useLayoutEffect'; @@ -66,14 +66,7 @@ const buttongroup = style( display: 'inline-flex', position: 'relative', maxWidth: 'full', - gap: { - size: { - S: 8, - M: 12, - L: 12, - XL: 12 - } - }, + gap: groupGap(), flexDirection: { default: 'row', orientation: { diff --git a/packages/@react-spectrum/s2/src/Checkbox.tsx b/packages/@react-spectrum/s2/src/Checkbox.tsx index a324ee21473..dc2afdc5df2 100644 --- a/packages/@react-spectrum/s2/src/Checkbox.tsx +++ b/packages/@react-spectrum/s2/src/Checkbox.tsx @@ -24,6 +24,7 @@ import {ContextValue, useSlottedContext} from 'react-aria-components/slots'; import { controlBorderRadius, controlFont, + controlGap, controlSize, getAllowedOverrides, StyleProps @@ -89,7 +90,7 @@ const field = style( default: ['max-content', '1fr'], isNoVisibleLabel: ['max-content'] }, - columnGap: 'text-to-control', + columnGap: controlGap(), alignContent: 'start', width: { default: 'fit', diff --git a/packages/@react-spectrum/s2/src/CheckboxGroup.tsx b/packages/@react-spectrum/s2/src/CheckboxGroup.tsx index 071c1f6ac0e..210495a3162 100644 --- a/packages/@react-spectrum/s2/src/CheckboxGroup.tsx +++ b/packages/@react-spectrum/s2/src/CheckboxGroup.tsx @@ -25,7 +25,7 @@ import { Orientation, SpectrumLabelableProps } from '@react-types/shared'; -import {field, getAllowedOverrides, StyleProps} from './style-utils' with {type: 'macro'}; +import {field, getAllowedOverrides, groupGap, StyleProps} from './style-utils' with {type: 'macro'}; import {FieldLabel, HelpText} from './Field'; import {FormContext, useFormProps} from './Form'; import {style} from '../style' with {type: 'macro'}; @@ -104,12 +104,7 @@ export const CheckboxGroup = forwardRef(function CheckboxGroup( UNSAFE_className + style( { - ...field(), - // Double the usual gap because of the internal padding within checkbox that spectrum has. - '--field-gap': { - type: 'rowGap', - value: 'calc(var(--field-height) - 1lh)' - } + ...field() }, getAllowedOverrides() )( @@ -146,7 +141,7 @@ export const CheckboxGroup = forwardRef(function CheckboxGroup( } }, lineHeight: 'ui', - rowGap: '--field-gap', + rowGap: groupGap().density.spacious, // Spectrum uses a fixed spacing value for horizontal, // but the gap changes depending on t-shirt size in vertical. columnGap: 16, diff --git a/packages/@react-spectrum/s2/src/ColorSlider.tsx b/packages/@react-spectrum/s2/src/ColorSlider.tsx index b1031a87424..b8b09599625 100644 --- a/packages/@react-spectrum/s2/src/ColorSlider.tsx +++ b/packages/@react-spectrum/s2/src/ColorSlider.tsx @@ -17,7 +17,12 @@ import { import {ColorHandle} from './ColorHandle'; import {ContextValue} from 'react-aria-components/slots'; -import {controlFont, getAllowedOverrides, StyleProps} from './style-utils' with {type: 'macro'}; +import { + controlFont, + controlGap, + getAllowedOverrides, + StyleProps +} from './style-utils' with {type: 'macro'}; import {createContext, forwardRef, useRef} from 'react'; import { DOMRef, @@ -91,7 +96,7 @@ export const ColorSlider = forwardRef(function ColorSlider( }, gridTemplateColumns: ['1fr', 'auto'], gridTemplateAreas: ['label output', 'track track'], - rowGap: 4 + rowGap: controlGap().size.S }, getAllowedOverrides() )(renderProps, styles) diff --git a/packages/@react-spectrum/s2/src/ColorSwatchPicker.tsx b/packages/@react-spectrum/s2/src/ColorSwatchPicker.tsx index cf96d46c72d..5829193fe57 100644 --- a/packages/@react-spectrum/s2/src/ColorSwatchPicker.tsx +++ b/packages/@react-spectrum/s2/src/ColorSwatchPicker.tsx @@ -20,8 +20,8 @@ import {ColorSwatchProps, InternalColorSwatchContext} from './ColorSwatch'; import {ContextValue, SlotProps} from 'react-aria-components/slots'; import {createContext, forwardRef, ReactElement, ReactNode} from 'react'; import {DOMRef, DOMRefValue, ValueBase} from '@react-types/shared'; -import {focusRing, space, style} from '../style' with {type: 'macro'}; -import {getAllowedOverrides, StyleProps} from './style-utils' with {type: 'macro'}; +import {focusRing, style} from '../style' with {type: 'macro'}; +import {getAllowedOverrides, groupGap, StyleProps} from './style-utils' with {type: 'macro'}; import {useDOMRef} from './useDOMRef'; import {useSpectrumContextProps} from './useSpectrumContextProps'; @@ -81,9 +81,9 @@ export const ColorSwatchPicker = forwardRef(function ColorSwatchPicker( flexWrap: 'wrap', gap: { density: { - compact: space(2), - regular: 4, - spacious: space(6) + compact: groupGap().density.compact, + regular: groupGap().density.default.size.XS, + spacious: groupGap().density.default.size.M } } }, diff --git a/packages/@react-spectrum/s2/src/ComboBox.tsx b/packages/@react-spectrum/s2/src/ComboBox.tsx index 231664bc8ed..6cf4b467b85 100644 --- a/packages/@react-spectrum/s2/src/ComboBox.tsx +++ b/packages/@react-spectrum/s2/src/ComboBox.tsx @@ -48,7 +48,9 @@ import { control, controlBorderRadius, controlFont, + controlPadding, controlSize, + controlTemplate, field, fieldInput, getAllowedOverrides, @@ -70,7 +72,6 @@ import { } from 'react'; import {createFocusableRef} from './useDOMRef'; import {createLeafComponent} from 'react-aria/CollectionBuilder'; -import {edgeToText} from '../style/spectrum-theme' with {type: 'macro'}; import {FieldErrorIcon, FieldGroup, FieldLabel, HelpText, Input} from './Field'; import {FormContext, useFormProps} from './Form'; import {forwardRefType} from './types'; @@ -229,7 +230,7 @@ const progressCircleStyles = style({ } }, marginStart: { - isInput: 'text-to-visual' + isInput: 'text-to-visual' // TODO } }); @@ -252,7 +253,7 @@ const emptyStateText = style({ }, display: 'flex', alignItems: 'center', - paddingStart: 'edge-to-text' + paddingStart: 'edge-to-text' // TODO }); export let listbox = style<{size: 'S' | 'M' | 'L' | 'XL'}>({ @@ -265,6 +266,7 @@ export let listbox = style<{size: 'S' | 'M' | 'L' | 'XL'}>({ fontFamily: 'sans', fontSize: controlFont(), outlineStyle: 'none' + // TODO where to put popover padding like picker? }); export let listboxItem = style( @@ -292,10 +294,34 @@ export let listboxItem = style( gridTemplateAreas: ['. checkmark icon label .', '. . . description .'], gridTemplateColumns: { size: { - S: [edgeToText(24), 'auto', 'auto', 'minmax(0, 1fr)', edgeToText(24)], - M: [edgeToText(32), 'auto', 'auto', 'minmax(0, 1fr)', edgeToText(32)], - L: [edgeToText(40), 'auto', 'auto', 'minmax(0, 1fr)', edgeToText(40)], - XL: [edgeToText(48), 'auto', 'auto', 'minmax(0, 1fr)', edgeToText(48)] + S: [ + controlPadding({size: 'S'}), + 'auto', + 'auto', + 'minmax(0, 1fr)', + controlPadding({size: 'S'}) + ], + M: [ + controlPadding({size: 'M'}), + 'auto', + 'auto', + 'minmax(0, 1fr)', + controlPadding({size: 'M'}) + ], + L: [ + controlPadding({size: 'L'}), + 'auto', + 'auto', + 'minmax(0, 1fr)', + controlPadding({size: 'L'}) + ], + XL: [ + controlPadding({size: 'XL'}), + 'auto', + 'auto', + 'minmax(0, 1fr)', + controlPadding({size: 'XL'}) + ] } }, gridTemplateRows: { @@ -324,26 +350,12 @@ export let listboxHeader = style<{size?: 'S' | 'M' | 'L' | 'XL'}>({ boxSizing: 'border-box', minHeight: controlSize(), paddingY: centerPadding(), - marginX: { - size: { - S: `[${edgeToText(24)}]`, - M: `[${edgeToText(32)}]`, - L: `[${edgeToText(40)}]`, - XL: `[${edgeToText(48)}]` - } - } + marginX: controlTemplate().paddingX }); const separatorWrapper = style({ display: 'flex', - marginX: { - size: { - S: `[${edgeToText(24)}]`, - M: `[${edgeToText(32)}]`, - L: `[${edgeToText(40)}]`, - XL: `[${edgeToText(48)}]` - } - }, + marginX: controlTemplate().paddingX, height: 12, alignItems: 'center' }); @@ -360,7 +372,7 @@ const dividerStyle = style({ const avatar = style({ gridArea: 'icon', - marginEnd: 'text-to-visual' + marginEnd: 'text-to-visual' // TODO }); // Not from any design, just following the sizing of the existing rows diff --git a/packages/@react-spectrum/s2/src/ContextualHelp.tsx b/packages/@react-spectrum/s2/src/ContextualHelp.tsx index 6db9e3e1012..fb7a8c215de 100644 --- a/packages/@react-spectrum/s2/src/ContextualHelp.tsx +++ b/packages/@react-spectrum/s2/src/ContextualHelp.tsx @@ -1,5 +1,6 @@ import {ActionButton} from './ActionButton'; import {AriaLabelingProps, DOMProps, FocusableRef, FocusableRefValue} from '@react-types/shared'; +import {container, containerPadding, StyleProps} from './style-utils' with {type: 'macro'}; import { ContentContext, FooterContext, @@ -18,8 +19,7 @@ import {mergeProps} from 'react-aria/mergeProps'; import {mergeStyles} from '../style/runtime'; import {Placement} from 'react-aria-components/Popover'; import {Popover, PopoverDialogProps} from './Popover'; -import {space, style} from '../style' with {type: 'macro'}; -import {StyleProps} from './style-utils' with {type: 'macro'}; +import {style} from '../style' with {type: 'macro'}; import {TextContext} from 'react-aria-components/Text'; import {useId} from 'react-aria/useId'; import {useLabels} from 'react-aria/private/utils/useLabels'; @@ -34,17 +34,17 @@ export interface ContextualHelpPopoverProps extends Omit diff --git a/packages/@react-spectrum/s2/src/CustomDialog.tsx b/packages/@react-spectrum/s2/src/CustomDialog.tsx index 36845f9732e..b7835748c1c 100644 --- a/packages/@react-spectrum/s2/src/CustomDialog.tsx +++ b/packages/@react-spectrum/s2/src/CustomDialog.tsx @@ -52,7 +52,7 @@ const dialogStyle = style( padding: { padding: { default: { - default: 24, + default: 24, // TODO: what should these be? sm: 32 }, none: 0 diff --git a/packages/@react-spectrum/s2/src/DateField.tsx b/packages/@react-spectrum/s2/src/DateField.tsx index bd1355d1e3c..a595651bce1 100644 --- a/packages/@react-spectrum/s2/src/DateField.tsx +++ b/packages/@react-spectrum/s2/src/DateField.tsx @@ -21,13 +21,14 @@ import { } from 'react-aria-components/DateField'; import {ContextValue} from 'react-aria-components/slots'; -import {createContext, forwardRef, PropsWithChildren, ReactElement, Ref, useContext} from 'react'; import { + controlTemplate, field, fieldInput, getAllowedOverrides, StyleProps } from './style-utils' with {type: 'macro'}; +import {createContext, forwardRef, PropsWithChildren, ReactElement, Ref, useContext} from 'react'; import {FieldErrorIcon, FieldGroup, FieldLabel, HelpText} from './Field'; import {FormContext} from 'react-aria-components/Form'; import { @@ -168,7 +169,7 @@ export const DateField = /*#__PURE__*/ (forwardRef as forwardRefType)(function D styles={style({ ...fieldInput(), textWrap: 'nowrap', - paddingX: 'edge-to-text' + paddingX: controlTemplate().paddingX })({size})}> diff --git a/packages/@react-spectrum/s2/src/DatePicker.tsx b/packages/@react-spectrum/s2/src/DatePicker.tsx index 7b457036761..19416af1701 100644 --- a/packages/@react-spectrum/s2/src/DatePicker.tsx +++ b/packages/@react-spectrum/s2/src/DatePicker.tsx @@ -10,23 +10,27 @@ * governing permissions and limitations under the License. */ +import { + accessoryGap, + containerPadding, + control, + controlBorderRadius, + controlGap, + field, + fieldInput, + getAllowedOverrides, + StyleProps +} from './style-utils' with {type: 'macro'}; import { DatePicker as AriaDatePicker, DatePickerProps as AriaDatePickerProps, DateValue } from 'react-aria-components/DatePicker'; -import {baseColor, focusRing, fontRelative, space, style} from '../style' with {type: 'macro'}; +import {baseColor, focusRing, fontRelative, style} from '../style' with {type: 'macro'}; import {Button, ButtonRenderProps} from 'react-aria-components/Button'; import {Calendar, CalendarProps} from './Calendar'; import CalendarIcon from '../s2wf-icons/S2_Icon_Calendar_20_N.svg'; import {ContextValue, Provider} from 'react-aria-components/slots'; -import { - controlBorderRadius, - field, - fieldInput, - getAllowedOverrides, - StyleProps -} from './style-utils' with {type: 'macro'}; import { createContext, forwardRef, @@ -116,7 +120,7 @@ const inputButton = style @@ -296,12 +293,11 @@ export function CalendarPopover(
diff --git a/packages/@react-spectrum/s2/src/DateRangePicker.tsx b/packages/@react-spectrum/s2/src/DateRangePicker.tsx index 53f48264260..5137deb0c74 100644 --- a/packages/@react-spectrum/s2/src/DateRangePicker.tsx +++ b/packages/@react-spectrum/s2/src/DateRangePicker.tsx @@ -10,6 +10,14 @@ * governing permissions and limitations under the License. */ +import { + accessoryGap, + control, + field, + fieldInput, + getAllowedOverrides, + StyleProps +} from './style-utils' with {type: 'macro'}; import { DateRangePicker as AriaDateRangePicker, DateRangePickerProps as AriaDateRangePickerProps, @@ -19,12 +27,6 @@ import {CalendarButton, CalendarPopover, timeField} from './DatePicker'; import {ContextValue} from 'react-aria-components/slots'; import {createContext, forwardRef, ReactElement, Ref, useContext, useState} from 'react'; import {DateInput, DateInputContainer, InvalidIndicator} from './DateField'; -import { - field, - fieldInput, - getAllowedOverrides, - StyleProps -} from './style-utils' with {type: 'macro'}; import {FieldGroup, FieldLabel, HelpText} from './Field'; import {FormContext} from 'react-aria-components/Form'; import { @@ -165,8 +167,8 @@ export const DateRangePicker = /*#__PURE__*/ (forwardRef as forwardRefType)( styles={style({ ...fieldInput(), textWrap: 'nowrap', - paddingStart: 'edge-to-text', - paddingEnd: 4 + paddingStart: control({}).paddingX, + paddingEnd: accessoryGap() })({size})}> diff --git a/packages/@react-spectrum/s2/src/Disclosure.tsx b/packages/@react-spectrum/s2/src/Disclosure.tsx index 1ea0a0baa0c..23cd16112dd 100644 --- a/packages/@react-spectrum/s2/src/Disclosure.tsx +++ b/packages/@react-spectrum/s2/src/Disclosure.tsx @@ -19,20 +19,21 @@ import { forwardRefType, GlobalDOMAttributes } from '@react-types/shared'; -import { - baseColor, - centerPadding, - focusRing, - lightDark, - space, - style -} from '../style' with {type: 'macro'}; +import {baseColor, centerPadding, focusRing, lightDark, style} from '../style' with {type: 'macro'}; import {Button} from 'react-aria-components/Button'; import {CenterBaseline} from './CenterBaseline'; import Chevron from '../ui-icons/Chevron'; import {ContextValue, Provider, useSlottedContext} from 'react-aria-components/slots'; +import { + controlTemplate, + getAllowedOverrides, + StyleProps, + StylesPropWithFont, + UnsafeStyles, + verticalPadding +} from './style-utils' with {type: 'macro'}; import { DisclosureStateContext, Disclosure as RACDisclosure, @@ -41,12 +42,6 @@ import { DisclosureProps as RACDisclosureProps } from 'react-aria-components/Disclosure'; import {filterDOMProps} from 'react-aria/filterDOMProps'; -import { - getAllowedOverrides, - StyleProps, - StylesPropWithFont, - UnsafeStyles -} from './style-utils' with {type: 'macro'}; import {Heading} from 'react-aria-components/Heading'; import React, {createContext, forwardRef, ReactNode, useContext} from 'react'; import {useDOMRef} from './useDOMRef'; @@ -166,6 +161,7 @@ const headingStyle = style({ const buttonStyles = style( { ...focusRing(), + ...controlTemplate(), outlineOffset: -2, font: 'heading', color: { @@ -189,9 +185,8 @@ const buttonStyles = style( display: 'flex', flexGrow: 1, alignItems: 'baseline', - paddingX: 'calc(self(minHeight) * 3/8 - 1px)', paddingY: centerPadding(), - gap: 'calc(self(minHeight) * 3/8 - 1px)', + gap: controlTemplate().paddingX, minHeight: { // compact is equivalent to 'control', but other densities have more padding. size: { @@ -282,7 +277,7 @@ function DisclosureHeaderWithForwardRef(props: DisclosureHeaderProps, ref: DOMRe
{children} @@ -359,16 +354,9 @@ const panelStyles = style({ }); const panelInner = style({ - paddingTop: 8, - paddingBottom: 16, - paddingX: { - size: { - S: 8, - M: space(9), - L: 12, - XL: space(15) - } - } + paddingTop: verticalPadding('L'), + paddingBottom: verticalPadding('2XL'), + paddingX: controlTemplate().paddingX }); /** diff --git a/packages/@react-spectrum/s2/src/DragPreview.tsx b/packages/@react-spectrum/s2/src/DragPreview.tsx index 1836f505404..7b73a43cc76 100644 --- a/packages/@react-spectrum/s2/src/DragPreview.tsx +++ b/packages/@react-spectrum/s2/src/DragPreview.tsx @@ -12,7 +12,7 @@ import {baseColor, fontRelative, style} from '../style' with {type: 'macro'}; import {centerBaseline} from './CenterBaseline'; -import {controlFont} from './style-utils' with {type: 'macro'}; +import {controlFont, controlGap} from './style-utils' with {type: 'macro'}; import {DEFAULT_SLOT, Provider} from 'react-aria-components/slots'; import {DragItem} from '@react-types/shared'; import {IconContext} from './Icon'; @@ -64,7 +64,7 @@ export let iconCenterWrapper = style({ export let icon = style({ display: 'block', size: fontRelative(20), - marginEnd: 'text-to-visual', + marginEnd: controlGap().size.M, '--iconPrimary': { type: 'fill', value: 'currentColor' diff --git a/packages/@react-spectrum/s2/src/DropZone.tsx b/packages/@react-spectrum/s2/src/DropZone.tsx index d080e637af4..a7f8a223511 100644 --- a/packages/@react-spectrum/s2/src/DropZone.tsx +++ b/packages/@react-spectrum/s2/src/DropZone.tsx @@ -10,21 +10,20 @@ * governing permissions and limitations under the License. */ +import { + containerPadding, + getAllowedOverrides, + StylesPropWithHeight, + UnsafeStyles +} from './style-utils' with {type: 'macro'}; import {ContextValue} from 'react-aria-components/slots'; - import {createContext, forwardRef, ReactNode} from 'react'; - import {DOMProps, DOMRef, DOMRefValue, GlobalDOMAttributes} from '@react-types/shared'; import { DropZoneRenderProps, DropZone as RACDropZone, DropZoneProps as RACDropZoneProps } from 'react-aria-components/DropZone'; -import { - getAllowedOverrides, - StylesPropWithHeight, - UnsafeStyles -} from './style-utils' with {type: 'macro'}; import {IllustratedMessageContext} from './IllustratedMessage'; import intlMessages from '../intl/*.json'; import {style} from '../style' with {type: 'macro'}; @@ -94,7 +93,7 @@ const dropzone = style( isFocusVisible: 'blue-800' }, borderRadius: 'lg', - padding: 24, + padding: containerPadding({size: 'XL'}), boxSizing: 'border-box' }, getAllowedOverrides({height: true}) diff --git a/packages/@react-spectrum/s2/src/Form.tsx b/packages/@react-spectrum/s2/src/Form.tsx index 9c10c0b776f..e70f87347b2 100644 --- a/packages/@react-spectrum/s2/src/Form.tsx +++ b/packages/@react-spectrum/s2/src/Form.tsx @@ -10,9 +10,9 @@ * governing permissions and limitations under the License. */ +import {controlGap, getAllowedOverrides, StyleProps} from './style-utils' with {type: 'macro'}; import {createContext, forwardRef, ReactNode, useContext, useMemo} from 'react'; import {DOMRef, GlobalDOMAttributes, SpectrumLabelableProps} from '@react-types/shared'; -import {getAllowedOverrides, StyleProps} from './style-utils' with {type: 'macro'}; import {Form as RACForm, FormProps as RACFormProps} from 'react-aria-components/Form'; import {style} from '../style' with {type: 'macro'}; import {useDOMRef} from './useDOMRef'; @@ -108,6 +108,7 @@ export const Form = /*#__PURE__*/ forwardRef(function Form( } }, // TODO: confirm when we have tokens + // UPDATE: still no tokens rowGap: { size: { XS: 16, @@ -117,7 +118,7 @@ export const Form = /*#__PURE__*/ forwardRef(function Form( XL: 40 } }, - columnGap: 'text-to-control' + columnGap: controlGap() }, getAllowedOverrides() )({labelPosition, size}, props.styles) diff --git a/packages/@react-spectrum/s2/src/IllustratedMessage.tsx b/packages/@react-spectrum/s2/src/IllustratedMessage.tsx index e4fe8f8ffbc..3fbba5718c7 100644 --- a/packages/@react-spectrum/s2/src/IllustratedMessage.tsx +++ b/packages/@react-spectrum/s2/src/IllustratedMessage.tsx @@ -11,14 +11,16 @@ */ import {ButtonGroupContext} from './ButtonGroup'; -import {ContentContext, HeadingContext} from './Content'; -import {ContextValue, Provider} from 'react-aria-components/slots'; import { + containerGap, + containerPadding, controlFont, getAllowedOverrides, StylesPropWithHeight, UnsafeStyles } from './style-utils' with {type: 'macro'}; +import {ContentContext, HeadingContext} from './Content'; +import {ContextValue, Provider} from 'react-aria-components/slots'; import {createContext, forwardRef, ReactNode} from 'react'; import {DOMProps, DOMRef, DOMRefValue} from '@react-types/shared'; import {filterDOMProps} from 'react-aria/filterDOMProps'; @@ -81,17 +83,31 @@ const illustratedMessage = style { diff --git a/packages/@react-spectrum/s2/src/InlineAlert.tsx b/packages/@react-spectrum/s2/src/InlineAlert.tsx index b45e81af0df..92bb161c7d0 100644 --- a/packages/@react-spectrum/s2/src/InlineAlert.tsx +++ b/packages/@react-spectrum/s2/src/InlineAlert.tsx @@ -11,6 +11,7 @@ */ import AlertTriangle from '../s2wf-icons/S2_Icon_AlertTriangle_20_N.svg'; +import {banner, getAllowedOverrides, StyleProps} from './style-utils' with {type: 'macro'}; import CheckmarkCircle from '../s2wf-icons/S2_Icon_CheckmarkCircle_20_N.svg'; import {ComponentType, createContext, forwardRef, ReactNode, useEffect, useRef} from 'react'; import {ContentContext, HeadingContext} from './Content'; @@ -18,7 +19,6 @@ import {ContextValue, Provider, SlotProps} from 'react-aria-components/slots'; import {DOMProps, DOMRef, DOMRefValue} from '@react-types/shared'; import {filterDOMProps} from 'react-aria/filterDOMProps'; import {focusRing, style} from '../style' with {type: 'macro'}; -import {getAllowedOverrides, StyleProps} from './style-utils' with {type: 'macro'}; import {IconContext} from './Icon'; import InfoCircle from '../s2wf-icons/S2_Icon_InfoCircle_20_N.svg'; import intlMessages from '../intl/*.json'; @@ -63,7 +63,7 @@ const inlineAlert = style( display: 'inline-block', position: 'relative', boxSizing: 'border-box', - padding: 24, + padding: banner().paddingX.density.default, // TODO design is this correct? why not follow other banners? borderRadius: 'lg', borderStyle: 'solid', borderWidth: 2, diff --git a/packages/@react-spectrum/s2/src/ListView.tsx b/packages/@react-spectrum/s2/src/ListView.tsx index 41d69a077b5..3ff78294912 100644 --- a/packages/@react-spectrum/s2/src/ListView.tsx +++ b/packages/@react-spectrum/s2/src/ListView.tsx @@ -40,6 +40,7 @@ import { import { controlFont, getAllowedOverrides, + listItem, StylesPropWithHeight, UnsafeStyles } from './style-utils' with {type: 'macro'}; @@ -452,17 +453,18 @@ const listitem = style< '. dragbutton . checkmark icon label actions actionmenu trailing-icon .', '. . . . . description actions actionmenu trailing-icon .' ], + // TODO why don't we have a template area defined for non-draggable?? gridTemplateColumns: [ - 4, + listItem().paddingX, 'auto', - 8, + 8, // TODO missing from design 'auto', 'auto', 'minmax(0, 1fr)', 'auto', 'auto', 'var(--trailing-icon-width)', - 6 + listItem().paddingX ], gridTemplateRows: '1fr auto', rowGap: { @@ -804,7 +806,7 @@ const listCheckbox = style({ gridArea: 'checkmark', gridRowEnd: 'span 2', alignSelf: 'center', - marginEnd: 8, + marginEnd: listItem().gap.default, visibility: { default: 'visible', isDisabled: 'hidden' @@ -817,7 +819,7 @@ const listTrailingIcon = style({ alignSelf: 'center', display: 'flex', alignItems: 'center', - marginStart: 'text-to-visual' + marginStart: listItem().gap.size.S }); let dragButtonContainer = style({ diff --git a/packages/@react-spectrum/s2/src/Menu.tsx b/packages/@react-spectrum/s2/src/Menu.tsx index d040ece4697..cc10d5acf1f 100644 --- a/packages/@react-spectrum/s2/src/Menu.tsx +++ b/packages/@react-spectrum/s2/src/Menu.tsx @@ -41,6 +41,7 @@ import {ContextValue, DEFAULT_SLOT, Provider, useSlottedContext} from 'react-ari import { control, controlFont, + controlPadding, controlSize, getAllowedOverrides, StyleProps @@ -57,7 +58,6 @@ import { } from 'react'; import {divider} from './Divider'; import {DOMRef, DOMRefValue, GlobalDOMAttributes, PressEvent} from '@react-types/shared'; -import {edgeToText} from '../style/spectrum-theme' with {type: 'macro'}; import {forwardRefType} from './types'; import {HeaderContext, HeadingContext, KeyboardContext, Text, TextContext} from './Content'; import {IconContext} from './Icon'; @@ -127,10 +127,46 @@ export const MenuContext = const menuItemGrid = { size: { - S: [edgeToText(24), 'auto', 'auto', 'minmax(0, 1fr)', 'auto', 'auto', 'auto', edgeToText(24)], - M: [edgeToText(32), 'auto', 'auto', 'minmax(0, 1fr)', 'auto', 'auto', 'auto', edgeToText(32)], - L: [edgeToText(40), 'auto', 'auto', 'minmax(0, 1fr)', 'auto', 'auto', 'auto', edgeToText(40)], - XL: [edgeToText(48), 'auto', 'auto', 'minmax(0, 1fr)', 'auto', 'auto', 'auto', edgeToText(48)] + S: [ + controlPadding({size: 'S'}), + 'auto', + 'auto', + 'minmax(0, 1fr)', + 'auto', + 'auto', + 'auto', + controlPadding({size: 'S'}) + ], + M: [ + controlPadding({size: 'M'}), + 'auto', + 'auto', + 'minmax(0, 1fr)', + 'auto', + 'auto', + 'auto', + controlPadding({size: 'M'}) + ], + L: [ + controlPadding({size: 'L'}), + 'auto', + 'auto', + 'minmax(0, 1fr)', + 'auto', + 'auto', + 'auto', + controlPadding({size: 'L'}) + ], + XL: [ + controlPadding({size: 'XL'}), + 'auto', + 'auto', + 'minmax(0, 1fr)', + 'auto', + 'auto', + 'auto', + controlPadding({size: 'XL'}) + ] } } as const; diff --git a/packages/@react-spectrum/s2/src/NumberField.tsx b/packages/@react-spectrum/s2/src/NumberField.tsx index 79fba8077a1..489672f058c 100644 --- a/packages/@react-spectrum/s2/src/NumberField.tsx +++ b/packages/@react-spectrum/s2/src/NumberField.tsx @@ -10,6 +10,16 @@ * governing permissions and limitations under the License. */ +import { + accessoryGap, + controlBorderRadius, + controlGap, + controlTemplate, + field, + fieldInput, + getAllowedOverrides, + StyleProps +} from './style-utils' with {type: 'macro'}; import Add from '../ui-icons/Add'; import { ButtonProps as AriaButtonProps, @@ -20,15 +30,8 @@ import { NumberField as AriaNumberField, NumberFieldProps as AriaNumberFieldProps } from 'react-aria-components/NumberField'; -import {baseColor, space, style} from '../style' with {type: 'macro'}; +import {baseColor, style} from '../style' with {type: 'macro'}; import {ContextValue, useContextProps} from 'react-aria-components/slots'; -import { - controlBorderRadius, - field, - fieldInput, - getAllowedOverrides, - StyleProps -} from './style-utils' with {type: 'macro'}; import { createContext, CSSProperties, @@ -109,7 +112,7 @@ const inputButton = style< }, height: 'auto', marginStart: { - default: 'text-to-control', + default: controlGap(), type: { increment: 0 } @@ -151,22 +154,8 @@ const iconStyles = style({ const stepperContainerStyles = style({ display: 'flex', flexDirection: 'row', - gap: { - size: { - S: 8, - M: 4, - L: 8, - XL: 8 - } - }, - marginEnd: { - size: { - S: 2, - M: 4, - L: space(6), - XL: space(6) - } - } + gap: accessoryGap(), + marginEnd: accessoryGap() }); /** @@ -249,10 +238,10 @@ export const NumberField = forwardRef(function NumberField( size={size} styles={style({ ...fieldInput(), - paddingStart: 'edge-to-text', + paddingStart: controlTemplate().paddingX, paddingEnd: { default: 0, - isStepperHidden: 'edge-to-text' + isStepperHidden: controlTemplate().paddingX } })({size, isStepperHidden: hideStepper})}> diff --git a/packages/@react-spectrum/s2/src/Picker.tsx b/packages/@react-spectrum/s2/src/Picker.tsx index a4feceb71f9..ad8bb391f92 100644 --- a/packages/@react-spectrum/s2/src/Picker.tsx +++ b/packages/@react-spectrum/s2/src/Picker.tsx @@ -60,16 +60,18 @@ import { control, controlBorderRadius, controlFont, + controlGap, + controlPadding, field, fieldInput, getAllowedOverrides, + popover, StyleProps } from './style-utils' with {type: 'macro'}; import {createHideableComponent} from 'react-aria/private/collections/Hidden'; import {createShadowTreeWalker} from 'react-aria/private/utils/shadowdom/ShadowTreeWalker'; import {css} from '../style/style-macro' with {type: 'macro'}; import {Divider, listbox, listboxHeader, listboxItem, LOADER_ROW_HEIGHTS} from './ComboBox'; -import {edgeToText} from '../style/spectrum-theme' with {type: 'macro'}; import {FieldErrorIcon, FieldLabel, HelpText} from './Field'; import {FormContext, useFormProps} from './Form'; import {forwardRefType} from './types'; @@ -196,7 +198,7 @@ const inputButton = style({ }, transition: 'default', paddingX: { - default: 'edge-to-text', + default: control({shape: 'default', icon: true}).paddingX, isQuiet: 0 }, backgroundColor: { @@ -229,21 +231,58 @@ const quietFocusLine = style({ }); export let menu = style({ + ...popover(), + gap: 0, outlineStyle: 'none', display: 'grid', width: 'full', gridTemplateColumns: { size: { - S: [edgeToText(24), 'auto', 'auto', 'minmax(0, 1fr)', 'auto', 'auto', 'auto', edgeToText(24)], - M: [edgeToText(32), 'auto', 'auto', 'minmax(0, 1fr)', 'auto', 'auto', 'auto', edgeToText(32)], - L: [edgeToText(40), 'auto', 'auto', 'minmax(0, 1fr)', 'auto', 'auto', 'auto', edgeToText(40)], - XL: [edgeToText(48), 'auto', 'auto', 'minmax(0, 1fr)', 'auto', 'auto', 'auto', edgeToText(48)] + S: [ + controlPadding({size: 'S'}), + 'auto', + 'auto', + 'minmax(0, 1fr)', + 'auto', + 'auto', + 'auto', + controlPadding({size: 'S'}) + ], + M: [ + controlPadding({size: 'M'}), + 'auto', + 'auto', + 'minmax(0, 1fr)', + 'auto', + 'auto', + 'auto', + controlPadding({size: 'M'}) + ], + L: [ + controlPadding({size: 'L'}), + 'auto', + 'auto', + 'minmax(0, 1fr)', + 'auto', + 'auto', + 'auto', + controlPadding({size: 'L'}) + ], + XL: [ + controlPadding({size: 'XL'}), + 'auto', + 'auto', + 'minmax(0, 1fr)', + 'auto', + 'auto', + 'auto', + controlPadding({size: 'XL'}) + ] } }, boxSizing: 'border-box', maxHeight: 'inherit', overflow: 'auto', - padding: 8, fontFamily: 'sans', fontSize: controlFont(), gridAutoRows: 'min-content' @@ -288,7 +327,7 @@ const iconStyles = style({ const avatar = style({ gridArea: 'icon', - marginEnd: 'text-to-visual' + marginEnd: controlGap() }); const loadingWrapperStyles = style({ @@ -706,7 +745,7 @@ const PickerButton = createHideableComponent(function PickerButton( slots: { avatar: { size: avatarSize[size ?? 'M'], - styles: avatar + styles: avatar({size}) } } } @@ -829,7 +868,7 @@ export function PickerItem(props: PickerItemProps): ReactNode { context={AvatarContext} value={{ slots: { - avatar: {size: avatarSize[size], styles: avatar} + avatar: {size: avatarSize[size], styles: avatar({size})} } }}> + })({size})}> ( { display: 'flex', - gap: 'text-to-visual', + gap: controlGap(), alignItems: 'baseline', width: 'fit', font: controlFont(), diff --git a/packages/@react-spectrum/s2/src/style-utils.ts b/packages/@react-spectrum/s2/src/style-utils.ts index 1c6cfff83bd..dfd6ee7ee4a 100644 --- a/packages/@react-spectrum/s2/src/style-utils.ts +++ b/packages/@react-spectrum/s2/src/style-utils.ts @@ -11,7 +11,8 @@ */ import {CSSProperties} from 'react'; -import {fontRelative as internalFontRelative} from '../style/spectrum-theme'; +import {getSetToken, getToken} from '../style/tokens'; +import {fontRelative as internalFontRelative, size} from '../style/spectrum-theme'; import {StyleString} from '../style/types'; /** @@ -89,7 +90,7 @@ export const field = () => type: 'rowGap', value: centerPadding('var(--field-height)') }, - columnGap: 12, + columnGap: 12, // TODO: what token to use here? controlGap would be 6px for medium disableTapHighlight: true }) as const; @@ -239,6 +240,226 @@ const controlSizeS = { } } as const; +// Base Gap - dynamic +export const controlGap = () => + ({ + default: size(parseFloat(getToken('base-gap-medium'))), + size: { + XS: size(parseFloat(getToken('base-gap-extra-small'))), + S: size(parseFloat(getToken('base-gap-small'))), + M: size(parseFloat(getToken('base-gap-medium'))), + L: size(parseFloat(getToken('base-gap-large'))), + XL: size(parseFloat(getToken('base-gap-extra-large'))) + } + }) as const; + +// Accessory Gap - dynamic +export const accessoryGap = () => + ({ + default: size(parseFloat(getToken('accessory-gap-medium'))), + size: { + XS: size(parseFloat(getToken('accessory-gap-extra-small'))), + S: size(parseFloat(getToken('accessory-gap-small'))), + M: size(parseFloat(getToken('accessory-gap-medium'))), + L: size(parseFloat(getToken('accessory-gap-large'))), + XL: size(parseFloat(getToken('accessory-gap-extra-large'))), + '2XL': size(parseFloat(getToken('accessory-gap-2x-large'))) + } + }) as const; + +// Group Gap - dynamic +export const groupGap = () => + ({ + default: size(parseFloat(getToken('group-gap-medium'))), + size: { + default: size(parseFloat(getToken('group-gap-medium'))), + XS: size(parseFloat(getToken('group-gap-extra-small'))), + S: size(parseFloat(getToken('group-gap-small'))), + M: size(parseFloat(getToken('group-gap-medium'))), + L: size(parseFloat(getToken('group-gap-large'))), + XL: size(parseFloat(getToken('group-gap-extra-large'))) + }, + density: { + default: { + size: { + default: size(parseFloat(getToken('group-gap-medium'))), + XS: size(parseFloat(getToken('group-gap-extra-small'))), + S: size(parseFloat(getToken('group-gap-small'))), + M: size(parseFloat(getToken('group-gap-medium'))), + L: size(parseFloat(getToken('group-gap-large'))), + XL: size(parseFloat(getToken('group-gap-extra-large'))) + } + }, + compact: size(parseFloat(getToken('group-gap-compact'))), + spacious: { + size: { + XS: size(parseFloat(getToken('group-gap-extra-small-spacious'))), + S: size(parseFloat(getToken('group-gap-small-spacious'))), + M: size(parseFloat(getToken('group-gap-medium-spacious'))), + L: size(parseFloat(getToken('group-gap-large-spacious'))), + XL: size(parseFloat(getToken('group-gap-extra-large-spacious'))) + } + } + } + }) as const; + +const textGapTokens = { + XS: size(parseFloat(getToken('text-gap-extra-small'))), + S: size(parseFloat(getToken('text-gap-small'))), + M: size(parseFloat(getToken('text-gap-medium'))), + L: size(parseFloat(getToken('text-gap-large'))), + XL: size(parseFloat(getToken('text-gap-extra-large'))) +}; + +export const textGap = (props: {size: keyof typeof textGapTokens}) => { + let {size = 'M'} = props; + return textGapTokens[size]; +}; + +export const text = () => + ({ + default: size(parseFloat(getToken('text-gap-medium'))), + size: { + ...textGapTokens + } + }) as const; + +// Base Horizontal Padding - dynamic + +const containerGapTokens = { + '2XS': size(parseFloat(getToken('container-gap-2x-small'))), + XS: size(parseFloat(getToken('container-gap-extra-small'))), + S: size(parseFloat(getToken('container-gap-small'))), + M: size(parseFloat(getToken('container-gap-medium'))), + L: size(parseFloat(getToken('container-gap-large'))), + XL: size(parseFloat(getToken('container-gap-extra-large'))), + '2XL': size(parseFloat(getToken('container-gap-2x-large'))) +}; + +const containerPaddingTokens = { + '2XS': size(parseFloat(getToken('container-padding-2x-small'))), + XS: size(parseFloat(getToken('container-padding-extra-small'))), + S: size(parseFloat(getToken('container-padding-small'))), + M: size(parseFloat(getToken('container-padding-medium'))), + L: size(parseFloat(getToken('container-padding-large'))), + XL: size(parseFloat(getToken('container-padding-extra-large'))), + '2XL': size(parseFloat(getToken('container-padding-2x-large'))), + '3XL': size(parseFloat(getToken('container-padding-3x-large'))) +}; + +export const containerGap = (props: {size: keyof typeof containerGapTokens}) => { + let {size = 'M'} = props; + return containerGapTokens[size]; +}; + +export const containerPadding = (props: {size: keyof typeof containerPaddingTokens}) => { + let {size = 'M'} = props; + return containerPaddingTokens[size]; +}; + +export const container = () => + ({ + gap: { + default: size(parseFloat(getToken('container-gap-medium'))), + size: { + ...containerGapTokens + } + }, + padding: { + default: size(parseFloat(getToken('container-padding-medium'))), + size: { + ...containerPaddingTokens + } + } + }) as const; + +export const popover = () => + ({ + gap: size(parseFloat(getToken('popover-gap'))), + padding: size(parseFloat(getToken('popover-padding'))) + }) as const; + +export const controlPadding = (props: {size: keyof typeof horizontalPaddingTokens}) => { + let {size = 'M'} = props; + return horizontalPaddingTokens[size]; +}; + +const verticalPaddingTokens = { + XS: size(parseFloat(getToken('base-padding-vertical-extra-small'))), + S: size(parseFloat(getToken('base-padding-vertical-small'))), + M: size(parseFloat(getToken('base-padding-vertical-medium'))), + L: size(parseFloat(getToken('base-padding-vertical-large'))), + XL: size(parseFloat(getToken('base-padding-vertical-extra-large'))), + '2XL': size(parseFloat(getToken('base-padding-vertical-2x-large'))) +} as const; + +const horizontalPaddingTokens = { + XS: size(parseFloat(getSetToken('base-padding-horizontal-extra-small'))), + S: size(parseFloat(getSetToken('base-padding-horizontal-small'))), + M: size(parseFloat(getSetToken('base-padding-horizontal-medium'))), + L: size(parseFloat(getSetToken('base-padding-horizontal-large'))), + XL: size(parseFloat(getSetToken('base-padding-horizontal-extra-large'))), + '2XL': size(parseFloat(getSetToken('base-padding-horizontal-2x-large'))) +} as const; + +// Base Vertical Padding - static +export const verticalPadding = (size: keyof typeof verticalPaddingTokens = 'M') => + verticalPaddingTokens[size]; + +// Base Horizontal Padding - static +export const horizontalPadding = (size: keyof typeof horizontalPaddingTokens = 'M') => + horizontalPaddingTokens[size]; + +export const controlTemplate = () => + ({ + paddingX: { + size: { + ...horizontalPaddingTokens + } + }, + paddingY: { + size: { + ...verticalPaddingTokens + } + } + }) as const; + +export const banner = () => + ({ + paddingX: { + density: { + default: size(parseFloat(getToken('banner-padding-horizontal'))), + compact: size(parseFloat(getToken('banner-padding-horizontal-compact'))) + } + }, + paddingY: size(parseFloat(getToken('banner-padding-vertical'))), + gap: { + orientation: { + horizontal: size(parseFloat(getToken('banner-gap-horizontal'))), + vertical: size(parseFloat(getToken('banner-gap-vertical'))) + } + } + }) as const; + +export const listItem = () => + ({ + gap: { + default: size(parseFloat(getToken('list-item-gap-medium'))), + size: { + S: size(parseFloat(getToken('list-item-gap-small'))), + M: size(parseFloat(getToken('list-item-gap-medium'))) + } + }, + paddingX: size(parseFloat(getToken('list-item-padding-horizontal'))), + paddingY: { + default: size(parseFloat(getToken('list-item-padding-vertical-regular'))), + density: { + default: size(parseFloat(getToken('list-item-padding-vertical-regular'))), + spacious: size(parseFloat(getToken('list-item-padding-vertical-spacious'))) + } + } + }) as const; + // This generates the border radius for t-shirt sizes using the // Major Second logarithmic scale. export const controlBorderRadius = (size: 'default' | 'sm' = 'default') => @@ -268,6 +489,8 @@ interface ControlOptions { icon?: boolean; } +type ControlPaddingX = {default: `calc(${string})`; size: typeof horizontalPaddingTokens}; + interface ControlResult { font: ReturnType; boxSizing?: 'border-box'; @@ -277,8 +500,8 @@ interface ControlResult { height?: ReturnType; display?: 'flex'; alignItems?: 'center' | {default: 'baseline'; [iconOnly]: 'center'}; - columnGap?: 'text-to-visual'; - paddingX?: 'pill' | 'edge-to-text' | {default: 'pill' | 'edge-to-text'; [iconOnly]: 0}; + columnGap?: ReturnType; + paddingX?: 'pill' | ControlPaddingX | {default: 'pill' | ControlPaddingX; [iconOnly]: 0}; paddingY?: 0 | `[${string}]`; } @@ -289,7 +512,10 @@ const iconOnly = ':has([slot=icon]):not(:has([data-rsp-slot=text]))'; * The text can optionally wrap, aligning the icon with the first line of text. */ export function control(options: ControlOptions): ControlResult { - let paddingX = options.shape === 'pill' ? ('pill' as const) : ('edge-to-text' as const); + let paddingX = + options.shape === 'pill' + ? ('pill' as const) + : {default: horizontalPaddingTokens.M, size: horizontalPaddingTokens}; let result: ControlResult = { font: controlFont(), display: 'flex', @@ -306,7 +532,7 @@ export function control(options: ControlOptions): ControlResult { } if (options.icon) { - result.columnGap = 'text-to-visual'; + result.columnGap = controlGap(); result.paddingX = { default: paddingX, [iconOnly]: 0 diff --git a/packages/@react-spectrum/s2/style/spectrum-theme.ts b/packages/@react-spectrum/s2/style/spectrum-theme.ts index 3690d893241..96c64803668 100644 --- a/packages/@react-spectrum/s2/style/spectrum-theme.ts +++ b/packages/@react-spectrum/s2/style/spectrum-theme.ts @@ -32,8 +32,8 @@ import { autoStaticColor, ColorRef, colorScale, - ColorToken, colorToken, + ColorToken, fontSizeToken, generateOverlayColorScale, getToken, @@ -427,12 +427,24 @@ export function space(this: MacroContext | void, px: number): string { const relativeSpacing = { // font-size relative values + /** + * @deprecated Use `controlGap()` from `style-utils`, which selects a `base-gap-*` tier per + * component size. + */ 'text-to-control': fontRelative(10), + /** + * @deprecated Use `controlGap()` from `style-utils`, which selects a `base-gap-*` tier per + * component size. + */ 'text-to-visual': { default: fontRelative(6), // -> 5px, 5px, 6px, 7px, 8px touch: fontRelative(8, 17) // -> 6px, 7px, 8px, 9px, 10px, should be 7px, 7px, 8px, 9px, 11px }, // height relative values + /** + * @deprecated Use `controlPadding()` from `style-utils`, which selects a + * `base-padding-horizontal-*` tier per component size. + */ 'edge-to-text': 'calc(self(height, self(minHeight)) * 3 / 8)', pill: 'calc(self(height, self(minHeight)) / 2)' } as const; diff --git a/packages/@react-spectrum/s2/style/tokens.ts b/packages/@react-spectrum/s2/style/tokens.ts index 8f04d400e25..7f4518090dd 100644 --- a/packages/@react-spectrum/s2/style/tokens.ts +++ b/packages/@react-spectrum/s2/style/tokens.ts @@ -27,6 +27,14 @@ export function getToken(name: TokenName): string { return (tokens[name] as any).value; } +// Some dimension tokens store their value under a responsive set (e.g. desktop/mobile) +// rather than a top-level `value`. In S2 the touch scale is applied via the `--s2-scale` +// CSS variable, so we read the desktop value and let that variable produce the touch value. +export function getSetToken(name: TokenName, set: 'desktop' | 'mobile' = 'desktop'): string { + let token = tokens[name] as any; + return token.sets ? token.sets[set].value : token.value; +} + export interface ColorToken { type: 'color'; light: string;