From b66c3e42421db7412e0cc27ac6e983f9c59a34f3 Mon Sep 17 00:00:00 2001 From: Kenny Lin Date: Tue, 15 Jul 2025 10:36:26 -0400 Subject: [PATCH 1/6] somewhat working example --- .../src/lib/Typography/Anchor/Anchor.mdx | 3 + .../lib/Typography/Anchor/Anchor.stories.tsx | 77 ++++++++++++++++++- 2 files changed, 79 insertions(+), 1 deletion(-) diff --git a/packages/styleguide/src/lib/Typography/Anchor/Anchor.mdx b/packages/styleguide/src/lib/Typography/Anchor/Anchor.mdx index 9ab4dff4c49..55681bd1875 100644 --- a/packages/styleguide/src/lib/Typography/Anchor/Anchor.mdx +++ b/packages/styleguide/src/lib/Typography/Anchor/Anchor.mdx @@ -27,6 +27,9 @@ export const parameters = { + + + ## Usage Use an anchor to navigate to another page, resource, or location on the same page. diff --git a/packages/styleguide/src/lib/Typography/Anchor/Anchor.stories.tsx b/packages/styleguide/src/lib/Typography/Anchor/Anchor.stories.tsx index d9b2703ac0b..3542af95922 100644 --- a/packages/styleguide/src/lib/Typography/Anchor/Anchor.stories.tsx +++ b/packages/styleguide/src/lib/Typography/Anchor/Anchor.stories.tsx @@ -1,9 +1,17 @@ -import { Anchor, GridBox, Text } from '@codecademy/gamut'; +import { + Anchor, + BaseTextProps, + Box, + GridBox, + Text, + ToolTip, +} from '@codecademy/gamut'; import { MiniArrowRightIcon, MiniInfoOutlineIcon, } from '@codecademy/gamut-icons'; import type { Meta, StoryObj } from '@storybook/react'; +import React, { useCallback, useEffect, useRef, useState } from 'react'; import { PolymorphicAnchors, VariantsExample } from './Anchor.examples'; @@ -85,3 +93,70 @@ export const IconModes: Story = { export const PolymorphicAnchor: Story = { render: () => , }; + +type AnchorAndTextProps = { + isTruncated: boolean; + truncateLines?: BaseTextProps['truncateLines'] | undefined; + children: React.ReactNode; +}; + +export const AnchorAndText = React.forwardRef< + HTMLDivElement, + AnchorAndTextProps +>(({ children, isTruncated, truncateLines }, ref) => { + return ( + + {isTruncated && truncateLines ? ( + + {children} + + ) : ( + children + )} + + ); +}); + +export const TruncateWithTooltip: React.FC<{ text: string, toolTipString: string }> = ({ text, toolTipString }) => { + const textRef = useRef(null); + const shouldTruncate = useCallback(() => text.length > 150, [text]); + + const [isTruncated, setIsTruncated] = useState(shouldTruncate()); + + useEffect(() => { + const el = textRef.current; + if (el) { + const style = window.getComputedStyle(el); + const textOverStyle = style.getPropertyValue('text-overflow'); + setIsTruncated(textOverStyle === 'ellipsis'); + } + }, [shouldTruncate]); + + return ( + + {isTruncated ? ( + + + {text} + + + ) : ( + {text} + )} + + ); +}; + +export const TruncateWithToolTipExample: Story = { + render: () => ( + + ), +}; + +export const TruncateWithNoToolTipExample: Story = { + render: () => , +}; From 1974374c13ba28e36d35cdee80cc46ca1799d653 Mon Sep 17 00:00:00 2001 From: Kenny Lin Date: Tue, 15 Jul 2025 10:51:06 -0400 Subject: [PATCH 2/6] update tooltip prop --- .../lib/Typography/Anchor/Anchor.stories.tsx | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/packages/styleguide/src/lib/Typography/Anchor/Anchor.stories.tsx b/packages/styleguide/src/lib/Typography/Anchor/Anchor.stories.tsx index 3542af95922..955446e59c3 100644 --- a/packages/styleguide/src/lib/Typography/Anchor/Anchor.stories.tsx +++ b/packages/styleguide/src/lib/Typography/Anchor/Anchor.stories.tsx @@ -117,7 +117,10 @@ export const AnchorAndText = React.forwardRef< ); }); -export const TruncateWithTooltip: React.FC<{ text: string, toolTipString: string }> = ({ text, toolTipString }) => { +export const TruncateWithTooltip: React.FC<{ + text: string; + toolTipString: string; +}> = ({ text, toolTipString }) => { const textRef = useRef(null); const shouldTruncate = useCallback(() => text.length > 150, [text]); @@ -135,7 +138,7 @@ export const TruncateWithTooltip: React.FC<{ text: string, toolTipString: string return ( {isTruncated ? ( - + ( - + ), }; export const TruncateWithNoToolTipExample: Story = { - render: () => , + render: () => ( + + ), }; From 4a46b01ec62313b21919c9b311bbda0d7e0a79d2 Mon Sep 17 00:00:00 2001 From: Kenny Lin Date: Tue, 15 Jul 2025 11:23:29 -0400 Subject: [PATCH 3/6] simplify PoC --- .../lib/Typography/Anchor/Anchor.stories.tsx | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/packages/styleguide/src/lib/Typography/Anchor/Anchor.stories.tsx b/packages/styleguide/src/lib/Typography/Anchor/Anchor.stories.tsx index 955446e59c3..13aec8c367a 100644 --- a/packages/styleguide/src/lib/Typography/Anchor/Anchor.stories.tsx +++ b/packages/styleguide/src/lib/Typography/Anchor/Anchor.stories.tsx @@ -122,25 +122,14 @@ export const TruncateWithTooltip: React.FC<{ toolTipString: string; }> = ({ text, toolTipString }) => { const textRef = useRef(null); - const shouldTruncate = useCallback(() => text.length > 150, [text]); - - const [isTruncated, setIsTruncated] = useState(shouldTruncate()); - - useEffect(() => { - const el = textRef.current; - if (el) { - const style = window.getComputedStyle(el); - const textOverStyle = style.getPropertyValue('text-overflow'); - setIsTruncated(textOverStyle === 'ellipsis'); - } - }, [shouldTruncate]); + const shouldTruncate = text.length > 150; return ( - {isTruncated ? ( + {shouldTruncate ? ( From 330b2d66d9147c6abd1a24764573ee62231225fb Mon Sep 17 00:00:00 2001 From: Kenny Lin Date: Tue, 15 Jul 2025 11:36:44 -0400 Subject: [PATCH 4/6] formatted --- .../src/lib/Typography/Anchor/Anchor.stories.tsx | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/packages/styleguide/src/lib/Typography/Anchor/Anchor.stories.tsx b/packages/styleguide/src/lib/Typography/Anchor/Anchor.stories.tsx index 13aec8c367a..a18f5f5c6bf 100644 --- a/packages/styleguide/src/lib/Typography/Anchor/Anchor.stories.tsx +++ b/packages/styleguide/src/lib/Typography/Anchor/Anchor.stories.tsx @@ -11,7 +11,7 @@ import { MiniInfoOutlineIcon, } from '@codecademy/gamut-icons'; import type { Meta, StoryObj } from '@storybook/react'; -import React, { useCallback, useEffect, useRef, useState } from 'react'; +import React from 'react'; import { PolymorphicAnchors, VariantsExample } from './Anchor.examples'; @@ -121,18 +121,13 @@ export const TruncateWithTooltip: React.FC<{ text: string; toolTipString: string; }> = ({ text, toolTipString }) => { - const textRef = useRef(null); const shouldTruncate = text.length > 150; return ( {shouldTruncate ? ( - + {text} From 495de6253630da4b0a3e635ca7770b4248487f3b Mon Sep 17 00:00:00 2001 From: Kenny Lin Date: Tue, 15 Jul 2025 23:15:31 -0400 Subject: [PATCH 5/6] updated example with responsive container --- .../lib/Typography/Anchor/Anchor.stories.tsx | 85 ++++++++++--------- 1 file changed, 46 insertions(+), 39 deletions(-) diff --git a/packages/styleguide/src/lib/Typography/Anchor/Anchor.stories.tsx b/packages/styleguide/src/lib/Typography/Anchor/Anchor.stories.tsx index a18f5f5c6bf..0c1905ffcff 100644 --- a/packages/styleguide/src/lib/Typography/Anchor/Anchor.stories.tsx +++ b/packages/styleguide/src/lib/Typography/Anchor/Anchor.stories.tsx @@ -1,11 +1,4 @@ -import { - Anchor, - BaseTextProps, - Box, - GridBox, - Text, - ToolTip, -} from '@codecademy/gamut'; +import { Anchor, Box, GridBox, Text, ToolTip } from '@codecademy/gamut'; import { MiniArrowRightIcon, MiniInfoOutlineIcon, @@ -94,45 +87,59 @@ export const PolymorphicAnchor: Story = { render: () => , }; -type AnchorAndTextProps = { - isTruncated: boolean; - truncateLines?: BaseTextProps['truncateLines'] | undefined; - children: React.ReactNode; -}; - -export const AnchorAndText = React.forwardRef< - HTMLDivElement, - AnchorAndTextProps ->(({ children, isTruncated, truncateLines }, ref) => { - return ( - - {isTruncated && truncateLines ? ( - - {children} - - ) : ( - children - )} - - ); -}); - export const TruncateWithTooltip: React.FC<{ text: string; toolTipString: string; }> = ({ text, toolTipString }) => { - const shouldTruncate = text.length > 150; + const containerRef = React.useRef(null); + const [adjustedText, setAdjustedText] = React.useState(text); + + const calculateMaxText = (containerWidth: number) => { + // Assuming an average character width of 8px, adjust as necessary + const averageCharWidth = 8; + const maxChars = Math.floor(containerWidth / averageCharWidth); + return maxChars; + }; + + const [shouldTruncate, setShouldTruncate] = React.useState(false); + + React.useEffect(() => { + const handleResize = () => { + if (containerRef.current) { + const { width } = containerRef.current.getBoundingClientRect(); + const maxTextLength = calculateMaxText(width); + const isTruncated = maxTextLength < text.length; + if (isTruncated) { + // Adjust the text to fit within the max length + const truncatedText = text.slice(0, maxTextLength) + '...'; + setAdjustedText(truncatedText); + } else { + setAdjustedText(text); + } + setShouldTruncate(isTruncated); + } + }; + handleResize(); // Initial check + window.addEventListener('resize', handleResize); + return () => { + window.removeEventListener('resize', handleResize); + }; + }); + + const anchor = ( + + {adjustedText} + + ); return ( - + {shouldTruncate ? ( - - {text} - + {anchor} ) : ( - {text} + anchor )} ); @@ -141,7 +148,7 @@ export const TruncateWithTooltip: React.FC<{ export const TruncateWithToolTipExample: Story = { render: () => ( ), @@ -150,7 +157,7 @@ export const TruncateWithToolTipExample: Story = { export const TruncateWithNoToolTipExample: Story = { render: () => ( ), From 3a4e895a8d561b1f40ff7bcf78553b0770a9e842 Mon Sep 17 00:00:00 2001 From: Kenny Lin Date: Wed, 16 Jul 2025 10:07:53 -0400 Subject: [PATCH 6/6] slight refactor --- .../src/lib/Typography/Anchor/Anchor.stories.tsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/styleguide/src/lib/Typography/Anchor/Anchor.stories.tsx b/packages/styleguide/src/lib/Typography/Anchor/Anchor.stories.tsx index 0c1905ffcff..41da65c6db5 100644 --- a/packages/styleguide/src/lib/Typography/Anchor/Anchor.stories.tsx +++ b/packages/styleguide/src/lib/Typography/Anchor/Anchor.stories.tsx @@ -4,7 +4,7 @@ import { MiniInfoOutlineIcon, } from '@codecademy/gamut-icons'; import type { Meta, StoryObj } from '@storybook/react'; -import React from 'react'; +import React, { useEffect, useRef, useState } from 'react'; import { PolymorphicAnchors, VariantsExample } from './Anchor.examples'; @@ -91,8 +91,8 @@ export const TruncateWithTooltip: React.FC<{ text: string; toolTipString: string; }> = ({ text, toolTipString }) => { - const containerRef = React.useRef(null); - const [adjustedText, setAdjustedText] = React.useState(text); + const containerRef = useRef(null); + const [adjustedText, setAdjustedText] = useState(text); const calculateMaxText = (containerWidth: number) => { // Assuming an average character width of 8px, adjust as necessary @@ -101,9 +101,9 @@ export const TruncateWithTooltip: React.FC<{ return maxChars; }; - const [shouldTruncate, setShouldTruncate] = React.useState(false); + const [shouldTruncate, setShouldTruncate] = useState(false); - React.useEffect(() => { + useEffect(() => { const handleResize = () => { if (containerRef.current) { const { width } = containerRef.current.getBoundingClientRect();