Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

improve font-size consistency with textMarginRatio property #134

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ import Avatar, { ConfigProvider } from 'react-avatar';
| `fgColor` | *string* | #FFF | Used in combination with `name` and `value`. Give the text a fixed color with a hex like for example #FF0000 |
| `size` | *[length][1]* | 50px | Size of the avatar |
| `textSizeRatio` | *number* | 3 | For text based avatars the size of the text as a fragment of size (size / textSizeRatio) |
| `textMarginRatio` | *number* | .15 | For text based avatars. The size of the minimum margin between the text and the avatar's edge, used to make sure the text will always fit inside the avatar. (calculated as `size * textMarginRatio`) |
| `round` | *bool or [length][1]* | false | The amount of `border-radius` to apply to the avatar corners, `true` shows the avatar in a circle. |
| `src` | *string* | | Fallback image to use |
| `style` | *object* | | Style that will be applied on the root element |
Expand Down
36 changes: 36 additions & 0 deletions demo/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,42 @@ class Demo extends React.Component {
</div>
</section>

<section>
<h2>Initials are always restrained to a margin</h2>
<div>
<Avatar name="A B C B W X Y Z" size={40} textSizeRatio={1} />
<Avatar name="A B C B W X Y Z" size={100} round={true} textSizeRatio={1} />
<Avatar name="A B C B W X Y Z" size={150} round="20px" textSizeRatio={1} />
<Avatar name="A B C B W X Y Z" size={200} textSizeRatio={1} />
</div>
<div>
<Avatar name="A B C B W X Y Z" size="30pt" textSizeRatio={1} />
<Avatar name="A B C B W X Y Z" size="90pt" round={true} textSizeRatio={1} />
<Avatar name="A B C B W X Y Z" size="130pt" round="20px" textSizeRatio={1} />
<Avatar name="A B C B W X Y Z" size="170pt" textSizeRatio={1} />
</div>
<div>
<Avatar value="A B C B W X Y Z" size="4vw" textSizeRatio={1} />
<Avatar value="A B C B W X Y Z" size="6vw" round={true} textSizeRatio={1} />
<Avatar value="A B C B W X Y Z" size="10vw" round="20px" textSizeRatio={1} />
<Avatar value="A B C B W X Y Z" size="15vw" textSizeRatio={1} />
</div>
<div style={{ overflow: 'hidden', margin: '0 auto', width: '800px', textAlign: 'center' }}>
<div style={{ width: '200px', height: '200px', float: 'left' }}>
<Avatar value="A B C B W X Y Z" skypeId={this.state.skypeId} size="30%" />
</div>
<div style={{ width: '200px', height: '200px', float: 'left' }}>
<Avatar value="A B C B W X Y Z" size="45%" round={true} />
</div>
<div style={{ width: '200px', height: '200px', float: 'left' }}>
<Avatar value="A B C B W X Y Z" size="60%" round="20px" />
</div>
<div style={{ width: '200px', height: '200px', float: 'left' }}>
<Avatar value="A B C B W X Y Z" size="100%" />
</div>
</div>
</section>

<section>
<h2>Custom colors</h2>
<div>
Expand Down
4 changes: 4 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ export interface ReactAvatarProps {
* For text based avatars the size of the text as a fragment of size (size / textSizeRatio)
*/
textSizeRatio?: number;
/**
* For text based avatars. The size of the minimum margin between the text and the avatar's edge, used to make sure the text will always fit inside the avatar. (calculated as `size * textMarginRatio`)
*/
textMarginRatio?: number;
/**
* The amount of `border-radius` to apply to the avatar corners, `true` shows the avatar in a circle.
*/
Expand Down
42 changes: 29 additions & 13 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ class Avatar extends PureComponent {
PropTypes.string
]),
textSizeRatio: PropTypes.number,
textMarginRatio: PropTypes.number,
unstyled: PropTypes.bool,
cache: PropTypes.object,
onClick: PropTypes.func
Expand All @@ -93,6 +94,7 @@ class Avatar extends PureComponent {
round: false,
size: 100,
textSizeRatio: 3,
textMarginRatio: .15,
unstyled: false
}

Expand Down Expand Up @@ -183,26 +185,37 @@ class Avatar extends PureComponent {
};

_scaleTextNode = (node) => {
const { unstyled, textSizeRatio } = this.props;

if (!node || unstyled) return;
const { unstyled, textSizeRatio, textMarginRatio } = this.props;

if (!node || unstyled)
return;

const parent = node.parentNode;
const spanNode = node.parentNode;
const tableNode = spanNode.parentNode;
const {
width: containerWidth,
height: containerHeight
} = spanNode.getBoundingClientRect();

// If the tableNode (outer-container) does not have its fontSize set yet,
// we'll set it according to "textSizeRatio"
if (!tableNode.style.fontSize) {
const baseFontSize = containerHeight / textSizeRatio;
tableNode.style.fontSize = `${baseFontSize}px`;
}

// Reset font-size such that scaling works correctly (#133)
parent.style.fontSize = null;
// Measure the actual width of the text after setting the container size
const { width: textWidth } = node.getBoundingClientRect();

const textWidth = node.getBoundingClientRect().width;
if (textWidth < 0)
return;

const containerWidth = parent.getBoundingClientRect().width;
const ratio = containerWidth / textWidth;
// Calculate the maximum width for the text based on "textMarginRatio"
const maxTextWidth = containerWidth * (1 - (2 * textMarginRatio));

// Set font-size on parent span, otherwise the `table-cell` span
// will cause alignment issues.
parent.style.fontSize = `calc((100% * ${ratio}) / ${textSizeRatio})`;
// If the text is too wide, scale it down by (maxWidth / actualWidth)
if (textWidth > maxTextWidth)
spanNode.style.fontSize = `calc(100% * ${maxTextWidth / textWidth})`;
}

_renderAsImage() {
Expand Down Expand Up @@ -246,13 +259,16 @@ class Avatar extends PureComponent {

const tableStyle = unstyled ? null : {
display: 'table',
tableLayout: 'fixed',
width: '100%',
height: '100%'
};

const spanStyle = unstyled ? null : {
display: 'table-cell',
verticalAlign: 'middle'
verticalAlign: 'middle',
fontSize: '100%',
whiteSpace: 'nowrap'
};

return (
Expand Down