diff --git a/packages/fast-components-react-msft/src/outline-button/outline-button.stories.tsx b/packages/fast-components-react-msft/src/outline-button/outline-button.stories.tsx index 226d7287004..e14fd706d39 100644 --- a/packages/fast-components-react-msft/src/outline-button/outline-button.stories.tsx +++ b/packages/fast-components-react-msft/src/outline-button/outline-button.stories.tsx @@ -2,6 +2,14 @@ import { storiesOf } from "@storybook/react"; import React from "react"; import { OutlineButton } from "./"; import { glyphFactory, SVGGlyph } from "../../assets/svg-element"; +import { DesignSystemProvider } from "@microsoft/fast-jss-manager-react"; +import { + accentPalette, + DesignSystem, + DesignSystemDefaults, + offsetsAlgorithm, +} from "@microsoft/fast-components-styles-msft"; +import { colorRecipeFactory } from "@microsoft/fast-components-styles-msft/dist/utilities/color/common"; storiesOf("Outline button", module) .add("Default", () => Outline button) @@ -48,4 +56,18 @@ storiesOf("Outline button", module) > Disabled outline anchor button - )); + )) + .add("Alternate style", () => { + const alternateDesignSystem: DesignSystem = Object.assign( + {}, + DesignSystemDefaults, + { + neutralOutline: offsetsAlgorithm(accentPalette, 10, 40, 16, 50), + } + ); + return ( + + Alternate style outline button + + ); + }); diff --git a/packages/fast-components-styles-msft/src/design-system/index.ts b/packages/fast-components-styles-msft/src/design-system/index.ts index 7e13489d6cc..4516130abbc 100644 --- a/packages/fast-components-styles-msft/src/design-system/index.ts +++ b/packages/fast-components-styles-msft/src/design-system/index.ts @@ -11,6 +11,8 @@ import { FontWeight } from "../utilities/fonts"; import designSystemSchema from "./design-system.schema"; import { accentPalette, neutralPalette } from "../default-palette"; import { isFunction } from "lodash-es"; +import { SwatchFamilyResolver } from "../utilities/color/common"; +import { offsetsAlgorithm } from "../utilities/color/offsets-algorithm"; export const defaultFontWeights: FontWeight = { light: 100, @@ -202,6 +204,8 @@ export interface DesignSystem { neutralOutlineHoverDelta: number; neutralOutlineActiveDelta: number; neutralOutlineFocusDelta: number; + + neutralOutline: SwatchFamilyResolver; } const designSystemDefaults: DesignSystem = { @@ -270,10 +274,20 @@ const designSystemDefaults: DesignSystem = { neutralDividerRestDelta: 8, + /** + * These would be deprecated / removed + */ neutralOutlineRestDelta: 25, neutralOutlineHoverDelta: 40, neutralOutlineActiveDelta: 16, neutralOutlineFocusDelta: 25, + + /** + * Recipes would be configured more like this. Is there a pattern we've used + * to define interface types like this in the schema instead of the properties + * that go into it? + */ + neutralOutline: offsetsAlgorithm(neutralPalette, 25, 40, 16, 25), }; /** diff --git a/packages/fast-components-styles-msft/src/outline-button/index.ts b/packages/fast-components-styles-msft/src/outline-button/index.ts index 52f773ba513..8e36c795032 100644 --- a/packages/fast-components-styles-msft/src/outline-button/index.ts +++ b/packages/fast-components-styles-msft/src/outline-button/index.ts @@ -3,15 +3,13 @@ import { ComponentStyles } from "@microsoft/fast-jss-manager"; import { applyFocusVisible, format, subtract, toPx } from "@microsoft/fast-jss-utilities"; import { DesignSystem } from "../design-system"; import { baseButton, buttonStyles } from "../patterns/button"; -import { - neutralFocus, - neutralForegroundRest, - neutralOutlineActive, - neutralOutlineHover, - neutralOutlineRest, -} from "../utilities/color"; +import { neutralFocus, neutralForegroundRest } from "../utilities/color"; import { horizontalSpacing } from "../utilities/density"; -import { focusOutlineWidth, outlineWidth } from "../utilities/design-system"; +import { + focusOutlineWidth, + neutralOutlineRecipe, + outlineWidth, +} from "../utilities/design-system"; import { highContrastDisabledBorder, highContrastLinkBorder, @@ -21,6 +19,7 @@ import { highContrastSelected, highContrastSelector, } from "../utilities/high-contrast"; +import { active, hover, rest } from "../utilities/color/common"; const styles: ComponentStyles = { ...baseButton, @@ -32,7 +31,7 @@ const styles: ComponentStyles border: format( "{0} solid {1}", toPx(outlineWidth), - neutralOutlineRest + rest(neutralOutlineRecipe) ), padding: format("0 {0}", horizontalSpacing(outlineWidth)), "&:hover:enabled": { @@ -40,7 +39,7 @@ const styles: ComponentStyles border: format( "{0} solid {1}", toPx(outlineWidth), - neutralOutlineHover + hover(neutralOutlineRecipe) ), ...highContrastSelected, }, @@ -49,7 +48,7 @@ const styles: ComponentStyles border: format( "{0} solid {1}", toPx(outlineWidth), - neutralOutlineActive + active(neutralOutlineRecipe) ), }, ...applyFocusVisible({ diff --git a/packages/fast-components-styles-msft/src/utilities/color/common.ts b/packages/fast-components-styles-msft/src/utilities/color/common.ts index 3dfd82b4918..8b98da817e5 100644 --- a/packages/fast-components-styles-msft/src/utilities/color/common.ts +++ b/packages/fast-components-styles-msft/src/utilities/color/common.ts @@ -143,6 +143,59 @@ export function swatchFamilyToSwatchRecipeFactory( }; } +function swatchFamilyResolverToSwatchRecipeFactory( + type: keyof T, + callback: DesignSystemResolver> +): SwatchRecipe { + const memoizedRecipe: typeof callback = memoize(callback); + return (arg: DesignSystem | SwatchResolver): any => { + if (typeof arg === "function") { + return (designSystem: DesignSystem): Swatch => { + return memoizedRecipe( + Object.assign({}, designSystem, { + backgroundColor: arg(designSystem), + }) + )(designSystem)[type as string]; + }; + } else { + return memoizedRecipe(arg)(arg)[type]; + } + }; +} + +export function rest( + swatchFamilyResolver: DesignSystemResolver +): SwatchRecipe { + return swatchFamilyResolverToSwatchRecipeFactory( + SwatchFamilyType.rest, + swatchFamilyResolver + ); +} +export function hover( + swatchFamilyResolver: DesignSystemResolver +): SwatchRecipe { + return swatchFamilyResolverToSwatchRecipeFactory( + SwatchFamilyType.hover, + swatchFamilyResolver + ); +} +export function active( + swatchFamilyResolver: DesignSystemResolver +): SwatchRecipe { + return swatchFamilyResolverToSwatchRecipeFactory( + SwatchFamilyType.active, + swatchFamilyResolver + ); +} +export function focus( + swatchFamilyResolver: DesignSystemResolver +): SwatchRecipe { + return swatchFamilyResolverToSwatchRecipeFactory( + SwatchFamilyType.focus, + swatchFamilyResolver + ); +} + /** * Converts a color string into a ColorRGBA64 instance. * Supports #RRGGBB and rgb(r, g, b) formats diff --git a/packages/fast-components-styles-msft/src/utilities/color/index.ts b/packages/fast-components-styles-msft/src/utilities/color/index.ts index 85421a7804f..70c268824c8 100644 --- a/packages/fast-components-styles-msft/src/utilities/color/index.ts +++ b/packages/fast-components-styles-msft/src/utilities/color/index.ts @@ -120,3 +120,4 @@ export { neutralFocus, neutralFocusInnerAccent } from "./neutral-focus"; export { neutralPaletteConfig, accentPaletteConfig } from "./color-constants"; export { isDarkMode, palette, PaletteType, Palette } from "./palette"; export { createColorPalette } from "./create-color-palette"; +export { offsetsAlgorithm } from "./offsets-algorithm"; diff --git a/packages/fast-components-styles-msft/src/utilities/color/neutral-outline.ts b/packages/fast-components-styles-msft/src/utilities/color/neutral-outline.ts index 0d94b80900c..e6deb37a3b4 100644 --- a/packages/fast-components-styles-msft/src/utilities/color/neutral-outline.ts +++ b/packages/fast-components-styles-msft/src/utilities/color/neutral-outline.ts @@ -1,5 +1,3 @@ -import { DesignSystem } from "../../design-system"; -import { findClosestBackgroundIndex, getSwatch, isDarkMode } from "./palette"; import { ColorRecipe, colorRecipeFactory, @@ -9,54 +7,55 @@ import { SwatchFamilyType, SwatchRecipe, } from "./common"; +import { offsetsAlgorithm } from "./offsets-algorithm"; +import { neutralPalette } from "../../default-palette"; import { neutralOutlineActiveDelta, neutralOutlineFocusDelta, neutralOutlineHoverDelta, neutralOutlineRestDelta, - neutralPalette, } from "../design-system"; -const neutralOutlineAlgorithm: SwatchFamilyResolver = ( - designSystem: DesignSystem -): SwatchFamily => { - const palette: string[] = neutralPalette(designSystem); - const backgroundIndex: number = findClosestBackgroundIndex(designSystem); - const direction: 1 | -1 = isDarkMode(designSystem) ? -1 : 1; - - const restDelta: number = neutralOutlineRestDelta(designSystem); - const restIndex: number = backgroundIndex + direction * restDelta; - const hoverDelta: number = neutralOutlineHoverDelta(designSystem); - const hoverIndex: number = restIndex + direction * (hoverDelta - restDelta); - const activeDelta: number = neutralOutlineActiveDelta(designSystem); - const activeIndex: number = restIndex + direction * (activeDelta - restDelta); - const focusDelta: number = neutralOutlineFocusDelta(designSystem); - const focusIndex: number = restIndex + direction * (focusDelta - restDelta); - - return { - rest: getSwatch(restIndex, palette), - hover: getSwatch(hoverIndex, palette), - active: getSwatch(activeIndex, palette), - focus: getSwatch(focusIndex, palette), - }; -}; +const neutralOutlineAlgorithm: SwatchFamilyResolver = offsetsAlgorithm( + neutralPalette, + neutralOutlineRestDelta, + neutralOutlineHoverDelta, + neutralOutlineActiveDelta, + neutralOutlineFocusDelta +); +/** + * @deprecated + */ export const neutralOutline: ColorRecipe = colorRecipeFactory( neutralOutlineAlgorithm ); + +/** + * @deprecated + */ export const neutralOutlineRest: SwatchRecipe = swatchFamilyToSwatchRecipeFactory( SwatchFamilyType.rest, - neutralOutline + neutralOutlineAlgorithm ); +/** + * @deprecated + */ export const neutralOutlineHover: SwatchRecipe = swatchFamilyToSwatchRecipeFactory( SwatchFamilyType.hover, - neutralOutline + neutralOutlineAlgorithm ); +/** + * @deprecated + */ export const neutralOutlineActive: SwatchRecipe = swatchFamilyToSwatchRecipeFactory( SwatchFamilyType.active, - neutralOutline + neutralOutlineAlgorithm ); +/** + * @deprecated + */ export const neutralOutlineFocus: SwatchRecipe = swatchFamilyToSwatchRecipeFactory( SwatchFamilyType.focus, - neutralOutline + neutralOutlineAlgorithm ); diff --git a/packages/fast-components-styles-msft/src/utilities/color/offsets-algorithm.ts b/packages/fast-components-styles-msft/src/utilities/color/offsets-algorithm.ts new file mode 100644 index 00000000000..4ef8cf9921d --- /dev/null +++ b/packages/fast-components-styles-msft/src/utilities/color/offsets-algorithm.ts @@ -0,0 +1,62 @@ +import { + checkDesignSystemResolver, + DesignSystem, + DesignSystemResolver, +} from "../../design-system"; +import { SwatchFamily, SwatchFamilyResolver } from "./common"; +import { findClosestBackgroundIndex, getSwatch, isDarkMode, Palette } from "./palette"; + +/** + * Function to derive colors from offset configuration. + */ +export function offsetsAlgorithm( + palette: Palette | DesignSystemResolver, + restDelta: number | DesignSystemResolver, + hoverDelta: number | DesignSystemResolver, + activeDelta: number | DesignSystemResolver, + focusDelta: number | DesignSystemResolver +): SwatchFamilyResolver { + return (designSystem: DesignSystem): SwatchFamily => { + const resolvedPalette: Palette = checkDesignSystemResolver(palette, designSystem); + + const backgroundIndex: number = findClosestBackgroundIndex(designSystem); + + const direction: 1 | -1 = isDarkMode(designSystem) ? -1 : 1; + + const resolvedRestDelta: number = checkDesignSystemResolver( + restDelta, + designSystem + ); + const resolvedHoverDelta: number = checkDesignSystemResolver( + hoverDelta, + designSystem + ); + const resolvedActiveDelta: number = checkDesignSystemResolver( + activeDelta, + designSystem + ); + const resolvedFocusDelta: number = checkDesignSystemResolver( + focusDelta, + designSystem + ); + + return { + rest: getSwatch( + backgroundIndex + direction * resolvedRestDelta, + resolvedPalette + ), + hover: getSwatch( + backgroundIndex + direction * resolvedHoverDelta, + resolvedPalette + ), + active: getSwatch( + backgroundIndex + direction * resolvedActiveDelta, + resolvedPalette + ), + focus: getSwatch( + backgroundIndex + direction * resolvedFocusDelta, + resolvedPalette + ), + }; + }; +} diff --git a/packages/fast-components-styles-msft/src/utilities/design-system.ts b/packages/fast-components-styles-msft/src/utilities/design-system.ts index f011b1e2aa3..bea6027cae7 100644 --- a/packages/fast-components-styles-msft/src/utilities/design-system.ts +++ b/packages/fast-components-styles-msft/src/utilities/design-system.ts @@ -5,6 +5,7 @@ import designSystemDefaults, { import { Palette } from "../utilities/color/palette"; import { Direction } from "@microsoft/fast-web-utilities"; import { FontWeight } from "./fonts"; +import { SwatchFamilyResolver } from "./color/common"; /** * Safely retrieves the value from a key of the DesignSystem. @@ -250,3 +251,7 @@ export const getFontWeight: DesignSystemResolver = getDesignSystemVa export const neutralOutlineFocusDelta: DesignSystemResolver< number > = getDesignSystemValue("neutralOutlineFocusDelta"); + +export const neutralOutlineRecipe: DesignSystemResolver< + SwatchFamilyResolver +> = getDesignSystemValue("neutralOutline");