Skip to content
Merged
81 changes: 81 additions & 0 deletions pages/icon/icon-inherit-sizing.page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import React from 'react';

import Icon from '~components/icon';
import Link from '~components/link';
import TextContent from '~components/text-content';

export default function IconInheritSizingPage() {
return (
<div style={{ padding: '20px' }}>
<h1>Icon Inherit Sizing Test</h1>

<small style={{ fontSize: '12px', lineHeight: '16px', fontFamily: 'Amazon Ember', paddingBlock: '8px' }}>
Font: 12px, Line-height: 16px (body small text). The{' '}
<Link external={true} variant="primary" fontSize="inherit" href="https://example.com">
external link
</Link>{' '}
should have normal (16x16) icon.
</small>

<p style={{ fontSize: '14px', lineHeight: '20px', fontFamily: 'Amazon Ember', paddingBlock: '8px' }}>
Font: 14px, Line-height: 20px (body normal text). The{' '}
<Link external={true} variant="primary" fontSize="inherit" href="https://example.com">
external link
</Link>{' '}
should have normal (16x16) icon.
</p>

<p style={{ fontSize: '16px', lineHeight: '24px', fontFamily: 'Amazon Ember', paddingBlock: '8px' }}>
Font: 16px, Line-height: 24px. The{' '}
<Link external={true} variant="primary" fontSize="inherit" href="https://example.com">
external link
</Link>{' '}
icon should have normal (16x16).
</p>

<p style={{ fontSize: '18px', lineHeight: '24px', fontFamily: 'Amazon Ember', paddingBlock: '8px' }}>
Font: 18px, Line-height: 24px. The{' '}
<Link external={true} variant="primary" fontSize="inherit" href="https://example.com">
external link
</Link>{' '}
icon should have normal (16x16).
</p>

<p style={{ fontSize: '20px', lineHeight: '24px', fontFamily: 'Amazon Ember', paddingBlock: '8px' }}>
Font: 20px, Line-height: 24px. The{' '}
<Link external={true} variant="primary" fontSize="inherit" href="https://example.com">
external link
</Link>{' '}
should have medium (20x20) icon.
</p>

<p style={{ fontSize: '22px', lineHeight: '24px', fontFamily: 'Amazon Ember', paddingBlock: '8px' }}>
Font: 22px, Line-height: 24px. The{' '}
<Link external={true} variant="primary" fontSize="inherit" href="https://example.com">
external link
</Link>{' '}
should have medium (20x20) icon.
</p>

<TextContent>
<h1>
<Icon name="status-positive" size="big" /> Heading 1 - Font: 24px, Line height: 30px
</h1>
<h2>
<Icon name="status-positive" size="inherit" /> Heading 2 - Font: 20px, Line height: 24px
</h2>
<h3>
<Icon name="status-positive" size="normal" /> Heading 3 - Font: 18px, Line height: 22px
</h3>
<h4>
<Icon name="status-positive" size="normal" /> Heading 4 - Font: 16px, Line height: 20px
</h4>
<h5>
<Icon name="status-positive" size="normal" /> Heading 5 - Font: 14px, Line height: 18px
</h5>
</TextContent>
</div>
);
}
14 changes: 10 additions & 4 deletions src/icon/internal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,19 @@ type InternalIconProps = IconProps &
badge?: boolean;
};

function iconSizeMap(height: number | null) {
function iconSizeMap(height: number | null, fontSize?: number | null) {
if (height === null) {
// This is the best guess for the contextual height while server rendering.
return 'normal';
}

// Only display medium size icon when both line-height >= 24px AND font-size >= 20px
// This prevents icons from becoming medium size inappropriately
if (height >= 50) {
return 'large';
} else if (height >= 36) {
return 'big';
} else if (height >= 24) {
} else if (height >= 24 && !!fontSize && fontSize >= 20) {
return 'medium';
} else if (height <= 16) {
return 'small';
Expand All @@ -56,8 +58,9 @@ const InternalIcon = ({
// To ensure a re-render is triggered on visual mode changes
useVisualRefresh();
const [parentHeight, setParentHeight] = useState<number | null>(null);
const [parentFontSize, setParentFontSize] = useState<number | null>(null);
const contextualSize = size === 'inherit';
const iconSize = contextualSize ? iconSizeMap(parentHeight) : size;
const iconSize = contextualSize ? iconSizeMap(parentHeight, parentFontSize) : size;
const inlineStyles = contextualSize && parentHeight !== null ? { height: `${parentHeight}px` } : {};
const baseProps = getBaseProps(props);

Expand All @@ -79,9 +82,12 @@ const InternalIcon = ({
if (!contextualSize || !iconRef.current) {
return;
}
const { lineHeight } = getComputedStyle(iconRef.current);
const computedStyle = getComputedStyle(iconRef.current);
const { lineHeight, fontSize } = computedStyle;
const newParentHeight = parseInt(lineHeight, 10);
const newParentFontSize = parseInt(fontSize, 10);
setParentHeight(newParentHeight);
setParentFontSize(newParentFontSize);
});

const mergedRef = useMergeRefs(iconRef, __internalRootRef);
Expand Down
Loading