-
Notifications
You must be signed in to change notification settings - Fork 2.2k
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
SVG Icons! #2028
SVG Icons! #2028
Changes from 45 commits
414032e
dd72980
a26afdb
85e41b3
50c460b
3b2ff4b
36159e8
ea5fbf8
739e643
87e8f09
eb79ca2
e242f50
a82d096
718ff50
5e042e5
a0f70da
fe13ed7
9ef12bb
2fd23d6
f99ee70
fc5dd11
3f900a7
99b11e9
fb3a8fc
84dc720
dd37942
063a648
a9feff4
728288a
647d608
1089e6e
9ef3861
5049f57
de0df31
84ef214
394df5c
0d2c391
08bb074
e10ea0c
1069282
e47e2a6
daa8c56
de3013b
ab45534
a2ab952
8fa9b92
3ddec4c
0115861
b871252
2a8caae
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -87,6 +87,14 @@ Styleguide pt-button | |
color: $pt-icon-color; | ||
} | ||
|
||
// icon-only button | ||
.pt-icon:first-child:last-child { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. π© |
||
// center icon horizontally. this works for large buttons too. | ||
$icon-margin-offset: -($pt-button-height - $pt-icon-size-standard) / 2; | ||
margin-right: $icon-margin-offset; | ||
margin-left: $icon-margin-offset; | ||
} | ||
|
||
/* | ||
Advanced icon usage | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -74,7 +74,6 @@ export abstract class AbstractButton<T> extends React.Component<React.HTMLProps< | |
[Classes.DISABLED]: disabled, | ||
[Classes.LOADING]: this.props.loading, | ||
}, | ||
Classes.iconClass(this.props.iconName), | ||
Classes.intentClass(this.props.intent), | ||
this.props.className, | ||
); | ||
|
@@ -114,7 +113,7 @@ export abstract class AbstractButton<T> extends React.Component<React.HTMLProps< | |
}; | ||
|
||
protected renderChildren(): React.ReactNode { | ||
const { loading, rightIconName, text } = this.props; | ||
const { iconName, loading, rightIconName, text } = this.props; | ||
|
||
const children = React.Children.map(this.props.children, (child, index) => { | ||
if (child === "") { | ||
|
@@ -127,12 +126,15 @@ export abstract class AbstractButton<T> extends React.Component<React.HTMLProps< | |
return child; | ||
}); | ||
|
||
return [ | ||
loading ? <Spinner className="pt-small pt-button-spinner" key="spinner" /> : undefined, | ||
text != null ? <span key="text">{text}</span> : undefined, | ||
...children, | ||
<Icon className={Classes.ALIGN_RIGHT} iconName={rightIconName} key="icon" />, | ||
]; | ||
return ( | ||
<> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. so. nice. |
||
<Icon iconName={iconName} /> | ||
{loading && <Spinner className="pt-small pt-button-spinner" />} | ||
{text != null && <span>{text}</span>} | ||
{children} | ||
<Icon className={Classes.ALIGN_RIGHT} iconName={rightIconName} /> | ||
</> | ||
); | ||
} | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,13 +4,62 @@ | |
See [**Icons**](#icons) for a searchable list of all available UI icons. | ||
</div> | ||
|
||
<div class="pt-callout pt-intent-primary pt-icon-info-sign"> | ||
<h5>SVG icons in 2.0</h5> | ||
Blueprint 2.0 introduced SVG icon support throughout the ecosystem, and moved icon resources to a separate | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: no need for the comma here (I noticed your prose style does this a lot and I generally don't mind for code comments, but I'm more picky about it in actual documentation). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. also, "throughout the ecosystem" is a bit of a stretch. I would remove that phrase entirely. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. sometimes, i use commas to indicate where to pause, for maximal dramatic effect. π |
||
__@blueprintjs/icons__ package. The `Icon` component now renders SVG paths and the icon classes are no longer | ||
used by any Blueprint React component. Icon font support has been preserved but should be considered legacy, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "... but should be considered a legacy feature that will be removed in a future major version." |
||
and we plan to remove the icon fonts in a future major version. | ||
</div> | ||
|
||
This section describes two ways of using the UI icon font: via CSS or via React component. | ||
|
||
Many Blueprint components provide an `iconName` prop, which supports both the | ||
full name `pt-icon-projects` and the short name `projects`. | ||
|
||
@reactExample IconExample | ||
|
||
@## JavaScript API | ||
|
||
The `Icon` component is available in the __@blueprintjs/core__ package. | ||
Make sure to review the [general usage docs for JS components](#blueprint.usage). | ||
|
||
Use the `<Icon>` component to easily render __SVG icons__ in React. The `iconName` prop is typed | ||
such that editors can offer autocomplete for known icon names. The optional `iconSize` prop ensures | ||
you'll never forget a sizing class and clarifies the expected width and height of the icon element. | ||
The component also accepts all valid HTML props for an `<svg>` element. | ||
|
||
Data files in the __@blueprintjs/icons__ package provide SVG path information for Blueprint's 300+ icons | ||
for 16px and 20px grids. The `iconName` prop dictates which SVG is rendered, and `iconSize` determines | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. another unnecessary comma here There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i actually thought long and hard about this one |
||
which pixel grid is used: `iconSize >= 20` will use the 20px grid and smaller icons will use the 16px grid. | ||
|
||
```tsx | ||
// string literals are supported through IconName union type | ||
<Icon iconName="cross" /> | ||
<Icon iconName="pt-icon-globe" iconSize={20} /> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. probably shouldn't encourage the long names with There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. follow-up PR. still technically supported. |
||
<Icon iconName="graph" iconSize={40} intent={Intent.PRIMARY} /> | ||
|
||
// can also use IconClasses string enum and Icon.SIZE_* constants | ||
import { IconClasses } from "@blueprintjs/core"; | ||
<Icon iconName={IconClasses.ALIGN_LEFT} iconSize={Icon.SIZE_LARGE} /> | ||
|
||
// can pass all valid HTML props | ||
<Icon iconName="add" onClick={this.handleAdd} onKeyDown={this.handleAddKeys}> | ||
``` | ||
|
||
@interface IIconProps | ||
|
||
@## CSS API | ||
|
||
<div class="pt-callout pt-intent-warning pt-icon-warning-sign"> | ||
<h5>Icon fonts are legacy in 2.0</h5> | ||
Blueprint's icon fonts should be considered legacy, and we plan to remove them in a future major version. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. use the same phrasing I suggested above |
||
The SVGs rendered by the React component do not suffer from the blurriness of icon fonts, and browser | ||
support is equivalent. | ||
</div> | ||
|
||
The CSS-only icons API uses the __icon fonts__ from the __@blueprintjs/icons__ package. | ||
|
||
To use Blueprint UI icons via CSS, you must apply two classes to a `<span>` element: | ||
- a __sizing class__, either `pt-icon-standard` (16px) or `pt-icon-large` (20px) | ||
- an __icon name class__, such as `pt-icon-projects` | ||
|
@@ -30,26 +79,3 @@ Icon classes also support the four `.pt-intent-*` modifiers to color the image. | |
necessary, set a `font-size` that is whole multiple of 16 or 20 with the relevant size class. | ||
You can instead use the class `pt-icon` to make the icon inherit its size from surrounding text. | ||
</div> | ||
|
||
@## JavaScript API | ||
|
||
Use the `<Icon>` component to easily render icons in React. The required `iconName` prop is typed | ||
such that editors can offer autocomplete for known icon names. The optional `iconSize` prop ensures | ||
you'll never forget a sizing class and clarifies the expected width and height of the icon element. | ||
The component also accepts all valid HTML props for a `<span>` element. | ||
|
||
```tsx | ||
// string literals are supported through IconName union type | ||
<Icon iconName="cross" /> | ||
<Icon iconName="pt-icon-globe" iconSize="inherit" /> | ||
<Icon iconName="graph" iconSize={20} intent={Intent.PRIMARY} /> | ||
|
||
// can also use IconClasses string enum and Icon.SIZE_* constants | ||
import { IconClasses } from "@blueprintjs/core"; | ||
<Icon iconName={IconClasses.ALIGN_LEFT} iconSize={Icon.SIZE_LARGE} /> | ||
|
||
// can pass all valid HTML props | ||
<Icon iconName="add" onClick={this.handleAdd} onKeyDown={this.handleAddKeys}> | ||
``` | ||
|
||
@interface IIconProps |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,60 +7,73 @@ | |
import * as classNames from "classnames"; | ||
import * as React from "react"; | ||
|
||
import { IconName } from "@blueprintjs/icons"; | ||
import { IconName, IconSvgPaths16, IconSvgPaths20, LegacyIconName } from "@blueprintjs/icons"; | ||
import { Classes, IIntentProps, IProps } from "../../common"; | ||
|
||
export { IconName }; | ||
|
||
export interface IIconProps extends IIntentProps, IProps { | ||
/** | ||
* Color of icon. Equivalent to setting CSS `fill` property. | ||
*/ | ||
color?: string; | ||
|
||
/** | ||
* Name of the icon (with or without `"pt-icon-"` prefix). | ||
* If `undefined`, this component will render nothing. | ||
* If omitted or `undefined`, this component will render nothing. | ||
*/ | ||
iconName: IconName | undefined; | ||
iconName?: LegacyIconName; | ||
|
||
/** | ||
* Size of the icon. | ||
* Blueprint provides each icon in two sizes: 16px and 20px. The keyword `"inherit"` will | ||
* render a 20px icon but inherit `font-size` from its parent. | ||
* Constants are exposed for each of these values on the component itself: | ||
* `Icon.SIZE_(STANDARD|LARGE|INHERIT)`, | ||
* @default 16 | ||
* Size of the icon, in pixels. | ||
* Blueprint contains 16px and 20px SVG icon images, | ||
* and chooses the appropriate resolution based on this prop. | ||
* @default Icon.SIZE_STANDARD = 16 | ||
*/ | ||
iconSize?: 16 | 20 | "inherit"; | ||
iconSize?: number; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. no default? |
||
|
||
/** CSS style properties. */ | ||
style?: React.CSSProperties; | ||
} | ||
|
||
export class Icon extends React.PureComponent<IIconProps & React.HTMLAttributes<HTMLSpanElement>, never> { | ||
export class Icon extends React.PureComponent<IIconProps & React.SVGAttributes<SVGElement>> { | ||
public static displayName = "Blueprint2.Icon"; | ||
|
||
public static readonly SIZE_STANDARD = 16 as 16; | ||
public static readonly SIZE_LARGE = 20 as 20; | ||
public static readonly SIZE_INHERIT = "inherit" as "inherit"; | ||
public static readonly SIZE_STANDARD = 16; | ||
public static readonly SIZE_LARGE = 20; | ||
|
||
public render() { | ||
if (this.props.iconName == null) { | ||
return null; | ||
} | ||
const { className, iconName, intent, iconSize = Icon.SIZE_STANDARD, ...restProps } = this.props; | ||
const { className, iconName: iconNameProp, iconSize = Icon.SIZE_STANDARD, intent, ...svgProps } = this.props; | ||
const iconName = iconNameProp.replace("pt-icon-", "") as IconName; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: leave the prop as |
||
|
||
const classes = classNames( | ||
getSizeClass(iconSize), | ||
Classes.iconClass(iconName), | ||
Classes.intentClass(intent), | ||
className, | ||
// choose which pixel grid is most appropriate for given icon size | ||
const pixelGridSize = iconSize >= Icon.SIZE_LARGE ? Icon.SIZE_LARGE : Icon.SIZE_STANDARD; | ||
const classes = classNames(Classes.ICON, Classes.intentClass(intent), className); | ||
const viewBox = `0 0 ${pixelGridSize} ${pixelGridSize}`; | ||
return ( | ||
<svg | ||
{...svgProps} | ||
className={classes} | ||
data-icon={iconName} | ||
width={iconSize} | ||
height={iconSize} | ||
viewBox={viewBox} | ||
> | ||
<title>{iconName}</title> | ||
{this.renderSvgPaths(pixelGridSize, iconName)} | ||
</svg> | ||
); | ||
return <span className={classes} {...restProps} />; | ||
} | ||
} | ||
|
||
// NOTE: not using a type alias here so the full union will appear in the interface docs | ||
function getSizeClass(size: 16 | 20 | "inherit") { | ||
switch (size) { | ||
case Icon.SIZE_STANDARD: | ||
return Classes.ICON_STANDARD; | ||
case Icon.SIZE_LARGE: | ||
return Classes.ICON_LARGE; | ||
default: | ||
return Classes.ICON; | ||
private renderSvgPaths(pathsSize: number, iconName: IconName) { | ||
const svgPathsRecord = pathsSize === Icon.SIZE_STANDARD ? IconSvgPaths16 : IconSvgPaths20; | ||
const pathStrings = svgPathsRecord[iconName]; | ||
if (pathStrings == null) { | ||
return null; | ||
} | ||
return pathStrings.map((d, i) => <path key={i} d={d} fillRule="evenodd" />); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this change is unnecessary. we rarely work on icons source. you can run
lerna run dev --parallel --scope '@blueprintjs/icons'
in a separate console.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
in my experience, this change has been very helpful. especially cuz data files come from
icons
package but component comes fromcore
. all other dev aliases include package deps, so what's the harm here?