{"version":3,"names":["getColorOfNearestBackground","element","parent","parentNode","host","hasAttribute","BRAND_NAME","String","getAttribute","replace","tagName","DEFAULT_PAGE_BACKGROUND_COLOR","applySchemeDelegate","component","componentName","_b","_a","hostElement","toUpperCase","startsWith","substring","SCHEME_ALIAS_CONFIG","scheme","alias","schemeConfig","activeScheme","backgroundColor","schemeMap","get","setCssVariablesDelegate","componentHasAdoptedShadowStyle","shadowRoot","adoptedStyleSheets","baseStyleSheet","schemeStyleSheet","createSchemeStyleScheet","variableStyleSheet","variableStyleSheetExists","CSSStyleSheet","key","value","Object","entries","setCssVariable"],"sources":["src/common/colorable-component.ts"],"sourcesContent":["import { BackgroundColor } from \"../components/background/constants/background-types\";\nimport { createSchemeStyleScheet, setCssVariable } from \"../utils/css-variables\";\nimport { BRAND_NAME } from \"../constants/global-constants\";\nimport { DEFAULT_PAGE_BACKGROUND_COLOR, SCHEME_ALIAS_CONFIG } from \"../constants/colors\";\n\n/* HOW TO IMPLEMENT THIS INTERFACE:\n See the Checkbox component as a complex reference implementation!\n\n ========================================================================================================================teas========================\n STEP 1:\n Create an interface for your components scheme.\n This basically describes which properties will be colored and which properties your colors depend on.\n\n export interface MyComponentSchemeDefinition {\n color: EonColor;\n }\n ================================================================================================================================================\n STEP 2:\n Create an interface for your scheme configuration.\n The configuration should contains all schemes your component supports.\n\n export interface MyComponentSchemeConfiguration {\n red: MyComponentSchemeDefinition;\n bordeaux: MyComponentSchemeDefinition;\n }\n ================================================================================================================================================\n STEP 3:\n Define a type for the name of all schemes (in case of MyComponent: \"red\" | \"blue\" | \"bordeaux\").\n This will help API users to understand which colors they can set on your component and can also be used by the TypeScript compiler.\n\n export type MyComponentSchemeName = keyof MyComponentSchemeConfiguration;`\n ================================================================================================================================================\n STEP 4:\n Create and export a const MYCOMPONENT_SCHEME_CONFIG object implementing the MyComponentSchemeConfiguration interface.\n You need to explicitly set the type MyComponentSchemeConfiguration for the TS compiler to know that this will include all required schemes.\n Note that the keys of this config object define what schemes the developer can later set using the API.\n Your SchemeConfig are basically all the variables defined by the scheme. Currently, only colors are supported!\n\n export const MYCOMPONENT_SCHEME_CONFIG: MyComponentSchemeConfiguration = {\n red: {\n color: \"eon-red\"\n },\n bordeaux: {\n color: \"eon-bordeaux\"\n }\n } as const;\n ================================================================================================================================================\n STEP 5:\n Create a constant map MYCOMPONENT_SCHEME_MAP object that maps all BackgroundColors to the corresponding MyComponentSchemeDefinition.\n\n export const MYCOMPONENT_SCHEME_MAP: Map = new Map([\n [COLOR_WHITE, MYCOMPONENT_SCHEME_CONFIG.red], // use red on white background\n [COLOR_LIMEYELLOW, MYCOMPONENT_SCHEME_CONFIG.bordeaux], // use bordeaux on limeyellow background\n // ... do this for all background colors\n [\"default\", MYCOMPONENT_SCHEME_CONFIG.red]\n ]);\n ================================================================================================================================================\n STEP 6:\n Finally, implement the interface in your Stencil component like so:\n\n @Component({\n tag: \"eon-ui-my-component\",\n styleUrl: \"my-component.scss\",\n shadow: true\n })\n export class MyComponent implements ColorableComponent {\n @Element() hostElement: HTMLEonUiMyComponentElement;\n\n activeScheme = MyComponentSchemeDefinition; // STEP 1\n schemeConfig: MyComponentSchemeConfiguration; // STEP 2 & 4\n scheme: MyComponentSchemeName; // STEP 3\n schemeMap = MYCOMPONENT_SCHEME_MAP; // STEP 5\n\n applyScheme() {\n applySchemeDelegate(this); // use this unless you need something special\n }\n }\n\n Note that applySchemeDelegate sets a CSS variable on your hostElement for each property in your SchemeDefinition.\n It will have the same name as the property in your SchemeDefinition.\n In our example, because red is the default scheme, it will set:\n\n --color: var(--eon-red) // \"color\" is the name of your property and \"--eon-red\" is its value as defined in your scheme\n\n If you change the scheme to limeyellow, applyScheme will update the activeScheme to bordeaux and will set the CSS variable to\n\n --color: var(--eon-bordeaux)\n\n This means that you can write the stylesheet in your component against these CSS variables and can always just assume that they have\n the correct value for the scheme that is currently active. In my-component.scss, you can now just do this\n and the background-color of the component will change based on its active scheme:\n\n .myDiv {\n background-color: var(--color); // or shorthand: background-color: v(color);\n }\n ================================================================================================================================================\n*/\n\n/**\n * A colorable component can inherit its style (e.g. color / scheme) from the nearest enclosing background color.\n * Unfortunately, Stencil doesn't support component inheritance, so we can't provide a default implementation.\n * The goal of this interface is to guide you and to minimize and DRY the CSS you have to write.\n * Please check the comments in this code file for detailed instructions on how to implement this interface correctly!\n */\nexport interface ColorableComponent {\n /**\n * The host element of the custom component. Should be annotated with the Stencil decorator @Element().\n * @example @Element() hostElement: HTMLEonUiButtonElement;\n */\n hostElement;\n\n /**\n * A configuration object containing a schema name as key and the scheme definition as value.\n * @example `\n * const myComponentSchemeConfiguration = {\n * red: MySchemeDefinition = {color: red, textColor: white},\n * blue: MySchemeDefinition = {color: blue, textColor: black},\n * };`\n */\n schemeConfig: ComponentSchemeConfiguration;\n\n /**\n * The name of the scheme that is used.\n * It is a key of the schemeConfig object.\n * This should be decorated with Prop({ reflect: true }) as it should be part of the external API.\n * @example `@Prop() scheme: CheckboxSchemeName;`\n */\n scheme: keyof ComponentSchemeConfiguration;\n\n /**\n * Defines which scheme should be used for the each background.\n * Always add a \"default\" mapping on top of your scheme definitions!\n * @example `\n * schemeMap: Map = new Map([\n * [COLOR_WHITE, SCHEME_RED],\n * [COLOR_RED, SCHEME_BLUE],\n * [\"default\", SCHEME_RED]\n * ])`\n */\n schemeMap: Map;\n\n /**\n * The scheme that's currently active.\n * Use the applyScheme() function or your own implementation to set this.\n */\n activeScheme: ComponentSchemeConfiguration[keyof ComponentSchemeConfiguration];\n\n /**\n * Sets the activeScheme. Always call this in ComponentWillLoad().\n * Should always prefer an explicitly set scheme using the @Prop() scheme or consider the nearest background if no scheme is set.\n * If you don't need anything special here, just use our applySchemeDelegate like this:\n *\n * @default `\n * @Watch(\"scheme\")\n * applyScheme() {\n * applySchemeDelegate(this);\n * }\n * `\n */\n applyScheme(): void;\n\n /**\n * Sets the CSS variables depending on the current scheme. Always call this in ComponentDidLoad().\n * If you don't need anything special here, just use our setCssVariablesDelegate like this:\n *\n * @default `\n * @Watch(\"activeScheme\")\n * setCssVariables() {\n * setCssVariablesDelegate(this);\n * }\n * `\n */\n setCssVariables(): void;\n}\n\n/**\n * Traverses the DOM up to find the nearest enclosing Background component and returns its color.\n * Ex For E.ON: Returns DEFAULT_BACKGROUND_COLOR = eon-white if there is no enclosing background.\n * @param element\n */\nexport function getColorOfNearestBackground(element: HTMLElement): BackgroundColor {\n const parent = (element.parentNode as HTMLElement) || ((element as any).host as HTMLElement);\n if (!parent) {\n return null;\n }\n\n if (typeof parent.hasAttribute === \"function\" && parent.hasAttribute(\"inner-background\")) {\n if (BRAND_NAME === String(\"eon\")) {\n return parent\n .getAttribute(\"inner-background\")\n .replace(\"-darkgrey\", \"-red\")\n .replace(\"-active\", \"\")\n .replace(\"-dark\", \"\") as BackgroundColor;\n } else {\n return parent.getAttribute(\"inner-background\") as BackgroundColor;\n }\n }\n switch (parent.tagName) {\n case \"BODY\":\n return DEFAULT_PAGE_BACKGROUND_COLOR;\n case \"EON-UI-BACKGROUND\":\n return parent.getAttribute(\"color\") as BackgroundColor;\n default:\n break;\n }\n\n return getColorOfNearestBackground(parent);\n}\n\n/**\n * Default implementation for applyScheme(). Sets the activeScheme state and creates CSS variables for each property in your SchemeConfiguration.\n * If a scheme is supplied explicitely, it will always have precedence.\n * Otherwise, it's determined by finding the nearest enclosing background or falling back to the \"default\" scheme.\n * @param component A component implementing ColorableComponent.\n */\nexport function applySchemeDelegate(\n component: ColorableComponent\n) {\n // check if scheme is an alias\n let componentName = (component.hostElement?.tagName ?? \"\").toUpperCase().replace(/-/g, \"_\");\n if (componentName.startsWith(\"EON_UI_\")) {\n componentName = componentName.substring(7);\n }\n // console.log(componentName, SCHEME_ALIAS_CONFIG[componentName], component.scheme);\n if (SCHEME_ALIAS_CONFIG[componentName] && SCHEME_ALIAS_CONFIG[componentName][component.scheme]) {\n const alias = SCHEME_ALIAS_CONFIG[componentName][component.scheme];\n // console.log(componentName, alias);\n if (alias in ((component.schemeConfig as unknown) as object)) {\n component.activeScheme = component.schemeConfig[alias];\n return;\n }\n }\n\n // if no scheme set or the scheme which is set is not available for that specific component\n if (!component.scheme || !(component.scheme in ((component.schemeConfig as unknown) as object))) {\n // Expensive! No need to call this if an explicit scheme is set.\n const backgroundColor = getColorOfNearestBackground(component.hostElement);\n component.activeScheme = component.schemeMap.get(backgroundColor) || component.schemeMap.get(\"default\");\n } else {\n component.activeScheme = component.schemeConfig[component.scheme] || component.schemeMap.get(\"default\");\n }\n}\n\n/**\n * Sets a CSS variable for each definition in the activeScheme of the component. Only works with colors!\n * @param component A component implementing ColorableComponent.\n */\nexport function setCssVariablesDelegate(\n component: ColorableComponent\n) {\n if (component.activeScheme == null) {\n return;\n }\n\n // shadowed component in modern browser\n const componentHasAdoptedShadowStyle =\n component.hostElement.shadowRoot != null && (component.hostElement.shadowRoot as any).adoptedStyleSheets != null;\n\n if (componentHasAdoptedShadowStyle) {\n // In first index the whole stylesheet of component is stored. Hence, we need to keep it. Anything else stored here will be removed.\n const baseStyleSheet = component.hostElement.shadowRoot.adoptedStyleSheets[0];\n const schemeStyleSheet = createSchemeStyleScheet(component.activeScheme);\n const variableStyleSheet = component.hostElement.shadowRoot.adoptedStyleSheets[2];\n\n // Check if variableStyleSheet already exists.\n const variableStyleSheetExists = !!variableStyleSheet;\n\n // Adds or replaces scheme style set to adoptedStyleSheets of shadowroot.\n if (baseStyleSheet && schemeStyleSheet) {\n // Add variableStyleSheet if not exists.\n if (!variableStyleSheetExists) {\n component.hostElement.shadowRoot.adoptedStyleSheets = [baseStyleSheet, schemeStyleSheet, new CSSStyleSheet()];\n } else {\n component.hostElement.shadowRoot.adoptedStyleSheets = [baseStyleSheet, schemeStyleSheet, variableStyleSheet];\n }\n }\n\n return;\n }\n\n // if not shadowed component in modern browser\n for (let [key, value] of Object.entries(component.activeScheme)) {\n // this check allows also setting non color variable values to a component scheme\n if (typeof value === \"string\" && value.startsWith(\"eon-\")) {\n setCssVariable(component.hostElement, `--${key}`, `var(--${value})`);\n } else {\n setCssVariable(component.hostElement, `--${key}`, `${value}`);\n }\n }\n}\n\n/**\n * Use this helper function to get the NAME (key in your scheme config) of the scheme for a given BackgroundColor.\n *\n * This is required if you'd like to simulate a eon-ui-background enclosing a slotted colorable component.\n * A slotted child can never access the ShadowDOM of its host, so it would not be able to find the parent eon-ui-background.\n * In that case, you can ask the slotted child: \"If your backgroundColor was white, what would be the name of your scheme for that\".\n * Afterwards, you can set the scheme on the slotted child explicitly.\n *\n * @param component A component implementing ColorableComponent.\n * @param backgroundColor The background color of the component.\n */\nexport function getSchemeName(\n schemeMap: Map,\n schemeConfig: ComponentSchemeConfiguration,\n backgroundColor: BackgroundColor | \"default\"\n): string {\n const schemeDefinition = schemeMap.get(backgroundColor);\n const schemeName = Object.keys(schemeConfig).find((schemeName) => schemeConfig[schemeName] === schemeDefinition);\n return schemeName;\n}\n"],"mappings":"mIAoLgBA,EAA4BC,GAC1C,MAAMC,EAAUD,EAAQE,YAAgCF,EAAgBG,KACxE,IAAKF,EAAQ,CACX,OAAO,I,CAGT,UAAWA,EAAOG,eAAiB,YAAcH,EAAOG,aAAa,oBAAqB,CACxF,GAAIC,IAAeC,OAAO,OAAQ,CAChC,OAAOL,EACJM,aAAa,oBACbC,QAAQ,YAAa,QACrBA,QAAQ,UAAW,IACnBA,QAAQ,QAAS,G,KACf,CACL,OAAOP,EAAOM,aAAa,mB,EAG/B,OAAQN,EAAOQ,SACb,IAAK,OACH,OAAOC,EACT,IAAK,oBACH,OAAOT,EAAOM,aAAa,SAK/B,OAAOR,EAA4BE,EACrC,C,SAQgBU,EACdC,G,QAGA,IAAIC,IAAiBC,GAAAC,EAAAH,EAAUI,eAAW,MAAAD,SAAA,SAAAA,EAAEN,WAAO,MAAAK,SAAA,EAAAA,EAAI,IAAIG,cAAcT,QAAQ,KAAM,KACvF,GAAIK,EAAcK,WAAW,WAAY,CACvCL,EAAgBA,EAAcM,UAAU,E,CAG1C,GAAIC,EAAoBP,IAAkBO,EAAoBP,GAAeD,EAAUS,QAAS,CAC9F,MAAMC,EAAQF,EAAoBP,GAAeD,EAAUS,QAE3D,GAAIC,KAAWV,EAAUW,aAAqC,CAC5DX,EAAUY,aAAeZ,EAAUW,aAAaD,GAChD,M,EAKJ,IAAKV,EAAUS,UAAYT,EAAUS,UAAYT,EAAUW,cAAsC,CAE/F,MAAME,EAAkB1B,EAA4Ba,EAAUI,aAC9DJ,EAAUY,aAAeZ,EAAUc,UAAUC,IAAIF,IAAoBb,EAAUc,UAAUC,IAAI,U,KACxF,CACLf,EAAUY,aAAeZ,EAAUW,aAAaX,EAAUS,SAAWT,EAAUc,UAAUC,IAAI,U,CAEjG,C,SAMgBC,EACdhB,GAEA,GAAIA,EAAUY,cAAgB,KAAM,CAClC,M,CAIF,MAAMK,EACJjB,EAAUI,YAAYc,YAAc,MAASlB,EAAUI,YAAYc,WAAmBC,oBAAsB,KAE9G,GAAIF,EAAgC,CAElC,MAAMG,EAAiBpB,EAAUI,YAAYc,WAAWC,mBAAmB,GAC3E,MAAME,EAAmBC,EAAwBtB,EAAUY,cAC3D,MAAMW,EAAqBvB,EAAUI,YAAYc,WAAWC,mBAAmB,GAG/E,MAAMK,IAA6BD,EAGnC,GAAIH,GAAkBC,EAAkB,CAEtC,IAAKG,EAA0B,CAC7BxB,EAAUI,YAAYc,WAAWC,mBAAqB,CAACC,EAAgBC,EAAkB,IAAII,c,KACxF,CACLzB,EAAUI,YAAYc,WAAWC,mBAAqB,CAACC,EAAgBC,EAAkBE,E,EAI7F,M,CAIF,IAAK,IAAKG,EAAKC,KAAUC,OAAOC,QAAQ7B,EAAUY,cAAe,CAE/D,UAAWe,IAAU,UAAYA,EAAMrB,WAAW,QAAS,CACzDwB,EAAe9B,EAAUI,YAAa,KAAKsB,IAAO,SAASC,K,KACtD,CACLG,EAAe9B,EAAUI,YAAa,KAAKsB,IAAO,GAAGC,I,EAG3D,Q"}