Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
a8b36f0
first stab at multiple icons in anchors
LinKCoding Jul 25, 2025
465a796
let claude refactor functions for dryness
LinKCoding Jul 25, 2025
b9a28b1
more refactoring
LinKCoding Jul 25, 2025
54455c0
add new files
LinKCoding Jul 25, 2025
001db40
minor touch ups
LinKCoding Jul 25, 2025
765dcd9
refactor to use appendIconToContent inside appendMultiIconsToContent
LinKCoding Jul 28, 2025
2309e7b
fix importing and exporting
LinKCoding Jul 28, 2025
f1bf241
fix more imports
LinKCoding Jul 28, 2025
c9dd682
touched up stories
LinKCoding Jul 28, 2025
fe9a1dd
remove extra test
LinKCoding Jul 28, 2025
524e5b2
updated button to allow multiple icons
LinKCoding Jul 28, 2025
14f11eb
updated breakpoints for inline icons example
LinKCoding Jul 28, 2025
ad475e1
update anchor table example
LinKCoding Jul 28, 2025
8bb9112
edit check for what content should be in Anchor and Button
LinKCoding Jul 28, 2025
269984a
slight refactor with renderStyledIcon function
LinKCoding Jul 28, 2025
51d273f
moved common props back into the renderStyledIcon func directly
LinKCoding Jul 28, 2025
6e966f1
adding tests and slight mod
LinKCoding Jul 28, 2025
47ccbc0
more refactoring and test fixing
LinKCoding Jul 28, 2025
fd8208b
fix up tests
LinKCoding Jul 29, 2025
afe2dd5
more touch ups
LinKCoding Jul 29, 2025
6a21e20
updated menu and stories
LinKCoding Jul 29, 2025
8b4d004
update tests
LinKCoding Jul 29, 2025
f993b42
merged main
LinKCoding Aug 25, 2025
9ff54fb
mismatch tags
LinKCoding Aug 25, 2025
897b77d
editing menuitem to allow for iconPosition
LinKCoding Aug 25, 2025
c060ff2
added iconPosition and fixed up stories
LinKCoding Aug 26, 2025
e83158d
Merge branch 'main' into kl-gm-1052-anchor-both-sides
LinKCoding Aug 26, 2025
f676b8c
update bulbicon
LinKCoding Aug 27, 2025
9176ae0
fixed vertical alignment
LinKCoding Aug 29, 2025
eb4fd43
Merge branch 'main' into kl-gm-1052-anchor-both-sides
LinKCoding Sep 2, 2025
193c600
Merge branch 'main' into kl-gm-1052-anchor-both-sides
LinKCoding Sep 15, 2025
0584e39
applied Cass's feedback
LinKCoding Sep 15, 2025
c6d082a
updated disabled variant and added an example to SB
LinKCoding Sep 15, 2025
1a13976
updated anchor types
LinKCoding Sep 15, 2025
7e37ce1
Merge branch 'main' into kl-gm-1052-anchor-both-sides
dreamwasp Oct 7, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 57 additions & 0 deletions packages/gamut/src/Anchor/Anchor.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { forwardRef, RefObject } from 'react';

import { ButtonBase } from '../ButtonBase/ButtonBase';
import { AppendedIconProps, appendIconToContent } from '../helpers';
import { AnchorBase, AnchorExtProps } from './types';

export const Anchor = forwardRef<
HTMLAnchorElement | HTMLButtonElement,
AnchorExtProps
>(
(
{
children,
icon,
iconOffset,
iconPosition = 'left',
iconSize = 16,
isInlineIcon = true,
variant = 'inline',
...rest
},
ref
) => {
const content = appendIconToContent({
children,
iconOffset,
iconSize,
iconAndTextGap: 8,
isInlineIcon,
icon,
iconPosition,
} as AppendedIconProps);

if (!rest.href || rest.disabled) {
return (
<AnchorBase
as={ButtonBase}
ref={ref as RefObject<HTMLAnchorElement>}
variant={variant}
{...rest}
>
{content}
</AnchorBase>
);
}

return (
<AnchorBase
ref={ref as RefObject<HTMLAnchorElement>}
variant={variant}
{...rest}
>
{content}
</AnchorBase>
);
}
);
2 changes: 2 additions & 0 deletions packages/gamut/src/Anchor/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './Anchor';
export * from './types';
172 changes: 0 additions & 172 deletions packages/gamut/src/Anchor/index.tsx

