From 52af842770e14241fd3a6bcff5fbae9ab9ffda1e Mon Sep 17 00:00:00 2001 From: Rachel Yoo Date: Mon, 14 Jul 2025 16:51:15 -0400 Subject: [PATCH] add spin button to semantic style hooks --- .../etc/semantic-style-hooks-preview.api.md | 4 + .../library/package.json | 1 + .../src/component-styles/SpinButton/index.ts | 1 + .../useSemanticSpinButtonStyles.styles.ts | 453 ++++++++++++++++++ .../component-styles/semanticStyleHooks.ts | 3 + .../library/src/index.ts | 1 + .../etc/semantic-tokens.api.md | 36 +- .../src/components/input/tokens.ts | 8 +- .../src/fluentLegacyVariants.ts | 40 ++ .../semantic-tokens/src/fluentOverrides.ts | 3 + packages/semantic-tokens/src/index.ts | 14 +- packages/semantic-tokens/src/legacy/tokens.ts | 18 +- .../src/legacyVariant/tokens.ts | 108 ++++- 13 files changed, 656 insertions(+), 34 deletions(-) create mode 100644 packages/react-components/semantic-style-hooks-preview/library/src/component-styles/SpinButton/index.ts create mode 100644 packages/react-components/semantic-style-hooks-preview/library/src/component-styles/SpinButton/useSemanticSpinButtonStyles.styles.ts diff --git a/packages/react-components/semantic-style-hooks-preview/library/etc/semantic-style-hooks-preview.api.md b/packages/react-components/semantic-style-hooks-preview/library/etc/semantic-style-hooks-preview.api.md index 0e24b38bc112ac..e0b160bda483cf 100644 --- a/packages/react-components/semantic-style-hooks-preview/library/etc/semantic-style-hooks-preview.api.md +++ b/packages/react-components/semantic-style-hooks-preview/library/etc/semantic-style-hooks-preview.api.md @@ -49,6 +49,7 @@ import { RadioState } from '@fluentui/react-radio'; import { RatingDisplayState } from '@fluentui/react-rating'; import { RatingItemState } from '@fluentui/react-rating'; import { SliderState } from '@fluentui/react-slider'; +import { SpinButtonState } from '@fluentui/react-spinbutton'; import { SpinnerState } from '@fluentui/react-spinner'; import { SplitButtonState } from '@fluentui/react-button'; import { SwitchState } from '@fluentui/react-switch'; @@ -199,6 +200,9 @@ export const useSemanticRatingItemStyles: (_state: unknown) => RatingItemState; // @public export const useSemanticSliderStyles: (_state: unknown) => SliderState; +// @public +export const useSemanticSpinButtonStyles: (_state: unknown) => SpinButtonState; + // @public export const useSemanticSpinnerStyles: (_state: unknown) => SpinnerState; diff --git a/packages/react-components/semantic-style-hooks-preview/library/package.json b/packages/react-components/semantic-style-hooks-preview/library/package.json index 1249d332ab8ef4..559ae7b6068c2f 100644 --- a/packages/react-components/semantic-style-hooks-preview/library/package.json +++ b/packages/react-components/semantic-style-hooks-preview/library/package.json @@ -51,6 +51,7 @@ "@fluentui/react-rating": "^9.1.6", "@fluentui/react-shared-contexts": "^9.23.1", "@fluentui/react-slider": "^9.3.7", + "@fluentui/react-spinbutton": "^9.3.6", "@fluentui/react-spinner": "^9.5.11", "@fluentui/react-switch": "^9.2.6", "@fluentui/react-tabster": "^9.24.6", diff --git a/packages/react-components/semantic-style-hooks-preview/library/src/component-styles/SpinButton/index.ts b/packages/react-components/semantic-style-hooks-preview/library/src/component-styles/SpinButton/index.ts new file mode 100644 index 00000000000000..4c0c10f5b79ceb --- /dev/null +++ b/packages/react-components/semantic-style-hooks-preview/library/src/component-styles/SpinButton/index.ts @@ -0,0 +1 @@ +export { useSemanticSpinButtonStyles } from './useSemanticSpinButtonStyles.styles'; diff --git a/packages/react-components/semantic-style-hooks-preview/library/src/component-styles/SpinButton/useSemanticSpinButtonStyles.styles.ts b/packages/react-components/semantic-style-hooks-preview/library/src/component-styles/SpinButton/useSemanticSpinButtonStyles.styles.ts new file mode 100644 index 00000000000000..1d7535f823ea1e --- /dev/null +++ b/packages/react-components/semantic-style-hooks-preview/library/src/component-styles/SpinButton/useSemanticSpinButtonStyles.styles.ts @@ -0,0 +1,453 @@ +import { makeResetStyles, makeStyles, mergeClasses, shorthands } from '@griffel/react'; +import { spinButtonClassNames, type SpinButtonState } from '@fluentui/react-spinbutton'; +import { tokens } from '@fluentui/react-theme'; +import { getSlotClassNameProp_unstable } from '@fluentui/react-utilities'; +import * as semanticTokens from '@fluentui/semantic-tokens'; + +const spinButtonExtraClassNames = { + buttonActive: 'fui-SpinButton__button_active', +}; + +const fieldHeights = { + small: semanticTokens._ctrlSpinButtonSizeSmDefault, + medium: semanticTokens._ctrlSpinButtonSizeDefault, +}; + +const useRootClassName = makeResetStyles({ + display: 'inline-grid', + gridTemplateColumns: `1fr 24px`, + gridTemplateRows: '1fr 1fr', + columnGap: semanticTokens.gapInsideCtrlSmDefault, + rowGap: 0, + position: 'relative', + isolation: 'isolate', + verticalAlign: 'middle', + + backgroundColor: semanticTokens.ctrlInputBackgroundRest, + minHeight: fieldHeights.medium, + padding: `0 0 0 ${semanticTokens._ctrlSpinButtonPaddingHorizontal}`, + borderRadius: semanticTokens.cornerCtrlRest, + + // Apply border styles on the ::before pseudo element. + // We cannot use ::after since that is used for selection. + // Using the pseudo element allows us to place the border + // above content in the component which ensures the buttons + // line up visually with the border as expected. Without this + // there is a bit of a gap which can become very noticeable + // at high zoom or when OS zoom levels are not divisible by 2 + // (e.g., 150% on Windows in Firefox) + // This is most noticeable on the "outline" appearance which is + // also the default so it feels worth the extra ceremony to get right. + '::before': { + content: '""', + boxSizing: 'border-box', + position: 'absolute', + top: 0, + right: 0, + bottom: 0, + left: 0, + pointerEvents: 'none', + zIndex: 10, + border: `${semanticTokens.ctrlInputStrokeWidthRest} solid ${semanticTokens.ctrlInputStrokeRest}`, + borderBottomColor: semanticTokens.ctrlInputBottomLineStrokeRest, + borderBottomWidth: semanticTokens.ctrlInputBottomLineStrokeWidthRest, + borderRadius: semanticTokens.cornerCtrlRest, + }, + + '::after': { + boxSizing: 'border-box', + content: '""', + position: 'absolute', + right: 0, + bottom: 0, + left: 0, + zIndex: 20, + + // Maintaining the correct corner radius: + // Use the whole border-radius as the height and only put radii on the bottom corners. + // (Otherwise the radius would be automatically reduced to fit available space.) + // max() ensures the focus border still shows up even if someone sets tokens.borderRadiusMedium to 0. + height: `max(2px, ${semanticTokens.cornerCtrlPressed})`, + borderBottomLeftRadius: semanticTokens.cornerCtrlPressed, + borderBottomRightRadius: semanticTokens.cornerCtrlPressed, + + // Flat 2px border: + // By default borderBottom will cause little "horns" on the ends. The clipPath trims them off. + // (This could be done without trimming using `background: linear-gradient(...)`, but using + // borderBottom makes it easier for people to override the color if needed.) + borderBottom: `2px solid ${semanticTokens.ctrlInputBottomLineStrokeSelected}`, + clipPath: 'inset(calc(100% - 2px) 0 0 0)', + + // Animation for focus OUT + transform: 'scaleX(0)', + transitionProperty: 'transform', + transitionDuration: tokens.durationUltraFast, + transitionDelay: tokens.curveAccelerateMid, + + '@media screen and (prefers-reduced-motion: reduce)': { + transitionDuration: '0.01ms', + transitionDelay: '0.01ms', + }, + }, + + ':focus-within::after': { + // Animation for focus IN + transform: 'scaleX(1)', + transitionProperty: 'transform', + transitionDuration: tokens.durationNormal, + transitionDelay: tokens.curveDecelerateMid, + + '@media screen and (prefers-reduced-motion: reduce)': { + transitionDuration: '0.01ms', + transitionDelay: '0.01ms', + }, + }, + ':focus-within:active::after': { + // This is if the user clicks the field again while it's already focused + borderBottomColor: tokens.colorCompoundBrandStrokePressed, + }, + ':focus-within': { + outline: '2px solid transparent', + }, +}); + +const useRootStyles = makeStyles({ + small: { + minHeight: fieldHeights.small, + fontFamily: semanticTokens.textStyleDefaultRegularFontFamily, + fontSize: semanticTokens.textRampSmItemBodyFontSize, + fontWeight: semanticTokens.textStyleDefaultRegularWeight, + lineHeight: semanticTokens.textRampSmItemBodyLineHeight, + paddingLeft: semanticTokens.paddingCtrlSmHorizontalDefault, + }, + + medium: { + // set by useRootClassName + }, + + outline: { + // set by useRootClassName + }, + + outlineInteractive: { + ':hover::before': { + ...shorthands.borderColor(semanticTokens.ctrlInputStrokeHover), + borderBottomColor: semanticTokens.ctrlInputBottomLineStrokeHover, + }, + // DO NOT add a space between the selectors! It changes the behavior of make-styles. + ':active,:focus-within': { + '::before': { + ...shorthands.borderColor(semanticTokens.ctrlInputStrokePressed), + borderBottomColor: semanticTokens.ctrlInputBottomLineStrokePressed, + }, + }, + }, + + underline: { + '::before': { + ...shorthands.borderWidth(0, 0, '1px', 0), + borderRadius: semanticTokens.cornerZero, // corners look strange if rounded + }, + }, + + underlineInteractive: { + ':hover::before': { + borderBottomColor: semanticTokens.ctrlInputBottomLineStrokeHover, + }, + // DO NOT add a space between the selectors! It changes the behavior of make-styles. + ':active,:focus-within': { + '::before': { + borderBottomColor: semanticTokens.ctrlInputBottomLineStrokePressed, + }, + }, + '::after': { + borderRadius: semanticTokens.cornerZero, // remove rounded corners from focus underline + }, + }, + + filled: { + '::before': { + border: `1px solid ${semanticTokens.strokeLayer}`, + }, + }, + + 'filled-darker': { + backgroundColor: semanticTokens.strokeFlyout, + }, + 'filled-lighter': { + backgroundColor: semanticTokens.backgroundCtrlNeutralRest, + }, + + filledInteractive: { + // DO NOT add a space between the selectors! It changes the behavior of make-styles. + ':hover,:focus-within': { + '::before': { + // also handles pressed border color (:active) + ...shorthands.borderColor(semanticTokens.strokeCtrlOnActiveBrandPressed), + }, + }, + }, + + invalid: { + ':not(:focus-within),:hover:not(:focus-within)': { + '::before': { + ...shorthands.borderColor(semanticTokens.ctrlInputBackgroundError), + }, + }, + }, + + disabled: { + cursor: 'not-allowed', + backgroundColor: semanticTokens._ctrlSpinButtonBackgroundDisabled, + '::before': { + ...shorthands.borderColor(semanticTokens.ctrlInputStrokeDisabled), + + '@media (forced-colors: active)': { + ...shorthands.borderColor('GrayText'), + }, + }, + }, +}); + +const useInputClassName = makeResetStyles({ + gridColumnStart: '1', + gridColumnEnd: '2', + gridRowStart: '1', + gridRowEnd: '3', + outlineStyle: 'none', + border: '0', + padding: '0', + color: semanticTokens.foregroundCtrlNeutralPrimaryRest, + // Use literal "transparent" (not from the theme) to always let the color from the root show through + backgroundColor: 'transparent', + fontFamily: 'inherit', + fontSize: 'inherit', + fontWeight: 'inherit', + lineHeight: 'inherit', + width: '100%', + + '::placeholder': { + color: semanticTokens._ctrlSpinButtonNeutralSecondaryRest, + + opacity: 1, // browser style override + }, +}); + +const useInputStyles = makeStyles({ + disabled: { + color: semanticTokens.foregroundCtrlNeutralSecondaryDisabled, + + cursor: 'not-allowed', + backgroundColor: semanticTokens.ctrlChoiceBaseBackgroundDisabled, + + '::placeholder': { + color: semanticTokens.foregroundCtrlNeutralSecondaryDisabled, + }, + }, +}); + +const useBaseButtonClassName = makeResetStyles({ + display: 'inline-flex', + width: semanticTokens._ctrlSpinButtonSizeSmDefault, + alignItems: 'center', + justifyContent: 'center', + border: '0', + position: 'absolute', + + outlineStyle: 'none', + height: semanticTokens._ctrlSpinButtonSizeIconSecondary, + + // Use literal "transparent" (not from the theme) to always let the color from the root show through + backgroundColor: 'transparent', + color: semanticTokens._ctrlSpinButtonOnSubtleRest, + + // common button layout + gridColumnStart: '2', + borderRadius: '0', + padding: `0 ${semanticTokens._ctrlSpinButtonPaddingSmHorizontal}`, + + ':active': { + outlineStyle: 'none', + }, + + ':enabled': { + ':hover': { + cursor: 'pointer', + color: semanticTokens._ctrlSpinButtonForegroundOnSubtleHover, + backgroundColor: semanticTokens.backgroundCtrlSubtleHover, + }, + ':active': { + color: semanticTokens._ctrlSpinButtonForegroundOnSubtlePressed, + backgroundColor: semanticTokens.backgroundCtrlSubtlePressed, + }, + [`&.${spinButtonExtraClassNames.buttonActive}`]: { + color: semanticTokens._ctrlSpinButtonForegroundOnSubtlePressed, + backgroundColor: semanticTokens.backgroundCtrlSubtlePressed, + }, + }, + + ':disabled': { + cursor: 'not-allowed', + color: semanticTokens.foregroundCtrlOnSubtleDisabled, + }, +}); + +const useButtonStyles = makeStyles({ + increment: { + gridRowStart: '1', + borderTopRightRadius: semanticTokens.cornerCtrlSmRest, + paddingTop: '4px', + paddingBottom: '1px', + }, + decrement: { + gridRowStart: '2', + borderBottomRightRadius: semanticTokens.cornerCtrlSmRest, + paddingTop: '1px', + paddingBottom: '4px', + }, + // Padding values numbers don't align with design specs + // but visually the padding aligns. + // The icons are set in a 16x16px square but the artwork is inset from that + // so these padding values are computed by hand. + // Additionally the design uses fractional values so these are + // rounded to the nearest integer. + incrementButtonSmall: { + padding: '3px 6px 0px 4px', + height: '12px', + }, + + decrementButtonSmall: { + padding: '0px 6px 3px 4px', + height: '12px', + }, + + outline: { + // set by useButtonClassName + }, + + underline: { + backgroundColor: 'transparent', + color: semanticTokens._ctrlSpinButtonOnSubtleRest, + ':enabled': { + ':hover': { + color: semanticTokens._ctrlSpinButtonForegroundOnSubtleHover, + backgroundColor: semanticTokens.backgroundCtrlSubtleHover, + }, + ':active': { + color: semanticTokens._ctrlSpinButtonForegroundOnSubtlePressed, + backgroundColor: semanticTokens.backgroundCtrlSubtlePressed, + }, + [`&.${spinButtonExtraClassNames.buttonActive}`]: { + color: semanticTokens._ctrlSpinButtonForegroundOnSubtlePressed, + backgroundColor: semanticTokens.backgroundCtrlSubtlePressed, + }, + }, + ':disabled': { + color: semanticTokens.foregroundCtrlOnSubtleDisabled, + }, + }, + 'filled-darker': { + backgroundColor: 'transparent', + color: semanticTokens._ctrlSpinButtonOnSubtleRest, + + ':enabled': { + ':hover': { + color: semanticTokens._ctrlSpinButtonForegroundOnSubtleHover, + backgroundColor: tokens.colorNeutralBackground3Hover, + }, + ':active': { + color: semanticTokens._ctrlSpinButtonForegroundOnSubtlePressed, + backgroundColor: tokens.colorNeutralBackground3Pressed, + }, + [`&.${spinButtonExtraClassNames.buttonActive}`]: { + color: semanticTokens._ctrlSpinButtonForegroundOnSubtlePressed, + backgroundColor: tokens.colorNeutralBackground3Pressed, + }, + }, + ':disabled': { + color: semanticTokens.foregroundCtrlOnSubtleDisabled, + }, + }, + 'filled-lighter': { + backgroundColor: 'transparent', + color: semanticTokens._ctrlSpinButtonOnSubtleRest, + + ':enabled': { + ':hover': { + color: semanticTokens._ctrlSpinButtonForegroundOnSubtleHover, + backgroundColor: semanticTokens.backgroundCtrlNeutralHover, + }, + [`:active,&.${spinButtonExtraClassNames.buttonActive}`]: { + color: semanticTokens._ctrlSpinButtonForegroundOnSubtlePressed, + backgroundColor: semanticTokens.backgroundCtrlNeutralPressed, + }, + }, + ':disabled': { + color: semanticTokens.foregroundCtrlOnSubtleDisabled, + }, + }, +}); + +/** + * Apply styling to the SpinButton slots based on the state + */ +export const useSemanticSpinButtonStyles = (_state: unknown): SpinButtonState => { + 'use no memo'; + + const state = _state as SpinButtonState; + + const { appearance, spinState, size } = state; + const disabled = state.input.disabled; + const invalid = `${state.input['aria-invalid']}` === 'true'; + const filled = appearance.startsWith('filled'); + + const rootStyles = useRootStyles(); + const buttonStyles = useButtonStyles(); + const inputStyles = useInputStyles(); + + state.root.className = mergeClasses( + state.root.className, + spinButtonClassNames.root, + useRootClassName(), + rootStyles[size], + rootStyles[appearance], + filled && rootStyles.filled, + !disabled && appearance === 'outline' && rootStyles.outlineInteractive, + !disabled && appearance === 'underline' && rootStyles.underlineInteractive, + !disabled && filled && rootStyles.filledInteractive, + !disabled && invalid && rootStyles.invalid, + disabled && rootStyles.disabled, + getSlotClassNameProp_unstable(state.root), + ); + + state.incrementButton.className = mergeClasses( + state.incrementButton.className, + spinButtonClassNames.incrementButton, + spinState === 'up' && `${spinButtonExtraClassNames.buttonActive}`, + useBaseButtonClassName(), + buttonStyles.increment, + buttonStyles[appearance], + size === 'small' && buttonStyles.incrementButtonSmall, + getSlotClassNameProp_unstable(state.incrementButton), + ); + state.decrementButton.className = mergeClasses( + state.decrementButton.className, + spinButtonClassNames.decrementButton, + spinState === 'down' && `${spinButtonExtraClassNames.buttonActive}`, + useBaseButtonClassName(), + buttonStyles.decrement, + buttonStyles[appearance], + size === 'small' && buttonStyles.decrementButtonSmall, + getSlotClassNameProp_unstable(state.decrementButton), + ); + + state.input.className = mergeClasses( + state.input.className, + spinButtonClassNames.input, + useInputClassName(), + disabled && inputStyles.disabled, + getSlotClassNameProp_unstable(state.input), + ); + + return state; +}; diff --git a/packages/react-components/semantic-style-hooks-preview/library/src/component-styles/semanticStyleHooks.ts b/packages/react-components/semantic-style-hooks-preview/library/src/component-styles/semanticStyleHooks.ts index 0befde24f0bdb5..a418decfbb4fe7 100644 --- a/packages/react-components/semantic-style-hooks-preview/library/src/component-styles/semanticStyleHooks.ts +++ b/packages/react-components/semantic-style-hooks-preview/library/src/component-styles/semanticStyleHooks.ts @@ -69,6 +69,7 @@ import { useSemanticBreadcrumbDividerStyles, useSemanticBreadcrumbItemStyles, } from './Breadcrumb'; +import { useSemanticSpinButtonStyles } from './SpinButton'; export const SEMANTIC_STYLE_HOOKS: FluentProviderCustomStyleHooks = { // Accordion styles @@ -155,4 +156,6 @@ export const SEMANTIC_STYLE_HOOKS: FluentProviderCustomStyleHooks = { useBreadcrumbButtonStyles_unstable: useSemanticBreadcrumbButtonStyles, useBreadcrumbDividerStyles_unstable: useSemanticBreadcrumbDividerStyles, useBreadcrumbItemStyles_unstable: useSemanticBreadcrumbItemStyles, + // SpinButton styles + useSpinButtonStyles_unstable: useSemanticSpinButtonStyles, }; diff --git a/packages/react-components/semantic-style-hooks-preview/library/src/index.ts b/packages/react-components/semantic-style-hooks-preview/library/src/index.ts index db38c7f5298145..fcd924e22a90f7 100644 --- a/packages/react-components/semantic-style-hooks-preview/library/src/index.ts +++ b/packages/react-components/semantic-style-hooks-preview/library/src/index.ts @@ -73,3 +73,4 @@ export { useSemanticBreadcrumbDividerStyles, useSemanticBreadcrumbItemStyles, } from './component-styles/Breadcrumb'; +export { useSemanticSpinButtonStyles } from './component-styles/SpinButton'; diff --git a/packages/semantic-tokens/etc/semantic-tokens.api.md b/packages/semantic-tokens/etc/semantic-tokens.api.md index 7505e6ecf5b83a..1608c686af3ba5 100644 --- a/packages/semantic-tokens/etc/semantic-tokens.api.md +++ b/packages/semantic-tokens/etc/semantic-tokens.api.md @@ -1877,7 +1877,7 @@ export const ctrlInputBottomLineStrokeWidthPressed = "var(--smtc-ctrl-input-bott export const ctrlInputBottomLineStrokeWidthPressedRaw = "--smtc-ctrl-input-bottom-line-stroke-width-pressed"; // @public (undocumented) -export const ctrlInputBottomLineStrokeWidthRest = "var(--smtc-ctrl-input-bottom-line-stroke-width-rest, var(--smtc-stroke-width-default))"; +export const ctrlInputBottomLineStrokeWidthRest = "var(--smtc-ctrl-input-bottom-line-stroke-width-rest, var(--smtc-stroke-width-default, var(--strokeWidthThin)))"; // @public (undocumented) export const ctrlInputBottomLineStrokeWidthRestRaw = "--smtc-ctrl-input-bottom-line-stroke-width-rest"; @@ -1892,7 +1892,7 @@ export const ctrlInputBottomLineStrokeWidthSelectedRaw = "--smtc-ctrl-input-bott export const _ctrlInputNeutralForegroundPlaceholder = "var(--smtc-foreground-ctrl-neutral-secondary-rest, var(--colorNeutralForeground4))"; // @public (undocumented) -export const ctrlInputStrokeDisabled = "var(--smtc-ctrl-input-stroke-disabled, var(--smtc-stroke-ctrl-on-outline-disabled))"; +export const ctrlInputStrokeDisabled = "var(--smtc-ctrl-input-stroke-disabled, var(--smtc-stroke-ctrl-on-outline-disabled, var(--colorNeutralStrokeDisabled)))"; // @public (undocumented) export const ctrlInputStrokeDisabledRaw = "--smtc-ctrl-input-stroke-disabled"; @@ -1940,7 +1940,7 @@ export const ctrlInputStrokeWidthPressed = "var(--smtc-ctrl-input-stroke-width-p export const ctrlInputStrokeWidthPressedRaw = "--smtc-ctrl-input-stroke-width-pressed"; // @public (undocumented) -export const ctrlInputStrokeWidthRest = "var(--smtc-ctrl-input-stroke-width-rest, var(--smtc-stroke-width-default))"; +export const ctrlInputStrokeWidthRest = "var(--smtc-ctrl-input-stroke-width-rest, var(--smtc-stroke-width-default, var(--strokeWidthThin)))"; // @public (undocumented) export const ctrlInputStrokeWidthRestRaw = "--smtc-ctrl-input-stroke-width-rest"; @@ -3085,6 +3085,36 @@ export const ctrlSliderThumbSizeRest = "var(--smtc-ctrl-slider-thumb-size-rest, // @public (undocumented) export const ctrlSliderThumbSizeRestRaw = "--smtc-ctrl-slider-thumb-size-rest"; +// @public +export const _ctrlSpinButtonBackgroundDisabled = "var(--smtc-ctrl-input-background-disabled, var(--smtc-background-ctrl-neutral-disabled, var(--colorTransparentBackground)))"; + +// @public +export const _ctrlSpinButtonForegroundOnSubtleHover = "var(--smtc-foreground-ctrl-on-subtle-hover, var(--smtc-foreground-ctrl-neutral-primary-hover, var(--colorNeutralForeground3Hover)))"; + +// @public +export const _ctrlSpinButtonForegroundOnSubtlePressed = "var(--smtc-foreground-ctrl-on-subtle-pressed, var(--smtc-foreground-ctrl-neutral-primary-pressed, var(--colorNeutralForeground3Pressed)))"; + +// @public +export const _ctrlSpinButtonNeutralSecondaryRest = "var(--smtc-foreground-ctrl-neutral-secondary-rest, var(--colorNeutralForeground4))"; + +// @public +export const _ctrlSpinButtonOnSubtleRest = "var(--smtc-foreground-ctrl-on-subtle-rest, var(--smtc-foreground-ctrl-neutral-primary-rest, var(--colorNeutralForeground3)))"; + +// @public +export const _ctrlSpinButtonPaddingHorizontal = "var(--smtc-padding-ctrl-horizontal-default, var(--spacingHorizontalMNudge))"; + +// @public +export const _ctrlSpinButtonPaddingSmHorizontal = "var(--smtc-padding-ctrl-sm-horizontal-default, 5px)"; + +// @public +export const _ctrlSpinButtonSizeDefault = "var(--smtc-size-ctrl-default, 32px)"; + +// @public +export const _ctrlSpinButtonSizeIconSecondary = "var(--smtc-size-ctrl-icon-secondary, 16px)"; + +// @public +export const _ctrlSpinButtonSizeSmDefault = "var(--smtc-size-ctrl-sm-default, 24px)"; + // @public export const _ctrlSpinnerBackgroundEmpty = "var(--smtc-ctrl-progress-background-empty, var(--colorBrandStroke2Contrast))"; diff --git a/packages/semantic-tokens/src/components/input/tokens.ts b/packages/semantic-tokens/src/components/input/tokens.ts index 6fd0179f1398f5..4f551e962dfeed 100644 --- a/packages/semantic-tokens/src/components/input/tokens.ts +++ b/packages/semantic-tokens/src/components/input/tokens.ts @@ -18,6 +18,7 @@ import { colorNeutralBackgroundDisabled, colorPaletteRedBorder2, colorNeutralStroke1, + strokeWidthThin, strokeWidthThick, colorNeutralStrokeAccessible, colorNeutralStrokeAccessibleHover, @@ -25,6 +26,7 @@ import { colorCompoundBrandStroke, colorNeutralStroke1Hover, colorNeutralStroke1Pressed, + colorNeutralStrokeDisabled, } from '../../legacy/tokens'; import { statusDangerStrokeRaw } from '../../optional/variables'; import { @@ -65,11 +67,11 @@ export const ctrlInputBackgroundDisabled = `var(${ctrlInputBackgroundDisabledRaw export const ctrlInputBackgroundSelected = `var(${ctrlInputBackgroundSelectedRaw}, var(${backgroundCtrlNeutralRestRaw}, ${colorNeutralBackground1}))`; export const ctrlInputBackgroundError = `var(${ctrlInputBackgroundErrorRaw}, var(${backgroundCtrlNeutralRestRaw}, ${colorPaletteRedBorder2}))`; export const ctrlInputStrokeRest = `var(${ctrlInputStrokeRestRaw}, var(${strokeCtrlOnOutlineRestRaw}, ${colorNeutralStroke1}))`; -export const ctrlInputStrokeWidthRest = `var(${ctrlInputStrokeWidthRestRaw}, var(${strokeWidthDefaultRaw}))`; +export const ctrlInputStrokeWidthRest = `var(${ctrlInputStrokeWidthRestRaw}, var(${strokeWidthDefaultRaw}, ${strokeWidthThin}))`; export const ctrlInputStrokeWidthHover = `var(${ctrlInputStrokeWidthHoverRaw}, var(${strokeWidthDefaultRaw}))`; export const ctrlInputStrokeWidthPressed = `var(${ctrlInputStrokeWidthPressedRaw}, var(${strokeWidthDefaultRaw}))`; export const ctrlInputStrokeWidthSelected = `var(${ctrlInputStrokeWidthSelectedRaw})`; -export const ctrlInputBottomLineStrokeWidthRest = `var(${ctrlInputBottomLineStrokeWidthRestRaw}, var(${strokeWidthDefaultRaw}))`; +export const ctrlInputBottomLineStrokeWidthRest = `var(${ctrlInputBottomLineStrokeWidthRestRaw}, var(${strokeWidthDefaultRaw}, ${strokeWidthThin}))`; export const ctrlInputTextSelectionBackground = `var(${ctrlInputTextSelectionBackgroundRaw}, var(${backgroundCtrlBrandRestRaw}))`; export const ctrlInputTextSelectionForeground = `var(${ctrlInputTextSelectionForegroundRaw}, var(${foregroundCtrlOnBrandRestRaw}))`; export const ctrlInputBottomLineStrokeWidthHover = `var(${ctrlInputBottomLineStrokeWidthHoverRaw}, var(${strokeWidthDefaultRaw}))`; @@ -83,6 +85,6 @@ export const ctrlInputBottomLineStrokeSelected = `var(${ctrlInputBottomLineStrok export const ctrlInputBottomLineStrokeError = `var(${ctrlInputBottomLineStrokeErrorRaw}, unset)`; export const ctrlInputStrokeHover = `var(${ctrlInputStrokeHoverRaw}, var(${strokeCtrlOnOutlineHoverRaw}, ${colorNeutralStroke1Hover}))`; export const ctrlInputStrokePressed = `var(${ctrlInputStrokePressedRaw}, var(${strokeCtrlOnOutlinePressedRaw}, ${colorNeutralStroke1Pressed}))`; -export const ctrlInputStrokeDisabled = `var(${ctrlInputStrokeDisabledRaw}, var(${strokeCtrlOnOutlineDisabledRaw}))`; +export const ctrlInputStrokeDisabled = `var(${ctrlInputStrokeDisabledRaw}, var(${strokeCtrlOnOutlineDisabledRaw}, ${colorNeutralStrokeDisabled}))`; export const ctrlInputStrokeSelected = `var(${ctrlInputStrokeSelectedRaw}, var(${strokeCtrlOnOutlineRestRaw}, ${colorNeutralStroke1}))`; export const ctrlInputStrokeError = `var(${ctrlInputStrokeErrorRaw}, var(${statusDangerStrokeRaw}))`; diff --git a/packages/semantic-tokens/src/fluentLegacyVariants.ts b/packages/semantic-tokens/src/fluentLegacyVariants.ts index fd0c2d2021d8dc..6ff4dc3f799503 100644 --- a/packages/semantic-tokens/src/fluentLegacyVariants.ts +++ b/packages/semantic-tokens/src/fluentLegacyVariants.ts @@ -571,6 +571,46 @@ export const legacyFluentVariantsValues: LegacyFluentVariants = { originalToken: 'paddingCtrlHorizontalDefault', rawValue: '8px', }, + _ctrlSpinButtonBackgroundDisabled: { + f2Token: 'colorTransparentBackground', + originalToken: 'ctrlInputBackgroundDisabled', + }, + _ctrlSpinButtonForegroundOnSubtleHover: { + f2Token: 'colorNeutralForeground3Hover', + originalToken: 'foregroundCtrlOnSubtleHover', + }, + _ctrlSpinButtonForegroundOnSubtlePressed: { + f2Token: 'colorNeutralForeground3Pressed', + originalToken: 'foregroundCtrlOnSubtlePressed', + }, + _ctrlSpinButtonNeutralSecondaryRest: { + f2Token: 'colorNeutralForeground4', + originalToken: 'foregroundCtrlNeutralSecondaryRest', + }, + _ctrlSpinButtonOnSubtleRest: { + f2Token: 'colorNeutralForeground3', + originalToken: 'foregroundCtrlOnSubtleRest', + }, + _ctrlSpinButtonPaddingHorizontal: { + f2Token: 'spacingHorizontalMNudge', + originalToken: 'paddingCtrlHorizontalDefault', + }, + _ctrlSpinButtonPaddingSmHorizontal: { + originalToken: 'paddingCtrlSmHorizontalDefault', + rawValue: '5px', + }, + _ctrlSpinButtonSizeDefault: { + originalToken: 'sizeCtrlDefault', + rawValue: '32px', + }, + _ctrlSpinButtonSizeIconSecondary: { + originalToken: 'sizeCtrlIconSecondary', + rawValue: '16px', + }, + _ctrlSpinButtonSizeSmDefault: { + originalToken: 'sizeCtrlSmDefault', + rawValue: '24px', + }, _ctrlSpinnerBackgroundEmpty: { f2Token: 'colorBrandStroke2Contrast', originalToken: 'ctrlProgressBackgroundEmpty', diff --git a/packages/semantic-tokens/src/fluentOverrides.ts b/packages/semantic-tokens/src/fluentOverrides.ts index bf490553975cef..42d6c0bbde31d0 100644 --- a/packages/semantic-tokens/src/fluentOverrides.ts +++ b/packages/semantic-tokens/src/fluentOverrides.ts @@ -96,11 +96,14 @@ export const fluentOverrides: FluentOverrides = { ctrlInputBottomLineStrokePressed: { f2Token: 'colorNeutralStrokeAccessiblePressed' }, ctrlInputBottomLineStrokeRest: { f2Token: 'colorNeutralStrokeAccessible' }, ctrlInputBottomLineStrokeSelected: { f2Token: 'colorCompoundBrandStroke' }, + ctrlInputBottomLineStrokeWidthRest: { f2Token: 'strokeWidthThin' }, ctrlInputBottomLineStrokeWidthSelected: { f2Token: 'strokeWidthThick' }, + ctrlInputStrokeDisabled: { f2Token: 'colorNeutralStrokeDisabled' }, ctrlInputStrokeHover: { f2Token: 'colorNeutralStroke1Hover' }, ctrlInputStrokePressed: { f2Token: 'colorNeutralStroke1Pressed' }, ctrlInputStrokeRest: { f2Token: 'colorNeutralStroke1' }, ctrlInputStrokeSelected: { f2Token: 'colorNeutralStroke1' }, + ctrlInputStrokeWidthRest: { f2Token: 'strokeWidthThin' }, ctrlLinkForegroundBrandHover: { f2Token: 'colorBrandForegroundLinkHover' }, ctrlLinkForegroundBrandPressed: { f2Token: 'colorBrandForegroundLinkPressed' }, ctrlLinkForegroundBrandRest: { f2Token: 'colorBrandForegroundLink' }, diff --git a/packages/semantic-tokens/src/index.ts b/packages/semantic-tokens/src/index.ts index ed715f95c91871..c305a90b235dd9 100644 --- a/packages/semantic-tokens/src/index.ts +++ b/packages/semantic-tokens/src/index.ts @@ -1857,6 +1857,8 @@ export { _ctrlFieldPaddingCtrlTextTop, _ctrlFieldPaddingCtrlTextTopHorizontal, _ctrlFieldStatusDangerTintForeground, + _ctrlFieldStatusSuccessTintForeground, + _ctrlFieldStatusWarningTintForeground, _ctrlFocusOuterStrokeInteractive, _ctrlInputBackgroundRestDarker, _ctrlInputBackgroundRestLighter, @@ -1919,6 +1921,16 @@ export { _ctrlSliderPaddingDefault, _ctrlSliderSmBarSizeDefault, _ctrlSliderSmPaddingDefault, + _ctrlSpinButtonBackgroundDisabled, + _ctrlSpinButtonForegroundOnSubtleHover, + _ctrlSpinButtonForegroundOnSubtlePressed, + _ctrlSpinButtonNeutralSecondaryRest, + _ctrlSpinButtonOnSubtleRest, + _ctrlSpinButtonPaddingHorizontal, + _ctrlSpinButtonPaddingSmHorizontal, + _ctrlSpinButtonSizeDefault, + _ctrlSpinButtonSizeIconSecondary, + _ctrlSpinButtonSizeSmDefault, _ctrlSpinnerBackgroundEmpty, _ctrlSpinnerBackgroundFilled, _ctrlSpinnerItemBodyFontSize, @@ -1956,7 +1968,5 @@ export { _ctrlTreePaddingTextTop, _nullBackgroundColorHover, _nullBackgroundColorPressed, - _ctrlFieldStatusSuccessTintForeground, - _ctrlFieldStatusWarningTintForeground, } from './legacyVariant/tokens'; export { kumoSemanticTokens } from './themes/kumoTheme'; diff --git a/packages/semantic-tokens/src/legacy/tokens.ts b/packages/semantic-tokens/src/legacy/tokens.ts index 9d17720544bf50..dcfb009ffd8454 100644 --- a/packages/semantic-tokens/src/legacy/tokens.ts +++ b/packages/semantic-tokens/src/legacy/tokens.ts @@ -684,6 +684,11 @@ export const spacingVerticalXS = 'var(--spacingVerticalXS)'; * @public */ export const spacingVerticalSNudge = 'var(--spacingVerticalSNudge)'; +/** + * CSS custom property value for the {@link @fluentui/tokens#colorPaletteDarkOrangeForeground1 | `colorPaletteDarkOrangeForeground1`} design token. + * @public + */ +export const colorPaletteDarkOrangeForeground1 = 'var(--colorPaletteDarkOrangeForeground1)'; /** * CSS custom property value for the {@link @fluentui/tokens#colorNeutralForeground4 | `colorNeutralForeground4`} design token. * @public @@ -720,15 +725,15 @@ export const colorStatusDangerForeground1 = 'var(--colorStatusDangerForeground1) */ export const spacingVerticalMNudge = 'var(--spacingVerticalMNudge)'; /** - * CSS custom property value for the {@link @fluentui/tokens#colorBrandStroke2Contrast | `colorBrandStroke2Contrast`} design token. + * CSS custom property value for the {@link @fluentui/tokens#spacingHorizontalMNudge | `spacingHorizontalMNudge`} design token. * @public */ -export const colorBrandStroke2Contrast = 'var(--colorBrandStroke2Contrast)'; +export const spacingHorizontalMNudge = 'var(--spacingHorizontalMNudge)'; /** - * CSS custom property value for the {@link @fluentui/tokens#spacingHorizontalMNudge | `spacingHorizontalMNudge`} design token. + * CSS custom property value for the {@link @fluentui/tokens#colorBrandStroke2Contrast | `colorBrandStroke2Contrast`} design token. * @public */ -export const spacingHorizontalMNudge = 'var(--spacingHorizontalMNudge)'; +export const colorBrandStroke2Contrast = 'var(--colorBrandStroke2Contrast)'; /** * CSS custom property value for the {@link @fluentui/tokens#colorTransparentBackgroundHover | `colorTransparentBackgroundHover`} design token. * @public @@ -739,8 +744,3 @@ export const colorTransparentBackgroundHover = 'var(--colorTransparentBackground * @public */ export const colorTransparentBackgroundPressed = 'var(--colorTransparentBackgroundPressed)'; -/** - * CSS custom property value for the {@link @fluentui/tokens#colorPaletteDarkOrangeForeground1 | `colorPaletteDarkOrangeForeground1`} design token. - * @public - */ -export const colorPaletteDarkOrangeForeground1 = 'var(--colorPaletteDarkOrangeForeground1)'; diff --git a/packages/semantic-tokens/src/legacyVariant/tokens.ts b/packages/semantic-tokens/src/legacyVariant/tokens.ts index d14f0dc8b24c51..ca248ed81cd953 100644 --- a/packages/semantic-tokens/src/legacyVariant/tokens.ts +++ b/packages/semantic-tokens/src/legacyVariant/tokens.ts @@ -12,7 +12,7 @@ import { ctrlChoiceBaseSizeRaw, } from '../components/choice/variables'; import { ctrlFocusInnerStrokeWidthRaw, ctrlFocusOuterStrokeRaw } from '../components/focus/variables'; -import { ctrlInputBackgroundRestRaw } from '../components/input/variables'; +import { ctrlInputBackgroundRestRaw, ctrlInputBackgroundDisabledRaw } from '../components/input/variables'; import { ctrlListIndentLevel1Raw } from '../components/list/variables'; import { ctrlProgressBackgroundEmptyRaw, @@ -69,6 +69,10 @@ import { sizeCtrlIconRaw, foregroundCtrlOnBrandRestRaw, foregroundCtrlOnBrandDisabledRaw, + backgroundCtrlNeutralDisabledRaw, + paddingCtrlSmHorizontalDefaultRaw, + sizeCtrlIconSecondaryRaw, + sizeCtrlSmDefaultRaw, textGlobalBody3LineHeightRaw, foregroundCtrlBrandHoverRaw, foregroundCtrlBrandPressedRaw, @@ -122,6 +126,7 @@ import { spacingVerticalXXS, spacingVerticalSNudge, spacingHorizontalM, + colorPaletteDarkOrangeForeground1, colorTransparentStrokeInteractive, colorNeutralBackground3, colorNeutralForeground4, @@ -135,6 +140,7 @@ import { spacingVerticalMNudge, lineHeightBase300, colorNeutralForegroundDisabled, + spacingHorizontalMNudge, colorBrandStroke2Contrast, colorBrandStroke1, fontSizeBase400, @@ -143,10 +149,8 @@ import { colorNeutralForeground1Pressed, colorNeutralForeground2Hover, colorNeutralForeground2Pressed, - spacingHorizontalMNudge, colorTransparentBackgroundHover, colorTransparentBackgroundPressed, - colorPaletteDarkOrangeForeground1, } from '../legacy/tokens'; import { backgroundCtrlSubtleRestRaw, @@ -722,6 +726,20 @@ export const _ctrlFieldPaddingCtrlTextTopHorizontal = `var(${paddingCtrlTextTopR * please use statusDangerTintForeground instead. */ export const _ctrlFieldStatusDangerTintForeground = `var(${statusDangerTintForegroundRaw}, ${colorPaletteRedForeground1})`; +/** + * This is a legacy variant for statusSuccessTintForeground to enable backwards compatibility. + * It's purpose is to support Fluent UI legacy fallback variants only. + * This token is not intended for use in new semantic theme implementations + * please use statusSuccessTintForeground instead. + */ +export const _ctrlFieldStatusSuccessTintForeground = `var(${statusSuccessTintForegroundRaw}, ${colorPaletteGreenForeground1})`; +/** + * This is a legacy variant for statusWarningTintForeground to enable backwards compatibility. + * It's purpose is to support Fluent UI legacy fallback variants only. + * This token is not intended for use in new semantic theme implementations + * please use statusWarningTintForeground instead. + */ +export const _ctrlFieldStatusWarningTintForeground = `var(${statusWarningTintForegroundRaw}, ${colorPaletteDarkOrangeForeground1})`; /** * This is a legacy variant for ctrlFocusOuterStroke to enable backwards compatibility. * It's purpose is to support Fluent UI legacy fallback variants only. @@ -1156,6 +1174,76 @@ export const _ctrlSliderSmBarSizeDefault = `var(${sizeCtrlDefaultRaw}, 24px)`; * please use paddingCtrlHorizontalDefault instead. */ export const _ctrlSliderSmPaddingDefault = `var(${paddingCtrlHorizontalDefaultRaw}, 8px)`; +/** + * This is a legacy variant for ctrlInputBackgroundDisabled to enable backwards compatibility. + * It's purpose is to support Fluent UI legacy fallback variants only. + * This token is not intended for use in new semantic theme implementations + * please use ctrlInputBackgroundDisabled instead. + */ +export const _ctrlSpinButtonBackgroundDisabled = `var(${ctrlInputBackgroundDisabledRaw}, var(${backgroundCtrlNeutralDisabledRaw}, ${colorTransparentBackground}))`; +/** + * This is a legacy variant for foregroundCtrlOnSubtleHover to enable backwards compatibility. + * It's purpose is to support Fluent UI legacy fallback variants only. + * This token is not intended for use in new semantic theme implementations + * please use foregroundCtrlOnSubtleHover instead. + */ +export const _ctrlSpinButtonForegroundOnSubtleHover = `var(${foregroundCtrlOnSubtleHoverRaw}, var(${foregroundCtrlNeutralPrimaryHoverRaw}, ${colorNeutralForeground3Hover}))`; +/** + * This is a legacy variant for foregroundCtrlOnSubtlePressed to enable backwards compatibility. + * It's purpose is to support Fluent UI legacy fallback variants only. + * This token is not intended for use in new semantic theme implementations + * please use foregroundCtrlOnSubtlePressed instead. + */ +export const _ctrlSpinButtonForegroundOnSubtlePressed = `var(${foregroundCtrlOnSubtlePressedRaw}, var(${foregroundCtrlNeutralPrimaryPressedRaw}, ${colorNeutralForeground3Pressed}))`; +/** + * This is a legacy variant for foregroundCtrlNeutralSecondaryRest to enable backwards compatibility. + * It's purpose is to support Fluent UI legacy fallback variants only. + * This token is not intended for use in new semantic theme implementations + * please use foregroundCtrlNeutralSecondaryRest instead. + */ +export const _ctrlSpinButtonNeutralSecondaryRest = `var(${foregroundCtrlNeutralSecondaryRestRaw}, ${colorNeutralForeground4})`; +/** + * This is a legacy variant for foregroundCtrlOnSubtleRest to enable backwards compatibility. + * It's purpose is to support Fluent UI legacy fallback variants only. + * This token is not intended for use in new semantic theme implementations + * please use foregroundCtrlOnSubtleRest instead. + */ +export const _ctrlSpinButtonOnSubtleRest = `var(${foregroundCtrlOnSubtleRestRaw}, var(${foregroundCtrlNeutralPrimaryRestRaw}, ${colorNeutralForeground3}))`; +/** + * This is a legacy variant for paddingCtrlHorizontalDefault to enable backwards compatibility. + * It's purpose is to support Fluent UI legacy fallback variants only. + * This token is not intended for use in new semantic theme implementations + * please use paddingCtrlHorizontalDefault instead. + */ +export const _ctrlSpinButtonPaddingHorizontal = `var(${paddingCtrlHorizontalDefaultRaw}, ${spacingHorizontalMNudge})`; +/** + * This is a legacy variant for paddingCtrlSmHorizontalDefault to enable backwards compatibility. + * It's purpose is to support Fluent UI legacy fallback variants only. + * This token is not intended for use in new semantic theme implementations + * please use paddingCtrlSmHorizontalDefault instead. + */ +export const _ctrlSpinButtonPaddingSmHorizontal = `var(${paddingCtrlSmHorizontalDefaultRaw}, 5px)`; +/** + * This is a legacy variant for sizeCtrlDefault to enable backwards compatibility. + * It's purpose is to support Fluent UI legacy fallback variants only. + * This token is not intended for use in new semantic theme implementations + * please use sizeCtrlDefault instead. + */ +export const _ctrlSpinButtonSizeDefault = `var(${sizeCtrlDefaultRaw}, 32px)`; +/** + * This is a legacy variant for sizeCtrlIconSecondary to enable backwards compatibility. + * It's purpose is to support Fluent UI legacy fallback variants only. + * This token is not intended for use in new semantic theme implementations + * please use sizeCtrlIconSecondary instead. + */ +export const _ctrlSpinButtonSizeIconSecondary = `var(${sizeCtrlIconSecondaryRaw}, 16px)`; +/** + * This is a legacy variant for sizeCtrlSmDefault to enable backwards compatibility. + * It's purpose is to support Fluent UI legacy fallback variants only. + * This token is not intended for use in new semantic theme implementations + * please use sizeCtrlSmDefault instead. + */ +export const _ctrlSpinButtonSizeSmDefault = `var(${sizeCtrlSmDefaultRaw}, 24px)`; /** * This is a legacy variant for ctrlProgressBackgroundEmpty to enable backwards compatibility. * It's purpose is to support Fluent UI legacy fallback variants only. @@ -1415,17 +1503,3 @@ export const _nullBackgroundColorHover = `var(${nullColorRaw}, ${colorTransparen * please use nullColor instead. */ export const _nullBackgroundColorPressed = `var(${nullColorRaw}, ${colorTransparentBackgroundPressed})`; -/** - * This is a legacy variant for statusSuccessTintForeground to enable backwards compatibility. - * It's purpose is to support Fluent UI legacy fallback variants only. - * This token is not intended for use in new semantic theme implementations - * please use statusSuccessTintForeground instead. - */ -export const _ctrlFieldStatusSuccessTintForeground = `var(${statusSuccessTintForegroundRaw}, ${colorPaletteGreenForeground1})`; -/** - * This is a legacy variant for statusWarningTintForeground to enable backwards compatibility. - * It's purpose is to support Fluent UI legacy fallback variants only. - * This token is not intended for use in new semantic theme implementations - * please use statusWarningTintForeground instead. - */ -export const _ctrlFieldStatusWarningTintForeground = `var(${statusWarningTintForegroundRaw}, ${colorPaletteDarkOrangeForeground1})`;