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

[icons] fix: restore transform-origin style in static component markup #6639

Merged
merged 1 commit into from
Jan 10, 2024
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
3 changes: 3 additions & 0 deletions packages/core/src/components/icon/_icon.scss
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
/* stylelint-enable */
}

// TOOD: move to SVGIconContainer styles in @blueprintjs/icons in v6.0
> svg {
// prevent extra vertical whitespace
display: block;
Expand Down Expand Up @@ -59,6 +60,8 @@
//
// Icon font styles
//
// TOOD: move to @blueprintjs/icons in v6.0
//

span.#{$ns}-icon-standard {
@include pt-icon($pt-icon-size-standard);
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/components/icon/icon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ export const Icon: IconComponent = React.forwardRef(function <T extends Element>
return (
<SVGIconContainer<any>
children={pathElements}
// don't forward Classes.iconClass(icon) here, since the container will render that class
// don't forward `Classes.ICON` or `Classes.iconClass(icon)` here, since the container will render those classes
className={classNames(Classes.intentClass(intent), className)}
color={color}
htmlTitle={htmlTitle}
Expand Down
4 changes: 2 additions & 2 deletions packages/docs-app/src/blueprint.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,9 @@ The following example shows an `index.html` file; the same stylesheets should be

```html
<link href="path/to/node_modules/normalize.css/normalize.css" rel="stylesheet" />
<!-- blueprint-icons.css file must be included alongside blueprint.css! -->
<link href="path/to/node_modules/@blueprintjs/icons/lib/css/blueprint-icons.css" rel="stylesheet" />
<link href="path/to/node_modules/@blueprintjs/core/lib/css/blueprint.css" rel="stylesheet" />
<!-- blueprint-icons.css file must be included alongside blueprint.css for icon font support -->
<link href="path/to/node_modules/@blueprintjs/icons/lib/css/blueprint-icons.css" rel="stylesheet" />
<!-- add other blueprint-*.css files here -->
```

Expand Down
14 changes: 11 additions & 3 deletions packages/docs-app/src/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,20 +32,28 @@ The JavaScript components are stable and their APIs adhere to [semantic versioni
contains supporting media such as fonts and images.

```scss
// using node-style package resolution in a CSS file:
// using Node.js-style package resolution in a CSS file:
@import "normalize.css";
@import "@blueprintjs/core/lib/css/blueprint.css";
// include blueprint-icons.css for icon font support
@import "@blueprintjs/icons/lib/css/blueprint-icons.css";
```

```ts
// or using a ESM bundler which resolves CSS files as modules:
import "normalize.css";
import "@blueprintjs/core/lib/css/blueprint.css";
// include blueprint-icons.css for icon font support
import "@blueprintjs/icons/lib/css/blueprint-icons.css";
```

```html
<!-- or using plain old HTML -->
<head>
<!-- include dependencies manually -->
<link href="path/to/node_modules/normalize.css/normalize.css" rel="stylesheet" />
<link href="path/to/node_modules/@blueprintjs/core/lib/css/blueprint.css" rel="stylesheet" />
<!-- include blueprint-icons.css for icon font support -->
<link href="path/to/node_modules/@blueprintjs/icons/lib/css/blueprint-icons.css" rel="stylesheet" />
<!-- NOTE: blueprint-icons.css file must be included alongside blueprint.css! -->
</head>
```

Expand Down
13 changes: 13 additions & 0 deletions packages/icons/scripts/generate-icon-components.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,19 @@ import { parse } from "svg-parser";
import { generatedSrcDir, ICON_RASTER_SCALING_FACTOR, ICON_SIZES, scriptsDir } from "./common.mjs";

Handlebars.registerHelper("pascalCase", iconName => pascalCase(iconName));

/**
* Notes on icon component template implementation:
*
* The components rendered by this template (`<AddClip>`, `<Calendar>`, etc.) rely on a centered scale `transform` to
* display their SVG paths correctly.
*
* In this template, the `<path>` element applies `transform-origin` using the `style` attribute rather than
* `transformOrigin`. Although `trasformOrigin` was added as a supported SVG attribute to React in 2023,
* it is still difficult to use without compile-time and/or runtime errors, see:
* - https://github.com/facebook/react/pull/26130
* - https://github.com/palantir/blueprint/issues/6591
*/
const iconComponentTemplate = Handlebars.compile(readFileSync(resolve(scriptsDir, "iconComponent.tsx.hbs"), "utf8"));
const componentsIndexTemplate = Handlebars.compile(readFileSync(resolve(scriptsDir, "componentsIndex.ts.hbs"), "utf8"));
const indexTemplate = Handlebars.compile(readFileSync(resolve(scriptsDir, "index.ts.hbs"), "utf8"));
Expand Down
6 changes: 4 additions & 2 deletions packages/icons/scripts/iconComponent.tsx.hbs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2021 Palantir Technologies, Inc. All rights reserved.
* Copyright 2024 Palantir Technologies, Inc. All rights reserved.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
Expand All @@ -22,15 +22,17 @@ export const {{pascalCase iconName}}: React.FC<SVGIconProps> = React.forwardRef<
const isLarge = props.size! >= IconSize.LARGE;
const pixelGridSize = isLarge ? IconSize.LARGE : IconSize.STANDARD;
const translation = `${-1 * pixelGridSize / {{pathScaleFactor}} / 2}`;
const style = { transformOrigin: "center" };
return (
<SVGIconContainer iconName="{{iconName}}" ref={ref} {...props}>
<path
d={isLarge ? "{{icon20pxPath}}" : "{{icon16pxPath}}"}
fillRule="evenodd"
transform={`scale({{pathScaleFactor}}, -{{pathScaleFactor}}) translate(${translation}, ${translation})`}
style={style}
/>
</SVGIconContainer>
)
);
});
{{pascalCase iconName}}.defaultProps = {
size: IconSize.STANDARD,
Expand Down
14 changes: 0 additions & 14 deletions packages/icons/src/blueprint-icons.scss
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,3 @@ Licensed under the Apache License, Version 2.0.

@import "generated/16px/blueprint-icons-16";
@import "generated/20px/blueprint-icons-20";

/* stylelint-disable-next-line @blueprintjs/no-prefix-literal -- we don't have access to core variables in this file */
.bp5-icon-svg {
// Despite being added to added as a supported SVG attribute to React in 2023, the `transformOrigin` JSX attribute
// is still difficult to use in our statically-generated icon components (`<AddClip>`, `<Calendar>`, etc.)
// which rely on a centered scale `transform="..."` to display their `<path>` elements correctly. To work around
// this, we apply the necessary style in CSS instead. Note that this needs to apply directly to the `<path>` element
// and not the container `<svg>`. See:
// - https://github.com/facebook/react/pull/26130
// - https://github.com/palantir/blueprint/issues/6591
path {
transform-origin: center;
}
}
1 change: 0 additions & 1 deletion packages/icons/src/classes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,3 @@

const NS = "bp5";
export const ICON = `${NS}-icon`;
export const ICON_SVG = `${ICON}-svg`;
4 changes: 2 additions & 2 deletions packages/icons/src/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ reference: icons
@# Icons

The [**@blueprintjs/icons** NPM package](https://www.npmjs.com/package/@blueprintjs/icons)
provides provides over 500 vector UI icons in two sizes (16px and 20px) and two formats (SVG and fonts).
provides over 500 vector UI icons in two sizes (16px and 20px) and two formats (SVG and fonts).

<div class="@ns-callout @ns-intent-primary @ns-icon-info-sign">

Expand All @@ -17,7 +17,7 @@ See the [**`Icon` component documentation**](#core/components/icon) (in the `@bl
npm install --save @blueprintjs/icons
```

Import CSS with a bundler like webpack:
For icon font support, import CSS with a bundler like webpack:

```js
@import "@blueprintjs/icons/lib/css/blueprint-icons.css";
Expand Down
5 changes: 3 additions & 2 deletions packages/icons/src/svgIconContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -84,13 +84,14 @@ export const SVGIconContainer: SVGIconContainerComponent = React.forwardRef(func
ref={ref as React.Ref<SVGSVGElement>}
{...sharedSvgProps}
{...htmlProps}
className={classNames(Classes.ICON_SVG, className, svgProps?.className)}
className={classNames(className, svgProps?.className)}
>
{title && <title id={titleId}>{title}</title>}
{children}
</svg>
);
} else {
// N.B. styles for `Classes.ICON` are defined in @blueprintjs/core in `_icon.scss`
return React.createElement(
tagName,
{
Expand All @@ -100,7 +101,7 @@ export const SVGIconContainer: SVGIconContainerComponent = React.forwardRef(func
ref,
title: htmlTitle,
},
<svg data-icon={iconName} {...sharedSvgProps} className={classNames(Classes.ICON_SVG, svgProps?.className)}>
<svg data-icon={iconName} {...sharedSvgProps} className={svgProps?.className}>
{title && <title>{title}</title>}
{children}
</svg>,
Expand Down