From 15ed3b1c9254c2ff2e51a01bf435bec87a9eea45 Mon Sep 17 00:00:00 2001 From: Kenny Lin Date: Thu, 4 Jun 2026 09:50:54 -0400 Subject: [PATCH 1/3] first go at removing AccordionDep and related components --- .../version-plan-1780579286290.md | 17 ++ .../__snapshots__/gamut.test.ts.snap | 3 - .../AccordionAreaDeprecated.test.tsx | 48 ----- .../src/AccordionAreaDeprecated/index.tsx | 68 ------- .../ButtonDeprecated/index.tsx | 190 ------------------ .../ButtonDeprecated/styles/index.module.scss | 104 ---------- .../ButtonDeprecated/styles/mixins.scss | 109 ---------- .../ButtonDeprecated/styles/variables.scss | 53 ----- .../ButtonDeprecatedBase/index.tsx | 103 ---------- .../ButtonDeprecatedBase/styles.module.scss | 74 ------- .../AccordionButtonDeprecated.test.tsx | 38 ---- .../src/AccordionButtonDeprecated/index.tsx | 99 --------- .../styles.module.scss | 56 ------ .../__tests__/AccordionDeprecated.test.tsx | 47 ----- .../gamut/src/AccordionDeprecated/index.tsx | 92 --------- packages/gamut/src/index.tsx | 3 - .../styleguide/src/lib/Molecules/AboutToC.tsx | 4 - .../AccordionButtonDeprecated.mdx | 64 ------ .../AccordionButtonDeprecated.stories.tsx | 36 ---- .../AccordionDeprecated.mdx | 62 ------ .../AccordionDeprecated.stories.tsx | 44 ---- 21 files changed, 17 insertions(+), 1297 deletions(-) create mode 100644 .nx/version-plans/version-plan-1780579286290.md delete mode 100644 packages/gamut/src/AccordionAreaDeprecated/__tests__/AccordionAreaDeprecated.test.tsx delete mode 100644 packages/gamut/src/AccordionAreaDeprecated/index.tsx delete mode 100644 packages/gamut/src/AccordionButtonDeprecated/ButtonDeprecated/index.tsx delete mode 100644 packages/gamut/src/AccordionButtonDeprecated/ButtonDeprecated/styles/index.module.scss delete mode 100644 packages/gamut/src/AccordionButtonDeprecated/ButtonDeprecated/styles/mixins.scss delete mode 100755 packages/gamut/src/AccordionButtonDeprecated/ButtonDeprecated/styles/variables.scss delete mode 100644 packages/gamut/src/AccordionButtonDeprecated/ButtonDeprecatedBase/index.tsx delete mode 100644 packages/gamut/src/AccordionButtonDeprecated/ButtonDeprecatedBase/styles.module.scss delete mode 100644 packages/gamut/src/AccordionButtonDeprecated/__tests__/AccordionButtonDeprecated.test.tsx delete mode 100644 packages/gamut/src/AccordionButtonDeprecated/index.tsx delete mode 100755 packages/gamut/src/AccordionButtonDeprecated/styles.module.scss delete mode 100644 packages/gamut/src/AccordionDeprecated/__tests__/AccordionDeprecated.test.tsx delete mode 100644 packages/gamut/src/AccordionDeprecated/index.tsx delete mode 100644 packages/styleguide/src/lib/Molecules/AccordionButtonDeprecated/AccordionButtonDeprecated.mdx delete mode 100644 packages/styleguide/src/lib/Molecules/AccordionButtonDeprecated/AccordionButtonDeprecated.stories.tsx delete mode 100644 packages/styleguide/src/lib/Molecules/AccordionDeprecated/AccordionDeprecated.mdx delete mode 100644 packages/styleguide/src/lib/Molecules/AccordionDeprecated/AccordionDeprecated.stories.tsx diff --git a/.nx/version-plans/version-plan-1780579286290.md b/.nx/version-plans/version-plan-1780579286290.md new file mode 100644 index 00000000000..6f00aef03c7 --- /dev/null +++ b/.nx/version-plans/version-plan-1780579286290.md @@ -0,0 +1,17 @@ +--- +gamut: major +gamut-kit: major +--- + +Remove deprecated `HiddenText` and accordion components + +**BREAKING:** `HiddenText` is no longer exported from `@codecademy/gamut` + +- Migrate to `` for visually hidden, screen-reader-accessible text +- Removed Storybook docs for `HiddenText`; use the `Text` screenreader utility docs instead + +**BREAKING:** Remove `AccordionDeprecated`, `AccordionAreaDeprecated`, `AccordionButtonDeprecated`, and associated exported types + +- Migrate to `Disclosure` for expandable sections; use `List` with expandable rows when multiple accordions are needed +- Internal `ButtonDeprecated` and `ButtonDeprecatedBase` (accordion-only, not re-exported) are removed with the accordion stack +- Removed Storybook docs for deprecated accordion components diff --git a/packages/gamut/__tests__/__snapshots__/gamut.test.ts.snap b/packages/gamut/__tests__/__snapshots__/gamut.test.ts.snap index 7bdb1824d89..eba25e5d846 100644 --- a/packages/gamut/__tests__/__snapshots__/gamut.test.ts.snap +++ b/packages/gamut/__tests__/__snapshots__/gamut.test.ts.snap @@ -2,9 +2,6 @@ exports[`Gamut Exported Keys 1`] = ` [ - "AccordionAreaDeprecated", - "AccordionButtonDeprecated", - "AccordionDeprecated", "Alert", "Anchor", "AnchorBase", diff --git a/packages/gamut/src/AccordionAreaDeprecated/__tests__/AccordionAreaDeprecated.test.tsx b/packages/gamut/src/AccordionAreaDeprecated/__tests__/AccordionAreaDeprecated.test.tsx deleted file mode 100644 index 8dd0f303320..00000000000 --- a/packages/gamut/src/AccordionAreaDeprecated/__tests__/AccordionAreaDeprecated.test.tsx +++ /dev/null @@ -1,48 +0,0 @@ -import { setupRtl } from '@codecademy/gamut-tests'; -import { act } from 'react'; - -import { AccordionAreaDeprecated } from '..'; - -const defaultProps = { - children:
, - top: 'Click me!', -}; -const renderView = setupRtl(AccordionAreaDeprecated, defaultProps); - -jest.useFakeTimers(); - -describe('AccordionAreaDeprecated', () => { - it('starts collapsed when expanded is not true', () => { - const { view } = renderView({ expanded: false }); - - expect(view.queryByTestId('contents')).toBeNull(); - }); - - it('starts expanded when expanded is true', () => { - const { view } = renderView({ expanded: true }); - - view.getByTestId('contents'); - }); - - it('expands when props change to expand', () => { - const { view } = renderView({ expanded: false }); - - view.rerender(); - - view.getByTestId('contents'); - }); - - it('contracts after a delay when set to not expanded after being expanded', async () => { - const { view } = renderView({ expanded: true }); - - view.rerender( - - ); - - await act(async () => { - jest.runAllTimers(); - }); - - expect(view.queryByTestId('contents')).toBeNull(); - }); -}); diff --git a/packages/gamut/src/AccordionAreaDeprecated/index.tsx b/packages/gamut/src/AccordionAreaDeprecated/index.tsx deleted file mode 100644 index 19cd0d13170..00000000000 --- a/packages/gamut/src/AccordionAreaDeprecated/index.tsx +++ /dev/null @@ -1,68 +0,0 @@ -import styled from '@emotion/styled'; -import { motion } from 'framer-motion'; -import { useState } from 'react'; -import * as React from 'react'; -import { useIsomorphicLayoutEffect } from 'react-use'; - -export type AccordionAreaDeprecatedProps = { - children: React.ReactNode; - - className?: string; - - /** - * Whether the accordion is visually expanded to show its contents. - */ - expanded?: boolean; - - /** - * Contents of the clickable header button. - */ - top: React.ReactNode; -}; - -const transitionDuration = 0.2; - -const variants = { - expanded: { height: 'auto' }, - folded: { height: '0' }, -}; - -/** - * @deprecated - * This component is in the old visual identity and will be updated soon. - * - * Check the [Gamut Board](https://www.notion.so/codecademy/Gamut-Status-Timeline-dd3c135d3848464ea6eb1b48e68fbb1d) for component status - */ - -export const AccordionAreaDeprecated: React.FC< - AccordionAreaDeprecatedProps -> = ({ children, className, expanded, top }) => { - const [delayExpanded, setDelayExpanded] = useState(expanded); - - useIsomorphicLayoutEffect(() => { - const handle = setTimeout( - () => setDelayExpanded(expanded), - transitionDuration * 1000 - ); - - return () => clearTimeout(handle); - }, [expanded]); - - return ( -
- {top} - - {(expanded || delayExpanded) && children} - -
- ); -}; - -const StyledAccordionBody = styled(motion.div)` - overflow: hidden; -`; diff --git a/packages/gamut/src/AccordionButtonDeprecated/ButtonDeprecated/index.tsx b/packages/gamut/src/AccordionButtonDeprecated/ButtonDeprecated/index.tsx deleted file mode 100644 index ae65e0f0dd5..00000000000 --- a/packages/gamut/src/AccordionButtonDeprecated/ButtonDeprecated/index.tsx +++ /dev/null @@ -1,190 +0,0 @@ -/* eslint-disable react/destructuring-assignment */ -import cx from 'classnames'; -import hasIn from 'lodash/hasIn'; -import { ReactNode } from 'react'; -import * as React from 'react'; - -import { omitProps } from '../../utils'; -import { - ButtonDeprecatedBase, - ButtonDeprecatedBaseProps, -} from '../ButtonDeprecatedBase'; -// eslint-disable-next-line gamut/no-css-standalone -import styles from './styles/index.module.scss'; - -// themes can be an alias to a color -// or a unique button type -export const buttonPresetThemes = { - secondary: 'mint', - platform: 'greyblue', - lantern: 'darkmint', - royalblue: 'brand-purple', -} as const; - -const themes = [ - 'hyper', - 'navy', - 'red', - 'white', - 'brand-red', - 'brand-yellow', - 'brand-purple', - 'brand-dark-blue', - 'brand-blue', - 'mint', - 'darkmint', - 'grey', - 'greyblue', -] as const; - -export type ButtonDeprecatedThemes = - | keyof typeof buttonPresetThemes - | (typeof themes)[number]; - -const propKeys = [ - 'theme', - 'size', - 'outline', - 'underline', - 'link', - 'caps', - 'go', - 'children', - 'block', - 'className', - 'round', - 'square', - 'flat', - 'fitText', - 'onClick', -]; - -export type ButtonDeprecatedProps = ButtonDeprecatedBaseProps & { - /** - * Whether button should behave like a block element or inline. - */ - block?: boolean; - /** - * Capitalize the text of the button. - */ - caps?: boolean; - children: ReactNode; - /** - * Disables the button and adds visual indicators to show it is not interactive. - */ - disabled?: boolean; - /** - * Variant that displays the button as flat. - */ - flat?: boolean; - /** - * Adds a pulsing animation to the button - */ - go?: boolean; - /** - * Changes the button to a link with no visual indication - */ - href?: string; - /** - * Link relationship property to be used with `href` - */ - rel?: string; - /** - * Link target property to be used with `href` - */ - target?: string; - id?: string; - /** - * Variant that displays the button as an inline link element, but maintains its semantic meaning as a button. - */ - link?: boolean; - /** - * Variant the displays the button as a button that is outlined instead of solid. - */ - outline?: boolean; - /** - * Variant that rounds the corners of the button - */ - round?: boolean; - /** - * Variant that determines the size of the button - */ - size?: 'small' | 'large'; - /** - * Variant that displays the button as a square - */ - square?: boolean; - /** - * Variant that controls the background and text color of the button - * */ - theme?: ButtonDeprecatedThemes; - type?: string; - /** - * Variant that underlines the text of the button. - */ - underline?: boolean; - /** - * Determines whether button dimensions should be determined by the content - */ - fitText?: boolean; -}; - -const isPreset = (theme: string): theme is keyof typeof buttonPresetThemes => { - return hasIn(buttonPresetThemes, theme); -}; - -/** - * @deprecated - * This component is deprecated and is no longer supported. - * - * See [FillButon](https://gamut.codecademy.com/storybook/?path=/docs/atoms-button--fill-button#fill-button) - * - * @example - * import { FillButton } fom '@codecademy/gamut'; - * - * - */ - -export const ButtonDeprecated: React.FC = (props) => { - let { theme = 'brand-red' } = props; - - if (isPreset(theme)) { - theme = buttonPresetThemes[theme]; - } - - const typeClassName = props.link ? styles.link : styles.btn; - const themeClassName = props.link - ? styles[`link-${theme}`] - : styles[`btn-${theme}`]; - - const classes = cx( - typeClassName, - themeClassName, - styles[props.size!], - { - [styles.block]: props.block, - [styles.go]: props.go, - [styles.outline]: props.outline, - [styles.underline]: props.underline, - [styles.caps]: props.caps, - [styles.round]: props.round, - [styles.square]: props.square, - [styles.flat]: props.flat, - [styles['fit-text']]: props.fitText, - }, - props.className - ); - - const propsToTransfer = omitProps(propKeys, props); - - return ( - - {props.children} - - ); -}; diff --git a/packages/gamut/src/AccordionButtonDeprecated/ButtonDeprecated/styles/index.module.scss b/packages/gamut/src/AccordionButtonDeprecated/ButtonDeprecated/styles/index.module.scss deleted file mode 100644 index 6eae8bfe237..00000000000 --- a/packages/gamut/src/AccordionButtonDeprecated/ButtonDeprecated/styles/index.module.scss +++ /dev/null @@ -1,104 +0,0 @@ -@use "sass:color"; -@use "variables"; -@use "mixins"; -@use "~@codecademy/gamut-styles/utils" as *; -// -// Base styles -// - -.btn { - align-items: center; - display: inline-flex; - justify-content: center; - font-weight: variables.$btn-font-weight; - @include font-smoothing; - border: 1px solid transparent; - border-radius: variables.$btn-border-radius; - user-select: none; - @include mixins.button-size( - variables.$btn-padding-y, - variables.$btn-padding-x, - variables.$btn-font-size-base, - variables.$btn-line-height, - variables.$btn-min-width-sm - ); - transition: all 0.1s ease-in-out; -} - -// Future-proof disabling of clicks on `` elements -a.btn.disabled, -fieldset[disabled] a.btn { - pointer-events: none; -} - -@each $name, $color in variables.$btn-swatches { - @if $name == "brand-yellow" { - @include mixins.button-variants($name, $color-black, $color); - } @else if color.channel(color.to-space($color, hsl), "lightness") > 68 { - @include mixins.button-variants($name, $color-black, $color); - } @else { - @include mixins.button-variants($name, $color-white, $color); - } -} - -.round { - border-radius: variables.$btn-round-border-radius; -} - -.square { - border-radius: 0; -} -// -// Button Sizes -// - -.large { - // line-height: ensure even-numbered height of button next to large input - @include mixins.button-size( - variables.$btn-padding-y-lg, - variables.$btn-padding-x-lg, - variables.$btn-font-size-lg, - variables.$btn-line-height-lg, - variables.$btn-min-width-lg - ); -} - -.small { - // line-height: ensure proper height of button next to small input - @include mixins.button-size( - variables.$btn-padding-y-sm, - variables.$btn-padding-x-sm, - variables.$btn-font-size-sm, - variables.$btn-line-height-sm, - variables.$btn-min-width-sm - ); -} - -// -// Block buttovariables.n -// - -.block { - display: flex; - width: 100%; -} - -.caps { - text-transform: uppercase; -} - -.underline { - &:hover, - &:focus { - text-decoration: underline; - } -} - -// Specificity overrides -input[type="submit"], -input[type="reset"], -input[type="button"] { - &.block { - width: 100%; - } -} diff --git a/packages/gamut/src/AccordionButtonDeprecated/ButtonDeprecated/styles/mixins.scss b/packages/gamut/src/AccordionButtonDeprecated/ButtonDeprecated/styles/mixins.scss deleted file mode 100644 index dd4110529d1..00000000000 --- a/packages/gamut/src/AccordionButtonDeprecated/ButtonDeprecated/styles/mixins.scss +++ /dev/null @@ -1,109 +0,0 @@ -@use "sass:color"; -@use "~@codecademy/gamut-styles/utils" as *; -@use "variables"; - -// Button variants -// -// Easily pump out default styles, as well as :hover, :focus, :active, -// and disabled options for all buttons - -@mixin button-variant($color, $background, $border: transparent) { - $active-background: color.mix($color-black, $background); - - @if $border == transparent { - $active-border: transparent; - $active-border-hover: transparent; - } - - color: $color; - background-color: $background; - border-color: $border; - - &:hover { - box-shadow: 0 2px 4px variables.$btn-box-shadow-color; - } - - &:focus-visible { - box-shadow: 0 0 0 2px $color-white, 0 0 0 4px $background; - } - - &:focus-visible, - &:hover { - text-decoration: none; - color: $color; - - &:active { - box-shadow: 0 2px 4px variables.$btn-box-shadow-color; - } - } - - &:active { - background-color: $active-background; - } - - &:disabled { - background-color: variables.$btn-disabled-color; - - &:hover { - box-shadow: none; - } - } -} - -@mixin button-flat-variant($color) { - color: $color; - background-color: transparent; - - &:hover, - &:active { - box-shadow: none; - } - - &:focus-visible { - box-shadow: 0 0 0 2px $color-white, 0 0 0 4px $color; - } - - &:disabled { - color: variables.$btn-disabled-color; - background-color: transparent; - } -} - -// Button sizes -@mixin button-size( - $padding-y, - $padding-x, - $font-size, - $line-height, - $min-width -) { - padding: $padding-y $padding-x; - font-size: $font-size; - line-height: $line-height; - min-width: $min-width; - - &.fit-text { - min-width: 0; - min-height: 0; - } -} - -@mixin button-variants($name, $color, $background, $border: transparent) { - .btn-#{$name} { - @include button-variant($color, $background, $border); - &.flat { - @include button-flat-variant($background); - } - @content; - } - .link-#{$name} { - font-weight: bold; - @include font-smoothing; - color: $background; - text-decoration: underline; - - &:disabled { - color: variables.$btn-disabled-color; - } - } -} diff --git a/packages/gamut/src/AccordionButtonDeprecated/ButtonDeprecated/styles/variables.scss b/packages/gamut/src/AccordionButtonDeprecated/ButtonDeprecated/styles/variables.scss deleted file mode 100755 index ebdba8f9170..00000000000 --- a/packages/gamut/src/AccordionButtonDeprecated/ButtonDeprecated/styles/variables.scss +++ /dev/null @@ -1,53 +0,0 @@ -@use "~@codecademy/gamut-styles/utils" as *; - -$btn-padding-x: px-rem(16) !default; -$btn-padding-y: 0.375rem !default; -$btn-font-weight: bold !default; - -$btn-line-height: 1.5 !default; -$btn-line-height-lg: calc(4 / 3) !default; -$btn-line-height-sm: 1.5 !default; - -$btn-font-size-base: px-rem(16) !default; -$btn-font-size-lg: px-rem(20) !default; -$btn-font-size-sm: px-rem(16) !default; -$btn-font-size-xs: 0.75rem !default; - -$btn-padding-x-sm: 0.75rem !default; -$btn-padding-y-sm: 0.25rem !default; -$btn-min-width-sm: px-rem(128) !default; - -$btn-padding-x-lg: 1.25rem !default; -$btn-padding-y-lg: 0.75rem !default; -$btn-min-width-lg: px-rem(160) !default; - -$btn-border-radius: 2px !default; -$btn-round-border-radius: 50px !default; - -$btn-state-modifier: 20% !default; -$btn-color-modifier: 10% !default; -$btn-outline-hover-state-modifier: 0.9 !default; -$btn-outline-active-state-modifier: 0.6 !default; -$btn-box-shadow-focus-modifier: 0.5 !default; - -$btn-disabled-color: $color-gray-600; -$btn-box-shadow-color: rgba(0, 0, 0, 0.3); - -$btn-swatches: ( - // Gamut Next - "hyper": $color-hyper, - "red": $color-red, - "navy": $color-navy, - "white": $color-white, - "grey": $color-gray-300, - // Gamut Classic - "brand-blue": $color-blue-500, - "brand-red": $brand-red, - "brand-yellow": $brand-yellow, - "brand-purple": $brand-purple, - "brand-dark-blue": $brand-dark-blue, - // Editor - "mint": $deprecated-swatches-mint-700, - "darkmint": $deprecated-swatches-mint-800, - "greyblue": $deprecated-swatches-grey-blue-600 -); diff --git a/packages/gamut/src/AccordionButtonDeprecated/ButtonDeprecatedBase/index.tsx b/packages/gamut/src/AccordionButtonDeprecated/ButtonDeprecatedBase/index.tsx deleted file mode 100644 index fc96ae090a0..00000000000 --- a/packages/gamut/src/AccordionButtonDeprecated/ButtonDeprecatedBase/index.tsx +++ /dev/null @@ -1,103 +0,0 @@ -import cx from 'classnames'; -import { HTMLProps, ReactNode } from 'react'; -import * as React from 'react'; - -import { ChildComponentDescriptor } from '../../typings/react'; -import { omitProps } from '../../utils'; -// eslint-disable-next-line gamut/no-css-standalone -import styles from './styles.module.scss'; - -const propKeys = [ - 'children', - 'className', - 'href', - 'link', - 'onClick', - 'target', - 'rel', -]; - -export type ButtonDeprecatedBaseProps = Omit< - HTMLProps & HTMLProps, - 'as' | 'size' -> & { - /** - * Component type to wrap children with. - */ - as?: ChildComponentDescriptor; - /** - * @remarks We would love to properly type this with generics, but cannot yet. - * @see https://github.com/Codecademy/gamut/pull/270#discussion_r270917147 - * @see https://github.com/Microsoft/TypeScript/issues/21048 - */ - asProps?: any; - children?: ReactNode; - className?: string; - href?: string; - target?: string; - rel?: string; - /** - * Variant that displays the button as an inline link element, but maintains its semantic meaning as a button. - */ - link?: boolean; - /** - * @remarks - * Technically, this is only ever a button event *or* a link event. - * We '&' them together for ease of usage. - */ - onClick?: ( - event: React.MouseEvent & - React.MouseEvent - ) => void; -}; - -/** - * @deprecated - * This component is deprecated and is no longer supported. - * - * See [Anchor](https://gamut.codecademy.com/storybook/?path=/docs/typography-anchor--anchor) for similiar functionality - * - * @example - * import { Anchor } from '@codecademy/gamut'; - * - * Button - * - */ - -export const ButtonDeprecatedBase: React.FC = ( - props -) => { - const { href, className, link, onClick, target, rel } = props; - const { as: As, asProps = {}, ...restOfProps } = props; - const propsToTransfer = omitProps(propKeys, restOfProps); - - const classes = cx(styles.basicBtn, className, { - [styles.basicLink]: link, - }); - - const defaultProps = { - ...propsToTransfer, - className: classes, - onClick, - 'data-btn': true, - }; - - if (As) { - return ; - } - - if (href) { - // Check if this is a popup and and appropriate rel props if they don't exist (see https://web.dev/external-anchors-use-rel-noopener/) - const anchorProps = { - target, - rel: target === '_blank' && !rel ? 'noopener noreferrer' : rel, - }; - - // Anchor tag receives children content from propsToTransfer - // eslint-disable-next-line jsx-a11y/anchor-has-content - return ; - } - - // eslint-disable-next-line react/button-has-type - return