diff --git a/docs/guides/upgrade-guide.md b/docs/guides/upgrade-guide.md index 5519666d9d..08c8cf5789 100644 --- a/docs/guides/upgrade-guide.md +++ b/docs/guides/upgrade-guide.md @@ -135,9 +135,10 @@ type: example ``` + ### Breadcrumb -#### New tokens +#### New tokens - gapSm - Gap spacing for small size breadcrumbs - gapMd - Gap spacing for medium size breadcrumbs @@ -255,6 +256,13 @@ type: example - theme variable `invalidAsteriskColor` is now removed - `error` or `success` messages are no longer displayed when the component is '`readOnly` or `disabled` +### RangeInput + +- theme variable `handleShadow` is now renamed to `boxShadow` +- theme variable `handleFocusRingSize` is now removed style uses the `focusOutline.width` token +- theme variable `handleFocusRingColor` is now removed style uses the `sharedTokens.focusOutline.onColor` token +- theme variables `valueSmallPadding`,`valueMediumPadding` and `valueLargePadding` now only set the horizontal padding of the value. + ### TextInput - theme variable `requiredInvalidColor` is now removed diff --git a/packages/ui-range-input/src/RangeInput/index.tsx b/packages/ui-range-input/src/RangeInput/index.tsx index 70c17ee06c..d0b3aa3990 100644 --- a/packages/ui-range-input/src/RangeInput/index.tsx +++ b/packages/ui-range-input/src/RangeInput/index.tsx @@ -28,7 +28,7 @@ import { warn } from '@instructure/console' import { ContextView } from '@instructure/ui-view' import { FormField } from '@instructure/ui-form-field' import { addEventListener } from '@instructure/ui-dom-utils' -import { withStyleRework as withStyle } from '@instructure/emotion' +import { withStyle } from '@instructure/emotion' import { omitProps, pickProps, @@ -36,7 +36,6 @@ import { } from '@instructure/ui-react-utils' import generateStyle from './styles' -import generateComponentTheme from './theme' import type { RangeInputProps, RangeInputState } from './props' import { allowedProps } from './props' @@ -47,7 +46,7 @@ category: components --- **/ @withDeterministicId() -@withStyle(generateStyle, generateComponentTheme) +@withStyle(generateStyle) class RangeInput extends Component { static readonly componentId = 'RangeInput' static outputLocatorAttribute = 'data-range-output' diff --git a/packages/ui-range-input/src/RangeInput/styles.ts b/packages/ui-range-input/src/RangeInput/styles.ts index ac2313d90f..4e5268f46f 100644 --- a/packages/ui-range-input/src/RangeInput/styles.ts +++ b/packages/ui-range-input/src/RangeInput/styles.ts @@ -22,8 +22,10 @@ * SOFTWARE. */ -import type { RangeInputTheme } from '@instructure/shared-types' +import type { NewComponentTypes, SharedTokens } from '@instructure/ui-themes' import type { RangeInputProps, RangeInputStyle } from './props' +import { darken, alpha } from '@instructure/ui-color-utils' +import { boxShadowObjectsToCSSString } from '@instructure/ui-themes' /** * --- @@ -36,31 +38,34 @@ import type { RangeInputProps, RangeInputStyle } from './props' * @return {Object} The final style object, which will be used in the component */ const generateStyle = ( - componentTheme: RangeInputTheme, - props: RangeInputProps + componentTheme: NewComponentTypes['RangeInput'], + props: RangeInputProps, + sharedTokens: SharedTokens ): RangeInputStyle => { const { size, thumbVariant } = props const valueSizeVariants = { small: { fontSize: componentTheme.valueSmallFontSize, - padding: componentTheme.valueSmallPadding, + padding: `${'0 ' + componentTheme.valueSmallPadding}`, lineHeight: componentTheme.valueSmallLineHeight }, medium: { fontSize: componentTheme.valueMediumFontSize, - padding: componentTheme.valueMediumPadding, + padding: `${'0 ' + componentTheme.valueMediumPadding}`, lineHeight: componentTheme.valueMediumLineHeight }, large: { fontSize: componentTheme.valueLargeFontSize, - padding: componentTheme.valueLargePadding, + padding: `${'0 ' + componentTheme.valueLargePadding}`, lineHeight: componentTheme.valueLargeLineHeight } } const trackStyle = { borderRadius: '0.312em', - borderColor: 'transparent', + borderWidth: '1px', + borderStyle: 'solid', + borderColor: componentTheme.trackBorderColor, color: 'transparent', cursor: 'pointer', background: componentTheme.trackBackground, @@ -73,7 +78,7 @@ const generateStyle = ( deprecated: { width: componentTheme.handleSize, height: componentTheme.handleSize, - boxShadow: `0 0.0625rem 0 ${componentTheme.handleShadowColor}` + boxShadow: `0 0.0625rem 0 ${darken(componentTheme.handleShadowColor)}` }, accessible: { width: borderedHandleSize, @@ -82,7 +87,7 @@ const generateStyle = ( borderColor: componentTheme.handleBorderColor, borderStyle: 'solid', boxSizing: 'border-box', - boxShadow: componentTheme.handleShadow + boxShadow: boxShadowObjectsToCSSString(componentTheme.boxShadow) } } @@ -101,25 +106,29 @@ const generateStyle = ( const thumbPosition = { deprecated: { - marginTop: `calc(-1 * ${componentTheme.handleSize} / 4)` + marginTop: `calc(-1 * ${componentTheme.handleSize} / 4 - 1px)` }, accessible: { - marginTop: `calc(-1 * ${borderedHandleSize} / 4)` + marginTop: `calc(-1 * ${borderedHandleSize} / 4 - 1px)` } } const thumbFocusActiveStyle = { deprecated: { background: componentTheme.handleFocusBackground, - boxShadow: `0 0.0625rem 0 ${componentTheme.handleShadowColor}, 0 0 0 ${componentTheme.handleFocusOutlineWidth} ${componentTheme.handleFocusOutlineColor}` + boxShadow: `0 0.0625rem 0 ${darken( + componentTheme.handleShadowColor + )}, 0 0 0 ${componentTheme.handleFocusOutlineWidth} ${alpha( + componentTheme.handleFocusOutlineColor, + 40 + )}` }, accessible: { background: componentTheme.handleFocusBackground, boxShadow: - componentTheme.handleShadow + - ', ' + + `${boxShadowObjectsToCSSString(componentTheme.boxShadow)}, ` + `inset 0 0 0 ${componentTheme.handleFocusInset} ${componentTheme.handleFocusBackground}, ` + - `inset 0 0 0 calc(${componentTheme.handleFocusInset} + ${componentTheme.handleFocusRingSize}) ${componentTheme.handleFocusRingColor}` + `inset 0 0 0 calc(${componentTheme.handleFocusInset} + ${sharedTokens.focusOutline.width}) ${sharedTokens.focusOutline.onColor}` } } diff --git a/packages/ui-range-input/src/RangeInput/theme.ts b/packages/ui-range-input/src/RangeInput/theme.ts deleted file mode 100644 index 2b9fe4d6ce..0000000000 --- a/packages/ui-range-input/src/RangeInput/theme.ts +++ /dev/null @@ -1,96 +0,0 @@ -/* - * The MIT License (MIT) - * - * Copyright (c) 2015 - present Instructure, Inc. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -import { alpha, darken } from '@instructure/ui-color-utils' -import type { Theme, ThemeSpecificStyle } from '@instructure/ui-themes' -import { RangeInputTheme } from '@instructure/shared-types' - -/** - * Generates the theme object for the component from the theme and provided additional information - * @param {Object} theme The actual theme object. - * @return {Object} The final theme object with the overrides and component variables - */ -const generateComponentTheme = (theme: Theme): RangeInputTheme => { - const { colors, borders, typography, spacing, forms, key: themeName } = theme - - const themeSpecificStyle: ThemeSpecificStyle = { - canvas: { - handleBackground: theme['ic-brand-primary'], - handleHoverBackground: theme['ic-brand-primary'], - handleFocusBackground: theme['ic-brand-primary'], - - // Deprecated, remove with "deprecated" thumbVariant - handleShadowColor: darken(theme['ic-brand-primary'], 15), - handleFocusOutlineColor: alpha(theme['ic-brand-primary']!, 40) - } - } - - const componentVariables: RangeInputTheme = { - minWidth: '12.5rem', - - handleSize: '1.5rem', - handleBackground: colors?.contrasts?.blue4570, - handleBorderColor: colors?.contrasts?.white1010, - handleBorderSize: borders?.widthMedium, - handleShadow: - '0 0.0625rem 0.125rem rgba(0, 0, 0, .2), 0 0.0625rem 0.1875rem rgba(0, 0, 0, 0.1)', - - handleFocusInset: borders?.widthSmall, - handleFocusRingSize: borders?.widthMedium, - handleFocusRingColor: colors?.contrasts?.white1010, - - handleFocusBackground: colors?.contrasts?.blue4570, - handleHoverBackground: colors?.contrasts?.blue4570, - - // Deprecated, remove with "deprecated" thumbVariant - handleShadowColor: darken(colors?.contrasts?.blue5782, 10), - handleFocusOutlineColor: alpha(colors?.contrasts?.blue4570, 40), - handleFocusOutlineWidth: '0.75em', - - trackBackground: colors?.contrasts?.grey4570, - - valueColor: colors?.contrasts?.white1010, - valueFontFamily: typography?.fontFamily, - valueFontWeight: typography?.fontWeightNormal, - - valueSmallFontSize: typography?.fontSizeSmall, - valueSmallPadding: `0 ${spacing?.xSmall}`, - valueSmallLineHeight: forms?.inputHeightSmall, - - valueMediumFontSize: typography?.fontSizeMedium, - valueMediumPadding: `0 ${spacing?.small}`, - valueMediumLineHeight: forms?.inputHeightMedium, - - valueLargeFontSize: typography?.fontSizeLarge, - valueLargePadding: `0 ${spacing?.medium}`, - valueLargeLineHeight: forms?.inputHeightLarge - } - - return { - ...componentVariables, - ...themeSpecificStyle[themeName] - } -} - -export default generateComponentTheme diff --git a/packages/ui-themes/src/index.ts b/packages/ui-themes/src/index.ts index 024c8b096b..97944921cc 100644 --- a/packages/ui-themes/src/index.ts +++ b/packages/ui-themes/src/index.ts @@ -50,6 +50,7 @@ import { additionalPrimitives } from './sharedThemeTokens/colors/primitives' import dataVisualization from './sharedThemeTokens/colors/dataVisualization' +import { boxShadowObjectsToCSSString } from './utils/boxShadowObjectToString' import type { Canvas as NewCanvas, @@ -85,7 +86,8 @@ export { canvasHighContrast, primitives, additionalPrimitives, - dataVisualization + dataVisualization, + boxShadowObjectsToCSSString } export default canvas export type { diff --git a/packages/ui-themes/src/utils/boxShadowObjectToString.ts b/packages/ui-themes/src/utils/boxShadowObjectToString.ts index d98763427d..e18f25812c 100644 --- a/packages/ui-themes/src/utils/boxShadowObjectToString.ts +++ b/packages/ui-themes/src/utils/boxShadowObjectToString.ts @@ -27,20 +27,63 @@ import { TokenBoxshadowValueInst } from '../themes/newThemes/commonTypes' /** * Converts a BoxShadowObject from Token Studio to a CSS box-shadow string */ -function boxShadowObjectToString(boxShadowObject: TokenBoxshadowValueInst) { +function boxShadowToCSSString(boxShadowObject: TokenBoxshadowValueInst) { + // weird string concatenation is to make it look nice in the debugger if (boxShadowObject.type === 'innerShadow') { - return `inset ${boxShadowObject.x} - ${boxShadowObject.y} - ${boxShadowObject.blur ? boxShadowObject.blur : ''} - ${boxShadowObject.spread ? boxShadowObject.spread : ''} - ${boxShadowObject.color}` + return ( + `inset ${boxShadowObject.x} ` + + `${boxShadowObject.y} ` + + `${boxShadowObject.blur ? boxShadowObject.blur : ''} ` + + `${boxShadowObject.spread ? boxShadowObject.spread : ''} ` + + `${boxShadowObject.color}` + ) } - return `${boxShadowObject.x} - ${boxShadowObject.y} - ${boxShadowObject.blur ? boxShadowObject.blur : ''} - ${boxShadowObject.spread ? boxShadowObject.spread : ''} - ${boxShadowObject.color}` + return ( + `${boxShadowObject.x} ` + + `${boxShadowObject.y} ` + + `${boxShadowObject.blur ? boxShadowObject.blur : ''} ` + + `${boxShadowObject.spread ? boxShadowObject.spread : ''} ` + + `${boxShadowObject.color}` + ) } -export default boxShadowObjectToString -export { boxShadowObjectToString } +function getShadowsInOrder( + shadowsObj: Record +) { + return Object.keys(shadowsObj) + .sort((a, b) => { + const numA = parseInt(a) + const numB = parseInt(b) + return numA - numB + }) + .map((key) => shadowsObj[key]) +} + +/** + * Converts a box shadow object that looks like this: + * ``` + * { + * '1': {color: 'rgba(12, 0, 0, 0.2)', x:...}, + * '2': {color: 'rgba(0, 0, 0, 0.1)', x:...}, + * '0': {color: 'rgba(0, 0, 0, 0.1)', x:...} + * } + * ``` + * to a CSS box-shadow string e.g. + * ``` + * 0px 0.375rem 0.4375rem 0px rgba(12,0,0,0.2), + * 0px 0.625rem 1.75rem 0px rgba(0,0,0,0.1), + * 0px 0.625rem 1.75rem 0px rgba(0,0,0,0.1) + * ``` + */ +function boxShadowObjectsToCSSString( + shadowObject: Record +) { + const shadows = getShadowsInOrder(shadowObject) + let result = '' + for (const shadow of shadows) { + result += boxShadowToCSSString(shadow) + ',\n' + } + return result.slice(0, -2) +} + +export { boxShadowToCSSString, boxShadowObjectsToCSSString }