diff --git a/packages/graphic-walker/package.json b/packages/graphic-walker/package.json index 30b8b19b..0168217a 100644 --- a/packages/graphic-walker/package.json +++ b/packages/graphic-walker/package.json @@ -53,6 +53,7 @@ "postcss": "^8.3.7", "postinstall-postinstall": "^2.1.0", "re-resizable": "^6.9.8", + "react-color": "^2.19.3", "react-i18next": "^11.18.6", "react-leaflet": "^4.2.1", "react-shadow": "^20.0.0", diff --git a/packages/graphic-walker/src/components/sizeSetting.tsx b/packages/graphic-walker/src/components/sizeSetting.tsx index bf77fccf..78138605 100644 --- a/packages/graphic-walker/src/components/sizeSetting.tsx +++ b/packages/graphic-walker/src/components/sizeSetting.tsx @@ -98,6 +98,7 @@ const SizeSetting: React.FC = (props) => { className="w-4 h-4 inline-block mr-0.5 text-gray-900" /> {show && ( + <>
= (props) => { />
+ )} ); diff --git a/packages/graphic-walker/src/components/visualConfig/colorScheme.tsx b/packages/graphic-walker/src/components/visualConfig/colorScheme.tsx new file mode 100644 index 00000000..d62d7ff0 --- /dev/null +++ b/packages/graphic-walker/src/components/visualConfig/colorScheme.tsx @@ -0,0 +1,97 @@ +export const ColorSchemes = [ + { + name: 'accent', + value: ['#7fc97f', '#beaed4', '#fdc086', '#ffff99', '#386cb0', '#f0027f', '#bf5b17', '#666666'], + }, + { + name: 'category10', + value: ['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2', '#7f7f7f', '#bcbd22', '#17becf'], + }, + { + name: 'category20', + value: [ + '#1f77b4', + '#aec7e8', + '#ff7f0e', + '#ffbb78', + '#2ca02c', + '#98df8a', + '#d62728', + '#ff9896', + '#9467bd', + '#c5b0d5', + '#8c564b', + '#c49c94', + '#e377c2', + '#f7b6d2', + '#7f7f7f', + '#c7c7c7', + '#bcbd22', + '#dbdb8d', + '#17becf', + '#9edae5', + ], + }, + { + name: 'category20b', + value: [ + '#393b79', + '#5254a3', + '#6b6ecf', + '#9c9ede', + '#637939', + '#8ca252', + '#b5cf6b', + '#cedb9c', + '#8c6d31', + '#bd9e39', + '#e7ba52', + '#e7cb94', + '#843c39', + '#ad494a', + '#d6616b', + '#e7969c', + '#7b4173', + '#a55194', + '#ce6dbd', + '#de9ed6', + ], + }, + { + name: 'category20c', + value: [ + '#3182bd', + '#6baed6', + '#9ecae1', + '#c6dbef', + '#e6550d', + '#fd8d3c', + '#fdae6b', + '#fdd0a2', + '#31a354', + '#74c476', + '#a1d99b', + '#c7e9c0', + '#756bb1', + '#9e9ac8', + '#bcbddc', + '#dadaeb', + '#636363', + '#969696', + '#bdbdbd', + '#d9d9d9', + ], + }, + { + name: 'dark2', + value: ['#1b9e77', '#d95f02', '#7570b3', '#e7298a', '#66a61e', '#e6ab02', '#a6761d', '#666666'], + }, + { + name: 'paired', + value: ['#a6cee3', '#1f78b4', '#b2df8a', '#33a02c', '#fb9a99', '#e31a1c', '#fdbf6f', '#ff7f00', '#cab2d6', '#6a3d9a', '#ffff99', '#b15928'], + }, + { + name: 'pastel1', + value: ['#fbb4ae', '#b3cde3', '#ccebc5', '#decbe4', '#fed9a6', '#ffffcc', '#e5d8bd', '#fddaec', '#f2f2f2'], + }, +]; diff --git a/packages/graphic-walker/src/components/visualConfig/index.tsx b/packages/graphic-walker/src/components/visualConfig/index.tsx index 62435e14..21eff4e5 100644 --- a/packages/graphic-walker/src/components/visualConfig/index.tsx +++ b/packages/graphic-walker/src/components/visualConfig/index.tsx @@ -1,8 +1,8 @@ import { observer } from 'mobx-react-lite'; -import React, { useEffect, useState } from 'react'; +import React, { useEffect, useState, useRef } from 'react'; import { useGlobalStore } from '../../store'; -import { NonPositionChannelConfigList,PositionChannelConfigList } from '../../config'; - +import { NonPositionChannelConfigList, PositionChannelConfigList } from '../../config'; +import { TwitterPicker, BlockPicker, SketchPicker } from 'react-color'; import Modal from '../modal'; import { IVisualConfig } from '../../interfaces'; import PrimaryButton from '../button/primary'; @@ -10,19 +10,19 @@ import DefaultButton from '../button/default'; import { useTranslation } from 'react-i18next'; import Toggle from '../toggle'; import { runInAction, toJS } from 'mobx'; +import { ColorSchemes } from './colorScheme'; const VisualConfigPanel: React.FC = (props) => { const { commonStore, vizStore } = useGlobalStore(); const { showVisualConfigPanel } = commonStore; const { visualConfig } = vizStore; - const { coordSystem, geoms: [markType] } = visualConfig; + const { + coordSystem, + geoms: [markType], + } = visualConfig; const isChoropleth = coordSystem === 'geographic' && markType === 'choropleth'; const { t } = useTranslation(); - const formatConfigList: (keyof IVisualConfig['format'])[] = [ - 'numberFormat', - 'timeFormat', - 'normalizedNumberFormat', - ]; + const formatConfigList: (keyof IVisualConfig['format'])[] = ['numberFormat', 'timeFormat', 'normalizedNumberFormat']; const [format, setFormat] = useState({ numberFormat: visualConfig.format.numberFormat, timeFormat: visualConfig.format.timeFormat, @@ -39,11 +39,28 @@ const VisualConfigPanel: React.FC = (props) => { const [zeroScale, setZeroScale] = useState(visualConfig.zeroScale); const [scaleIncludeUnmatchedChoropleth, setScaleIncludeUnmatchedChoropleth] = useState(visualConfig.scaleIncludeUnmatchedChoropleth ?? false); const [background, setBackground] = useState(visualConfig.background); + const [defaultColor, setDefaultColor] = useState({ r: 91, g: 143, b: 249, a: 1 }); + const [displayColorPicker, setDisplayColorPicker] = useState(false); + const [displaySchemePicker, setDisplaySchemePicker] = useState(false); + const selectColor = useRef('rgb(91, 143, 249)'); + + const getRGBA = (rgba) => { + console.log(rgba) + let arr = rgba.match(/\d+/g); + console.log("arr",arr) + return { + r: arr[0], + g: arr[1], + b: arr[2], + a: arr[3] + } + }; useEffect(() => { setZeroScale(visualConfig.zeroScale); setBackground(visualConfig.background); setResolve(toJS(visualConfig.resolve)); + setDefaultColor(getRGBA(visualConfig.primaryColor)) setScaleIncludeUnmatchedChoropleth(visualConfig.scaleIncludeUnmatchedChoropleth ?? false); setFormat({ numberFormat: visualConfig.format.numberFormat, @@ -59,124 +76,186 @@ const VisualConfigPanel: React.FC = (props) => { commonStore.setShowVisualConfigPanel(false); }} > -
-

{t('config.format')}

-

- {t(`config.formatGuidesDocs`)}:{' '} - - {t(`config.readHere`)} - -

- {formatConfigList.map((fc) => ( -
- +
{ + setDisplayColorPicker(false); + }} + > +
+

Scheme

+
+

Primary Color

+
{ + e.stopPropagation(); + e.preventDefault(); + }} + > +
{ + e.stopPropagation(); + e.preventDefault(); + setDisplayColorPicker(true); + }} + >
+
+ {displayColorPicker && ( + { + console.log(color.hex); + console.log('event', event); + setDefaultColor(color.rgb); + }} + /> + )} +
+
+
+ + {/* {ColorSchemes.map((scheme) => { + return ( +
+
{scheme.name}
+ {scheme.value.map((c, index) => { + return
; + })} +
+ ); + })} */} +
+
+

{t('config.format')}

+

+ {t(`config.formatGuidesDocs`)}:{' '} + + {t(`config.readHere`)} + +

+ {formatConfigList.map((fc) => ( +
+ +
+ { + setFormat((f) => ({ + ...f, + [fc]: e.target.value, + })); + }} + /> +
+
+ ))} +

{t('config.background')}

+
+
{ - setFormat((f) => ({ - ...f, - [fc]: e.target.value, - })); + setBackground(e.target.value); }} />
- ))} -

{t('config.background')}

-
- -
- { - setBackground(e.target.value); +

{t('config.independence')}

+
+
+ {PositionChannelConfigList.map((pc) => ( + { + setResolve((r) => ({ + ...r, + [pc]: e, + })); + }} + /> + ))} + {NonPositionChannelConfigList.map((npc) => ( + { + setResolve((r) => ({ + ...r, + [npc]: e, + })); + }} + /> + ))} +
+
+

{t('config.zeroScale')}

+
+ { + setZeroScale(en); }} />
-
-

