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

[PLAY-1397] Support Aliasing for Playbook-icons #3479

Merged
merged 12 commits into from
Jun 27, 2024
Merged
Original file line number Diff line number Diff line change
@@ -1,43 +1,8 @@
import React from "react"

import { linkFormat } from "../../../../../utilities/website_sidebar_helper"

import { Hero } from "../../components/Hero"
import {
Roofing,
Powergon,
Nitro,
ChevronDown,
Times,
Bars,
Calendar,
Filter,
Edit,
Trash,
Check,
Plus,
Search
} from '@powerhome/playbook-icons-react'

import { Body, Icon, Title, Flex, FlexItem, Card } from "playbook-ui"

const pbIcons = {
roofing: Roofing,
nitro: Nitro,
powergon: Powergon,
chevrondown: ChevronDown,
times: Times,
bars: Bars,
calendar: Calendar,
filter: Filter,
edit: Edit,
trash: Trash,
check: Check,
plus: Plus,
search: Search
}

window.PB_ICONS = pbIcons

export default function IconList() {

Expand Down Expand Up @@ -66,14 +31,14 @@ export default function IconList() {
hover={{ shadow: "deeper" }}
cursor='pointer'
>
<Icon icon="roofing" />
<Icon icon="circle-arrow-right" />
</Card>
<Card
marginRight='sm'
hover={{ shadow: "deeper" }}
cursor='pointer'
>
<Icon icon="powergon" />
<Icon icon="arrow-circle-right" />
</Card>
<Card
marginRight='sm'
Expand Down
14 changes: 14 additions & 0 deletions playbook-website/app/javascript/packs/application.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,20 @@ import { Turbo } from "@hotwired/turbo-rails"
// Disable Turbo Drive by default (Turbo Drive is equivalent to Turbolinks)
Turbo.session.drive = false

// Icons from playbook-icons-react for testing
import * as icons from "@powerhome/playbook-icons-react"

window.PB_ICONS = {}

function pascalToKebabCase(str) {
return str.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase()
}

Object.entries(icons).forEach(([key, value]) => {
const iconName = pascalToKebabCase(key)
window.PB_ICONS[iconName] = value
})


document.addEventListener('DOMContentLoaded', () => {
const anchors = new AnchorJS()
Expand Down
6 changes: 3 additions & 3 deletions playbook-website/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@
"release": "RAILS_ENV=production NODE_ENV=production ./bin/webpack"
},
"dependencies": {
"@fortawesome/fontawesome-pro": "^6.2.1",
"@fortawesome/fontawesome-pro": "6.2.1",
"@mapbox/mapbox-gl-draw": "^1.4.1",
"@powerhome/playbook-icons": "0.0.1-alpha.16",
"@powerhome/playbook-icons-react": "0.0.1-alpha.8",
"@powerhome/playbook-icons": "0.0.1-alpha.25",
"@powerhome/playbook-icons-react": "0.0.1-alpha.25",
"@powerhome/power-fonts": "0.0.1-alpha.4",
"@rails/webpacker": "5.4.3",
"@svgr/webpack": "5.5.0",
Expand Down
4 changes: 2 additions & 2 deletions playbook/app/pb_kits/playbook/pb_dropdown/dropdown.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ test('generated custom Trigger', () => {
options={options}
>
<Dropdown.Trigger>
<Icon icon="home" />
<Icon icon="elephant" />
</Dropdown.Trigger>
{options.map((option) => (
<Dropdown.Option key={option.id}
Expand All @@ -182,7 +182,7 @@ test('generated custom Trigger', () => {

const kit = screen.getByTestId(testId)
const trigger = kit.querySelector('.pb_dropdown_trigger')
const customTrigger = trigger.querySelector('.fa-home.pb_icon_kit.fa-fw')
const customTrigger = trigger.querySelector('.fa-elephant.pb_icon_kit.fa-fw')
expect(customTrigger).toBeInTheDocument()
})

Expand Down
43 changes: 37 additions & 6 deletions playbook/app/pb_kits/playbook/pb_icon/_icon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import classnames from 'classnames'
import { buildAriaProps, buildDataProps, buildHtmlProps } from '../utilities/props'
import { GlobalProps, globalProps } from '../utilities/globalProps'
import { isValidEmoji } from '../utilities/validEmojiChecker'
import aliasesJson from './icon_aliases.json'

export type IconSizes = "lg"
| "xs"
Expand Down Expand Up @@ -40,6 +41,19 @@ type IconProps = {
spin?: boolean,
} & GlobalProps

type AliasType = string | string[];

interface Aliases {
[key: string]: AliasType;
}

interface AliasesJson {
aliases: Aliases;
}

const aliases: AliasesJson = aliasesJson;


const flipMap = {
horizontal: 'fa-flip-horizontal',
vertical: 'fa-flip-vertical',
Expand All @@ -52,6 +66,22 @@ declare global {
var PB_ICONS: {[key: string]: React.FunctionComponent<any>}
}

// Resolve alias function
const resolveAlias = (icon: string): string => {
const alias = aliases.aliases[icon];

if (alias) {
if (Array.isArray(alias)) {
return alias[0];
} else {
return alias;
}
}

return icon;
};


const Icon = (props: IconProps) => {
const {
aria = {},
Expand All @@ -74,7 +104,8 @@ const Icon = (props: IconProps) => {
spin = false,
} = props

let iconElement: ReactSVGElement | null = typeof(icon) === "object" ? icon : null
const resolvedIcon = resolveAlias(icon as string)
let iconElement: ReactSVGElement | null = typeof(resolvedIcon) === "object" ? resolvedIcon : null

const faClasses = {
'fa-border': border,
Expand All @@ -90,12 +121,12 @@ const Icon = (props: IconProps) => {

if (!customIcon && !iconElement) {
const PowerIcon: React.FunctionComponent<any> | undefined =
window.PB_ICONS ? window.PB_ICONS[icon as string] : null
window.PB_ICONS ? window.PB_ICONS[resolvedIcon as string] : null

if (PowerIcon) {
iconElement = <PowerIcon /> as ReactSVGElement
} else {
faClasses[`fa-${icon}`] = icon as string
faClasses[`fa-${resolvedIcon}`] = resolvedIcon as string
}
}

Expand All @@ -115,7 +146,7 @@ const Icon = (props: IconProps) => {
className
)

aria.label ? null : aria.label = `${icon} icon`
aria.label ? null : aria.label = `${resolvedIcon} icon`
const ariaProps: {[key: string]: any} = buildAriaProps(aria)
const dataProps: {[key: string]: any} = buildDataProps(data)
const htmlProps = buildHtmlProps(htmlOptions)
Expand All @@ -137,7 +168,7 @@ const Icon = (props: IconProps) => {
}
</>
)
else if (isValidEmoji(icon as string))
else if (isValidEmoji(resolvedIcon as string))
return (
<>
<span
Expand All @@ -146,7 +177,7 @@ const Icon = (props: IconProps) => {
className={classesEmoji}
id={id}
>
{icon}
{resolvedIcon}
</span>
</>
)
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1,6 @@
<%= pb_rails("icon", props: { icon: "user", fixed_width: true }) %>
<%= pb_rails("icon", props: { icon: "angles-down", fixed_width: true }) %>
<%= pb_rails("icon", props: { icon: "circle-arrow-right", fixed_width: true }) %>
<%= pb_rails("icon", props: { icon: "arrow-circle-right", fixed_width: true }) %>

<%= pb_rails("caption", props: { text: "Font Awesome (no alias & not in our Playbook-icons lib)", margin_y: "md" }) %>
<%= pb_rails("icon", props: { icon: "elephant", fixed_width: true }) %>
26 changes: 21 additions & 5 deletions playbook/app/pb_kits/playbook/pb_icon/docs/_icon_default.jsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,29 @@
import React from 'react'
import React from "react"

import Icon from '../_icon'
import Icon from "../_icon"
import {Caption} from "../.."

const IconDefault = (props) => {
return (
<div>
<Icon
fixedWidth
icon="user"
<Icon fixedWidth
icon='angles-down'
{...props}
/>
jasperfurniss marked this conversation as resolved.
Show resolved Hide resolved
<Icon fixedWidth
icon='circle-arrow-right'
{...props}
/>
<Icon fixedWidth
icon='arrow-circle-right'
{...props}
/>
<Caption
jasperfurniss marked this conversation as resolved.
Show resolved Hide resolved
marginY='md'
text='Font Awesome (no alias & not in our Playbook-icons lib)'
/>
<Icon fixedWidth
icon='elephant'
{...props}
jasperfurniss marked this conversation as resolved.
Show resolved Hide resolved
/>
</div>
Expand Down
22 changes: 21 additions & 1 deletion playbook/app/pb_kits/playbook/pb_icon/icon.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
# rubocop:disable Style/HashLikeCase

require "open-uri"
require "json"

module Playbook
module PbIcon
Expand Down Expand Up @@ -38,6 +39,8 @@ class Icon < Playbook::KitBase
prop :spin, type: Playbook::Props::Boolean,
default: false

ALIASES = JSON.parse(File.read(Playbook::Engine.root.join("app/pb_kits/playbook/pb_icon/icon_aliases.json")))["aliases"].freeze

def valid_emoji?
emoji_regex = /\p{Emoji}/
emoji_regex.match?(icon)
Expand Down Expand Up @@ -83,7 +86,8 @@ def asset_path
return unless Rails.application.config.respond_to?(:icon_path)

base_path = Rails.application.config.icon_path
icon_path = Dir.glob(Rails.root.join(base_path, "**", "#{icon}.svg")).first
resolved_icon = resolve_alias(icon)
icon_path = Dir.glob(Rails.root.join(base_path, "**", "#{resolved_icon}.svg")).first
icon_path if icon_path && File.exist?(icon_path)
end

Expand All @@ -106,6 +110,22 @@ def is_svg?

private

def resolve_alias(icon)
aliases = ALIASES[icon]
return icon unless aliases

if aliases.is_a?(Array)
aliases.find { |alias_name| file_exists?(alias_name) } || icon
else
aliases
end
end

def file_exists?(alias_name)
base_path = Rails.application.config.icon_path
File.exist?(Dir.glob(Rails.root.join(base_path, "**", "#{alias_name}.svg")).first)
end

def svg_size
size.nil? ? "1x" : size
end
Expand Down
39 changes: 39 additions & 0 deletions playbook/app/pb_kits/playbook/pb_icon/icon_aliases.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{
"aliases": {
"arrow-alt-circle-right": "circle-right",
"angles-down": "angle-double-down",
"arrow-alt-down": "down",
"arrow-alt-up": "up",
"arrow-right-long": "long-arrow-right",
"arrow-to-bottom": "arrow-down-to-line",
"arrows-h": "arrows-left-right",
"calendar-days": "calendar-alt",
"circle-arrow-right": "arrow-circle-right",
"clock-rotate-left": "history",
"close": [
"times",
"xmark"
],
"ellipsis-h": "ellipsis",
"exclamation-circle": "circle-exclamation",
"external-link": "arrow-up-right-from-square",
"file-lines": "file-alt",
"gear": "cog",
"home": "house",
"info-circle": "circle-info",
"map-o": "map",
"message": "comment-alt",
"minus-circle": "circle-minus",
"money": "money-bill",
"mouse-pointer": "arrow-pointer",
"nitro": "nitro-n",
"play-circle": "circle-play",
"plus-circle": "circle-plus",
"plus-square": "square-plus",
"powergon": "powergon-p",
"question-circle": "circle-question",
"roofing": "product-roofing",
"shelves": "inventory",
"th-list": "table-list"
}
}
1 change: 1 addition & 0 deletions playbook/app/pb_kits/playbook/pb_icon/types.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
declare module 'js-yaml'
20 changes: 10 additions & 10 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2201,9 +2201,9 @@
resolved "https://npm.powerapp.cloud/@fortawesome/fontawesome-free/-/fontawesome-free-6.2.1.tgz#344baf6ff9eaad7a73cff067d8c56bfc11ae5304"
integrity sha512-viouXhegu/TjkvYQoiRZK3aax69dGXxgEjpvZW81wIJdxm5Fnvp3VVIP4VHKqX4SvFw6qpmkILkD4RJWAdrt7A==

"@fortawesome/fontawesome-pro@^6.2.1":
"@fortawesome/fontawesome-pro@6.2.1":
version "6.2.1"
resolved "https://npm.powerapp.cloud/@fortawesome/fontawesome-pro/-/6.2.1/fontawesome-pro-6.2.1.tgz#1cd5b79d93fdb955ef8a04996fef20a44207a6f0"
resolved "https://npm.powerapp.cloud/@fortawesome/fontawesome-pro/-/fontawesome-pro-6.2.1.tgz#1cd5b79d93fdb955ef8a04996fef20a44207a6f0"
integrity sha512-dHk7iiCf5MCmoUvmrYzfN/I3gebpgpA1oqlOffgOThnsaAR4kpaQ5YMTdkdG99Of1hnN0Bok6R+HE28zXb3SOg==

"@gar/promisify@^1.0.1":
Expand Down Expand Up @@ -2832,15 +2832,15 @@
resolved "https://npm.powerapp.cloud/@powerhome/eslint-config/-/eslint-config-0.1.0.tgz#f1e1151481f51421186ba8caad99fadb24b1fe51"
integrity sha512-8e5DRgnKPbJ+ofAtqjUPZTxcgHg/TVf52WeNqAGBUXSS4QWHemL6fj1n/YHfAIvx3aMUhFwrw2lUNofUocgK3A==

"@powerhome/playbook-icons-react@0.0.1-alpha.8":
version "0.0.1-alpha.8"
resolved "https://npm.powerapp.cloud/@powerhome/playbook-icons-react/-/d71ffd31679c57b3a7358718ce84b2f9e5f0c577#d71ffd31679c57b3a7358718ce84b2f9e5f0c577"
integrity sha512-SUM1/MsJb4nnNEz2A9PMXa8hgBeCdGCNQWEdrozy1l2/1GZOkiw28aGIUZZN3LAR2+0hRRNhVhcetfpuGCZcFg==
"@powerhome/playbook-icons-react@0.0.1-alpha.25":
version "0.0.1-alpha.25"
resolved "https://npm.powerapp.cloud/@powerhome/playbook-icons-react/-/3a700f9b6d6427aefe0fb94039e292cea462fe9e#3a700f9b6d6427aefe0fb94039e292cea462fe9e"
integrity sha512-0h53TdW/PrUrwYFxonE0dIN9vupqAVLwBv70hSrRkrKb8chuLc/+kBtL15MeSJ+9cWIXF0ocFOHBlNTc25hmyw==

"@powerhome/playbook-icons@0.0.1-alpha.16":
version "0.0.1-alpha.16"
resolved "https://npm.powerapp.cloud/@powerhome/playbook-icons/-/273baad6202de2736f9e38287e5589e00f47dfb8#273baad6202de2736f9e38287e5589e00f47dfb8"
integrity sha512-Kim7OqGxotUuhcxHBQI8a1M184DvzSyHU3ZmN/B6JANcw2jIOVL9z0f+qa9Trgij1cmyY444WC51LDbYaGvEug==
"@powerhome/playbook-icons@0.0.1-alpha.25":
version "0.0.1-alpha.25"
resolved "https://npm.powerapp.cloud/@powerhome/playbook-icons/-/261d2f40561f1d4d0505e4af18892916941ed1a0#261d2f40561f1d4d0505e4af18892916941ed1a0"
integrity sha512-LtnN8E/yHaXzjQG+sZfpUbGA9Xdqpwhx8aFSPvg0lGf7phOoNFHSmjXhK0a36bZnPn0tIGBct9LhSzp6zhyVBA==

"@powerhome/power-fonts@0.0.1-alpha.4":
version "0.0.1-alpha.4"
Expand Down
Loading