UNPKG

metamorphosis

Version:

A css variable management library that helps create and organize variables into easily configurable themes.

131 lines (130 loc) 3.99 kB
import { isBlank } from "@alanscodelog/utils/isBlank"; import { Base } from "./Base.js"; import { getTotalSteps } from "./internal.js"; import { lerp, defaultKeyNamer } from "./utils.js"; const getStepPercent = (percent, startPercent, endPercent) => { let stopPercent = percent - startPercent; let stopPercentTotal = endPercent - startPercent; if (stopPercent < 0) stopPercent = 0; if (stopPercentTotal === 0) { stopPercent = 1; stopPercentTotal = 1; } return stopPercent / stopPercentTotal; }; class InterpolatedVars extends Base { name; unit; values; ready = false; value = []; interpolated = {}; options = { roundTo: 3, exclude: [], keyLimit: 10, keyName: defaultKeyNamer, interpolator: lerp, separator: "-", steps: 10 }; constructor(name, unit, values, options = {}) { super(); if (isBlank(name)) throw new Error("Name cannot be blank."); this.name = name; this.unit = unit; this.set(values); this.setOpts(options); this.ready = true; this.notify(); } setOpts(value) { this.options = { ...this.options, ...value }; if (this.ready) { this.notify(); } } set(value) { const hasStops = Array.isArray(value[0]); if (this.ready) { for (const val of this.values) { const v = hasStops ? val[1] : val; v?.removeDep(this); } } if (hasStops && value.find((entry) => entry[0] > 1) !== void 0) { throw new Error("Stop Entry percentage must be expressed in a value from 0 to 1."); } this.values = hasStops ? [...value].sort((a, b) => a[0] - b[0]) : value; for (const val of this.values) { const v = hasStops ? val[1] : val; v.addDep(this); } if (this.ready) { this.notify(); } } notify() { this.recompute(); this._notify(); } recompute() { const valRes = []; const interpolatedRes = {}; const steps = this.options.steps; const totalSteps = getTotalSteps(steps); const { values, name } = this; const hasStops = Array.isArray(values[0]); const lastStopIndex = values.length - 1; const nonStopStepPercent = lastStopIndex === 0 ? 0 : 1 / lastStopIndex; const state = {}; let stopIndex = -1; let nextStopIndex = -1; let startPercent = -1; let endPercent = -1; for (let i = 0; i < totalSteps; i++) { let percent = Array.isArray(steps) ? steps[i] : i / (steps - 1); let startVal, endVal; if (hasStops) { while ((stopIndex < 0 || endPercent < percent) && stopIndex < values.length - 1) { stopIndex++; startPercent = values[stopIndex][0]; nextStopIndex = Math.min(stopIndex + 1, lastStopIndex); endPercent = values[nextStopIndex][0]; } startVal = values[stopIndex][1]; endVal = values[nextStopIndex][1]; percent = getStepPercent(percent, startPercent, endPercent); } else { const startValIndex = Math.floor(percent * lastStopIndex); const endValIndex = Math.min(startValIndex + 1, lastStopIndex); startPercent = startValIndex * nonStopStepPercent; endPercent = endValIndex * nonStopStepPercent; percent = getStepPercent(percent, startPercent, endPercent); startVal = values[startValIndex]; endVal = values[endValIndex]; } const keyName = this.options.keyName({ i, steps, totalSteps, name: this.name, keyLimit: this.options.keyLimit, separator: this.options.separator }); const val = this.options.interpolator({ start: startVal, end: endVal, name, percent, state, step: i, keyName, totalSteps, steps, exclude: this.options.exclude, roundTo: this.options.roundTo }); valRes.push(val); interpolatedRes[keyName] = this.unit(val); } this.value = valRes; this.interpolated = interpolatedRes; } } export { InterpolatedVars };