ember-container-query
Version:
Make container queries that harness the power of Ember
109 lines (105 loc) • 3.15 kB
JavaScript
import { registerDestructor } from '@ember/destroyable';
import { action } from '@ember/object';
import { debounce } from '@ember/runloop';
import { service } from '@ember/service';
import Modifier from 'ember-modifier';
import { g, i, n } from 'decorator-transforms/runtime';
class ContainerQueryModifier extends Modifier {
static {
g(this.prototype, "resizeObserver", [service]);
}
#resizeObserver = (i(this, "resizeObserver"), void 0);
_dataAttributes = [];
_element;
_named;
dimensions;
queryResults;
get dataAttributePrefix() {
return this._named.dataAttributePrefix ?? 'container-query';
}
get debounce() {
return this._named.debounce ?? 0;
}
get features() {
return this._named.features ?? {};
}
constructor(owner, args) {
super(owner, args);
registerDestructor(this, () => {
this.resizeObserver.unobserve(this._element, this.onResize);
});
}
evaluateQueries() {
const queryResults = {};
for (const [featureName, metadata] of Object.entries(this.features)) {
const {
dimension,
min,
max
} = metadata;
const value = this.dimensions[dimension];
queryResults[featureName] = min <= value && value < max;
}
this.queryResults = queryResults;
}
measureDimensions(element) {
const height = element.clientHeight;
const width = element.clientWidth;
this.dimensions = {
aspectRatio: width / height,
height,
width
};
}
modify(element, _positional, named) {
this._named = named;
this.registerResizeObserver(element);
this.queryContainer(element);
}
queryContainer(element) {
this.measureDimensions(element);
this.evaluateQueries();
this.resetDataAttributes(element);
this.setDataAttributes(element);
this._named.onQuery?.({
dimensions: this.dimensions,
queryResults: this.queryResults
});
}
registerResizeObserver(element) {
this.resizeObserver.unobserve(this._element, this.onResize);
this._element = element;
this.resizeObserver.observe(this._element, this.onResize);
}
resetDataAttributes(element) {
this._dataAttributes.forEach(dataAttribute => {
element.removeAttribute(dataAttribute);
});
this._dataAttributes = [];
}
setDataAttributes(element) {
const prefix = this.dataAttributePrefix;
for (const [featureName, meetsFeature] of Object.entries(this.queryResults)) {
if (!meetsFeature) {
continue;
}
const dataAttribute = prefix ? `data-${prefix}-${String(featureName)}` : `data-${String(featureName)}`;
element.setAttribute(dataAttribute, '');
this._dataAttributes.push(dataAttribute);
}
}
onResize(resizeObserverEntry) {
const element = resizeObserverEntry.target;
if (this.debounce > 0) {
// eslint-disable-next-line ember/no-runloop
debounce(this, this.queryContainer, element, this.debounce);
return;
}
this.queryContainer(element);
}
static {
n(this.prototype, "onResize", [action]);
}
}
export { ContainerQueryModifier as default };
//# sourceMappingURL=container-query.js.map