This file was deleted.

92 changes: 92 additions & 0 deletions packages/gamut/src/Anchor/styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import { variant } from '@codecademy/gamut-styles';

import { ButtonSelectors } from '../ButtonBase/ButtonBase';

const outlineFocusVisible = {
[ButtonSelectors.OUTLINE]: {
content: "''",
position: 'absolute',
inset: -4,
borderRadius: 'md',
border: 2,
borderColor: 'primary',
opacity: 0,
zIndex: 0,
},

[ButtonSelectors.OUTLINE_FOCUS_VISIBLE]: {
opacity: 1,
},
} as const;

const underlineFocusVisible = {
[ButtonSelectors.FOCUS_VISIBLE]: {
outline: 'currentColor solid 2px',
borderRadius: 'sm',
outlineOffset: '1.5px',
textDecoration: 'underline',
},
} as const;

export const anchorVariants = variant({
base: {
display: 'inline-block',
bg: 'transparent',
boxShadow: 'none',
border: 'none',
p: 0,
fontSize: 'inherit',
position: 'relative',
color: 'primary',
whiteSpace: 'nowrap',
[ButtonSelectors.HOVER]: {
textDecoration: 'none',
cursor: 'pointer',
},
[ButtonSelectors.DISABLED]: {
cursor: 'not-allowed',
textDecoration: 'none',
color: 'text-disabled',
},
},
variants: {
standard: {
color: 'primary',
fontWeight: 'bold',
WebkitFontSmoothing: 'antialiased',
MozOsxFontSmoothing: 'grayscale',
[ButtonSelectors.HOVER]: {
textDecoration: 'underline',
},
[ButtonSelectors.FOCUS_VISIBLE]: {
WebkitFontSmoothing: 'antialiased',
MozOsxFontSmoothing: 'grayscale',
outline: 'none',
},
...outlineFocusVisible,
},
inline: {
display: 'inline',
whiteSpace: 'initial',
textDecoration: 'underline',
...underlineFocusVisible,
},
interface: {
color: 'text',
whiteSpace: 'initial',
[ButtonSelectors.HOVER]: {
color: 'primary',
},
[ButtonSelectors.FOCUS_VISIBLE]: {
color: 'primary',
outline: 'none',
},
...outlineFocusVisible,
},
'standard-secondary': {
color: 'text',
textDecoration: 'underline',
...underlineFocusVisible,
},
},
});
36 changes: 36 additions & 0 deletions packages/gamut/src/Anchor/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { styledOptions, system } from '@codecademy/gamut-styles';
import { StyleProps, variance } from '@codecademy/variance';
import styled from '@emotion/styled';
import { ComponentProps, HTMLProps } from 'react';

import { ButtonBase } from '../ButtonBase';
import { AppendedIconProps } from '../helpers';
import { anchorVariants } from './styles';

export interface AnchorProps
extends StyleProps<typeof anchorProps>,
StyleProps<typeof anchorVariants> {
onClick?: HTMLProps<HTMLAnchorElement>['onClick'];
}

const anchorProps = variance.compose(
system.layout,
system.space,
system.typography
);

export const AnchorBase = styled('a', styledOptions<'a'>())<AnchorProps>(
anchorVariants,
anchorProps
);

type AnchorAsAnchor = ComponentProps<typeof AnchorBase> & {
disabled?: never;
};

type AnchorAsButton = Exclude<ComponentProps<typeof AnchorBase>, 'ref'> &
ComponentProps<typeof ButtonBase>

type AnchorBaseProps = AnchorAsAnchor | AnchorAsButton;

export type AnchorExtProps = Partial<AppendedIconProps> & AnchorBaseProps;
Loading
Loading