-
Notifications
You must be signed in to change notification settings - Fork 0
Polymorph()
polymorph(element, styles, config, globals)| Param | Type | Info |
|---|---|---|
element |
HTMLElement |
The DOM element to style |
styles |
(Object|Function|Array) |
The style rules to apply to element
|
[config] |
Object |
Module configuration |
[globals] |
Object |
Global/theming properties |
stylesas Objectstylesas Functionstylesas Array- Style Root Module
- Style Components
- Style Sub-Components
- Style Elements with Applied Modifiers
- Style Elements when Condition is Met
- Style Reference Element
- Style Keywords
For basic styling of modules and components you can pass an Object containing your desired stylistic properties.
polymorph(element, {
'display': 'block',
'position': 'relative',
'modifier(hidden)': {
'display': 'none'
},
someComponent: {
'color': 'red',
'font-size': '24px'
},
anotherComponent: component => ({
'color': window.UI.someUtility(component) ? 'blue' : 'black',
'font-size': '12px'
})
});You can pass the styles parameter as a Function that follows a specific signature, allowing you to pass configuration and add more flexibility.
configandglobalsrefer to the optional parameters passed to thepolymorph()call
styles(element, config, globals)Function (HTMLElement, Object, Object) => (Array.<Object>|Object)const config = {
colorPrimary: 'red',
sizePrimary: '24px',
sizeSecondary: '12px'
}
polymorph(element, (element, config, globals) => ({
'display': element.matches('[class*="-hidden"]') ? 'none' : 'block',
'position': 'relative',
someComponent: {
'color': config.colorPrimary,
'font-size': config.sizePrimary
},
anotherComponent: component => ({
'color': globals.someUtility(component) ? 'blue' : 'black',
'font-size': config.sizeSecondary
})
}), config, window.UI);You can return an array of style objects and sequentially apply each ruleset in the array:
polymorph(element, element => ([
{
// some style rules...
},
someOtherRulesetUtility(element),
{
'color': 'red' // will take priority as it is last to be applied
}
]);You can pass an array of Objects/Functions/Arrys that Polymorph will sequentially execute.
You can also pass an array of properties for components/sub-components
polymorph(element, [
{
...
},
element => ([
{
...
},
{
...
}
]),
[
{...},
element => ({...})
]
});To style the root module (the DOM element matched by element), pass any valid CSS property and value to an Object:
<div class="accordion" id="alpha"></div>polymorph(document.getElementById('alpha'), {
'color': 'red'
});<div id="alpha" style="color: red;"></div>Learn more about Components
To style a component, pass your desired CSS properties to an Object assigned to a key which corresponds to the Component name:
<div class="accordion" id="alpha">
<div class="accordion_panel"></div>
<div class="accordion_panel"></div>
</div>polymorph(document.getElementById('alpha'), {
panel: {
'color': 'blue'
}
});<div class="accordion" id="alpha">
<div class="accordion_panel" style="color: blue;"></div>
<div class="accordion_panel" style="color: blue;"></div>
</div>You can access the Component's DOM node by passing a Function instead of an Object:
<div class="accordion" id="alpha">
<div class="accordion_panel"></div>
<div class="accordion_panel-active"></div>
</div>polymorph(document.getElementById('alpha'), {
panel: panel => {
const color = panel.matches('[class*="-active"]') ? 'red' : 'blue';
return {
'color': color
}
}
});polymorph(document.getElementById('alpha'), {
panel: panel => ({
'color': panel.modifier('active') ? 'red' : 'blue'
})
});<div class="accordion" id="alpha">
<div class="accordion_panel" style="color: blue;"></div>
<div class="accordion_panel-active" style="color: red;"></div>
</div>Where possible, it is recommended to avoid using Sub-Components and stick to regular Components
<div class="header" id="alpha">
<ul class="header_navigation">
<li class="header_navigation_item">...</li>
<li class="header_navigation_item">...</li>
</ul>
</div>polymorph(document.getElementById('alpha'), {
navigation: {
'sub-component(item)': {
'color': 'blue'
}
}
});...or if you are confident about not having naming conflicts:
polymorph(document.getElementById('alpha'), {
navigation: {
item: {
'color': 'blue'
}
}
});<div class="header" id="alpha">
<ul class="header_navigation">
<li class="header_navigation_item" style="color: blue;">...</li>
<li class="header_navigation_item" style="color: blue;">...</li>
</ul>
</div>An alternative approach using sQuery could be:
polymorph(document.getElementById('alpha'), {
navigation: navigation => {
navigation.getSubComponents('item').forEach(item => polymorph(item, {
'color': 'blue'
}));
return {
// navigation component styles
}
}
});<div class="button-large-round-active" id="alpha"></div>polymorph(document.getElementById('alpha'), {
'background': 'grey',
'font-size': '14px',
'modifier(large)': {
'font-size': '24px'
},
'modifier(round)': {
'border-radius': '4px'
},
'modifier(active)': {
'background': 'green'
},
});polymorph(document.getElementById('alpha'), element => ({
'background': element.matches('[class*="-active"]') ? 'green' : 'grey',
'font-size': element.matches('[class*="-large"]') ? '24px' : '14px',
'border-radius': element.matches('[class*="-round"]') ? '4px' : null
}));polymorph(document.getElementById('alpha'), element => ({
'background': element.modifier('active') ? 'green' : 'grey',
'font-size': element.modifier('large') ? '24px' : '14px',
'border-radius': element.modifier('round') ? '4px' : null
}));<div class="button-large-round-active" id="alpha" style="background-color: green; font-size: 24px; border-radius: 4px;"></div><div class="button"></div>
<div class="button-large-round-active"></div>
<div class="button-active"></div>sQuery('button', button => {
polymorph(button, element => ({
'background': element.modifier('active') ? 'green' : 'grey',
'font-size': element.modifier('large') ? '24px' : '14px',
'border-radius': element.modifier('round') ? '4px' : null
}));
});<div class="button" style="background: grey; font-size: 14px;"></div>
<div class="button-large-round-active" id="alpha" style="background: green; font-size: 24px; border-radius: 4px;"></div>
<div class="button-active" style="background: green; font-size: 14px;"></div><div class="accordion" id="alpha">
<div class="accordion_panel"></div>
<div class="accordion_panel-active"></div>
</div>polymorph(document.getElementById('alpha'), {
panel: {
'color': 'blue',
'modifier(active)': {
'color': 'red'
}
}
});polymorph(document.getElementById('alpha'), {
panel: panel => ({
'color': panel.matches('[class*="-active"]') ? 'red' : 'blue'
})
});polymorph(document.getElementById('alpha'), {
panel: panel => ({
'color': panel.is('active') ? 'red' : 'blue'
})
});polymorph(document.getElementById('alpha'), {
panel: panel => ([
{
styles: {
'color': 'blue'
}
},
{
condition: () => panel.is('active'),
styles: {
'color': 'red'
}
}
])
});It's possible to apply styles to an element when a certain condition is met (if you only need to apply styles when an element has an applied modifier, see the Style Elements with Applied Modifiers section).
- The condition should be a function that returns a boolean (unless the function returns a
truthyvalue, the styles will not be applied) and assigned to theconditionkey - Styles should be assigned to the
styleskey
const styles = {
someComponent: {
condition: () => window.someGlobalCondition,
styles: {
// some styles
}
}
}The above styles will only be applied if window.someGlobalCondition is a truthy value.
const styles = {
someComponent: [() => window.someGlobalCondition, {
// some styles
}]
}It's possible to apply styles to a reference element:
- Reference element should be assigned to the
elementkey - Styles should be assigned to the
styleskey
const someReferenceElement = document.getElementById('someElement');
const styles = {
someIdentifier: {
element: someReferenceElement,
styles: {
// some styles
}
}
}const someReferenceElement = document.getElementById('someElement');
const styles = {
someIdentifier: [someReferenceElement, {
// some styles
}]
}...as documented by the Style Components and Style Sub-Components sections.
Apply style properties when the element or a child component/sub-component is hovered
polymorph(element, {
someComponent: {
'color': 'red',
':hover': {
'color': 'blue'
}
}
});Apply style properties when the element or a child component/sub-component is focused
polymorph(element, {
someComponent: {
'outline': 'none',
':focus': {
'outline': '2px solid blue'
}
}
});Style a parent
groupelement
<div class="group-button">
<div class="button">Button</div>
<div class="button">Button</div>
<div class="button">Button</div>
</div>document.querySelectorAll('.button').forEach(button => {
polymorph(button, {
group: {
'display': 'flex'
}
});
});<div class="group-button" style="display: flex;">
<div class="button">Button</div>
<div class="button">Button</div>
<div class="button">Button</div>
</div>Style a parent
wrapperelement
<div class="wrapper-header">
<div class="header>...</div>
</div>
polymorph(document.querySelector('.header'), {
wrapper: {
'position': 'absolute'
}
});<div class="wrapper-header" style="position: absolute;">
<div class="header>...</div>
</div>
Pass a configuration Object to your styles, allowing you to separate potentially configurable properties from your source code.
const config = {
colorPrimary: 'red',
sizePrimary: '24px',
sizeSecondary: '12px'
}
polymorph(element, (element, config) => ({
'display': element.matches('[class*="-hidden"]') ? 'none' : 'block',
'position': 'relative',
someComponent: {
'color': config.colorPrimary,
'font-size': config.sizePrimary
}
}), config);Polymorph requires a value for modfierGlue and componentGlue; these values can be set manually via configuration or retrieved dynamically (otherwise they will fallback to - and _ respectively).
polymorph(element, styles, { componentGlue: '__', modifierGlue: '--' }); By assigning the values to a global window.Synergy object, they will be picked up automatically by Polymorph.
window.Synergy = {
componentGlue: '__',
modifierGlue: '--'
}Pass a global Object to your styles, allowing you to share common tools and utilities.
window.UI.someUtility = element => {...};
polymorph(element, (element, config, globals) => ({
'display': element.matches('[class*="-hidden"]') ? 'none' : 'block',
'position': 'relative',
someComponent: component => ({
'color': globals.someUtility(component) ? 'blue' : 'black',
'font-size': '12px'
})
}), {}, window.UI);