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

[tag] use Icon in remove button #2231

Merged
merged 2 commits into from
Mar 14, 2018
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
10 changes: 7 additions & 3 deletions packages/core/src/components/tag/_common.scss
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,6 @@ $tag-padding-large: ($tag-height-large - $pt-icon-size-large) / 2 !default;
}

@mixin pt-tag-remove() {
@include pt-icon();
position: absolute;
top: 0;
right: 0;
Expand All @@ -103,12 +102,17 @@ $tag-padding-large: ($tag-height-large - $pt-icon-size-large) / 2 !default;
opacity: 1;
}

&::before {
// CSS API support
&:empty::before {
@include pt-icon();
content: $pt-icon-small-cross;
}

.pt-large & {
@include pt-icon-sized($pt-icon-size-large);
padding: $tag-padding-large;

&:empty::before {
@include pt-icon-sized($pt-icon-size-large);
}
}
}
3 changes: 2 additions & 1 deletion packages/core/src/components/tag/tag.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

Tags are great for lists of strings.

@reactExample TagExample

@## CSS API

An optional "remove" button can be added inside a tag as a `button.pt-tag-remove`. Also add the
Expand Down Expand Up @@ -41,4 +43,3 @@ Blueprint class name.

@interface ITagProps

@reactExample TagExample
28 changes: 14 additions & 14 deletions packages/core/src/components/tag/tag.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,8 @@
import classNames from "classnames";
import * as React from "react";

import { Utils } from "../../common";
import { IIntentProps, IProps, removeNonHTMLProps } from "../../common/props";

import * as Classes from "../../common/classes";
import { Classes, IIntentProps, IProps, Utils } from "../../common";
import { Icon } from "../icon/icon";

export interface ITagProps extends IProps, IIntentProps, React.HTMLAttributes<HTMLSpanElement> {
/**
Expand All @@ -31,26 +29,28 @@ export class Tag extends React.PureComponent<ITagProps, {}> {
public static displayName = "Blueprint2.Tag";

public render() {
const { active, className, intent, onRemove } = this.props;
const { active, children, className, intent, onRemove, ...htmlProps } = this.props;
const isRemovable = Utils.isFunction(onRemove);
const tagClasses = classNames(
Classes.TAG,
Classes.intentClass(intent),
{
[Classes.TAG_REMOVABLE]: onRemove != null,
[Classes.TAG_REMOVABLE]: isRemovable,
[Classes.ACTIVE]: active,
},
className,
);
const button = Utils.isFunction(onRemove) ? (
<button type="button" className={Classes.TAG_REMOVE} onClick={this.onRemoveClick} />
) : (
undefined
);
const isLarge = tagClasses.indexOf(Classes.LARGE) >= 0;
const removeButton = isRemovable ? (
<button type="button" className={Classes.TAG_REMOVE} onClick={this.onRemoveClick}>
<Icon icon="small-cross" iconSize={isLarge ? Icon.SIZE_LARGE : Icon.SIZE_STANDARD} />
</button>
) : null;

return (
<span {...removeNonHTMLProps(this.props)} className={tagClasses}>
{this.props.children}
{button}
<span {...htmlProps} className={tagClasses}>
{children}
{removeButton}
</span>
);
}
Expand Down
86 changes: 48 additions & 38 deletions packages/docs-app/src/examples/core-examples/tagExample.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,53 +6,63 @@

import * as React from "react";

import { Classes, Intent, Tag } from "@blueprintjs/core";
import { BaseExample } from "@blueprintjs/docs-theme";
import { Button, Classes, Intent, Switch, Tag } from "@blueprintjs/core";
import { BaseExample, handleBooleanChange, handleStringChange } from "@blueprintjs/docs-theme";
import classNames from "classnames";
import { IntentSelect } from "./common/intentSelect";

export class TagExample extends BaseExample<{ showTag?: boolean }> {
public state = {
showTag: true,
export interface ITagExampleState {
intent: Intent;
large: boolean;
minimal: boolean;
removable: boolean;
tags: string[];
}

export class TagExample extends BaseExample<ITagExampleState> {
public state: ITagExampleState = {
intent: Intent.NONE,
large: false,
minimal: false,
removable: false,
tags: INITIAL_TAGS,
};

protected className = "docs-tag-example";

protected renderExample() {
return (
<div>
<Tag className={Classes.MINIMAL} intent={Intent.PRIMARY}>
@jkillian
</Tag>
<Tag className={Classes.MINIMAL} intent={Intent.PRIMARY}>
@adahiya
</Tag>
<Tag className={Classes.MINIMAL} intent={Intent.PRIMARY}>
@ggray
</Tag>
<Tag className={Classes.MINIMAL} intent={Intent.PRIMARY}>
@allorca
</Tag>
<Tag className={Classes.MINIMAL} intent={Intent.PRIMARY}>
@bdwyer
</Tag>
<Tag className={Classes.MINIMAL} intent={Intent.PRIMARY}>
@piotrk
</Tag>
{this.maybeRenderTag()}
</div>
);
}
private handleIntentChange = handleStringChange((intent: Intent) => this.setState({ intent }));
private handleLargeChange = handleBooleanChange(large => this.setState({ large }));
private handleMinimalChange = handleBooleanChange(minimal => this.setState({ minimal }));
private handleRemovableChange = handleBooleanChange(removable => this.setState({ removable }));

private maybeRenderTag() {
if (this.state.showTag) {
protected renderExample() {
const { intent, large, minimal, removable } = this.state;
const tagClasses = classNames({ [Classes.LARGE]: large, [Classes.MINIMAL]: minimal });
const tags = this.state.tags.map(tag => {
const onRemove = () => this.setState({ tags: this.state.tags.filter(t => t !== tag) });
return (
<Tag className={Classes.MINIMAL} intent={Intent.PRIMARY} onRemove={this.deleteTag}>
@dlipowicz
<Tag key={tag} className={tagClasses} intent={intent} onRemove={removable && onRemove}>
{tag}
</Tag>
);
} else {
return undefined;
}
});
return <div>{tags}</div>;
}

private deleteTag = () => this.setState({ showTag: false });
protected renderOptions() {
const { intent, large, minimal, removable } = this.state;
return [
[
<Switch key="large" label="Large" checked={large} onChange={this.handleLargeChange} />,
<Switch key="minimal" label="Minimal" checked={minimal} onChange={this.handleMinimalChange} />,
<Switch key="removable" label="Removable" checked={removable} onChange={this.handleRemovableChange} />,
],
[<IntentSelect key="intent" intent={intent} onChange={this.handleIntentChange} />],
[<Button key="reset" text="Reset tags" onClick={this.resetTags} />],
];
}

private resetTags = () => this.setState({ tags: INITIAL_TAGS });
}

const INITIAL_TAGS = ["@jkillian", "@adahiya", "@ggray", "@allorca", "@bdwyer", "@piotrk"];