playbook_ui 13.16.0.pre.alpha.play1141iconkitusinglibrary2060 → 13.17.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/pb_kits/playbook/_playbook.scss +14 -12
- data/app/pb_kits/playbook/index.js +2 -1
- data/app/pb_kits/playbook/pb_advanced_table/Components/CollapsibleTrail.tsx +30 -0
- data/app/pb_kits/playbook/pb_advanced_table/Components/CustomCell.tsx +62 -0
- data/app/pb_kits/playbook/pb_advanced_table/Components/LoadingCell.tsx +5 -0
- data/app/pb_kits/playbook/pb_advanced_table/Components/SortIconButton.tsx +30 -0
- data/app/pb_kits/playbook/pb_advanced_table/Components/SubRowHeaderRow.tsx +61 -0
- data/app/pb_kits/playbook/pb_advanced_table/Components/TableHeaderCell.tsx +128 -0
- data/app/pb_kits/playbook/pb_advanced_table/Components/ToggleIconButton.tsx +28 -0
- data/app/pb_kits/playbook/pb_advanced_table/Context/AdvancedTableContext.tsx +5 -0
- data/app/pb_kits/playbook/pb_advanced_table/README.md +288 -0
- data/app/pb_kits/playbook/pb_advanced_table/SubKits/TableBody.tsx +95 -0
- data/app/pb_kits/playbook/pb_advanced_table/SubKits/TableHeader.tsx +51 -0
- data/app/pb_kits/playbook/pb_advanced_table/Utilities/BrowserCheck.tsx +5 -0
- data/app/pb_kits/playbook/pb_advanced_table/Utilities/ExpansionControlHelpers.tsx +63 -0
- data/app/pb_kits/playbook/pb_advanced_table/Utilities/IconHelpers.tsx +8 -0
- data/app/pb_kits/playbook/pb_advanced_table/Utilities/types.ts +8 -0
- data/app/pb_kits/playbook/pb_advanced_table/_advanced_table.scss +98 -0
- data/app/pb_kits/playbook/pb_advanced_table/_advanced_table.tsx +245 -0
- data/app/pb_kits/playbook/pb_advanced_table/advanced_table.test.jsx +56 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_default.jsx +49 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_default.md +13 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_advanced_table_sort.jsx +57 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_description.md +1 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/_mock_data.js +278 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/example.yml +6 -0
- data/app/pb_kits/playbook/pb_advanced_table/docs/index.js +2 -0
- data/app/pb_kits/playbook/pb_advanced_table/scss_partials/_loading.scss +71 -0
- data/app/pb_kits/playbook/pb_advanced_table/scss_partials/_pseudo_states.scss +12 -0
- data/app/pb_kits/playbook/pb_flex/_flex.tsx +1 -1
- data/app/pb_kits/playbook/pb_icon/_icon.scss +6 -48
- data/app/pb_kits/playbook/pb_icon/_icon.tsx +36 -107
- data/app/pb_kits/playbook/pb_icon/docs/_icon_custom.html.erb +11 -5
- data/app/pb_kits/playbook/pb_icon/docs/_icon_custom.jsx +18 -44
- data/app/pb_kits/playbook/pb_icon/docs/_icon_custom.md +5 -10
- data/app/pb_kits/playbook/pb_icon/icon.html.erb +4 -6
- data/app/pb_kits/playbook/pb_icon/icon.rb +10 -33
- data/app/pb_kits/playbook/pb_nav/_nav_item.test.js +2 -2
- data/app/pb_kits/playbook/pb_table/_table.tsx +29 -29
- data/app/pb_kits/playbook/playbook-doc.js +2 -0
- data/app/pb_kits/playbook/utilities/globalProps.ts +1 -1
- data/dist/menu.yml +4 -1
- data/dist/playbook-rails.js +6 -6
- data/lib/playbook/version.rb +1 -1
- metadata +34 -7
@@ -0,0 +1,71 @@
|
|
1
|
+
|
2
|
+
//animation scss
|
3
|
+
@keyframes wave {
|
4
|
+
0% {
|
5
|
+
background-position: -468px 0;
|
6
|
+
}
|
7
|
+
100% {
|
8
|
+
background-position: 468px 0;
|
9
|
+
}
|
10
|
+
}
|
11
|
+
|
12
|
+
.content-loading {
|
13
|
+
pointer-events: none;
|
14
|
+
p,
|
15
|
+
.pb_body_kit_light,
|
16
|
+
.loading-toggle-icon,
|
17
|
+
.pb_caption_kit_md,
|
18
|
+
h4,
|
19
|
+
.loading-cell {
|
20
|
+
position: relative;
|
21
|
+
color: rgba($white, 0) !important;
|
22
|
+
background: rgba($white, 0) !important;
|
23
|
+
border: 0 !important;
|
24
|
+
&::after {
|
25
|
+
content: "";
|
26
|
+
position: absolute;
|
27
|
+
top: $space-xxs;
|
28
|
+
left: 0;
|
29
|
+
width: 100%;
|
30
|
+
height: calc(100% - #{$space-xxs * 2});
|
31
|
+
display: block;
|
32
|
+
border-radius: $border-rad-light;
|
33
|
+
animation-duration: 1.5s;
|
34
|
+
animation-fill-mode: forwards;
|
35
|
+
animation-iteration-count: infinite;
|
36
|
+
animation-name: wave;
|
37
|
+
animation-timing-function: linear;
|
38
|
+
background: $silver;
|
39
|
+
background-color: $silver;
|
40
|
+
background-image: linear-gradient(
|
41
|
+
to left,
|
42
|
+
$silver 0%,
|
43
|
+
lighten($silver, 1%) 50%,
|
44
|
+
lighten($silver, 1%) 60%,
|
45
|
+
$silver 80%,
|
46
|
+
$silver 100%
|
47
|
+
);
|
48
|
+
background-repeat: no-repeat;
|
49
|
+
background-size: 800px 104px;
|
50
|
+
}
|
51
|
+
}
|
52
|
+
|
53
|
+
.loading-cell {
|
54
|
+
height: $space_sm + 4;
|
55
|
+
}
|
56
|
+
|
57
|
+
.loading-toggle-icon {
|
58
|
+
width: $space_sm - 1;
|
59
|
+
height: $space_sm - 1;
|
60
|
+
margin-bottom: $space_xxs + 2;
|
61
|
+
&::after {
|
62
|
+
height: $space_sm - 1;
|
63
|
+
border-radius: $border_radius_rounded;
|
64
|
+
}
|
65
|
+
}
|
66
|
+
|
67
|
+
svg,
|
68
|
+
img {
|
69
|
+
visibility: hidden;
|
70
|
+
}
|
71
|
+
}
|
@@ -10,7 +10,7 @@ type FlexProps = {
|
|
10
10
|
data?: GenericObject,
|
11
11
|
horizontal?: "left" | "center" | "right" | "stretch" | "none",
|
12
12
|
justify?: "start" | "center" | "end" | "around" | "between" | "evenly" | "none",
|
13
|
-
htmlOptions?: {[key: string]: string | number | boolean | (() => void)},
|
13
|
+
htmlOptions?: {[key: string]: string | number | boolean | (() => void) | ((arg?: unknown) => void)},
|
14
14
|
id?: string,
|
15
15
|
inline?: boolean,
|
16
16
|
orientation?: "row" | "column",
|
@@ -1,51 +1,9 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
@keyframes pb_icon_spin {
|
9
|
-
0% {
|
10
|
-
-webkit-transform: rotate(0);
|
11
|
-
transform: rotate(0);
|
12
|
-
}
|
13
|
-
100% {
|
14
|
-
-webkit-transform: rotate(360deg);
|
15
|
-
transform: rotate(360deg);
|
16
|
-
}
|
17
|
-
};
|
18
|
-
|
19
|
-
svg {
|
20
|
-
&.pb_icon_kit {
|
21
|
-
path {
|
22
|
-
fill: currentColor !important;
|
23
|
-
}
|
24
|
-
@each $r in $rotate-list {
|
25
|
-
&.rotate_#{$r} {
|
26
|
-
transform: rotate(#{$r}deg);
|
27
|
-
}
|
28
|
-
}
|
29
|
-
@each $f, $v in $flip-list {
|
30
|
-
&.flip_#{$f} {
|
31
|
-
transform: scale($v);
|
32
|
-
}
|
33
|
-
}
|
34
|
-
&.pulse {
|
35
|
-
animation-name: pb_icon_spin;
|
36
|
-
animation-direction: normal;
|
37
|
-
animation-duration: 1s;
|
38
|
-
animation-iteration-count: infinite;
|
39
|
-
animation-timing-function: steps(8);
|
40
|
-
}
|
41
|
-
&.spin {
|
42
|
-
animation-name: pb_icon_spin;
|
43
|
-
animation-delay: 0s;
|
44
|
-
animation-direction: normal;
|
45
|
-
animation-duration: 2s;
|
46
|
-
animation-iteration-count: infinite;
|
47
|
-
animation-timing-function: linear;
|
48
|
-
}
|
1
|
+
// Rails custom icon styles
|
2
|
+
svg.pb_custom_icon {
|
3
|
+
width: 1em;
|
4
|
+
fill: currentColor;
|
5
|
+
path {
|
6
|
+
fill: currentColor;
|
49
7
|
}
|
50
8
|
}
|
51
9
|
|
@@ -1,14 +1,13 @@
|
|
1
|
-
import React
|
1
|
+
import React from 'react'
|
2
2
|
import classnames from 'classnames'
|
3
3
|
import { buildAriaProps, buildDataProps, buildHtmlProps } from '../utilities/props'
|
4
4
|
import { GlobalProps, globalProps } from '../utilities/globalProps'
|
5
5
|
import { isValidEmoji } from '../utilities/validEmojiChecker'
|
6
6
|
|
7
|
-
type
|
7
|
+
export type IconSizes = "lg"
|
8
8
|
| "xs"
|
9
9
|
| "sm"
|
10
|
-
|
11
|
-
export type IconSizes = IconSizeNames | "1x"
|
10
|
+
| "1x"
|
12
11
|
| "2x"
|
13
12
|
| "3x"
|
14
13
|
| "4x"
|
@@ -22,14 +21,13 @@ export type IconSizes = IconSizeNames | "1x"
|
|
22
21
|
|
23
22
|
type IconProps = {
|
24
23
|
aria?: {[key: string]: string},
|
25
|
-
aspectRatio?: string,
|
26
24
|
border?: string,
|
27
25
|
className?: string,
|
28
26
|
customIcon?: {[key: string] :SVGElement},
|
29
27
|
data?: {[key: string]: string},
|
30
28
|
fixedWidth?: boolean,
|
31
29
|
flip?: "horizontal" | "vertical" | "both" | "none",
|
32
|
-
icon: string
|
30
|
+
icon: string,
|
33
31
|
htmlOptions?: {[key: string]: string | number | boolean | (() => void)},
|
34
32
|
id?: string,
|
35
33
|
inverse?: boolean,
|
@@ -42,66 +40,16 @@ type IconProps = {
|
|
42
40
|
spin?: boolean,
|
43
41
|
} & GlobalProps
|
44
42
|
|
45
|
-
const iconSizeMap = {
|
46
|
-
base: 16,
|
47
|
-
xs: .75,
|
48
|
-
sm: .875,
|
49
|
-
lg: 1.25
|
50
|
-
}
|
51
|
-
|
52
|
-
const getSvgDimensions = (aspectRatio = '1:1', size: string): {width: number, height: number} | null => {
|
53
|
-
if (!size) return null
|
54
|
-
const aspect = aspectRatio.split(':')
|
55
|
-
|
56
|
-
const scale = size.toLowerCase().endsWith('x') ?
|
57
|
-
parseInt(size.replace(/\x/i, '')) :
|
58
|
-
iconSizeMap[size as IconSizeNames]
|
59
|
-
|
60
|
-
return {
|
61
|
-
width: (iconSizeMap.base * scale) * parseInt(aspect[0]),
|
62
|
-
height: (iconSizeMap.base * scale) * parseInt(aspect[1])
|
63
|
-
}
|
64
|
-
}
|
65
|
-
|
66
43
|
const flipMap = {
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
none: ''
|
72
|
-
},
|
73
|
-
svg: {
|
74
|
-
horizontal: 'flip_horizontal',
|
75
|
-
vertical: 'flip_vertical',
|
76
|
-
both: 'flip_horizontal flip_vertical',
|
77
|
-
none: ''
|
78
|
-
}
|
79
|
-
}
|
80
|
-
const pulseMap = {
|
81
|
-
fa: 'fa-pulse',
|
82
|
-
svg: 'pulse'
|
83
|
-
}
|
84
|
-
const spinMap = {
|
85
|
-
fa: 'fa-spin',
|
86
|
-
svg: 'spin'
|
87
|
-
}
|
88
|
-
const rotateMap = {
|
89
|
-
fa: {
|
90
|
-
90: 'fa-rotate-90',
|
91
|
-
180: 'fa-rotate-180',
|
92
|
-
270: 'fa-rotate-270'
|
93
|
-
},
|
94
|
-
svg: {
|
95
|
-
90: 'rotate_90',
|
96
|
-
180: 'rotate_180',
|
97
|
-
270: 'rotate_270'
|
98
|
-
}
|
44
|
+
horizontal: 'fa-flip-horizontal',
|
45
|
+
vertical: 'fa-flip-vertical',
|
46
|
+
both: 'fa-flip-horizontal fa-flip-vertical',
|
47
|
+
none: ""
|
99
48
|
}
|
100
49
|
|
101
50
|
const Icon = (props: IconProps) => {
|
102
51
|
const {
|
103
52
|
aria = {},
|
104
|
-
aspectRatio,
|
105
53
|
border = false,
|
106
54
|
className,
|
107
55
|
customIcon,
|
@@ -109,52 +57,46 @@ const Icon = (props: IconProps) => {
|
|
109
57
|
fixedWidth = true,
|
110
58
|
flip = "none",
|
111
59
|
htmlOptions = {},
|
112
|
-
icon
|
60
|
+
icon,
|
113
61
|
id,
|
114
62
|
inverse = false,
|
115
63
|
listItem = false,
|
116
64
|
pull,
|
117
65
|
pulse = false,
|
118
66
|
rotation,
|
119
|
-
size
|
67
|
+
size,
|
120
68
|
fontStyle = 'far',
|
121
69
|
spin = false,
|
122
70
|
} = props
|
123
71
|
|
124
|
-
const
|
125
|
-
|
72
|
+
const faClasses = {
|
73
|
+
'fa-border': border,
|
74
|
+
'fa-fw': fixedWidth,
|
75
|
+
'fa-inverse': inverse,
|
76
|
+
'fa-li': listItem,
|
77
|
+
'fa-pulse': pulse,
|
78
|
+
'fa-spin': spin,
|
79
|
+
[`fa-${size}`]: size,
|
80
|
+
[`fa-pull-${pull}`]: pull,
|
81
|
+
[`fa-rotate-${rotation}`]: rotation,
|
126
82
|
|
127
|
-
|
128
|
-
const svgProps = isFA ? null : {...{fill: 'currentColor'}, ...getSvgDimensions(aspectRatio, size)}
|
83
|
+
}
|
129
84
|
|
130
|
-
|
85
|
+
// Lets check and see if the icon prop is referring to a custom Power icon...
|
86
|
+
// If so, then set fa-icon to "custom"
|
87
|
+
// this ensures the JS will not do any further operations
|
88
|
+
// faClasses[`fa-${icon}`] = customIcon ? 'custom' : icon
|
89
|
+
if (!customIcon) faClasses[`fa-${icon}`] = icon
|
90
|
+
|
91
|
+
const classes = classnames(
|
92
|
+
flipMap[flip],
|
131
93
|
'pb_icon_kit',
|
132
|
-
|
94
|
+
customIcon ? '' : fontStyle,
|
95
|
+
faClasses,
|
133
96
|
globalProps(props),
|
134
97
|
className
|
135
98
|
)
|
136
99
|
|
137
|
-
const transformClasses = classnames(
|
138
|
-
flip ? flipMap[isFA ? 'fa' : 'svg'][flip] : null,
|
139
|
-
pulse ? pulseMap[isFA ? 'fa' : 'svg'] : null,
|
140
|
-
rotation ? rotateMap[isFA ? 'fa' : 'svg'][rotation] : null,
|
141
|
-
spin ? spinMap[isFA ? 'fa' : 'svg'] : null,
|
142
|
-
)
|
143
|
-
if (transformClasses) classes += ` ${transformClasses}`
|
144
|
-
|
145
|
-
if (isFA) {
|
146
|
-
const faClassList = {
|
147
|
-
'fa-border': border,
|
148
|
-
'fa-fw': (iconElement) ? false : fixedWidth,
|
149
|
-
'fa-inverse': inverse,
|
150
|
-
'fa-li': listItem,
|
151
|
-
[`fa-${size}`]: size,
|
152
|
-
[`fa-pull-${pull}`]: pull,
|
153
|
-
}
|
154
|
-
faClassList[`fa-${icon}`] = icon as string
|
155
|
-
classes += ` ${classnames(faClassList)}`
|
156
|
-
}
|
157
|
-
|
158
100
|
const classesEmoji = classnames(
|
159
101
|
'pb_icon_kit_emoji',
|
160
102
|
globalProps(props),
|
@@ -168,21 +110,20 @@ const Icon = (props: IconProps) => {
|
|
168
110
|
|
169
111
|
// Add a conditional here to show only the SVG if custom
|
170
112
|
const displaySVG = (customIcon: any) => {
|
171
|
-
if (
|
113
|
+
if (customIcon)
|
172
114
|
return (
|
173
115
|
<>
|
174
116
|
{
|
175
|
-
React.cloneElement(
|
117
|
+
React.cloneElement(customIcon, {
|
176
118
|
...dataProps,
|
177
119
|
...htmlProps,
|
178
|
-
...svgProps,
|
179
120
|
className: classes,
|
180
121
|
id,
|
181
122
|
})
|
182
123
|
}
|
183
124
|
</>
|
184
125
|
)
|
185
|
-
else if (isValidEmoji(icon
|
126
|
+
else if (isValidEmoji(icon))
|
186
127
|
return (
|
187
128
|
<>
|
188
129
|
<span
|
@@ -195,19 +136,7 @@ const Icon = (props: IconProps) => {
|
|
195
136
|
</span>
|
196
137
|
</>
|
197
138
|
)
|
198
|
-
|
199
|
-
return (
|
200
|
-
<>
|
201
|
-
<img
|
202
|
-
{...dataProps}
|
203
|
-
{...htmlProps}
|
204
|
-
{...svgProps}
|
205
|
-
className={classes}
|
206
|
-
id={id}
|
207
|
-
src={iconURL}
|
208
|
-
/>
|
209
|
-
</>
|
210
|
-
)
|
139
|
+
|
211
140
|
else
|
212
141
|
return (
|
213
142
|
<>
|
@@ -232,4 +161,4 @@ const Icon = (props: IconProps) => {
|
|
232
161
|
)
|
233
162
|
}
|
234
163
|
|
235
|
-
export default Icon
|
164
|
+
export default Icon
|
@@ -2,9 +2,15 @@
|
|
2
2
|
<div class="icon-wrapper">
|
3
3
|
|
4
4
|
<% svg_url = "https://upload.wikimedia.org/wikipedia/commons/3/3b/Wrench_font_awesome.svg" %>
|
5
|
-
<p><%= pb_rails("icon", props: {
|
6
|
-
<p><%= pb_rails("icon", props: { rotation: 90,
|
7
|
-
<p><%= pb_rails("icon", props: { spin: true,
|
8
|
-
<p><%= pb_rails("icon", props: { size: "5x",
|
9
|
-
<p><%= pb_rails("icon", props: { flip: "horizontal", size: "5x",
|
5
|
+
<p><%= pb_rails("icon", props: { custom_icon: svg_url } ) %></p>
|
6
|
+
<p><%= pb_rails("icon", props: { rotation: 90, custom_icon: svg_url, size: "2x" } ) %></p>
|
7
|
+
<p><%= pb_rails("icon", props: { spin: true, custom_icon: svg_url, size: "3x" } ) %></p>
|
8
|
+
<p><%= pb_rails("icon", props: { size: "5x", custom_icon: svg_url } ) %></p>
|
9
|
+
<p><%= pb_rails("icon", props: { flip: "horizontal", size: "5x", custom_icon: svg_url } ) %></p>
|
10
|
+
|
11
|
+
<%= pb_rails("body", props: {
|
12
|
+
text: "Custom icons are compatible with other icon props (size, rotation,
|
13
|
+
spin, flip, etc). Their SVG fill colors will be inherited from
|
14
|
+
parent element's css color properties."
|
15
|
+
} ) %>
|
10
16
|
</div>
|
@@ -1,59 +1,33 @@
|
|
1
1
|
import React from 'react'
|
2
2
|
import { Icon } from '../../'
|
3
3
|
|
4
|
+
// import Icons as config from 'power-icons'
|
4
5
|
const config = {
|
5
|
-
|
6
|
-
<svg
|
6
|
+
moon: (
|
7
|
+
<svg
|
8
|
+
ariaHidden="true"
|
9
|
+
focusable="false"
|
10
|
+
role="img"
|
11
|
+
viewBox="0 0 512 512"
|
7
12
|
xmlns="http://www.w3.org/2000/svg"
|
8
13
|
>
|
9
|
-
<
|
10
|
-
|
11
|
-
|
14
|
+
<path
|
15
|
+
d="M448 0H64C28.7 0 0 28.7 0 64v288c0 35.3 28.7 64 64 64h96v84c0 7.1 5.8 12 12 12 2.4 0 4.9-.7 7.1-2.4L304 416h144c35.3 0 64-28.7 64-64V64c0-35.3-28.7-64-64-64zm16 352c0 8.8-7.2 16-16 16H288l-12.8 9.6L208 428v-60H64c-8.8 0-16-7.2-16-16V64c0-8.8 7.2-16 16-16h384c8.8 0 16 7.2 16 16v288zM336 184h-56v-56c0-8.8-7.2-16-16-16h-16c-8.8 0-16 7.2-16 16v56h-56c-8.8 0-16 7.2-16 16v16c0 8.8 7.2 16 16 16h56v56c0 8.8 7.2 16 16 16h16c8.8 0 16-7.2 16-16v-56h56c8.8 0 16-7.2 16-16v-16c0-8.8-7.2-16-16-16z"
|
16
|
+
fill="currentColor"
|
17
|
+
/>
|
12
18
|
</svg>
|
13
19
|
),
|
14
20
|
}
|
15
21
|
|
16
22
|
const IconCustom = (props) => {
|
17
23
|
return (
|
18
|
-
<
|
19
|
-
<
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
<p>
|
26
|
-
<Icon
|
27
|
-
icon={config.icon}
|
28
|
-
rotation={90}
|
29
|
-
size="2x"
|
30
|
-
{...props}
|
31
|
-
/>
|
32
|
-
</p>
|
33
|
-
<p>
|
34
|
-
<Icon
|
35
|
-
icon={config.icon}
|
36
|
-
size="3x"
|
37
|
-
spin
|
38
|
-
{...props}
|
39
|
-
/>
|
40
|
-
</p>
|
41
|
-
<p>
|
42
|
-
<Icon
|
43
|
-
icon={config.icon}
|
44
|
-
size="5x"
|
45
|
-
{...props}
|
46
|
-
/>
|
47
|
-
</p>
|
48
|
-
<p>
|
49
|
-
<Icon
|
50
|
-
flip="horizontal"
|
51
|
-
icon={config.icon}
|
52
|
-
size="5x"
|
53
|
-
{...props}
|
54
|
-
/>
|
55
|
-
</p>
|
56
|
-
</React.Fragment>
|
24
|
+
<div>
|
25
|
+
<Icon
|
26
|
+
customIcon={config.moon}
|
27
|
+
size="7x"
|
28
|
+
{...props}
|
29
|
+
/>
|
30
|
+
</div>
|
57
31
|
)
|
58
32
|
}
|
59
33
|
|
@@ -4,21 +4,16 @@ When using custom icons it is important to introduce a "clean" SVG. In order to
|
|
4
4
|
|
5
5
|
Attributes must be React compatible e.g. <code>xmlns:xlink</code> should be <code>xmlnsXlink</code> and so on. <strong>There should be no hyphenated attributes and no semi-colons!.</strong>
|
6
6
|
|
7
|
-
Fill colors with regards to <code>g</code> or <code>path</code> nodes, e.g. <code>fill="black"</code>, should be replaced with
|
7
|
+
Fill colors with regards to <code>g</code> or <code>path</code> nodes, e.g. <code>fill="black"</code>, should be replaced with <code>currentColor</code> ala <code>fill="currentColor"</code>. Your mileage may vary depending on the complexity of your SVG.
|
8
8
|
|
9
|
-
Pay attention to your custom icon's dimensions and `viewBox` attribute. It is best to use a `viewBox="0 0 512 512"` starting point
|
9
|
+
Pay attention to your custom icon's dimensions and `viewBox` attribute. It is best to use a `viewBox="0 0 512 512"` starting point __when designing instead of trying to retrofit the viewbox afterwards__!
|
10
10
|
|
11
|
-
You must source
|
11
|
+
You must source *your own SVG into component/view* you are working on. This can easily be done in programmatic and maintainable ways.
|
12
12
|
|
13
13
|
### React
|
14
14
|
|
15
|
-
|
16
|
-
- Sending the absolute path to your SVG (e.g. `/my/path/to/icon.svg`) results in an `img` node with the `src` attribute set to the provided path:
|
17
|
-
|
18
|
-
```html
|
19
|
-
<img src="host.com/my/path/to/icon.svg" />
|
20
|
-
```
|
15
|
+
So long as you have a valid React `<SVG>` node, you can send it as the `customIcon` prop and the kit will take care of the rest.
|
21
16
|
|
22
17
|
### Rails
|
23
18
|
|
24
|
-
|
19
|
+
Some Rails applications use only webpack(er) which means using `image_url` will be successful over `image_path` in most cases especially development where Webpack Dev Server is serving assets over HTTP. Rails applications still using Asset Pipeline may use `image_path` or `image_url`. Of course, YMMV depending on any custom configurations in your Rails application.
|
@@ -1,9 +1,7 @@
|
|
1
|
-
<% if object.
|
2
|
-
<%= object.render_svg %>
|
3
|
-
<% elsif object.valid_emoji
|
4
|
-
<span class="pb_icon_kit_emoji">
|
5
|
-
<%= object.icon.html_safe %>
|
6
|
-
</span>
|
1
|
+
<% if object.custom_icon %>
|
2
|
+
<%= object.render_svg(object.custom_icon) %>
|
3
|
+
<% elsif object.valid_emoji(object.icon) %>
|
4
|
+
<span class="pb_icon_kit_emoji"><%= object.icon.html_safe %></span>
|
7
5
|
<% else %>
|
8
6
|
<%= content_tag(:i, nil,
|
9
7
|
id: object.id,
|
@@ -38,7 +38,7 @@ module Playbook
|
|
38
38
|
prop :spin, type: Playbook::Props::Boolean,
|
39
39
|
default: false
|
40
40
|
|
41
|
-
def valid_emoji
|
41
|
+
def valid_emoji(icon)
|
42
42
|
emoji_regex = /\p{Emoji}/
|
43
43
|
emoji_regex.match?(icon)
|
44
44
|
end
|
@@ -79,42 +79,19 @@ module Playbook
|
|
79
79
|
)
|
80
80
|
end
|
81
81
|
|
82
|
-
def render_svg
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
def is_svg?
|
93
|
-
(icon || custom_icon.to_s).include?(".svg")
|
82
|
+
def render_svg(path)
|
83
|
+
if File.extname(path) == ".svg"
|
84
|
+
doc = Nokogiri::XML(URI.open(path)) # rubocop:disable Security/Open
|
85
|
+
svg = doc.at_css "svg"
|
86
|
+
svg["class"] = "pb_custom_icon " + object.custom_icon_classname
|
87
|
+
raw doc
|
88
|
+
else
|
89
|
+
raise("Custom icon must be an svg. Please check your path and file type.")
|
90
|
+
end
|
94
91
|
end
|
95
92
|
|
96
93
|
private
|
97
94
|
|
98
|
-
def svg_size
|
99
|
-
size.nil? ? "1x" : size
|
100
|
-
end
|
101
|
-
|
102
|
-
def svg_dims
|
103
|
-
{ "lg" => 1.25,
|
104
|
-
"xs" => 0.75,
|
105
|
-
"sm" => 0.875,
|
106
|
-
"1x" => 1,
|
107
|
-
"2x" => 2,
|
108
|
-
"3x" => 3,
|
109
|
-
"4x" => 4,
|
110
|
-
"5x" => 5,
|
111
|
-
"6x" => 6,
|
112
|
-
"7x" => 7,
|
113
|
-
"8x" => 8,
|
114
|
-
"9x" => 9,
|
115
|
-
"10x" => 10 }
|
116
|
-
end
|
117
|
-
|
118
95
|
def border_class
|
119
96
|
border ? "fa-border" : nil
|
120
97
|
end
|
@@ -95,11 +95,11 @@ test('should not have a left border', () => {
|
|
95
95
|
test('should have a right icon', () => {
|
96
96
|
render(<NavDefault iconRight="angle-down" />)
|
97
97
|
const kit = screen.getByTestId(itemTestId)
|
98
|
-
expect(kit).toContainHTML('<i class="pb_icon_kit far
|
98
|
+
expect(kit).toContainHTML('<i class="pb_icon_kit far fa-fw fa-angle-down pb_nav_list_item_icon_right" />')
|
99
99
|
})
|
100
100
|
|
101
101
|
test('should have a left icon', () => {
|
102
102
|
render(<NavDefault iconLeft="users-class" />)
|
103
103
|
const kit = screen.getByTestId(itemTestId)
|
104
|
-
expect(kit).toContainHTML('<i class="pb_icon_kit far
|
104
|
+
expect(kit).toContainHTML('<i class="pb_icon_kit far fa-fw fa-users-class pb_nav_list_item_icon_left" />')
|
105
105
|
})
|