diff --git a/playbook/app/pb_kits/playbook/pb_icon/_icon.scss b/playbook/app/pb_kits/playbook/pb_icon/_icon.scss
index 59aa945237..953e8b5ba2 100644
--- a/playbook/app/pb_kits/playbook/pb_icon/_icon.scss
+++ b/playbook/app/pb_kits/playbook/pb_icon/_icon.scss
@@ -1,3 +1,20 @@
+@import "../tokens/colors";
+
+// All the merges below create $icon_colors, a map of all color tokens in colors.scss
+$merge_kits1: map-merge($status_colors, $category_colors);
+$merge_kits2: map-merge($merge_kits1, $product_colors);
+$merge_kits3: map-merge($merge_kits2, $text_colors);
+$icon_colors: map-merge($merge_kits3, $data_colors);
+
+.pb_custom_icon, .pb_icon_kit {
+ @each $color_name, $color_value in $icon_colors {
+ &[class*="#{$color_name}"] {
+ color: $color_value;
+ }
+ }
+}
+
+// Rails custom icon styles
svg.pb_custom_icon {
width: 1em;
fill: currentColor;
diff --git a/playbook/app/pb_kits/playbook/pb_icon/_icon.tsx b/playbook/app/pb_kits/playbook/pb_icon/_icon.tsx
index c7ccbb9d43..42085e59d6 100644
--- a/playbook/app/pb_kits/playbook/pb_icon/_icon.tsx
+++ b/playbook/app/pb_kits/playbook/pb_icon/_icon.tsx
@@ -23,6 +23,7 @@ type IconProps = {
aria?: {[key: string]: string},
border?: string,
className?: string,
+ color?: string,
customIcon?: {[key: string] :SVGElement},
data?: {[key: string]: string},
fixedWidth?: boolean,
@@ -121,6 +122,7 @@ const Icon = (props: IconProps) => {
aria = {},
border = false,
className,
+ color,
customIcon,
data = {},
fixedWidth = true,
@@ -169,6 +171,7 @@ const Icon = (props: IconProps) => {
(!iconElement && !customIcon) ? 'pb_icon_kit' : '',
(iconElement || customIcon) ? 'pb_custom_icon' : fontStyle,
iconElement ? 'svg-inline--fa' : '',
+ color ? `color_${color}` : '',
globalProps(props),
className
)
diff --git a/playbook/app/pb_kits/playbook/pb_icon/docs/_icon_color.html.erb b/playbook/app/pb_kits/playbook/pb_icon/docs/_icon_color.html.erb
new file mode 100644
index 0000000000..3e3b2e5520
--- /dev/null
+++ b/playbook/app/pb_kits/playbook/pb_icon/docs/_icon_color.html.erb
@@ -0,0 +1,5 @@
+<%= pb_rails("flex", props: {orientation: "column"}) do %>
+ <%= pb_rails("icon", props: { icon: "user", fixed_width: true, color: "primary", padding_bottom: "sm", size: "2x" }) %>
+ <%= pb_rails("icon", props: { icon: "recycle", fixed_width: true, color: "data_4", padding_bottom: "sm", size: "2x" }) %>
+ <%= pb_rails("icon", props: { icon: "roofing", fixed_width: true, color: "product_5_background", size: "2x" }) %>
+<% end %>
\ No newline at end of file
diff --git a/playbook/app/pb_kits/playbook/pb_icon/docs/_icon_color.jsx b/playbook/app/pb_kits/playbook/pb_icon/docs/_icon_color.jsx
new file mode 100644
index 0000000000..d3662eb89c
--- /dev/null
+++ b/playbook/app/pb_kits/playbook/pb_icon/docs/_icon_color.jsx
@@ -0,0 +1,34 @@
+import React from "react"
+import Icon from "../_icon"
+
+const IconDefault = (props) => {
+ return (
+
+
+
+
+
+ )
+}
+
+export default IconDefault
diff --git a/playbook/app/pb_kits/playbook/pb_icon/docs/_icon_color.md b/playbook/app/pb_kits/playbook/pb_icon/docs/_icon_color.md
new file mode 100644
index 0000000000..98aeb62f78
--- /dev/null
+++ b/playbook/app/pb_kits/playbook/pb_icon/docs/_icon_color.md
@@ -0,0 +1 @@
+Pass any text, status, data, product, or category Playbook color token to the `color` prop to change any icon's color.
\ No newline at end of file
diff --git a/playbook/app/pb_kits/playbook/pb_icon/docs/example.yml b/playbook/app/pb_kits/playbook/pb_icon/docs/example.yml
index a2cef377dd..9d0f648d79 100644
--- a/playbook/app/pb_kits/playbook/pb_icon/docs/example.yml
+++ b/playbook/app/pb_kits/playbook/pb_icon/docs/example.yml
@@ -9,6 +9,7 @@ examples:
- icon_sizes: Icon Sizes
- icon_custom: Icon Custom
- icon_fa_kit: Icon with FontAwesome Kit
+ - icon_color: Icon Color
react:
- icon_default: Icon Default
@@ -20,6 +21,7 @@ examples:
- icon_sizes: Icon Sizes
- icon_custom: Icon Custom
- icon_fa_kit: Icon with FontAwesome Kit
+ - icon_color: Icon Color
swift:
- icon_default_swift: Icon Default
diff --git a/playbook/app/pb_kits/playbook/pb_icon/docs/index.js b/playbook/app/pb_kits/playbook/pb_icon/docs/index.js
index 72808f09ac..8aa0aefb6a 100644
--- a/playbook/app/pb_kits/playbook/pb_icon/docs/index.js
+++ b/playbook/app/pb_kits/playbook/pb_icon/docs/index.js
@@ -7,3 +7,4 @@ export { default as IconBorder } from './_icon_border.jsx'
export { default as IconSizes } from './_icon_sizes.jsx'
export { default as IconCustom } from './_icon_custom.jsx'
export { default as IconFaKit} from './_icon_fa_kit.jsx'
+export { default as IconColor } from './_icon_color.jsx'
diff --git a/playbook/app/pb_kits/playbook/pb_icon/icon.rb b/playbook/app/pb_kits/playbook/pb_icon/icon.rb
index eb9ba3c05a..ebd1322e9e 100644
--- a/playbook/app/pb_kits/playbook/pb_icon/icon.rb
+++ b/playbook/app/pb_kits/playbook/pb_icon/icon.rb
@@ -36,6 +36,7 @@ class Icon < Playbook::KitBase
default: "far"
prop :spin, type: Playbook::Props::Boolean,
default: false
+ prop :color, type: Playbook::Props::String
def valid_emoji?
emoji_regex = /\p{Emoji}/
@@ -45,6 +46,7 @@ def valid_emoji?
def classname
generate_classname(
"pb_icon_kit",
+ color_class,
font_style_class,
icon_class,
border_class,
@@ -65,6 +67,7 @@ def custom_icon_classname
generate_classname(
"pb_icon_kit",
border_class,
+ color_class,
fixed_width_class,
flip_class,
inverse_class,
@@ -104,7 +107,8 @@ def render_svg
svg["aria"] = object.aria
svg["height"] = "auto"
svg["width"] = "auto"
- doc.at_css("path")["fill"] = "currentColor"
+ fill_color = object.color || "currentColor"
+ doc.at_css("path")["fill"] = fill_color
raw doc
end
@@ -200,6 +204,10 @@ def spin_class
class_name = is_svg? ? "spin" : "fa-spin"
spin ? class_name : nil
end
+
+ def color_class
+ color ? "color_#{color}" : nil
+ end
end
end
end
diff --git a/playbook/app/pb_kits/playbook/pb_icon/icon.test.js b/playbook/app/pb_kits/playbook/pb_icon/icon.test.js
index 2e61187286..9f872e74a8 100644
--- a/playbook/app/pb_kits/playbook/pb_icon/icon.test.js
+++ b/playbook/app/pb_kits/playbook/pb_icon/icon.test.js
@@ -12,7 +12,7 @@ describe("Icon Kit", () => {
data={{ testid: testId }}
fixedWidth
icon="user"
- />
+ />
)
const kit = screen.getByTestId(testId)
@@ -27,7 +27,7 @@ describe("Icon Kit", () => {
fixedWidth
icon="user"
rotation={rotateProp}
- />
+ />
)
const kit = screen.getByTestId(testId)
@@ -44,7 +44,7 @@ describe("Icon Kit", () => {
fixedWidth
flip="horizontal"
icon="user"
- />
+ />
)
const kit = screen.getByTestId(testId)
@@ -59,7 +59,7 @@ describe("Icon Kit", () => {
fixedWidth
icon="spinner"
spin
- />
+ />
)
const kit = screen.getByTestId(testId)
@@ -73,7 +73,7 @@ describe("Icon Kit", () => {
fixedWidth
icon="arrow-left"
pull="left"
- />
+ />
)
const kit = screen.getByTestId(testId)
@@ -87,7 +87,7 @@ describe("Icon Kit", () => {
fixedWidth
icon="arrow-left"
pull="left"
- />
+ />
)
const kit = screen.getByTestId(testId)
@@ -101,7 +101,7 @@ describe("Icon Kit", () => {
data={{ testid: testId }}
fixedWidth
icon="user"
- />
+ />
)
const kit = screen.getByTestId(testId)
@@ -128,7 +128,7 @@ describe("Icon Kit", () => {
data={{ testid: testId }}
icon="user"
size={sizeProp}
- />
+ />
)
const kit = screen.getByTestId(testId)
@@ -145,11 +145,24 @@ describe("Icon Kit", () => {
fixedWidth
fontStyle="fas"
icon="user"
- />
+ />
)
const kit = screen.getByTestId(testId)
expect(kit).toHaveClass("fa-user pb_icon_kit fa-fw fas")
})
+ test("renders with color prop", () => {
+ render(
+
+ )
+
+ const kit = screen.getByTestId(testId)
+ expect(kit).toHaveClass("color_primary")
+ })
+
})
\ No newline at end of file
diff --git a/playbook/spec/pb_kits/playbook/kits/icon_spec.rb b/playbook/spec/pb_kits/playbook/kits/icon_spec.rb
index ff9a2a1df8..a8ca6e5785 100644
--- a/playbook/spec/pb_kits/playbook/kits/icon_spec.rb
+++ b/playbook/spec/pb_kits/playbook/kits/icon_spec.rb
@@ -51,6 +51,11 @@
is_expected.to define_prop(:spin)
.of_type(Playbook::Props::Boolean)
}
+ it {
+ is_expected.to define_prop(:color)
+ .of_type(Playbook::Props::String)
+ .with_default(nil)
+ }
describe "#custom_icon" do
it "returns an icon with custom data-collapsible-main attribute", :aggregate_failures do
@@ -83,5 +88,16 @@
expect(subject.new(icon: icon, spin: true).classname).to eq "pb_icon_kit far fa-user fa-spin"
expect(subject.new(icon: icon, classname: "additional_class").classname).to eq "pb_icon_kit far fa-user additional_class"
end
+ it "includes color class when color prop is provided", :aggregate_failures do
+ icon = "user"
+ color = "primary"
+
+ expect(subject.new(icon: icon, color: color).classname).to include "color_primary"
+ end
+ it "does not include color class when color prop is not provided", :aggregate_failures do
+ icon = "user"
+
+ expect(subject.new(icon: icon).classname).not_to include "color_"
+ end
end
end