@codecademy/gamut

72.5.172.5.2-alpha.319fdb.0
~

Modified (4 files)

Index: package/dist/Card/index.js
===================================================================
--- package/dist/Card/index.js
+++ package/dist/Card/index.js
@@ -1,9 +1,9 @@
 import { CheckerDense } from '@codecademy/gamut-patterns';
 import { borderRadii } from '@codecademy/gamut-styles';
 import * as React from 'react';
 import { DynamicCardWrapper, MotionBox, StaticCardWrapper } from './elements';
-import { hoverShadowLeft, hoverShadowRight, patternFadeInOut } from './styles';
+import { patternFadeInOut, useCardElevation } from './styles';
 import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
 export const Card = ({
   children,
   variant = 'default',
@@ -20,9 +20,9 @@
   const resolvedBorderRadius = borderRadii[trueBorderRadius];
   const SelectedWrapper = variant === 'default' ? DynamicCardWrapper : StaticCardWrapper;
   const hasPattern = shadow === 'patternLeft' || shadow === 'patternRight';
   const isOutline = shadow === 'outline';
-  const setHoverShadow = shadow === 'patternRight' ? hoverShadowRight(resolvedBorderRadius) : hoverShadowLeft(resolvedBorderRadius);
+  const setHoverShadow = useCardElevation(shadow, resolvedBorderRadius);
   const initialVariant = isOutline ? 'initialOutline' : 'initial';
   const animateVariant = isOutline ? 'animateOutline' : 'animate';
   return /*#__PURE__*/_jsxs(MotionBox, {
     height: height,
Index: package/dist/Card/styles.js
===================================================================
--- package/dist/Card/styles.js
+++ package/dist/Card/styles.js
@@ -1,8 +1,28 @@
 import { theme, timingValues, variant } from '@codecademy/gamut-styles';
+import { useTheme } from '@emotion/react';
+
+/**
+ * The theme's elevation scale is flattened to dashcase tokens (`rest-shadow`,
+ * `hoverMirrored-transform`, ...), so per-state groups don't exist on the
+ * theme at runtime. This regroups one state's tokens into a spreadable style
+ * object, mapping the `shadow` token onto the `boxShadow` property
+ * framer-motion animates.
+ */
+const getElevationStyles = (elevation, state) => ({
+  boxShadow: elevation[`${state}-shadow`],
+  transform: elevation[`${state}-transform`]
+});
 const SHADOW_OFFSET = 8;
 const SHADOW_OFFSET_INITIAL = 6;
-const TRANSFORM_OFFSET = 4;
+const REST_TRANSITION = {
+  duration: timingValues.fast / 1000,
+  ease: 'easeOut'
+};
+const HOVER_TRANSITION = {
+  duration: timingValues.fast / 1000,
+  ease: 'easeIn'
+};
 export const cardVariants = variant({
   defaultVariant: 'default',
   base: {
     color: 'text'
@@ -55,59 +75,43 @@
       ease: 'easeIn'
     }
   }
 };
-export const hoverShadowLeft = borderRadius => ({
-  initial: {
-    boxShadow: `0px 0px 0 ${theme.colors['shadow-primary']}`,
-    borderRadius,
-    transition: {
-      duration: timingValues.fast / 1000,
-      ease: 'easeOut'
+
+/**
+ * Motion variants for a Card's hover elevation, read from the active theme's
+ * `elevation` scale so each theme controls its own shadow and lift.
+ * `patternRight` cards cast their shadow on the opposite side, so they use the
+ * `hoverMirrored` tokens.
+ */
+export const useCardElevation = (shadow, borderRadius) => {
+  const {
+    elevation
+  } = useTheme();
+  const hoverState = shadow === 'patternRight' ? 'hoverMirrored' : 'hover';
+  return {
+    initial: {
+      ...getElevationStyles(elevation, 'rest'),
+      borderRadius,
+      transition: REST_TRANSITION
+    },
+    // outline variants keep their bespoke two-layer shadow but share the
+    // elevation scale's transforms
+    initialOutline: {
+      ...getElevationStyles(elevation, 'rest'),
+      boxShadow: `-${SHADOW_OFFSET_INITIAL}px ${SHADOW_OFFSET_INITIAL}px 0 0px ${theme.colors['background-current']}, -${SHADOW_OFFSET_INITIAL}px ${SHADOW_OFFSET_INITIAL}px 0 1px ${theme.colors['border-primary']}`,
+      borderRadius,
+      transition: REST_TRANSITION
+    },
+    animate: {
+      ...getElevationStyles(elevation, hoverState),
+      borderRadius,
+      transition: HOVER_TRANSITION
+    },
+    animateOutline: {
+      ...getElevationStyles(elevation, 'hover'),
+      boxShadow: `-${SHADOW_OFFSET}px ${SHADOW_OFFSET}px 0 0px ${theme.colors['shadow-primary']}, -${SHADOW_OFFSET}px ${SHADOW_OFFSET}px 0 1px ${theme.colors['shadow-primary']}`,
+      borderRadius,
+      transition: HOVER_TRANSITION
     }
-  },
-  initialOutline: {
-    boxShadow: `-${SHADOW_OFFSET_INITIAL}px ${SHADOW_OFFSET_INITIAL}px 0 0px ${theme.colors['background-current']}, -${SHADOW_OFFSET_INITIAL}px ${SHADOW_OFFSET_INITIAL}px 0 1px ${theme.colors['border-primary']}`,
-    borderRadius,
-    transition: {
-      duration: timingValues.fast / 1000,
-      ease: 'easeOut'
-    }
-  },
-  animate: {
-    transform: `translate(${TRANSFORM_OFFSET}px, -${TRANSFORM_OFFSET}px)`,
-    boxShadow: `-${SHADOW_OFFSET}px ${SHADOW_OFFSET}px 0 ${theme.colors['shadow-primary']}`,
-    borderRadius,
-    transition: {
-      duration: timingValues.fast / 1000,
-      ease: 'easeIn'
-    }
-  },
-  animateOutline: {
-    transform: `translate(${TRANSFORM_OFFSET}px, -${TRANSFORM_OFFSET}px)`,
-    boxShadow: `-${SHADOW_OFFSET}px ${SHADOW_OFFSET}px 0 0px ${theme.colors['shadow-primary']}, -${SHADOW_OFFSET}px ${SHADOW_OFFSET}px 0 1px ${theme.colors['shadow-primary']}`,
-    borderRadius,
-    transition: {
-      duration: timingValues.fast / 1000,
-      ease: 'easeIn'
-    }
-  }
-});
-export const hoverShadowRight = borderRadius => ({
-  initial: {
-    boxShadow: `0px 0px 0 ${theme.colors['shadow-primary']}`,
-    borderRadius,
-    transition: {
-      duration: timingValues.fast / 1000,
-      ease: 'easeOut'
-    }
-  },
-  animate: {
-    transform: `translate(-${TRANSFORM_OFFSET}px, -${TRANSFORM_OFFSET}px)`,
-    boxShadow: `${SHADOW_OFFSET}px ${SHADOW_OFFSET}px 0 ${theme.colors['shadow-primary']}`,
-    borderRadius,
-    transition: {
-      duration: timingValues.fast / 1000,
-      ease: 'easeIn'
-    }
-  }
-});
\ No newline at end of file
+  };
+};
\ No newline at end of file
Index: package/package.json
===================================================================
--- package/package.json
+++ package/package.json
@@ -1,16 +1,16 @@
 {
   "name": "@codecademy/gamut",
   "description": "Styleguide & Component library for Codecademy",
-  "version": "72.5.1",
+  "version": "72.5.2-alpha.319fdb.0",
   "author": "Codecademy Engineering <[email protected]>",
   "bin": "./bin/gamut.mjs",
   "dependencies": {
-    "@codecademy/gamut-icons": "9.57.11",
-    "@codecademy/gamut-illustrations": "0.58.16",
-    "@codecademy/gamut-patterns": "0.10.35",
-    "@codecademy/gamut-styles": "20.1.0",
-    "@codecademy/variance": "0.26.1",
+    "@codecademy/gamut-icons": "9.57.12-alpha.319fdb.0",
+    "@codecademy/gamut-illustrations": "0.58.17-alpha.319fdb.0",
+    "@codecademy/gamut-patterns": "0.10.36-alpha.319fdb.0",
+    "@codecademy/gamut-styles": "20.1.1-alpha.319fdb.0",
+    "@codecademy/variance": "0.26.2-alpha.319fdb.0",
     "@formatjs/intl-locale": "5.3.1",
     "@react-aria/interactions": "3.25.0",
     "@types/marked": "^4.0.8",
     "@vidstack/react": "^1.12.12",
Index: package/dist/Card/styles.d.ts
===================================================================
--- package/dist/Card/styles.d.ts
+++ package/dist/Card/styles.d.ts
@@ -1,9 +1,11 @@
+import { StyleProps } from '@codecademy/variance';
+import { Theme } from '@emotion/react';
 export declare const cardVariants: (props: import("@codecademy/variance/dist/types/config").VariantProps<"variant", false | "beige" | "hyper" | "navy" | "yellow" | "white" | "default"> & {
-    theme?: import("@emotion/react").Theme;
+    theme?: Theme;
 }) => import("@codecademy/variance").CSSObject;
 export declare const shadowVariants: (props: import("@codecademy/variance/dist/types/config").VariantProps<"shadow", false | "outline" | "none" | "patternLeft" | "patternRight"> & {
-    theme?: import("@emotion/react").Theme;
+    theme?: Theme;
 }) => import("@codecademy/variance").CSSObject;
 export declare const patternFadeInOut: {
     initial: {
         opacity: number;
@@ -19,59 +21,48 @@
             ease: string;
         };
     };
 };
-export declare const hoverShadowLeft: (borderRadius?: string) => {
+/**
+ * Motion variants for a Card's hover elevation, read from the active theme's
+ * `elevation` scale so each theme controls its own shadow and lift.
+ * `patternRight` cards cast their shadow on the opposite side, so they use the
+ * `hoverMirrored` tokens.
+ */
+export declare const useCardElevation: (shadow: StyleProps<typeof shadowVariants>["shadow"], borderRadius?: string) => {
     initial: {
-        boxShadow: string;
         borderRadius: string | undefined;
         transition: {
-            duration: number;
-            ease: string;
+            readonly duration: number;
+            readonly ease: "easeOut";
         };
+        boxShadow: string;
+        transform: string;
     };
     initialOutline: {
         boxShadow: string;
         borderRadius: string | undefined;
         transition: {
-            duration: number;
-            ease: string;
+            readonly duration: number;
+            readonly ease: "easeOut";
         };
+        transform: string;
     };
     animate: {
-        transform: string;
-        boxShadow: string;
         borderRadius: string | undefined;
         transition: {
-            duration: number;
-            ease: string;
+            readonly duration: number;
+            readonly ease: "easeIn";
         };
+        boxShadow: string;
+        transform: string;
     };
     animateOutline: {
-        transform: string;
         boxShadow: string;
         borderRadius: string | undefined;
         transition: {
-            duration: number;
-            ease: string;
+            readonly duration: number;
+            readonly ease: "easeIn";
         };
-    };
-};
-export declare const hoverShadowRight: (borderRadius?: string) => {
-    initial: {
-        boxShadow: string;
-        borderRadius: string | undefined;
-        transition: {
-            duration: number;
-            ease: string;
-        };
-    };
-    animate: {
         transform: string;
-        boxShadow: string;
-        borderRadius: string | undefined;
-        transition: {
-            duration: number;
-            ease: string;
-        };
     };
 };