Closed petermonte closed 4 years ago
Note: I've read the documentation stating that an extra custom animation can be added, but how would this be possible if all calls are dynamic?
Thanks for the pen. The problem is that the browser only triggers one animation per element unless multiple animations are explicitly defined in the css.
Here's how you can do it with custom animation names: https://codepen.io/muicss/pen/JjjKgYB
And here's how you can do it with multiple listeners: https://codepen.io/muicss/pen/LYYZwmo
thanks @amorey,
Unfortunately, like I said, I'm building an entire UI framework kit that as an ocean of helpers/utilities, components, modules and widgets and all should trigger by themselves once added to the DOM. This means that I can't control all the css animation properties of all possible combinations that all apps can create.
For example I can have something like this:
<tabs class="tabs-fill" data-class-xs="tabs-justify tabs-outline">
Two triggers are created with this tabs element:
sentinel.on('tabs', function(el) {
uikit.tabs(el);
});
sentinel.on(['[data-class-xs]', '[data-class-sm]', '[data-class-md]', '[data-class-lg]'], function(el) {
uikit.swappclass(el);
});
So this is just a small combination of so many others that can exist. It's only until until now that I'm facing this problem since I'm starting to make use of multiple combination of components with class helpers.
I really don't know how to overcome this. I might use an hybrid approach like described here where the animationstart
is triggered for the entire document and the event.target
is parsed and directed to the respective classes.
Triggering animationStart
for every element will degrade performance but you can probably limit the number of triggers by being more selective with the CSS:
tabs, [data-uikit-*] {
animation-duration: .0001s;
animation-name: uikit-node-inserted;
}
sentinel.on('!uikit-node-inserted', function(el) {
if (el.tagName === 'TABS') { /* do something */ }
if (/data-uikit-class-xs/.test(el.className)) { /* do something */ }
});
@amorey thanks.
Gonna drop here a simple example of how I adapted Sentinel to my App, in case someone encounters the same issue. This example is to show how we can have a component running with multiple calls with Sentinel avoiding css animation name conflicts.
You can check the code running at https://codepen.io/petermonte/pen/Vwwqgjv
I've used a component like a simple Tabs using a classname selector and another functionality using an attribute definition. So this is a very likely scenario to happen on an APP.
.tabs,
[data-attribute] {
animation-duration: .0001s;
animation-name: node-inserted;
}
This is where we focus our APP methods for component registration
;(function(){
"use strict";
const _components = [];
window.APP = function (){
// APP MAIN FUNCTION
}
APP.getRegisteredComponents = function () {
return _components;
};
APP.registerComponent = function (_name, _callback, _selector) {
if (!APP.hasOwnProperty(_name)) {
// Register the component function on our main APP
Object.defineProperty(APP, _name, {
value: _callback,
enumerable: true,
configurable: true
});
// Record component for Sentinel to run
_components.push({
name: _name,
callback: _callback,
selector: _selector
});
}
return true;
};
APP.runSentinel = function () {
sentinel.on('!node-inserted', function(el) {
APP.getRegisteredComponents().forEach(function(component){
if(el.matches(component.selector)){
component.callback(el);
}
});
});
return true;
};
}());
So we can have a component that is based on a classname, or an attribute, etc.
;(function(){
"use strict";
function tabs (el){
// Lets prevent processing a component that as already been processed
if (el.dataset.tabsInit == 'true'){
return el;
}
// RUN EVERYTHING NEEDED FOR THE COMPONENT
console.log('component of type tabs :', el);
// Register the init state
el.dataset.tabsInit = true;
return el;
}
APP.registerComponent(
'tabs',
tabs,
'.tabs:not([data-tabs-init="true"])'
);
}());
;(function(){
"use strict";
function functionalityByAttr (el){
// Lets prevent processing a component that as already been processed
if (el.dataset.functionalityByAttrInit == 'true'){
return el;
}
// RUN EVERYTHING NEEDED FOR THE COMPONENT
console.log('functionality by attribute :', el);
// Register the init state
el.dataset.functionalityByAttrInit = true;
return el;
}
APP.registerComponent(
'functionalityByAttr',
functionalityByAttr,
'[data-attribute]:not([data-functionality-by-attribute="true"])'
);
}());
Now that we have all our css and script configured we run Sentinel to listen to any added element to the DOM
APP.runSentinel();
<div class="tabs" data-attribute="abcd">
...
</div>
Thanks for sharing! Nice use of .matches()
.
Context:
I'm using the Sentinel.js to initialise several components and functionalities on the DOM.
Issue:
Most of these components get to use plenty of css and js functionalities by using classnames or attributes. It seems that some of them get ignored or overwritten.
I've created a demo to show this behaviour: https://codepen.io/petermonte/pen/XWWKRNv?editors=0010
Code:
HTML
CSS
JS
Expected:
the idea is that all calls should run adding up all the changes to the element. Play arround by commenting all js sentinel calls and see how the element only reacts the a single call.