@@ -29,58 +29,81 @@ import { View } from '@instructure/ui-view'
2929import { ColorName } from '../ColorName'
3030import type { ColorCardProps } from './props'
3131import { allowedProps } from './props'
32- class ColorCard extends Component < ColorCardProps > {
33- static displayName = 'ColorCard'
34- static allowedProps = allowedProps
35- static defaultProps = {
36- minimal : false
37- }
3832
39- parseColor ( value : string ) {
40- // 6-digit hex: #RRGGBB
41- const hex6 = / ^ # ( [ a - f \d ] { 2 } ) ( [ a - f \d ] { 2 } ) ( [ a - f \d ] { 2 } ) $ / i. exec ( value )
42- if ( hex6 ) {
43- return {
44- hex : value . toUpperCase ( ) ,
45- rgb : `${ parseInt ( hex6 [ 1 ] , 16 ) } ,${ parseInt ( hex6 [ 2 ] , 16 ) } ,${ parseInt (
46- hex6 [ 3 ] ,
47- 16
48- ) } `
49- }
33+ type ParsedColor = {
34+ hex ?: string
35+ rgb ?: string
36+ alpha ?: string
37+ } | null
38+
39+ // Cache parsed results so theme re-renders skip the regex work.
40+ const colorCache = new Map < string , ParsedColor > ( )
41+
42+ function parseColor ( value : string ) : ParsedColor {
43+ if ( colorCache . has ( value ) ) return colorCache . get ( value ) !
44+
45+ // 6-digit hex: #RRGGBB
46+ const hex6 = / ^ # ( [ a - f \d ] { 2 } ) ( [ a - f \d ] { 2 } ) ( [ a - f \d ] { 2 } ) $ / i. exec ( value )
47+ if ( hex6 ) {
48+ const result : ParsedColor = {
49+ hex : value . toUpperCase ( ) ,
50+ rgb : `${ parseInt ( hex6 [ 1 ] , 16 ) } ,${ parseInt ( hex6 [ 2 ] , 16 ) } ,${ parseInt (
51+ hex6 [ 3 ] ,
52+ 16
53+ ) } `
54+ }
55+ colorCache . set ( value , result )
56+ return result
57+ }
58+ // 8-digit hex with alpha: #RRGGBBAA
59+ const hex8 = / ^ # ( [ a - f \d ] { 2 } ) ( [ a - f \d ] { 2 } ) ( [ a - f \d ] { 2 } ) ( [ a - f \d ] { 2 } ) $ / i. exec (
60+ value
61+ )
62+ if ( hex8 ) {
63+ const alpha = Math . round ( ( parseInt ( hex8 [ 4 ] , 16 ) / 255 ) * 100 )
64+ const result : ParsedColor = {
65+ hex : value . toUpperCase ( ) ,
66+ rgb : `${ parseInt ( hex8 [ 1 ] , 16 ) } ,${ parseInt ( hex8 [ 2 ] , 16 ) } ,${ parseInt (
67+ hex8 [ 3 ] ,
68+ 16
69+ ) } `,
70+ alpha : `${ alpha } %`
5071 }
51- // 8-digit hex with alpha: #RRGGBBAA
52- const hex8 = / ^ # ( [ a - f \d ] { 2 } ) ( [ a - f \d ] { 2 } ) ( [ a - f \d ] { 2 } ) ( [ a - f \d ] { 2 } ) $ / i. exec (
72+ colorCache . set ( value , result )
73+ return result
74+ }
75+ // rgba(r,g,b,a)
76+ const rgba =
77+ / ^ r g b a ? \( \s * ( \d + ) \s * , \s * ( \d + ) \s * , \s * ( \d + ) (?: \s * , \s * ( [ \d . ] + ) ) ? \s * \) / i. exec (
5378 value
5479 )
55- if ( hex8 ) {
56- const alpha = Math . round ( ( parseInt ( hex8 [ 4 ] , 16 ) / 255 ) * 100 )
57- return {
58- hex : value . toUpperCase ( ) ,
59- rgb : `${ parseInt ( hex8 [ 1 ] , 16 ) } ,${ parseInt ( hex8 [ 2 ] , 16 ) } ,${ parseInt (
60- hex8 [ 3 ] ,
61- 16
62- ) } `,
63- alpha : `${ alpha } %`
64- }
65- }
66- // rgba(r,g,b,a)
67- const rgba =
68- / ^ r g b a ? \( \s * ( \d + ) \s * , \s * ( \d + ) \s * , \s * ( \d + ) (?: \s * , \s * ( [ \d . ] + ) ) ? \s * \) / i. exec (
69- value
70- )
71- if ( rgba ) {
72- const alpha =
73- rgba [ 4 ] !== undefined
74- ? `${ Math . round ( parseFloat ( rgba [ 4 ] ) * 100 ) } %`
75- : undefined
76- return { rgb : `${ rgba [ 1 ] } ,${ rgba [ 2 ] } ,${ rgba [ 3 ] } ` , alpha }
80+ if ( rgba ) {
81+ const alpha =
82+ rgba [ 4 ] !== undefined
83+ ? `${ Math . round ( parseFloat ( rgba [ 4 ] ) * 100 ) } %`
84+ : undefined
85+ const result : ParsedColor = {
86+ rgb : `${ rgba [ 1 ] } ,${ rgba [ 2 ] } ,${ rgba [ 3 ] } ` ,
87+ alpha
7788 }
78- return null
89+ colorCache . set ( value , result )
90+ return result
91+ }
92+
93+ colorCache . set ( value , null )
94+ return null
95+ }
96+
97+ class ColorCard extends Component < ColorCardProps > {
98+ static displayName = 'ColorCard'
99+ static allowedProps = allowedProps
100+ static defaultProps = {
101+ minimal : false
79102 }
80103
81104 render ( ) {
82105 const { name, hex, minimal } = this . props
83- const parsed = this . parseColor ( hex )
106+ const parsed = parseColor ( hex )
84107 return (
85108 < View
86109 as = "figure"
0 commit comments