diff --git a/samples/sampler/.storybook/main.js b/samples/sampler/.storybook/main.js
index fc4e5a9732..fdc7360a06 100644
--- a/samples/sampler/.storybook/main.js
+++ b/samples/sampler/.storybook/main.js
@@ -17,7 +17,8 @@ module.exports = {
'@enact/storybook-utils/addons/actions',
'@enact/storybook-utils/addons/controls',
'@enact/storybook-utils/addons/docs',
- '@enact/storybook-utils/addons/toolbars'
+ '@enact/storybook-utils/addons/toolbars',
+ '../colors-toolbar/manager.js'
],
webpackFinal: async (config, {configType}) => {
return webpack(config, configType, __dirname);
diff --git a/samples/sampler/.storybook/preview.js b/samples/sampler/.storybook/preview.js
index 8dca7e3ef4..0e6431bff0 100644
--- a/samples/sampler/.storybook/preview.js
+++ b/samples/sampler/.storybook/preview.js
@@ -7,6 +7,28 @@ import {themes} from '@storybook/theming';
import ThemeEnvironment from '../src/ThemeEnvironment';
+// custom decorator imports
+import {addDecorator} from '@storybook/react';
+import {platform} from '@enact/webos/platform';
+
+import {CustomStoryDecorator} from '../colors-toolbar/CustomStoryDecorator';
+
+// if running in webos environment, render a list of color pickers in every story
+export const GlobalDecorator = (Story) => {
+ if (platform.tv) {
+ return (
+
+
+
+
+ )
+ } else {
+ return ;
+ }
+};
+
+addDecorator(GlobalDecorator);
+
// NOTE: Locales taken from strawman. Might need to add more in the future.
const locales = {
'local': '',
@@ -96,7 +118,13 @@ export const globalTypes = {
'debug aria': getBooleanType('debug aria'),
'debug layout': getBooleanType('debug layout'),
'debug spotlight': getBooleanType('debug spotlight'),
- 'debug sprites': getBooleanType('debug sprites')
+ 'debug sprites': getBooleanType('debug sprites'),
+ // custom theme globalTypes
+ 'componentBackgroundColor': 'string',
+ 'focusBackgroundColor': 'string',
+ 'popupBackgroundColor': 'string',
+ 'subtitleTextColor': 'string',
+ 'textColor': 'string'
};
export const decorators = [ThemeEnvironment];
diff --git a/samples/sampler/colors-toolbar/ColorPicker.js b/samples/sampler/colors-toolbar/ColorPicker.js
new file mode 100644
index 0000000000..be51f0bb95
--- /dev/null
+++ b/samples/sampler/colors-toolbar/ColorPicker.js
@@ -0,0 +1,52 @@
+import PropTypes from 'prop-types';
+import React, {useCallback} from 'react'; // eslint-disable-line
+import {useGlobals} from '@storybook/api';
+
+import {
+ BACKGROUNDCOLOR_ADDON_ID,
+ BACKGROUNDCOLOR_DEFAULT_VALUE,
+ FOCUSBGCOLOR_ADDON_ID,
+ FOCUSBGCOLOR_DEFAULT_VALUE,
+ POPUPBGCOLOR_ADDON_ID,
+ POPUPBGCOLOR_DEFAULT_VALUE,
+ SUBTEXTCOLOR_DEFAULT_VALUE,
+ TEXT_ADDON_ID,
+ TEXT_DEFAULT_VALUE
+} from './constants';
+
+const ColorPicker = ({colorPickerType}) => {
+ const [globals, updateGlobals] = useGlobals();
+
+ const getDefaultColor = () => {
+ switch (colorPickerType) {
+ case BACKGROUNDCOLOR_ADDON_ID:
+ return BACKGROUNDCOLOR_DEFAULT_VALUE;
+ case FOCUSBGCOLOR_ADDON_ID:
+ return FOCUSBGCOLOR_DEFAULT_VALUE;
+ case POPUPBGCOLOR_ADDON_ID:
+ return POPUPBGCOLOR_DEFAULT_VALUE;
+ case TEXT_ADDON_ID:
+ return TEXT_DEFAULT_VALUE;
+ default:
+ return SUBTEXTCOLOR_DEFAULT_VALUE;
+ }
+ };
+
+ const handleColorChange = useCallback((ev) => {
+ updateGlobals({[colorPickerType]: ev.target.value});
+ }, [colorPickerType, updateGlobals]);
+
+ return (
+
+ );
+};
+
+ColorPicker.propTypes = {
+ colorPickerType: PropTypes.string
+};
+
+export default ColorPicker;
diff --git a/samples/sampler/colors-toolbar/CustomStoryDecorator.js b/samples/sampler/colors-toolbar/CustomStoryDecorator.js
new file mode 100644
index 0000000000..1caab84baf
--- /dev/null
+++ b/samples/sampler/colors-toolbar/CustomStoryDecorator.js
@@ -0,0 +1,137 @@
+// this component has been added as an alternative of built-in HTML color picker which does not work in webos environment
+import Button from '@enact/sandstone/Button';
+import {ColorPicker as SandstoneColorPicker} from '@enact/sandstone/ColorPicker';
+import Scroller from '@enact/sandstone/Scroller';
+import LS2Request from '@enact/webos/LS2Request';
+import {useCallback, useContext} from 'react';
+
+import {AppContext} from './constants';
+import {generateStylesheet} from '../utils/generateStylesheet';
+
+import css from './CustomStoryDecorator.module.less';
+
+const request = new LS2Request();
+
+export const CustomStoryDecorator = () => {
+ const {context, setContext} = useContext(AppContext);
+ const {componentBackgroundColor, focusBackgroundColor, popupBackgroundColor, subtitleTextColor, textColor} = context;
+
+ const onColorChange = useCallback((color, newColor) => {
+ // a copy of the context object is created
+ const newContext = Object.assign({}, context);
+ // update the color value on the newly created object with what gets received from `event` (handleBackgroundColor, handleFocusBgColor...)
+ newContext[color] = newColor;
+ // generate the new stylesheet based on the updated color
+ newContext.colors = generateStylesheet(
+ newContext.componentBackgroundColor,
+ newContext.focusBackgroundColor,
+ newContext.popupBackgroundColor,
+ newContext.subtitleTextColor,
+ newContext.textColor
+ );
+ setContext(newContext);
+
+ request.send({
+ service: 'luna://com.webos.service.settings/',
+ method: 'setSystemSettings',
+ parameters: {
+ category: 'customUi',
+ settings: {
+ theme: JSON.stringify(newContext)
+ }
+ },
+ onSuccess: () => {
+ console.log('setSystemSettings onSuccess'); // eslint-disable-line no-console
+ }
+ });
+ }, [context, setContext]);
+
+ const handleComponentBgColor = useCallback((ev) => {
+ onColorChange('componentBackgroundColor', ev);
+ }, [onColorChange]);
+ const handleFocusBgColor = useCallback((ev) => {
+ onColorChange('focusBackgroundColor', ev);
+ }, [onColorChange]);
+ const handlePopupBgColor = useCallback((ev) => {
+ onColorChange('popupBackgroundColor', ev);
+ }, [onColorChange]);
+ const handleTextColor = useCallback((ev) => {
+ onColorChange('textColor', ev);
+ }, [onColorChange]);
+ const handleSubTextColor = useCallback((ev) => {
+ onColorChange('subtitleTextColor', ev);
+ }, [onColorChange]);
+
+ const handleResetButton = useCallback(() => {
+ // a copy of the context object is created
+ const newContext = Object.assign({}, context);
+ // generate the new stylesheet with default sandstone colors
+ newContext.colors = generateStylesheet(
+ newContext.componentBackgroundColor,
+ newContext.focusBackgroundColor,
+ newContext.popupBackgroundColor,
+ newContext.subtitleTextColor,
+ newContext.textColor
+ );
+ setContext(newContext);
+
+ request.send({
+ service: 'luna://com.webos.service.settings/',
+ method: 'setSystemSettings',
+ parameters: {
+ category: 'customUi',
+ settings: {
+ theme: JSON.stringify(newContext)
+ }
+ },
+ onSuccess: () => {
+ console.log('setSystemSettings onSuccess'); // eslint-disable-line no-console
+ }
+ });
+ }, []); // eslint-disable-line
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
diff --git a/samples/sampler/colors-toolbar/CustomStoryDecorator.module.less b/samples/sampler/colors-toolbar/CustomStoryDecorator.module.less
new file mode 100644
index 0000000000..37f86185b8
--- /dev/null
+++ b/samples/sampler/colors-toolbar/CustomStoryDecorator.module.less
@@ -0,0 +1,61 @@
+// CustomStoryDecorator styles
+
+@import '~@enact/sandstone/styles/mixins.less';
+
+// CSS variables needed to override generated custom colors
+// Note: These variables need to be updated when corresponding value from sandstone/styles/colors.less is changed
+@sand-text-color: #e6e6e6;
+@sand-focus-bg-color-rgb: 230, 230, 230;
+@sand-overlay-bg-color-rgb: 87, 94, 102;
+@sand-text-color-rgb: 230, 230, 230;
+@sand-progress-color-rgb: 230, 230, 230;
+@sand-component-bg-color: #7d848c;
+@sand-component-text-color-rgb: 230, 230, 230;
+
+.colorPickersBlock {
+ width: 30%;
+ height: 65%;
+ position: absolute;
+ right: 51px;
+ bottom: 51px;
+ background: #2e3239;
+ border-radius: 30px;
+ padding: 12px;
+}
+
+.colorPicker {
+ color: @sand-text-color;
+
+ .focus({
+ --sand-focus-bg-color-rgb: @sand-focus-bg-color-rgb;
+ })
+}
+
+.colorPopup {
+ --sand-overlay-bg-color-rgb: @sand-overlay-bg-color-rgb;
+ --sand-text-color-rgb: @sand-text-color-rgb;
+}
+
+.colorPickerSliders {
+ .colorSlider {
+ --sand-focus-bg-color-rgb: @sand-focus-bg-color-rgb;
+ }
+}
+
+.scrollerColors {
+ --sand-progress-color-rgb: @sand-progress-color-rgb;
+}
+
+.resetButtonBlock {
+ border-top: 3px solid #e6e6e6;
+ padding-top: 9px;
+}
+
+.resetButton {
+ --sand-component-bg-color: @sand-component-bg-color;
+ --sand-component-text-color-rgb: @sand-component-text-color-rgb;
+
+ .focus({
+ --sand-focus-bg-color-rgb: @sand-focus-bg-color-rgb;
+ })
+}
diff --git a/samples/sampler/colors-toolbar/ToolbarButton.js b/samples/sampler/colors-toolbar/ToolbarButton.js
new file mode 100644
index 0000000000..1230c41d43
--- /dev/null
+++ b/samples/sampler/colors-toolbar/ToolbarButton.js
@@ -0,0 +1,38 @@
+import {IconButton, Icons, TooltipLinkList, WithTooltip} from '@storybook/components';
+import PropTypes from 'prop-types';
+import React from 'react';
+
+import ColorPicker from './ColorPicker';
+
+const ToolbarButton = React.memo(({active = true, buttonName, colorPickerType, tooltipName}) => {
+ const tooltipLink = {
+ center: ,
+ id: colorPickerType,
+ key: colorPickerType,
+ left: {tooltipName || colorPickerType},
+ title: true
+ };
+
+ const tooltip = ;
+
+ return (
+
+
+ {buttonName || colorPickerType}
+
+
+ );
+});
+
+ToolbarButton.prototypes = {
+ active: PropTypes.boolean,
+ buttonName: PropTypes.string,
+ colorPickerType: PropTypes.string.isRequired,
+ tooltipName: PropTypes.string
+};
+
+export default ToolbarButton;
diff --git a/samples/sampler/colors-toolbar/constants.js b/samples/sampler/colors-toolbar/constants.js
new file mode 100644
index 0000000000..7de2020d6e
--- /dev/null
+++ b/samples/sampler/colors-toolbar/constants.js
@@ -0,0 +1,39 @@
+import {createContext} from 'react';
+
+// Object containing the default CSS values of Sandstone used for generating custom theme
+// NOTE: These values need to be updated when corresponding value from sandstone/styles/colors.less is changed
+export const defaultSandstoneColors = {
+ componentBackgroundColor: '#7d848c', // equivalent of @sand-component-bg-color - styles/colors.less
+ focusBackgroundColor: '#e6e6e6', // equivalent of @sand-focus-bg-color-rgb - styles/colors.less
+ popupBackgroundColor: '#575e66', // equivalent of @sand-overlay-bg-color-rgb - styles/colors.less
+ subtitleTextColor: '#abaeb3', // equivalent of @sand-text-sub-color - styles/colors.less
+ textColor: '#e6e6e6' // equivalent of @sand-text-color-rgb - styles/colors.less
+};
+
+export const customColorsContext = {
+ activeTheme: 'defaultTheme',
+ componentBackgroundColor: defaultSandstoneColors.componentBackgroundColor,
+ focusBackgroundColor: defaultSandstoneColors.focusBackgroundColor,
+ popupBackgroundColor: defaultSandstoneColors.popupBackgroundColor,
+ subtitleTextColor: defaultSandstoneColors.subtitleTextColor,
+ textColor: defaultSandstoneColors.textColor
+};
+
+export const AppContext = createContext(null);
+
+export const BACKGROUNDCOLOR_ADDON_ID = "componentBackgroundColor";
+export const BACKGROUNDCOLOR_DEFAULT_VALUE = defaultSandstoneColors.componentBackgroundColor;
+
+export const FOCUSBGCOLOR_ADDON_ID = "focusBackgroundColor";
+export const FOCUSBGCOLOR_DEFAULT_VALUE = defaultSandstoneColors.focusBackgroundColor;
+
+export const POPUPBGCOLOR_ADDON_ID = "popupBackgroundColor";
+export const POPUPBGCOLOR_DEFAULT_VALUE = defaultSandstoneColors.popupBackgroundColor;
+
+export const SUBTEXTCOLOR_ADDON_ID = "subtitleTextColor";
+export const SUBTEXTCOLOR_DEFAULT_VALUE = defaultSandstoneColors.subtitleTextColor;
+
+export const TEXT_ADDON_ID = "textColor";
+export const TEXT_DEFAULT_VALUE = defaultSandstoneColors.textColor;
+
+export const TOOLBAR_ADDON_ID = "toolbar-colors";
diff --git a/samples/sampler/colors-toolbar/manager.js b/samples/sampler/colors-toolbar/manager.js
new file mode 100644
index 0000000000..6908b78ccd
--- /dev/null
+++ b/samples/sampler/colors-toolbar/manager.js
@@ -0,0 +1,59 @@
+import {platform} from '@enact/webos/platform';
+import {addons, types} from '@storybook/addons';
+import React from 'react'; // eslint-disable-line
+
+import {
+ BACKGROUNDCOLOR_ADDON_ID,
+ FOCUSBGCOLOR_ADDON_ID,
+ POPUPBGCOLOR_ADDON_ID,
+ TEXT_ADDON_ID,
+ SUBTEXTCOLOR_ADDON_ID,
+ TOOLBAR_ADDON_ID
+} from './constants';
+import ToolbarButton from './ToolbarButton';
+
+// render colors Globals only when running in non-webos environment
+if (!platform.tv) {
+ addons.register(TOOLBAR_ADDON_ID, () => {
+ const renderBackgroundColorButton = () => ;
+ const renderFocusBgColorButton = () => ;
+ const renderPopupBgColor = () => ;
+ const renderTextColorButton = () => ;
+ const renderSubTextColorButton = () => ;
+
+ addons.add(BACKGROUNDCOLOR_ADDON_ID, {
+ title: BACKGROUNDCOLOR_ADDON_ID,
+ type: types.TOOL,
+ match: ({viewMode}) => !!(viewMode && viewMode.match(/^(story|docs)$/)),
+ render: renderBackgroundColorButton
+ });
+
+ addons.add(FOCUSBGCOLOR_ADDON_ID, {
+ title: FOCUSBGCOLOR_ADDON_ID,
+ type: types.TOOL,
+ match: ({viewMode}) => !!(viewMode && viewMode.match(/^(story|docs)$/)),
+ render: renderFocusBgColorButton
+ });
+
+ addons.add(POPUPBGCOLOR_ADDON_ID, {
+ title: POPUPBGCOLOR_ADDON_ID,
+ type: types.TOOL,
+ match: ({viewMode}) => !!(viewMode && viewMode.match(/^(story|docs)$/)),
+ render: renderPopupBgColor
+ });
+
+ addons.add(TEXT_ADDON_ID, {
+ title: TEXT_ADDON_ID,
+ type: types.TOOL,
+ match: ({viewMode}) => !!(viewMode && viewMode.match(/^(story|docs)$/)),
+ render: renderTextColorButton
+ });
+
+ addons.add(SUBTEXTCOLOR_ADDON_ID, {
+ title: SUBTEXTCOLOR_ADDON_ID,
+ type: types.TOOL,
+ match: ({viewMode}) => !!(viewMode && viewMode.match(/^(story|docs)$/)),
+ render: renderSubTextColorButton
+ });
+ });
+}
diff --git a/samples/sampler/npm-shrinkwrap.json b/samples/sampler/npm-shrinkwrap.json
index 1d95a35aac..c4635a7012 100644
--- a/samples/sampler/npm-shrinkwrap.json
+++ b/samples/sampler/npm-shrinkwrap.json
@@ -15,6 +15,7 @@
"@enact/spotlight": "^4.9.0-beta.1",
"@enact/storybook-utils": "^5.1.4",
"@enact/ui": "^4.9.0-beta.1",
+ "@enact/webos": "^4.9.0-beta.1",
"@storybook/addons": "^6.5.16",
"@storybook/builder-webpack5": "^6.5.16",
"@storybook/manager-webpack5": "^6.5.16",
@@ -62779,6 +62780,17 @@
"warning": "^4.0.3"
}
},
+ "node_modules/@enact/webos": {
+ "version": "4.9.0-beta.1",
+ "resolved": "https://registry.npmjs.org/@enact/webos/-/webos-4.9.0-beta.1.tgz",
+ "integrity": "sha512-L65lJtE43C5UwQNEMwVITOOdOYj+nnTzKwaU/3HLC/tIvaeibbmePipQxgbBCkJacacas/XTKkMQkdMgVApA+A==",
+ "dependencies": {
+ "@enact/core": "^4.9.0-beta.1",
+ "prop-types": "^15.8.1",
+ "react": "^18.3.1",
+ "react-dom": "^18.3.1"
+ }
+ },
"node_modules/@gar/promisify": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz",
@@ -126287,6 +126299,17 @@
"warning": "^4.0.3"
}
},
+ "@enact/webos": {
+ "version": "4.9.0-beta.1",
+ "resolved": "https://registry.npmjs.org/@enact/webos/-/webos-4.9.0-beta.1.tgz",
+ "integrity": "sha512-L65lJtE43C5UwQNEMwVITOOdOYj+nnTzKwaU/3HLC/tIvaeibbmePipQxgbBCkJacacas/XTKkMQkdMgVApA+A==",
+ "requires": {
+ "@enact/core": "^4.9.0-beta.1",
+ "prop-types": "^15.8.1",
+ "react": "^18.3.1",
+ "react-dom": "^18.3.1"
+ }
+ },
"@gar/promisify": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz",
diff --git a/samples/sampler/package.json b/samples/sampler/package.json
index 79e49c96a8..0ccbc2d0fb 100644
--- a/samples/sampler/package.json
+++ b/samples/sampler/package.json
@@ -26,6 +26,7 @@
"@enact/spotlight": "^4.9.0-beta.1",
"@enact/storybook-utils": "^5.1.4",
"@enact/ui": "^4.9.0-beta.1",
+ "@enact/webos": "^4.9.0-beta.1",
"@storybook/addons": "^6.5.16",
"@storybook/builder-webpack5": "^6.5.16",
"@storybook/manager-webpack5": "^6.5.16",
diff --git a/samples/sampler/src/ThemeEnvironment/ThemeEnvironment.js b/samples/sampler/src/ThemeEnvironment/ThemeEnvironment.js
index 85b9461aa9..25c0c6709e 100644
--- a/samples/sampler/src/ThemeEnvironment/ThemeEnvironment.js
+++ b/samples/sampler/src/ThemeEnvironment/ThemeEnvironment.js
@@ -5,9 +5,17 @@ import kind from '@enact/core/kind';
import {Panels, Panel, Header} from '@enact/sandstone/Panels';
import ThemeDecorator from '@enact/sandstone/ThemeDecorator';
import PropTypes from 'prop-types';
+import {useEffect, useState} from 'react';
import css from './ThemeEnvironment.module.less';
+// custom theme imports
+import LS2Request from '@enact/webos/LS2Request';
+import {platform} from '@enact/webos/platform';
+
+import {AppContext, customColorsContext, defaultSandstoneColors} from '../../colors-toolbar/constants';
+import {generateStylesheet} from '../../utils/generateStylesheet';
+
const reloadPage = () => {
const {protocol, host, pathname} = window.parent.location;
window.parent.location.href = protocol + '//' + host + pathname;
@@ -65,23 +73,92 @@ const StorybookDecorator = (story, config = {}) => {
classes.debug = true;
}
+ // ---> beginning of custom theme code
+ const request = new LS2Request();
+ const [context, setContext] = useState(customColorsContext);
+
+ useEffect(() => {
+ if (platform.tv) {
+ request.send({
+ service: 'luna://com.webos.service.settings/',
+ method: 'getSystemSettings',
+ parameters: {
+ category: 'customUi',
+ keys: ['theme']
+ },
+ subscribe: true,
+ onSuccess: (res) => {
+ // update context with received data from `theme` key
+ if (res.settings.theme !== '' && res) {
+ const parsedKeyData = JSON.parse(res.settings.theme);
+ setContext({...parsedKeyData});
+ }
+ }
+ });
+ }
+ }, []); // eslint-disable-line react-hooks/exhaustive-deps
+
+ const [localColors, setLocalColors] = useState({
+ componentBackgroundColor: defaultSandstoneColors.componentBackgroundColor,
+ focusBackgroundColor: defaultSandstoneColors.focusBackgroundColor,
+ popupBackgroundColor: defaultSandstoneColors.popupBackgroundColor,
+ subtitleTextColor: defaultSandstoneColors.subtitleTextColor,
+ textColor: defaultSandstoneColors.textColor
+ });
+
+ const {
+ componentBackgroundColor,
+ focusBackgroundColor,
+ popupBackgroundColor,
+ subtitleTextColor,
+ textColor
+ } = platform.tv ? context : localColors;
+
+ // merge `generatedColors` with `background` image(global type) into the style object
+ const generatedColors = generateStylesheet(componentBackgroundColor, focusBackgroundColor, popupBackgroundColor, subtitleTextColor, textColor);
+ const background = {'--sand-env-background': globals.background === 'default' ? '' : globals.background};
+ const mergedStyles = {...generatedColors, ...background};
+
+ // update custom colors when a new color is picked from color picker
+ useEffect(() => {
+ setLocalColors({
+ componentBackgroundColor: globals.componentBackgroundColor || defaultSandstoneColors.componentBackgroundColor,
+ focusBackgroundColor: globals.focusBackgroundColor || defaultSandstoneColors.focusBackgroundColor,
+ popupBackgroundColor: globals.popupBackgroundColor || defaultSandstoneColors.popupBackgroundColor,
+ subtitleTextColor: globals.subtitleTextColor || defaultSandstoneColors.subtitleTextColor,
+ textColor: globals.textColor || defaultSandstoneColors.textColor
+ });
+ }, [globals]);
+
+ // some components render on a `floatingLayer` which is a sibling of `Theme`, so we need to apply colors to as well
+ useEffect(() => {
+ const floatLayerElement = document.getElementById("floatLayer");
+ // Apply the generated styles to the element
+ for (const property in generatedColors) {
+ if (generatedColors.hasOwnProperty(property)) { // eslint-disable-line
+ floatLayerElement.style.setProperty(property, generatedColors[property]);
+ }
+ }
+ }, [generatedColors]);
+ // <--- end of custom theme code
+
return (
-
- {sample}
-
+
+
+ {sample}
+
+
);
};
diff --git a/samples/sampler/utils/generateStylesheet.js b/samples/sampler/utils/generateStylesheet.js
new file mode 100644
index 0000000000..def9ba708b
--- /dev/null
+++ b/samples/sampler/utils/generateStylesheet.js
@@ -0,0 +1,28 @@
+import {hexToRGB} from './hexToRGB';
+
+export const generateStylesheet = (componentBackgroundColor, focusBackgroundColor, popupBackgroundColor, subTextColor, textColor) => {
+ const textColorRGB = hexToRGB(textColor);
+ const subTextColorRGB = hexToRGB(subTextColor);
+ const focusBgColorRGB = hexToRGB(focusBackgroundColor);
+ const popupBgColorRGB = hexToRGB(popupBackgroundColor);
+
+ // return stylesheet based on received colors
+ return {
+ '--sand-text-color-rgb': `${textColorRGB}`,
+ '--sand-text-sub-color': `${subTextColor}`,
+ '--sand-component-text-color-rgb': `${textColorRGB}`,
+ '--sand-component-text-sub-color-rgb': `${subTextColorRGB}`,
+ '--sand-component-bg-color': `${componentBackgroundColor}`,
+ '--sand-component-active-indicator-bg-color': `${focusBackgroundColor}`,
+ '--sand-focus-bg-color-rgb': `${focusBgColorRGB}`,
+ '--sand-selected-color-rgb': `${textColorRGB}`,
+ '--sand-disabled-focus-bg-color': `${subTextColor}`,
+ '--sand-overlay-bg-color-rgb': `${popupBgColorRGB}`,
+ '--sand-toggle-on-color': `${focusBackgroundColor}`,
+ '--sand-progress-color-rgb': `${textColorRGB}`,
+ '--sand-checkbox-color': `${focusBackgroundColor}`,
+ '--sand-alert-overlay-text-color-rgb': `${textColorRGB}`,
+ '--sand-alert-overlay-focus-text-color': `${subTextColorRGB}`,
+ '--sand-alert-overlay-disabled-selected-focus-color': `${focusBackgroundColor}`
+ };
+};
diff --git a/samples/sampler/utils/hexToRGB.js b/samples/sampler/utils/hexToRGB.js
new file mode 100644
index 0000000000..50bd736e16
--- /dev/null
+++ b/samples/sampler/utils/hexToRGB.js
@@ -0,0 +1,13 @@
+export const hexToRGB = (color) => {
+ const hexColor = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(color);
+
+ if (hexColor) {
+ const red = parseInt(hexColor[1], 16);
+ const green = parseInt(hexColor[2], 16);
+ const blue = parseInt(hexColor[3], 16);
+
+ return `${red}, ${green}, ${blue}`;
+ }
+
+ return null;
+};