{t('config.independence')}

-
-
- {PositionChannelConfigList.map((pc) => ( + {isChoropleth && ( +
{ - setResolve((r) => ({ - ...r, - [pc]: e, - })); + label="include unmatched choropleth in scale" + enabled={scaleIncludeUnmatchedChoropleth} + onChange={(en) => { + setScaleIncludeUnmatchedChoropleth(en); }} /> - ))} - {NonPositionChannelConfigList.map((npc) => ( - { - setResolve((r) => ({ - ...r, - [npc]: e, - })); - }} - /> - ))} -
-
-

{t('config.zeroScale')}

-
- { - setZeroScale(en); - }} - /> -
- {isChoropleth && ( -
- { - setScaleIncludeUnmatchedChoropleth(en); +
+ )} +
+ { + runInAction(() => { + vizStore.setVisualConfig('format', format); + vizStore.setVisualConfig('zeroScale', zeroScale); + vizStore.setVisualConfig('scaleIncludeUnmatchedChoropleth', scaleIncludeUnmatchedChoropleth); + vizStore.setVisualConfig('background', background); + vizStore.setVisualConfig('resolve', resolve); + vizStore.setVisualConfig('primaryColor',`rgba(${defaultColor.r},${defaultColor.g},${defaultColor.b},${defaultColor.a})`); + commonStore.setShowVisualConfigPanel(false); + + }); }} /> -
- )} -
- { - runInAction(() => { - vizStore.setVisualConfig('format', format); - vizStore.setVisualConfig('zeroScale', zeroScale); - vizStore.setVisualConfig('scaleIncludeUnmatchedChoropleth', scaleIncludeUnmatchedChoropleth); - vizStore.setVisualConfig('background', background); - vizStore.setVisualConfig('resolve', resolve); + { commonStore.setShowVisualConfigPanel(false); - }); - }} - /> - { - commonStore.setShowVisualConfigPanel(false); - }} - /> + }} + /> +
diff --git a/packages/graphic-walker/src/interfaces.ts b/packages/graphic-walker/src/interfaces.ts index 7bd4cbd4..eed9e0c8 100644 --- a/packages/graphic-walker/src/interfaces.ts +++ b/packages/graphic-walker/src/interfaces.ts @@ -238,6 +238,7 @@ export interface IVisualConfig { timeFormat?: string; normalizedNumberFormat?: string; }; + primaryColor?:string; resolve: { x?: boolean; y?: boolean; diff --git a/packages/graphic-walker/src/renderer/specRenderer.tsx b/packages/graphic-walker/src/renderer/specRenderer.tsx index b0313c96..18b67774 100644 --- a/packages/graphic-walker/src/renderer/specRenderer.tsx +++ b/packages/graphic-walker/src/renderer/specRenderer.tsx @@ -8,7 +8,7 @@ import ReactVega, { IReactVegaHandler } from '../vis/react-vega'; import { DeepReadonly, DraggableFieldState, IDarkMode, IRow, IThemeKey, IVisualConfig, VegaGlobalConfig, IComputationFunction } from '../interfaces'; import LoadingLayer from '../components/loadingLayer'; import { useCurrentMediaTheme } from '../utils/media'; -import { builtInThemes } from '../vis/theme'; +import { builtInThemes, usePrimaryColor} from '../vis/theme'; interface SpecRendererProps { name?: string; @@ -51,16 +51,19 @@ const SpecRenderer = forwardRef(function ( () => columns.slice(0, -1).filter((f) => f.analyticType === 'dimension'), [columns] ); - + + const defaultColor = visualConfig.primaryColor; + const isPivotTable = geoms[0] === 'table'; const hasFacet = rowLeftFacetFields.length > 0 || colLeftFacetFields.length > 0; const enableResize = size.mode === 'fixed' && !hasFacet && Boolean(onChartResize); const mediaTheme = useCurrentMediaTheme(dark); - const themeConfig = builtInThemes[themeKey ?? 'vega']?.[mediaTheme]; + const themeConfig = defaultColor? usePrimaryColor(defaultColor)[mediaTheme]:builtInThemes[themeKey ?? 'vega']?.[mediaTheme]; const vegaConfig = useMemo(() => { + console.log(themeConfig) const config: VegaGlobalConfig = { ...themeConfig, background: mediaTheme === 'dark' ? '#18181f' : '#ffffff', diff --git a/packages/graphic-walker/src/store/visualSpecStore.ts b/packages/graphic-walker/src/store/visualSpecStore.ts index c0ad4fdf..ed1a97f8 100644 --- a/packages/graphic-walker/src/store/visualSpecStore.ts +++ b/packages/graphic-walker/src/store/visualSpecStore.ts @@ -391,6 +391,7 @@ export class VizSpecStore { case configKey === 'background': case configKey === 'resolve': case configKey === 'limit': + case configKey === 'primaryColor': case configKey === 'stack': { return (config[configKey] = value); } diff --git a/packages/graphic-walker/src/utils/save.ts b/packages/graphic-walker/src/utils/save.ts index dda6a535..a112036a 100644 --- a/packages/graphic-walker/src/utils/save.ts +++ b/packages/graphic-walker/src/utils/save.ts @@ -44,6 +44,7 @@ export function initVisualConfig(): IVisualConfig { interactiveScale: false, sorted: 'none', zeroScale: true, + primaryColor: 'rgba(91, 143, 249,1)', scaleIncludeUnmatchedChoropleth: false, background: undefined, size: { diff --git a/packages/graphic-walker/src/vis/theme.ts b/packages/graphic-walker/src/vis/theme.ts index 2269e4cd..c05b00ec 100644 --- a/packages/graphic-walker/src/vis/theme.ts +++ b/packages/graphic-walker/src/vis/theme.ts @@ -20,6 +20,7 @@ const DARK_COMMON_DESIGN = { stroke: '#666' } } + export const VegaTheme = { light: { background: "transparent", @@ -134,3 +135,96 @@ export const builtInThemes: { [themeKey: string]: { light: any; dark: any; } } = vega: VegaTheme, g2: AntVTheme, }; + +export const usePrimaryColor = (defaultColor:string) => { + return { + light: { + area: { fill: defaultColor }, + bar: { fill: defaultColor }, + circle: { fill: defaultColor }, + line: { stroke: defaultColor }, + point: { stroke: defaultColor }, + rect: { fill: defaultColor }, + tick: { stroke: defaultColor }, + boxplot: { fill: defaultColor }, + errorbar: { stroke: defaultColor }, + errorband: { fill: defaultColor }, + arc: { fill: defaultColor }, + background: "transparent", + range: { + category: [ + "#5B8FF9", + "#61DDAA", + "#65789B", + "#F6BD16", + "#7262FD", + "#78D3F8", + "#9661BC", + "#F6903D", + "#008685", + "#F08BB4", + ], + diverging: ["#7b3294", "#c2a5cf", "#f7f7f7", "#a6dba0", "#008837"], + heatmap: ["#000000", "#7b3294", "#c2a5cf", "#f7f7f7", "#a6dba0", "#008837"], + ramp: [ + "#EBCCFF", + "#CCB0FF", + "#AE95FF", + "#907BFF", + "#7262FD", + "#5349E0", + "#2F32C3", + "#001BA7", + "#00068C" + ], + }, + scale: { + continuous: { range: ["#f7fbff", "#08306b"] }, + }, + }, + dark: { + ...DARK_COMMON_DESIGN, + area: { fill: defaultColor }, + bar: { fill: defaultColor }, + circle: { fill: defaultColor }, + line: { stroke: defaultColor }, + point: { stroke: defaultColor }, + rect: { fill: defaultColor }, + tick: { stroke: defaultColor }, + boxplot: { fill: defaultColor }, + errorbar: { stroke: defaultColor }, + errorband: { fill: defaultColor }, + arc: { fill: defaultColor }, + range: { + category: [ + "#5B8FF9", + "#61DDAA", + "#65789B", + "#F6BD16", + "#7262FD", + "#78D3F8", + "#9661BC", + "#F6903D", + "#008685", + "#F08BB4", + ], + diverging: ["#7b3294", "#c2a5cf", "#f7f7f7", "#a6dba0", "#008837"], + heatmap: ["#000000", "#7b3294", "#c2a5cf", "#f7f7f7", "#a6dba0", "#008837"], + ramp: [ + "#EBCCFF", + "#CCB0FF", + "#AE95FF", + "#907BFF", + "#7262FD", + "#5349E0", + "#2F32C3", + "#001BA7", + "#00068C" + ], + }, + scale: { + continuous: { range: ["#f7fbff", "#08306b"] }, + }, + }, + } +} \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index a3a914e4..30215990 100644 --- a/yarn.lock +++ b/yarn.lock @@ -513,6 +513,11 @@ resolved "https://registry.yarnpkg.com/@heroicons/react/-/react-2.0.16.tgz#562883c19ba2690c83380b42a9a5cce39dcbdb4a" integrity sha512-x89rFxH3SRdYaA+JCXwfe+RkE1SFTo9GcOkZettHer71Y3T7V+ogKmfw5CjTazgS3d0ClJ7p1NA+SP7VQLQcLw== +"@icons/material@^0.2.4": + version "0.2.4" + resolved "https://registry.npmmirror.com/@icons/material/-/material-0.2.4.tgz#e90c9f71768b3736e76d7dd6783fc6c2afa88bc8" + integrity sha512-QPcGmICAPbGLGb6F/yNf/KzKqvFx8z5qx3D1yFqVAjoFmXK35EgyW+cJ57Te3CNsmzblwtzakLGFqHPqrfb4Tw== + "@jridgewell/gen-mapping@^0.1.0": version "0.1.1" resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz#e5d2e450306a9491e3bd77e323e38d7aff315996" @@ -1748,7 +1753,12 @@ lilconfig@^2.0.5, lilconfig@^2.0.6: resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.0.6.tgz#32a384558bd58af3d4c6e077dd1ad1d397bc69d4" integrity sha512-9JROoBW7pobfsx+Sq2JsASvCo6Pfo6WWoUW79HuB1BCoBXD4PLWJPqDF6fNj67pqBYTbAHkE57M1kS/+L1neOg== -lodash@^4.17.11: +lodash-es@^4.17.15: + version "4.17.21" + resolved "https://registry.npmmirror.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee" + integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw== + +lodash@^4.0.1, lodash@^4.17.11, lodash@^4.17.15: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -1788,6 +1798,11 @@ magic-string@^0.27.0: dependencies: "@jridgewell/sourcemap-codec" "^1.4.13" +material-colors@^1.2.1: + version "1.2.6" + resolved "https://registry.npmmirror.com/material-colors/-/material-colors-1.2.6.tgz#6d1958871126992ceecc72f4bcc4d8f010865f46" + integrity sha512-6qE4B9deFBIa9YSpOc9O0Sgc43zTeVYbgDT5veRKSlB2+ZuHNoVVxA1L/ckMUayV9Ay9y7Z/SZCLcGteW9i7bg== + mdn-data@2.0.14: version "2.0.14" resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.14.tgz#7113fc4281917d63ce29b43446f701e68c25ba50" @@ -1989,7 +2004,7 @@ postinstall-postinstall@^2.1.0: resolved "https://registry.yarnpkg.com/postinstall-postinstall/-/postinstall-postinstall-2.1.0.tgz#4f7f77441ef539d1512c40bd04c71b06a4704ca3" integrity sha512-7hQX6ZlZXIoRiWNrbMQaLzUUfH+sSx39u8EJ9HYuDc1kLo9IXKWjM5RSquZN1ad5GnH8CGFM78fsAAQi3OKEEQ== -prop-types@^15.7.2: +prop-types@^15.5.10, prop-types@^15.7.2: version "15.8.1" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== @@ -2018,6 +2033,19 @@ re-resizable@^6.9.8: resolved "https://registry.yarnpkg.com/re-resizable/-/re-resizable-6.9.9.tgz#99e8b31c67a62115dc9c5394b7e55892265be216" integrity sha512-l+MBlKZffv/SicxDySKEEh42hR6m5bAHfNu3Tvxks2c4Ah+ldnWjfnVRwxo/nxF27SsUsxDS0raAzFuJNKABXA== +react-color@^2.19.3: + version "2.19.3" + resolved "https://registry.npmmirror.com/react-color/-/react-color-2.19.3.tgz#ec6c6b4568312a3c6a18420ab0472e146aa5683d" + integrity sha512-LEeGE/ZzNLIsFWa1TMe8y5VYqr7bibneWmvJwm1pCn/eNmrabWDh659JSPn9BuaMpEfU83WTOJfnCcjDZwNQTA== + dependencies: + "@icons/material" "^0.2.4" + lodash "^4.17.15" + lodash-es "^4.17.15" + material-colors "^1.2.1" + prop-types "^15.5.10" + reactcss "^1.2.0" + tinycolor2 "^1.4.1" + react-dom@^17.x: version "17.0.2" resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-17.0.2.tgz#ecffb6845e3ad8dbfcdc498f0d0a939736502c23" @@ -2110,6 +2138,13 @@ react@^17.x: loose-envify "^1.1.0" object-assign "^4.1.1" +reactcss@^1.2.0: + version "1.2.3" + resolved "https://registry.npmmirror.com/reactcss/-/reactcss-1.2.3.tgz#c00013875e557b1cf0dfd9a368a1c3dab3b548dd" + integrity sha512-KiwVUcFu1RErkI97ywr8nvx8dNOpT03rbnma0SSalTYjkrPYaEajR4a/MRt6DZ46K6arDRbWMNHF+xH7G7n/8A== + dependencies: + lodash "^4.0.1" + read-cache@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/read-cache/-/read-cache-1.0.0.tgz#e664ef31161166c9751cdbe8dbcf86b5fb58f774" @@ -2389,6 +2424,11 @@ tiny-invariant@^1.0.6: resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.3.1.tgz#8560808c916ef02ecfd55e66090df23a4b7aa642" integrity sha512-AD5ih2NlSssTCwsMznbvwMZpJ1cbhkGd2uueNxzv2jDlEeZdU04JQfRnggJQ8DrcVBGjAsCKwFBbDlVNtEMlzw== +tinycolor2@^1.4.1: + version "1.6.0" + resolved "https://registry.npmmirror.com/tinycolor2/-/tinycolor2-1.6.0.tgz#f98007460169b0263b97072c5ae92484ce02d09e" + integrity sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw== + to-fast-properties@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e"