Files
HomeAssistantVS/www/community/sensor-bar-card-plus/sensor-bar-card-plus.js
T
2026-07-20 22:52:35 -04:00

9652 lines
476 KiB
JavaScript

(() => {
var __getOwnPropNames = Object.getOwnPropertyNames;
var __esm = (fn, res, err) => function __init() {
if (err) throw err[0];
try {
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
} catch (e) {
throw err = [e], e;
}
};
var __commonJS = (cb, mod) => function __require() {
try {
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
} catch (e) {
throw mod = 0, e;
}
};
// src/config/normalize.js
function normalizeResolvableValue(value, entityValue, percentValue = null) {
const normalized = {
fixed: value != null ? value : null,
entity: entityValue != null ? entityValue : null
};
if (Number.isFinite(percentValue)) {
normalized.percent = percentValue;
}
return normalized;
}
function looksLikeEntityId(value) {
return typeof value === "string" && /^[a-z0-9_]+\.[a-z0-9_]+$/i.test(value.trim());
}
function parsePercentLiteral(value) {
if (typeof value !== "string") return null;
const match = value.match(/^\s*([+-]?(?:\d+(?:\.\d+)?|\.\d+))\s*%\s*$/);
if (!match) return null;
const percent = parseFloat(match[1]);
return Number.isFinite(percent) ? percent : null;
}
function getFiniteNumber(value) {
if (typeof value === "number") {
return Number.isFinite(value) ? value : null;
}
if (typeof value === "string") {
const trimmed = value.trim();
if (!trimmed) return null;
const num = Number(trimmed);
return Number.isFinite(num) ? num : null;
}
return null;
}
function normalizeStructuredResolvableValue(input, inheritedResolvable = null, defaultValue = null, options = {}) {
var _a, _b, _c, _d, _e, _f;
const { allowPercent = false } = options;
const inherited = inheritedResolvable != null ? inheritedResolvable : normalizeResolvableValue(defaultValue, null);
if (input === void 0) {
return { ...inherited };
}
if (input === null) {
return normalizeResolvableValue(null, null);
}
if (typeof input === "object" && !Array.isArray(input)) {
const value = (_b = (_a = input.fixed) != null ? _a : input.value) != null ? _b : null;
const entity = (_c = input.entity) != null ? _c : null;
const percent = allowPercent ? getFiniteNumber(input.percent) : null;
return normalizeResolvableValue(value, entity, percent);
}
if (looksLikeEntityId(input)) {
return normalizeResolvableValue(
(_e = (_d = inherited.fixed) != null ? _d : defaultValue) != null ? _e : null,
input,
(_f = inherited.percent) != null ? _f : null
);
}
if (allowPercent) {
const percent = parsePercentLiteral(input);
if (Number.isFinite(percent)) {
return normalizeResolvableValue(null, null, percent);
}
}
return normalizeResolvableValue(input, null);
}
function normalizeBaselineDirectionConfig(input, inheritedDirection = null) {
var _a;
const inherited = inheritedDirection != null ? inheritedDirection : { color: null };
if (input === void 0) {
return { ...inherited };
}
if (input === null) {
return { color: null };
}
if (typeof input === "object" && !Array.isArray(input)) {
return {
color: (_a = input.color) != null ? _a : null
};
}
return {
color: input
};
}
function normalizeOptionalEnabled(value) {
return value === true ? true : value === false ? false : null;
}
function normalizeBaselineConfig(entityConfig, cardConfig) {
var _a;
const cardBaseline = cardConfig == null ? void 0 : cardConfig.baseline;
const rawBaseline = entityConfig == null ? void 0 : entityConfig.baseline;
const inherited = {
enabled: normalizeOptionalEnabled(cardBaseline == null ? void 0 : cardBaseline.enabled),
at: (cardBaseline == null ? void 0 : cardBaseline.at) ? { ...cardBaseline.at } : normalizeResolvableValue(null, null),
above: normalizeBaselineDirectionConfig(void 0, cardBaseline == null ? void 0 : cardBaseline.above),
below: normalizeBaselineDirectionConfig(void 0, cardBaseline == null ? void 0 : cardBaseline.below)
};
if (rawBaseline === void 0) {
return inherited;
}
if (rawBaseline === null) {
return {
enabled: null,
at: normalizeResolvableValue(null, null),
above: { color: null },
below: { color: null }
};
}
if (typeof rawBaseline !== "object" || Array.isArray(rawBaseline)) {
return {
enabled: inherited.enabled,
at: normalizeStructuredResolvableValue(rawBaseline, inherited.at, null),
above: inherited.above,
below: inherited.below
};
}
return {
enabled: (_a = normalizeOptionalEnabled(rawBaseline.enabled)) != null ? _a : inherited.enabled,
at: normalizeStructuredResolvableValue(rawBaseline.at, inherited.at, null, { allowPercent: true }),
above: normalizeBaselineDirectionConfig(rawBaseline.above, inherited.above),
below: normalizeBaselineDirectionConfig(rawBaseline.below, inherited.below)
};
}
function inferSegmentEndValues(segments, fallbackEnd = null) {
const sorted = [...segments].sort((a, b) => a.from - b.from);
return sorted.map((segment, index) => {
var _a;
let to = Number.isFinite(segment.to) ? segment.to : null;
if (!Number.isFinite(to) && index < sorted.length - 1) {
to = sorted[index + 1].from;
}
if (!Number.isFinite(to) && Number.isFinite(fallbackEnd)) {
to = fallbackEnd;
}
return {
from: segment.from,
to,
color: segment.color,
label: (_a = segment.label) != null ? _a : null
};
});
}
function normalizeSeverityToSegments(input) {
if (!Array.isArray(input)) return null;
const segments = input.filter((segment) => Number.isFinite(segment == null ? void 0 : segment.from) && (segment == null ? void 0 : segment.color)).map((segment) => {
var _a;
return {
from: segment.from,
to: Number.isFinite(segment == null ? void 0 : segment.to) ? segment.to : null,
color: segment.color,
label: (_a = segment.label) != null ? _a : null
};
});
return inferSegmentEndValues(segments, 100);
}
function hasResolvableMagnitude(resolvable) {
return !!resolvable && (Number.isFinite(getFiniteNumber(resolvable.fixed)) || Number.isFinite(resolvable.percent));
}
function normalizeGaugeSegments(input) {
if (!Array.isArray(input)) return null;
const segments = input.map((segment) => {
var _a;
const from = normalizeStructuredResolvableValue(segment == null ? void 0 : segment.from, null, null, { allowPercent: true });
const to = (segment == null ? void 0 : segment.to) === void 0 ? null : normalizeStructuredResolvableValue(segment.to, null, null, { allowPercent: true });
if (!hasResolvableMagnitude(from) || !(segment == null ? void 0 : segment.color)) {
return null;
}
return {
from,
to,
color: segment.color,
label: (_a = segment.label) != null ? _a : null
};
}).filter(Boolean);
return segments.map((segment, index) => {
var _a;
return {
from: { ...segment.from },
to: segment.to ? { ...segment.to } : index < segments.length - 1 ? { ...segments[index + 1].from } : null,
color: segment.color,
label: (_a = segment.label) != null ? _a : null
};
});
}
function normalizeScaleBound(entityConfig, cardConfig, key, defaultValue) {
var _a, _b, _c, _d, _e, _f, _g, _h;
const cardScale = cardConfig == null ? void 0 : cardConfig.scale;
const entityScale = entityConfig == null ? void 0 : entityConfig.scale;
const entityKey = `${key}_entity`;
const cardBound = cardScale == null ? void 0 : cardScale[key];
const inherited = cardBound ? normalizeResolvableValue(
(_b = (_a = cardBound.fixed) != null ? _a : cardBound.value) != null ? _b : null,
(_c = cardBound.entity) != null ? _c : null
) : normalizeResolvableValue(
(_d = cardConfig == null ? void 0 : cardConfig[key]) != null ? _d : defaultValue,
(_e = cardConfig == null ? void 0 : cardConfig[entityKey]) != null ? _e : null
);
if ((entityScale == null ? void 0 : entityScale[key]) !== void 0) {
return normalizeStructuredResolvableValue(
entityScale[key],
inherited,
defaultValue
);
}
const entityOverride = entityConfig[entityKey];
const hasEntityOverride = entityOverride !== void 0 && entityOverride !== null;
const value = (_g = (_f = entityConfig[key]) != null ? _f : hasEntityOverride ? null : inherited.fixed) != null ? _g : inherited.entity ? null : defaultValue;
const entity = (_h = entityOverride != null ? entityOverride : inherited.entity) != null ? _h : null;
return normalizeResolvableValue(value, entity);
}
function normalizeScaleConfig(entityConfig, cardConfig) {
return {
min: normalizeScaleBound(entityConfig, cardConfig, "min", 0),
max: normalizeScaleBound(entityConfig, cardConfig, "max", 100)
};
}
function fillStyleToColorMode(fillStyle) {
switch (fillStyle) {
case "solid":
return "single";
case "gradient":
return "gradient";
case "bands":
return "severity";
case "soft_bands":
return "severity";
case "band_gradient":
return "severity_gradient";
default:
return null;
}
}
function colorModeToFillStyle(colorMode) {
switch (colorMode) {
case "single":
return "solid";
case "gradient":
return "gradient";
case "severity":
return "bands";
case "severity_gradient":
return "band_gradient";
default:
return null;
}
}
function normalizeBarModeConfig(barConfig = null, flatColorMode = null) {
var _a, _b, _c, _d, _e, _f;
const fillStyle = (_a = barConfig == null ? void 0 : barConfig.fill_style) != null ? _a : null;
const colorMode = (_c = (_b = barConfig == null ? void 0 : barConfig.color_mode) != null ? _b : flatColorMode) != null ? _c : null;
const normalizedColorMode = (_e = (_d = fillStyleToColorMode(fillStyle)) != null ? _d : colorMode) != null ? _e : "severity";
return {
fill_style: (_f = fillStyle != null ? fillStyle : colorModeToFillStyle(normalizedColorMode)) != null ? _f : "bands",
color_mode: normalizedColorMode
};
}
function resolveNormalizedBarMode(entityBar, entityConfig, cardBar, cardConfig) {
if ((entityBar == null ? void 0 : entityBar.fill_style) !== void 0 || (entityBar == null ? void 0 : entityBar.color_mode) !== void 0 || entityConfig.color_mode !== void 0) {
return normalizeBarModeConfig(entityBar, entityConfig.color_mode);
}
if ((cardBar == null ? void 0 : cardBar.fill_style) !== void 0 || (cardBar == null ? void 0 : cardBar.color_mode) !== void 0 || (cardConfig == null ? void 0 : cardConfig.color_mode) !== void 0) {
return normalizeBarModeConfig(cardBar, cardConfig == null ? void 0 : cardConfig.color_mode);
}
return normalizeBarModeConfig(null, null);
}
function normalizeGradientStops(input) {
if (!Array.isArray(input)) return input != null ? input : null;
return input.map((stop) => {
if (!stop || typeof stop !== "object" || Array.isArray(stop)) {
return stop;
}
const percentPos = parsePercentLiteral(stop.pos);
const numericPos = Number.isFinite(percentPos) ? percentPos : getFiniteNumber(stop.pos);
return {
...stop,
pos: Number.isFinite(numericPos) ? numericPos : stop.pos
};
});
}
function normalizeNeedleConfig(input, inheritedNeedle = null) {
var _a, _b, _c, _d;
const base = inheritedNeedle ? { show: (_a = inheritedNeedle.show) != null ? _a : false, color: (_b = inheritedNeedle.color) != null ? _b : "#ffffff" } : { show: false, color: "#ffffff" };
if (input === void 0) {
return { ...base };
}
if (typeof input === "boolean") {
return {
show: input,
color: "#ffffff"
};
}
if (input && typeof input === "object" && !Array.isArray(input)) {
return {
show: (_c = input.show) != null ? _c : base.show,
color: (_d = input.color) != null ? _d : base.color
};
}
return { ...base };
}
function normalizeBarConfig(entityConfig, cardConfig) {
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y;
const cardBar = cardConfig == null ? void 0 : cardConfig.bar;
const entityBar = entityConfig == null ? void 0 : entityConfig.bar;
const entityStructuredSegments = entityBar == null ? void 0 : entityBar.segments;
const entityTopLevelSegments = entityConfig.segments;
const entityLegacySeverity = entityConfig.severity;
const cardStructuredSegments = (_a = cardBar == null ? void 0 : cardBar.segments) != null ? _a : null;
const cardTopLevelSegments = (_b = cardConfig == null ? void 0 : cardConfig.segments) != null ? _b : null;
const cardLegacySeverity = (_c = cardConfig == null ? void 0 : cardConfig.severity) != null ? _c : null;
let segments = null;
let segment_space = (_d = cardBar == null ? void 0 : cardBar.segment_space) != null ? _d : "percent";
if (entityStructuredSegments !== void 0 && entityStructuredSegments !== null) {
segments = normalizeGaugeSegments(entityStructuredSegments);
segment_space = "scale";
} else if (entityTopLevelSegments !== void 0 && entityTopLevelSegments !== null) {
segments = normalizeGaugeSegments(entityTopLevelSegments);
segment_space = "scale";
} else if (entityLegacySeverity !== void 0 && entityLegacySeverity !== null) {
segments = normalizeSeverityToSegments(entityLegacySeverity);
segment_space = "percent";
} else if (cardStructuredSegments !== null && cardStructuredSegments !== void 0) {
segments = cardStructuredSegments.map((segment) => ({ ...segment }));
segment_space = (_e = cardBar == null ? void 0 : cardBar.segment_space) != null ? _e : "percent";
} else if (cardTopLevelSegments !== null && cardTopLevelSegments !== void 0) {
segments = normalizeGaugeSegments(cardTopLevelSegments);
segment_space = "scale";
} else if (cardLegacySeverity !== null && cardLegacySeverity !== void 0) {
segments = normalizeSeverityToSegments(cardLegacySeverity);
segment_space = "percent";
}
const structuredAboveTargetColor = (entityConfig == null ? void 0 : entityConfig.target) && typeof entityConfig.target === "object" && !Array.isArray(entityConfig.target) ? (_f = entityConfig.target.when_exceeded) == null ? void 0 : _f.fill_color : void 0;
const inheritedStructuredAboveTargetColor = (cardConfig == null ? void 0 : cardConfig.target) && typeof cardConfig.target === "object" && !Array.isArray(cardConfig.target) ? (_g = cardConfig.target.when_exceeded) == null ? void 0 : _g.fill_color : void 0;
const normalizedMode = resolveNormalizedBarMode(entityBar, entityConfig, cardBar, cardConfig);
return {
fill_style: normalizedMode.fill_style,
color_mode: normalizedMode.color_mode,
needle: normalizeNeedleConfig(entityBar == null ? void 0 : entityBar.needle, cardBar == null ? void 0 : cardBar.needle),
solid_fill: (_i = (_h = entityBar == null ? void 0 : entityBar.solid_fill) != null ? _h : cardBar == null ? void 0 : cardBar.solid_fill) != null ? _i : false,
color: (_m = (_l = (_k = (_j = entityBar == null ? void 0 : entityBar.color) != null ? _j : entityConfig.color) != null ? _k : cardBar == null ? void 0 : cardBar.color) != null ? _l : cardConfig == null ? void 0 : cardConfig.color) != null ? _m : "#4a9eff",
gradient_stops: normalizeGradientStops(
(_q = (_p = (_o = (_n = entityBar == null ? void 0 : entityBar.gradient_stops) != null ? _n : entityConfig.gradient_stops) != null ? _o : cardBar == null ? void 0 : cardBar.gradient_stops) != null ? _p : cardConfig == null ? void 0 : cardConfig.gradient_stops) != null ? _q : null
),
severity: segments,
segments,
segment_space,
animated: (_u = (_t = (_s = (_r = entityBar == null ? void 0 : entityBar.animated) != null ? _r : entityConfig.animated) != null ? _s : cardBar == null ? void 0 : cardBar.animated) != null ? _t : cardConfig == null ? void 0 : cardConfig.animated) != null ? _u : true,
above_target_color: (_y = (_x = (_w = (_v = structuredAboveTargetColor != null ? structuredAboveTargetColor : entityConfig.above_target_color) != null ? _v : cardBar == null ? void 0 : cardBar.above_target_color) != null ? _w : inheritedStructuredAboveTargetColor) != null ? _x : cardConfig == null ? void 0 : cardConfig.above_target_color) != null ? _y : null
};
}
function clampSupportedRowHeight(height) {
return Math.max(24, height);
}
function normalizeLabelPosition(position, fallback = "left") {
const normalized = typeof position === "string" ? position.trim().toLowerCase() : "";
return ["left", "above", "inside", "off", "hero"].includes(normalized) ? normalized : fallback;
}
function normalizeHeroSize(size, fallback = "medium") {
const normalized = typeof size === "string" ? size.trim().toLowerCase() : "";
return ["small", "medium", "large"].includes(normalized) ? normalized : fallback;
}
function normalizeHeroFontSize(value) {
if (!Number.isFinite(value)) return null;
return Math.min(112, Math.max(12, value));
}
function normalizeLayoutConfig(entityConfig, cardConfig) {
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y;
const cardLayout = cardConfig == null ? void 0 : cardConfig.layout;
const entityLayout = entityConfig == null ? void 0 : entityConfig.layout;
const entityLabel = entityLayout == null ? void 0 : entityLayout.label;
const entityHero = entityLayout == null ? void 0 : entityLayout.hero;
const cardLabel = cardLayout == null ? void 0 : cardLayout.label;
const cardHero = cardLayout == null ? void 0 : cardLayout.hero;
const isCardLevelNormalization = !cardConfig;
const rawHeight = (_d = (_c = (_b = (_a = entityLayout == null ? void 0 : entityLayout.height) != null ? _a : entityConfig.height) != null ? _b : cardLayout == null ? void 0 : cardLayout.height) != null ? _c : cardConfig == null ? void 0 : cardConfig.height) != null ? _d : 38;
const heightExplicit = (entityLayout == null ? void 0 : entityLayout.height) !== void 0 || entityConfig._height_explicit === true || !isCardLevelNormalization && entityConfig.height !== void 0 || (cardLayout == null ? void 0 : cardLayout.height_explicit) === true || (cardConfig == null ? void 0 : cardConfig._height_explicit) === true;
const labelPosition = normalizeLabelPosition(
(_h = (_g = (_f = (_e = entityLabel == null ? void 0 : entityLabel.position) != null ? _e : entityConfig.label_position) != null ? _f : cardLabel == null ? void 0 : cardLabel.position) != null ? _g : cardLayout == null ? void 0 : cardLayout.label_position) != null ? _h : cardConfig == null ? void 0 : cardConfig.label_position,
"left"
);
const heroFontSize = labelPosition === "hero" ? normalizeHeroFontSize((_i = entityHero == null ? void 0 : entityHero.value_size) != null ? _i : cardHero == null ? void 0 : cardHero.value_size) : null;
return {
label: {
position: labelPosition,
width: (_n = (_m = (_l = (_k = (_j = entityLabel == null ? void 0 : entityLabel.width) != null ? _j : entityConfig.label_width) != null ? _k : cardLabel == null ? void 0 : cardLabel.width) != null ? _l : cardLayout == null ? void 0 : cardLayout.label_width) != null ? _m : cardConfig == null ? void 0 : cardConfig.label_width) != null ? _n : 100
},
hero: {
size: normalizeHeroSize(
(_y = (_x = (_w = (_v = (_u = (_t = (_s = (_r = (_q = (_p = (_o = entityHero == null ? void 0 : entityHero.size) != null ? _o : entityLabel == null ? void 0 : entityLabel.hero_size) != null ? _p : entityLabel == null ? void 0 : entityLabel.heroSize) != null ? _q : entityConfig.hero_size) != null ? _r : entityConfig.heroSize) != null ? _s : cardHero == null ? void 0 : cardHero.size) != null ? _t : cardLabel == null ? void 0 : cardLabel.hero_size) != null ? _u : cardLabel == null ? void 0 : cardLabel.heroSize) != null ? _v : cardLayout == null ? void 0 : cardLayout.hero_size) != null ? _w : cardLayout == null ? void 0 : cardLayout.heroSize) != null ? _x : cardConfig == null ? void 0 : cardConfig.hero_size) != null ? _y : cardConfig == null ? void 0 : cardConfig.heroSize,
"medium"
),
value_size: heroFontSize
},
height: clampSupportedRowHeight(rawHeight),
height_explicit: heightExplicit
};
}
function normalizeFormattingConfig(entityConfig, cardConfig) {
var _a, _b, _c, _d, _e, _f, _g, _h;
const cardFormatting = cardConfig == null ? void 0 : cardConfig.formatting;
const entityFormatting = entityConfig == null ? void 0 : entityConfig.formatting;
return {
decimal: (_d = (_c = (_b = (_a = entityFormatting == null ? void 0 : entityFormatting.decimal) != null ? _a : entityConfig.decimal) != null ? _b : cardFormatting == null ? void 0 : cardFormatting.decimal) != null ? _c : cardConfig == null ? void 0 : cardConfig.decimal) != null ? _d : null,
unit: (_h = (_g = (_f = (_e = entityFormatting == null ? void 0 : entityFormatting.unit) != null ? _e : entityConfig.unit) != null ? _f : cardFormatting == null ? void 0 : cardFormatting.unit) != null ? _g : cardConfig == null ? void 0 : cardConfig.unit) != null ? _h : null
};
}
function normalizeTargetMarkerConfig(entityConfig, cardConfig) {
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B;
const cardTarget = cardConfig == null ? void 0 : cardConfig.target_marker;
const rawTarget = entityConfig == null ? void 0 : entityConfig.target;
const legacyCardTarget = (cardConfig == null ? void 0 : cardConfig.target) && typeof cardConfig.target === "object" && !Array.isArray(cardConfig.target) ? null : (_a = cardConfig == null ? void 0 : cardConfig.target) != null ? _a : null;
const inheritedTarget = cardTarget != null ? cardTarget : {
enabled: null,
source: normalizeResolvableValue(null, null),
color: (_b = cardConfig == null ? void 0 : cardConfig.target_color) != null ? _b : "#888",
show_label: (_c = cardConfig == null ? void 0 : cardConfig.show_target_label) != null ? _c : false
};
if (rawTarget && typeof rawTarget === "object" && !Array.isArray(rawTarget)) {
return {
enabled: (_e = (_d = normalizeOptionalEnabled(rawTarget.enabled)) != null ? _d : inheritedTarget.enabled) != null ? _e : null,
source: normalizeStructuredResolvableValue(rawTarget.at, inheritedTarget.source, null, { allowPercent: true }),
color: (_g = (_f = rawTarget.color) != null ? _f : entityConfig.target_color) != null ? _g : inheritedTarget.color,
show_label: (_j = (_i = (_h = rawTarget.label) == null ? void 0 : _h.show) != null ? _i : entityConfig.show_target_label) != null ? _j : inheritedTarget.show_label
};
}
const value = (_o = (_n = (_l = entityConfig.target) != null ? _l : (_k = inheritedTarget.source) == null ? void 0 : _k.fixed) != null ? _n : (_m = inheritedTarget.source) == null ? void 0 : _m.value) != null ? _o : legacyCardTarget;
const entity = (_s = (_r = (_q = entityConfig.target_entity) != null ? _q : (_p = inheritedTarget.source) == null ? void 0 : _p.entity) != null ? _r : cardConfig == null ? void 0 : cardConfig.target_entity) != null ? _s : null;
const percent = entityConfig.target === void 0 && entityConfig.target_entity === void 0 ? (_u = (_t = inheritedTarget.source) == null ? void 0 : _t.percent) != null ? _u : null : null;
return {
enabled: (_v = inheritedTarget.enabled) != null ? _v : null,
source: normalizeResolvableValue(value, entity, percent),
color: (_y = (_x = (_w = entityConfig.target_color) != null ? _w : inheritedTarget.color) != null ? _x : cardConfig == null ? void 0 : cardConfig.target_color) != null ? _y : "#888",
show_label: (_B = (_A = (_z = entityConfig.show_target_label) != null ? _z : inheritedTarget.show_label) != null ? _A : cardConfig == null ? void 0 : cardConfig.show_target_label) != null ? _B : false
};
}
function normalizePeakMarkerConfig(entityConfig, cardConfig) {
var _a, _b, _c, _d, _e, _f, _g, _h;
const cardPeak = cardConfig == null ? void 0 : cardConfig.peak_marker;
const entityPeak = entityConfig == null ? void 0 : entityConfig.peak;
return {
show: (_d = (_c = (_b = (_a = entityPeak == null ? void 0 : entityPeak.enabled) != null ? _a : entityConfig.show_peak) != null ? _b : cardPeak == null ? void 0 : cardPeak.show) != null ? _c : cardConfig == null ? void 0 : cardConfig.show_peak) != null ? _d : false,
color: (_h = (_g = (_f = (_e = entityPeak == null ? void 0 : entityPeak.color) != null ? _e : entityConfig.peak_color) != null ? _f : cardPeak == null ? void 0 : cardPeak.color) != null ? _g : cardConfig == null ? void 0 : cardConfig.peak_color) != null ? _h : "#888"
};
}
function normalizeEntityConfig(entityConfig, cardConfig) {
var _a;
const normalizedEntity = {
...entityConfig,
_normalized: true,
entity: entityConfig.entity,
name: (_a = entityConfig.name) != null ? _a : null,
icon: entityConfig.icon
};
normalizedEntity.layout = normalizeLayoutConfig(entityConfig, cardConfig);
normalizedEntity.scale = normalizeScaleConfig(entityConfig, cardConfig);
normalizedEntity.bar = normalizeBarConfig(entityConfig, cardConfig);
normalizedEntity.baseline = normalizeBaselineConfig(entityConfig, cardConfig);
normalizedEntity.formatting = normalizeFormattingConfig(entityConfig, cardConfig);
normalizedEntity.target_marker = normalizeTargetMarkerConfig(entityConfig, cardConfig);
normalizedEntity.peak_marker = normalizePeakMarkerConfig(entityConfig, cardConfig);
normalizedEntity.min = normalizedEntity.scale.min.fixed;
normalizedEntity.min_entity = normalizedEntity.scale.min.entity;
normalizedEntity.max = normalizedEntity.scale.max.fixed;
normalizedEntity.max_entity = normalizedEntity.scale.max.entity;
normalizedEntity.height = normalizedEntity.layout.height;
normalizedEntity.label_position = normalizedEntity.layout.label.position;
normalizedEntity.label_width = normalizedEntity.layout.label.width;
normalizedEntity.color_mode = normalizedEntity.bar.color_mode;
normalizedEntity.fill_style = normalizedEntity.bar.fill_style;
normalizedEntity.solid_fill = normalizedEntity.bar.solid_fill;
normalizedEntity.color = normalizedEntity.bar.color;
normalizedEntity.gradient_stops = normalizedEntity.bar.gradient_stops;
normalizedEntity.severity = normalizedEntity.bar.severity;
normalizedEntity.animated = normalizedEntity.bar.animated;
normalizedEntity.above_target_color = normalizedEntity.bar.above_target_color;
normalizedEntity.decimal = normalizedEntity.formatting.decimal;
normalizedEntity.unit = normalizedEntity.formatting.unit;
normalizedEntity.target = normalizedEntity.target_marker.source.fixed;
normalizedEntity.target_entity = normalizedEntity.target_marker.source.entity;
normalizedEntity.target_color = normalizedEntity.target_marker.color;
normalizedEntity.show_target_label = normalizedEntity.target_marker.show_label;
normalizedEntity.show_peak = normalizedEntity.peak_marker.show;
normalizedEntity.peak_color = normalizedEntity.peak_marker.color;
return normalizedEntity;
}
function normalizeCardConfig(rawConfig) {
var _a;
const baseConfig = {
title: "",
label_position: "left",
color_mode: "severity",
color: "#4a9eff",
animated: true,
show_peak: false,
peak_color: "#888",
target: null,
target_entity: null,
target_color: "#888",
show_target_label: false,
above_target_color: null,
baseline: null,
decimal: null,
gradient_stops: null,
min: 0,
min_entity: null,
max: 100,
max_entity: null,
height: 38,
label_width: 100,
severity: [
{ from: 0, to: 33, color: "#4CAF50" },
{ from: 33, to: 75, color: "#FF9800" },
{ from: 75, to: 100, color: "#F44336" }
],
...rawConfig
};
baseConfig._height_explicit = ((_a = rawConfig == null ? void 0 : rawConfig.layout) == null ? void 0 : _a.height) !== void 0 || (rawConfig == null ? void 0 : rawConfig.height) !== void 0;
if (baseConfig.entity && !baseConfig.entities) {
baseConfig.entities = [{
entity: baseConfig.entity,
...baseConfig.name !== void 0 ? { name: baseConfig.name } : {}
}];
}
baseConfig.entities = baseConfig.entities.map(
(e) => typeof e === "string" ? { entity: e } : e
);
const normalizedCard = {
...baseConfig,
_normalized: true
};
normalizedCard.layout = normalizeLayoutConfig(baseConfig, null);
normalizedCard.scale = normalizeScaleConfig(baseConfig, null);
normalizedCard.bar = normalizeBarConfig(baseConfig, null);
normalizedCard.baseline = normalizeBaselineConfig(baseConfig, null);
normalizedCard.formatting = normalizeFormattingConfig(baseConfig, null);
normalizedCard.target_marker = normalizeTargetMarkerConfig(baseConfig, null);
normalizedCard.peak_marker = normalizePeakMarkerConfig(baseConfig, null);
normalizedCard.entities = baseConfig.entities.map(
(entityCfg) => normalizeEntityConfig(entityCfg, normalizedCard)
);
return normalizedCard;
}
var init_normalize = __esm({
"src/config/normalize.js"() {
}
});
// src/config/resolve.js
function getEntityNumericValue(hass, entityId) {
var _a;
if (!entityId || !((_a = hass == null ? void 0 : hass.states) == null ? void 0 : _a[entityId])) return null;
const raw = hass.states[entityId].state;
const num = parseFloat(raw);
return Number.isFinite(num) ? num : null;
}
function getNumericValue(hass, value, entityId = null) {
const entityValue = getEntityNumericValue(hass, entityId);
if (entityValue !== null) return entityValue;
if (value === null || value === void 0 || value === "") return null;
const num = parseFloat(value);
return Number.isFinite(num) ? num : null;
}
function resolvePercentValue(percent, minValue, maxValue) {
if (!Number.isFinite(percent)) return null;
const safeMin = Number.isFinite(minValue) ? minValue : 0;
const safeMax = Number.isFinite(maxValue) ? maxValue : 100;
return safeMin + percent / 100 * (safeMax - safeMin);
}
function getNormalizedResolvableNumericValue(hass, resolvable, minValue = null, maxValue = null) {
var _a;
if (!resolvable) return null;
const entityValue = getEntityNumericValue(hass, resolvable.entity);
if (entityValue !== null) return entityValue;
const fixedValue = getNumericValue(hass, (_a = resolvable.fixed) != null ? _a : resolvable.value, null);
if (fixedValue !== null) return fixedValue;
if (Number.isFinite(resolvable.percent)) {
return resolvePercentValue(resolvable.percent, minValue, maxValue);
}
return null;
}
var init_resolve = __esm({
"src/config/resolve.js"() {
init_normalize();
}
});
// src/config/validate.js
function createDiagnostic(code, message, path, entity = null) {
return { code, message, path, entity };
}
function getStaticFixedValue(resolvable) {
var _a;
if (!resolvable || resolvable.entity || Number.isFinite(resolvable.percent)) {
return null;
}
return getFiniteNumber((_a = resolvable.fixed) != null ? _a : resolvable.value);
}
function addWarning(diagnostics, code, message, path, entity = null) {
diagnostics.warnings.push(createDiagnostic(code, message, path, entity));
}
function validateScaleBounds(diagnostics, scale, path, entity = null) {
const min = getStaticFixedValue(scale == null ? void 0 : scale.min);
const max = getStaticFixedValue(scale == null ? void 0 : scale.max);
if (Number.isFinite(min) && Number.isFinite(max) && min > max) {
addWarning(diagnostics, "scale.min_gt_max", "Scale minimum is greater than maximum.", path, entity);
}
return { min, max };
}
function validateTargetRange(diagnostics, config, scaleBounds, path, entity = null) {
var _a;
const target = getStaticFixedValue((_a = config == null ? void 0 : config.target_marker) == null ? void 0 : _a.source);
if (!Number.isFinite(target)) return;
const { min, max } = scaleBounds;
if (Number.isFinite(min) && Number.isFinite(max) && (target < min || target > max)) {
addWarning(diagnostics, "target.outside_scale", "Fixed target value is outside the fixed scale range.", path, entity);
}
}
function validateBaselineRange(diagnostics, config, scaleBounds, path, entity = null) {
var _a;
const baseline = getStaticFixedValue((_a = config == null ? void 0 : config.baseline) == null ? void 0 : _a.at);
if (!Number.isFinite(baseline)) return;
const { min, max } = scaleBounds;
if (Number.isFinite(min) && Number.isFinite(max) && (baseline < min || baseline > max)) {
addWarning(diagnostics, "baseline.outside_scale", "Fixed baseline value is outside the fixed scale range.", path, entity);
}
}
function hasConfiguredResolvableValue(resolvable) {
var _a;
return !!resolvable && (Number.isFinite(getFiniteNumber((_a = resolvable.fixed) != null ? _a : resolvable.value)) || Number.isFinite(resolvable.percent) || !!resolvable.entity);
}
function validateBaselineSuppressesNeedle(diagnostics, config, path, entity = null) {
var _a, _b, _c, _d;
const needleEnabled = ((_b = (_a = config == null ? void 0 : config.bar) == null ? void 0 : _a.needle) == null ? void 0 : _b.show) === true;
const baselineConfigured = ((_c = config == null ? void 0 : config.baseline) == null ? void 0 : _c.enabled) !== false && hasConfiguredResolvableValue((_d = config == null ? void 0 : config.baseline) == null ? void 0 : _d.at);
if (needleEnabled && baselineConfigured) {
addWarning(
diagnostics,
"baseline-suppresses-needle",
"Baseline rendering suppresses the needle marker.",
path,
entity
);
}
}
function getStaticSegmentBound(boundary) {
var _a;
if (!boundary || boundary.entity || Number.isFinite(boundary.percent)) return null;
return getFiniteNumber((_a = boundary.fixed) != null ? _a : boundary.value);
}
function validateSegments(diagnostics, segments, scaleBounds, path, entity = null) {
if (!Array.isArray(segments) || !segments.length) return;
const staticSegments = [];
const { min, max } = scaleBounds;
for (let index = 0; index < segments.length; index += 1) {
const segment = segments[index];
const from = getStaticSegmentBound(segment == null ? void 0 : segment.from);
const to = getStaticSegmentBound(segment == null ? void 0 : segment.to);
const segmentPath = `${path}.segments[${index}]`;
if (Number.isFinite(from) && Number.isFinite(to) && from > to) {
addWarning(diagnostics, "segments.from_gt_to", "Segment start is greater than segment end.", segmentPath, entity);
}
if (Number.isFinite(min) && Number.isFinite(max)) {
if (Number.isFinite(from) && (from < min || from > max)) {
addWarning(diagnostics, "segments.outside_scale", "Segment boundary is outside the fixed scale range.", segmentPath, entity);
}
if (Number.isFinite(to) && (to < min || to > max)) {
addWarning(diagnostics, "segments.outside_scale", "Segment boundary is outside the fixed scale range.", segmentPath, entity);
}
}
if (Number.isFinite(from) && Number.isFinite(to)) {
staticSegments.push({ from, to, path: segmentPath });
}
}
const sorted = [...staticSegments].sort((a, b) => a.from - b.from);
for (let index = 1; index < sorted.length; index += 1) {
const previous = sorted[index - 1];
const current = sorted[index];
if (current.from < previous.to) {
addWarning(diagnostics, "segments.overlap", "Fixed segments overlap.", current.path, entity);
}
}
}
function validateGradientStops(diagnostics, stops, path, entity = null) {
var _a;
if (!Array.isArray(stops)) return;
const seenPositions = /* @__PURE__ */ new Set();
for (let index = 0; index < stops.length; index += 1) {
const pos = getFiniteNumber((_a = stops[index]) == null ? void 0 : _a.pos);
const stopPath = `${path}.gradient_stops[${index}]`;
if (Number.isFinite(pos) && (pos < 0 || pos > 100)) {
addWarning(
diagnostics,
"gradient_stops.outside_range",
"Gradient stop position is outside 0..100.",
stopPath,
entity
);
}
if (Number.isFinite(pos)) {
if (seenPositions.has(pos)) {
addWarning(
diagnostics,
"duplicate-gradient-stop-position",
"Multiple gradient stops use the same position value.",
stopPath,
entity
);
} else {
seenPositions.add(pos);
}
}
}
}
function validateConfigScope(diagnostics, config, path, entity = null) {
var _a, _b;
const scaleBounds = validateScaleBounds(diagnostics, config == null ? void 0 : config.scale, path, entity);
validateTargetRange(diagnostics, config, scaleBounds, path, entity);
validateBaselineRange(diagnostics, config, scaleBounds, path, entity);
validateBaselineSuppressesNeedle(diagnostics, config, path, entity);
validateSegments(diagnostics, (_a = config == null ? void 0 : config.bar) == null ? void 0 : _a.segments, scaleBounds, `${path}.bar`, entity);
validateGradientStops(diagnostics, (_b = config == null ? void 0 : config.bar) == null ? void 0 : _b.gradient_stops, `${path}.bar`, entity);
}
function validateNormalizedConfig(config) {
var _a;
const diagnostics = {
warnings: [],
errors: []
};
if (!config || typeof config !== "object") {
return diagnostics;
}
validateConfigScope(diagnostics, config, "card");
const seenEntities = /* @__PURE__ */ new Set();
const entities = Array.isArray(config.entities) ? config.entities : [];
for (let index = 0; index < entities.length; index += 1) {
const entityConfig = entities[index];
const entityId = (_a = entityConfig == null ? void 0 : entityConfig.entity) != null ? _a : null;
const path = `entities[${index}]`;
if (!entityId) {
addWarning(diagnostics, "entities.missing_entity", "Entity row is missing an entity id.", path, null);
continue;
}
if (seenEntities.has(entityId)) {
addWarning(diagnostics, "entities.duplicate_entity", "Duplicate entity id in the same card config.", path, entityId);
} else {
seenEntities.add(entityId);
}
validateConfigScope(diagnostics, entityConfig, path, entityId);
}
return diagnostics;
}
var init_validate = __esm({
"src/config/validate.js"() {
init_normalize();
}
});
// src/view-model/row-view-model.js
function getDefaultEntityIcon(stateObj, entityId = "") {
var _a, _b, _c;
const deviceClass = String((_b = (_a = stateObj == null ? void 0 : stateObj.attributes) == null ? void 0 : _a.device_class) != null ? _b : "").trim();
if (deviceClass) {
const deviceClassIcons = {
apparent_power: "mdi:flash",
battery: "mdi:battery",
carbon_dioxide: "mdi:molecule-co2",
current: "mdi:current-ac",
energy: "mdi:lightning-bolt",
gas: "mdi:meter-gas",
humidity: "mdi:water-percent",
monetary: "mdi:cash",
power: "mdi:flash",
pressure: "mdi:gauge",
temperature: "mdi:thermometer",
voltage: "mdi:sine-wave",
water: "mdi:water",
weight: "mdi:weight",
wind_speed: "mdi:weather-windy"
};
if (deviceClassIcons[deviceClass]) {
return deviceClassIcons[deviceClass];
}
}
const domain = String(entityId || "").split(".")[0];
const domainIcons = {
sensor: "mdi:eye",
binary_sensor: "mdi:radiobox-marked",
switch: "mdi:toggle-switch-variant",
light: "mdi:lightbulb"
};
return (_c = domainIcons[domain]) != null ? _c : null;
}
function toScalePct(value, minValue, maxValue) {
if (!Number.isFinite(value)) return null;
const safeMin = Number.isFinite(minValue) ? minValue : 0;
const safeMax = Number.isFinite(maxValue) ? maxValue : 100;
const range = safeMax - safeMin || 1;
return Math.min(100, Math.max(0, (value - safeMin) / range * 100));
}
function formatNumericDisplay(rawVal, decimal = null) {
if (!Number.isFinite(rawVal)) return String(rawVal);
if (decimal !== null) {
return parseFloat(rawVal.toFixed(decimal)).toLocaleString();
}
return rawVal.toLocaleString();
}
function isTightUnit(unit) {
return ["h", "m", "s"].includes(String(unit || "").trim());
}
function formatDisplayWithUnit(display, unit) {
if (!unit) return String(display);
const cleanUnit = String(unit);
return `${display}${isTightUnit(cleanUnit) ? "" : " "}${cleanUnit}`;
}
function parseColorToRgb(color) {
const value = String(color || "").trim();
if (!value) return null;
const hexMatch = value.match(/^#([0-9a-f]{3}|[0-9a-f]{6})$/i);
if (hexMatch) {
const hex = hexMatch[1];
const full = hex.length === 3 ? hex.split("").map((char) => char + char).join("") : hex;
return {
r: parseInt(full.slice(0, 2), 16),
g: parseInt(full.slice(2, 4), 16),
b: parseInt(full.slice(4, 6), 16)
};
}
const rgbMatch = value.match(/^rgba?\(([^)]+)\)$/i);
if (rgbMatch) {
const parts = rgbMatch[1].split(",").map((part) => part.trim());
if (parts.length >= 3) {
return {
r: Math.max(0, Math.min(255, parseFloat(parts[0]))),
g: Math.max(0, Math.min(255, parseFloat(parts[1]))),
b: Math.max(0, Math.min(255, parseFloat(parts[2])))
};
}
}
return null;
}
function getNeedleBorderColor(color) {
const rgb = parseColorToRgb(color);
if (!rgb) return "#000000";
const toLinear = (channel) => {
const srgb = channel / 255;
return srgb <= 0.04045 ? srgb / 12.92 : ((srgb + 0.055) / 1.055) ** 2.4;
};
const luminance = 0.2126 * toLinear(rgb.r) + 0.7152 * toLinear(rgb.g) + 0.0722 * toLinear(rgb.b);
return luminance < 0.22 ? "#ffffff" : "#000000";
}
function getNeedleState(entityConfig, numericValue, minValue, maxValue, baselinePercent) {
var _a, _b, _c;
const needle = (_a = entityConfig == null ? void 0 : entityConfig.bar) == null ? void 0 : _a.needle;
if (!(needle == null ? void 0 : needle.show) || Number.isFinite(baselinePercent) || !Number.isFinite(numericValue)) {
const color2 = (_b = needle == null ? void 0 : needle.color) != null ? _b : "#ffffff";
return {
show: false,
percent: null,
pct: null,
color: color2,
borderColor: getNeedleBorderColor(color2),
edge: "middle"
};
}
const color = (_c = needle.color) != null ? _c : "#ffffff";
const percent = Math.min(100, Math.max(0, toScalePct(numericValue, minValue, maxValue)));
return {
show: true,
percent,
pct: percent,
color,
borderColor: getNeedleBorderColor(color),
edge: percent <= 0 ? "left" : percent >= 100 ? "right" : "middle"
};
}
function getPeakState(entityId, numericValue, minValue, maxValue, peaks, peakEnabled) {
if (!peakEnabled || !Number.isFinite(numericValue)) {
return {
value: null,
percent: null,
display: null,
visible: false
};
}
const existingPeak = getFiniteNumber(peaks == null ? void 0 : peaks[entityId]);
const peakValue = Number.isFinite(existingPeak) ? Math.max(existingPeak, numericValue) : numericValue;
return {
value: peakValue,
percent: toScalePct(peakValue, minValue, maxValue),
visible: true
};
}
function buildRowViewModel(options) {
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F, _G, _H, _I, _J, _K, _L, _M, _N, _O, _P, _Q, _R, _S;
const {
hass,
cardConfig,
entityConfig,
entityState,
peaks
} = options;
void cardConfig;
const entityId = (_a = entityConfig == null ? void 0 : entityConfig.entity) != null ? _a : null;
const rawState = (_b = entityState == null ? void 0 : entityState.state) != null ? _b : "";
const numericValue = getFiniteNumber(rawState);
const rawUnit = (_d = (_c = entityState == null ? void 0 : entityState.attributes) == null ? void 0 : _c.unit_of_measurement) != null ? _d : "";
const displayUnit = numericValue !== null ? (_g = (_f = (_e = entityConfig == null ? void 0 : entityConfig.formatting) == null ? void 0 : _e.unit) != null ? _f : rawUnit) != null ? _g : "" : "";
const min = getNormalizedResolvableNumericValue(hass, (_h = entityConfig == null ? void 0 : entityConfig.scale) == null ? void 0 : _h.min);
const max = getNormalizedResolvableNumericValue(hass, (_i = entityConfig == null ? void 0 : entityConfig.scale) == null ? void 0 : _i.max);
const safeMin = Number.isFinite(min) ? min : 0;
const safeMax = Number.isFinite(max) ? max : 100;
const percent = numericValue !== null ? toScalePct(numericValue, safeMin, safeMax) : 0;
const displayValue = numericValue === null ? rawState : formatNumericDisplay(numericValue, (_k = (_j = entityConfig == null ? void 0 : entityConfig.formatting) == null ? void 0 : _j.decimal) != null ? _k : null);
const targetValue = ((_l = entityConfig == null ? void 0 : entityConfig.target_marker) == null ? void 0 : _l.enabled) === false ? null : getNormalizedResolvableNumericValue(hass, (_m = entityConfig == null ? void 0 : entityConfig.target_marker) == null ? void 0 : _m.source, safeMin, safeMax);
const targetPercent = targetValue !== null ? toScalePct(targetValue, safeMin, safeMax) : null;
const targetVisible = targetValue !== null;
const targetDisplay = targetValue !== null ? formatDisplayWithUnit(
formatNumericDisplay(targetValue, (_o = (_n = entityConfig == null ? void 0 : entityConfig.formatting) == null ? void 0 : _n.decimal) != null ? _o : null),
(_r = (_q = (_p = entityConfig == null ? void 0 : entityConfig.formatting) == null ? void 0 : _p.unit) != null ? _q : rawUnit) != null ? _r : ""
) : null;
const baselineValue = ((_s = entityConfig == null ? void 0 : entityConfig.baseline) == null ? void 0 : _s.enabled) === false ? null : getNormalizedResolvableNumericValue(hass, (_t = entityConfig == null ? void 0 : entityConfig.baseline) == null ? void 0 : _t.at, safeMin, safeMax);
const baselinePercent = Number.isFinite(baselineValue) ? toScalePct(baselineValue, safeMin, safeMax) : null;
const baselineVisible = Number.isFinite(baselineValue);
const peakState = getPeakState(
entityId,
numericValue,
safeMin,
safeMax,
peaks,
((_u = entityConfig == null ? void 0 : entityConfig.peak_marker) == null ? void 0 : _u.show) === true
);
const peakDisplay = peakState.visible ? formatNumericDisplay(peakState.value, (_w = (_v = entityConfig == null ? void 0 : entityConfig.formatting) == null ? void 0 : _v.decimal) != null ? _w : null) : null;
return {
entityId,
name: (_z = (_y = entityConfig == null ? void 0 : entityConfig.name) != null ? _y : (_x = entityState == null ? void 0 : entityState.attributes) == null ? void 0 : _x.friendly_name) != null ? _z : entityId,
icon: (entityConfig == null ? void 0 : entityConfig.icon) === false ? false : (_C = (_B = entityConfig == null ? void 0 : entityConfig.icon) != null ? _B : (_A = entityState == null ? void 0 : entityState.attributes) == null ? void 0 : _A.icon) != null ? _C : getDefaultEntityIcon(entityState, entityId),
state: rawState,
numericValue,
rawUnit,
displayUnit,
min: safeMin,
max: safeMax,
percent,
displayValue,
unit: displayUnit,
barColor: (_E = (_D = entityConfig == null ? void 0 : entityConfig.bar) == null ? void 0 : _D.color) != null ? _E : null,
fillStyle: (_G = (_F = entityConfig == null ? void 0 : entityConfig.bar) == null ? void 0 : _F.fill_style) != null ? _G : null,
target: targetValue,
targetPercent,
targetDisplay,
targetVisible,
baseline: baselineValue,
baselinePercent,
baselineVisible,
peak: peakState.value,
peakPercent: peakState.percent,
peakDisplay,
peakVisible: peakState.visible,
segments: (_I = (_H = entityConfig == null ? void 0 : entityConfig.bar) == null ? void 0 : _H.segments) != null ? _I : null,
gradientStops: (_K = (_J = entityConfig == null ? void 0 : entityConfig.bar) == null ? void 0 : _J.gradient_stops) != null ? _K : null,
needle: getNeedleState(entityConfig, numericValue, safeMin, safeMax, baselinePercent),
classes: {
labelPosition: (_N = (_M = (_L = entityConfig == null ? void 0 : entityConfig.layout) == null ? void 0 : _L.label) == null ? void 0 : _M.position) != null ? _N : "left",
animated: ((_O = entityConfig == null ? void 0 : entityConfig.bar) == null ? void 0 : _O.animated) !== false
},
attributes: {
entity: entityId,
baseHeight: (_Q = (_P = entityConfig == null ? void 0 : entityConfig.layout) == null ? void 0 : _P.height) != null ? _Q : 38,
heightExplicit: ((_R = entityConfig == null ? void 0 : entityConfig.layout) == null ? void 0 : _R.height_explicit) === true,
barAnimated: ((_S = entityConfig == null ? void 0 : entityConfig.bar) == null ? void 0 : _S.animated) !== false
}
};
}
var init_row_view_model = __esm({
"src/view-model/row-view-model.js"() {
init_resolve();
init_normalize();
}
});
// src/utils/dom.js
function escapeHtml(value) {
if (value == null) return "";
return String(value).replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
}
var init_dom = __esm({
"src/utils/dom.js"() {
}
});
// src/card/SensorBarCard.js
var SensorBarCard;
var init_SensorBarCard = __esm({
"src/card/SensorBarCard.js"() {
init_normalize();
init_resolve();
init_validate();
init_row_view_model();
init_dom();
SensorBarCard = class extends HTMLElement {
static getConfigElement() {
return document.createElement("sensor-bar-card-plus-editor");
}
constructor() {
super();
this.attachShadow({ mode: "open" });
this._baseDomReady = false;
this._config = {};
this._diagnostics = { warnings: [], errors: [] };
this._lastDiagnosticsSignature = null;
this._hass = null;
this._peaks = {};
this._rendered = false;
this._resizeObserver = null;
this._densityPassScheduled = false;
this._densityPassDirty = false;
this._densityPassFrame = null;
this._densityPassRetries = 0;
this._boundWindowResize = () => this._schedulePostLayoutDensityPass();
this._ensureBaseDom();
}
connectedCallback() {
window.addEventListener("resize", this._boundWindowResize, { passive: true });
this._schedulePostLayoutDensityPass();
}
disconnectedCallback() {
window.removeEventListener("resize", this._boundWindowResize);
this._disconnectResizeObserver();
if (this._densityPassFrame) {
cancelAnimationFrame(this._densityPassFrame);
this._densityPassFrame = null;
}
this._densityPassScheduled = false;
this._densityPassDirty = false;
}
setConfig(config) {
if (!config.entities && !config.entity) {
throw new Error("You must define entities or entity");
}
this._rendered = false;
this._config = this.normalizeCardConfig(config);
const activeEntityIds = new Set(
(this._config.entities || []).map((entityConfig) => entityConfig.entity)
);
for (const entityId of Object.keys(this._peaks)) {
if (!activeEntityIds.has(entityId)) {
delete this._peaks[entityId];
}
}
this._diagnostics = validateNormalizedConfig(this._config);
this._logDiagnostics();
this._render();
}
_logDiagnostics() {
var _a;
const diagnostics = (_a = this._diagnostics) != null ? _a : { warnings: [], errors: [] };
const signature = JSON.stringify(diagnostics);
if (signature === this._lastDiagnosticsSignature) return;
this._lastDiagnosticsSignature = signature;
diagnostics.warnings.forEach((diagnostic) => {
console.warn(`[sensor-bar-card-plus] ${diagnostic.message}`, diagnostic);
});
diagnostics.errors.forEach((diagnostic) => {
console.warn(`[sensor-bar-card-plus] ${diagnostic.message}`, diagnostic);
});
}
// The normalized model is internal only. It preserves today's flat YAML
// while giving future work one structured compatibility layer to build on.
normalizeCardConfig(rawConfig) {
return normalizeCardConfig(rawConfig);
}
normalizeEntityConfig(entityConfig, cardConfig) {
return normalizeEntityConfig(entityConfig, cardConfig);
}
// Internal resolvable shape preserves today's flat `value + *_entity`
// behavior while canonicalizing the normalized form to `fixed + entity`.
normalizeResolvableValue(value, entityValue, percentValue = null) {
return normalizeResolvableValue(value, entityValue, percentValue);
}
_looksLikeEntityId(value) {
return looksLikeEntityId(value);
}
_parsePercentLiteral(value) {
return parsePercentLiteral(value);
}
_getFiniteNumber(value) {
return getFiniteNumber(value);
}
normalizeStructuredResolvableValue(input, inheritedResolvable = null, defaultValue = null, options = {}) {
return normalizeStructuredResolvableValue(input, inheritedResolvable, defaultValue, options);
}
normalizeBaselineDirectionConfig(input, inheritedDirection = null) {
return normalizeBaselineDirectionConfig(input, inheritedDirection);
}
normalizeBaselineConfig(entityConfig, cardConfig) {
return normalizeBaselineConfig(entityConfig, cardConfig);
}
inferSegmentEndValues(segments, fallbackEnd = null) {
const sorted = [...segments].sort((a, b) => a.from - b.from);
return sorted.map((segment, index) => {
var _a;
let to = Number.isFinite(segment.to) ? segment.to : null;
if (!Number.isFinite(to) && index < sorted.length - 1) {
to = sorted[index + 1].from;
}
if (!Number.isFinite(to) && Number.isFinite(fallbackEnd)) {
to = fallbackEnd;
}
return {
from: segment.from,
to,
color: segment.color,
label: (_a = segment.label) != null ? _a : null
};
});
}
normalizeSeverityToSegments(input) {
return normalizeSeverityToSegments(input);
}
_hasResolvableMagnitude(resolvable) {
return !!resolvable && (Number.isFinite(this._getFiniteNumber(resolvable.fixed)) || Number.isFinite(resolvable.percent));
}
normalizeGaugeSegments(input) {
return normalizeGaugeSegments(input);
}
normalizeScaleBound(entityConfig, cardConfig, key, defaultValue) {
return normalizeScaleBound(entityConfig, cardConfig, key, defaultValue);
}
normalizeScaleConfig(entityConfig, cardConfig) {
return normalizeScaleConfig(entityConfig, cardConfig);
}
_fillStyleToColorMode(fillStyle) {
return fillStyleToColorMode(fillStyle);
}
_colorModeToFillStyle(colorMode) {
return colorModeToFillStyle(colorMode);
}
_normalizeBarModeConfig(barConfig = null, flatColorMode = null) {
return normalizeBarModeConfig(barConfig, flatColorMode);
}
_resolveNormalizedBarMode(entityBar, entityConfig, cardBar, cardConfig) {
return resolveNormalizedBarMode(entityBar, entityConfig, cardBar, cardConfig);
}
_normalizeGradientStops(input) {
return normalizeGradientStops(input);
}
normalizeNeedleConfig(input, inheritedNeedle = null) {
return normalizeNeedleConfig(input, inheritedNeedle);
}
normalizeBarConfig(entityConfig, cardConfig) {
return normalizeBarConfig(entityConfig, cardConfig);
}
normalizeLayoutConfig(entityConfig, cardConfig) {
return normalizeLayoutConfig(entityConfig, cardConfig);
}
_clampSupportedRowHeight(height) {
return clampSupportedRowHeight(height);
}
normalizeFormattingConfig(entityConfig, cardConfig) {
return normalizeFormattingConfig(entityConfig, cardConfig);
}
normalizeTargetMarkerConfig(entityConfig, cardConfig) {
return normalizeTargetMarkerConfig(entityConfig, cardConfig);
}
normalizePeakMarkerConfig(entityConfig, cardConfig) {
return normalizePeakMarkerConfig(entityConfig, cardConfig);
}
_normalizeOptionalEnabled(value) {
return normalizeOptionalEnabled(value);
}
set hass(hass) {
const oldHass = this._hass;
this._hass = hass;
if (!oldHass) {
this._update();
return;
}
if (this._shouldUpdate(oldHass, hass)) {
this._update();
}
}
// Merge global config with per-entity overrides
_resolve(entityCfg) {
var _a, _b, _c, _d, _e, _f, _g;
const ecfg = (entityCfg == null ? void 0 : entityCfg._normalized) ? entityCfg : this.normalizeEntityConfig(entityCfg, this._config);
const stateObj = (_c = (_b = (_a = this._hass) == null ? void 0 : _a.states) == null ? void 0 : _b[ecfg.entity]) != null ? _c : null;
return {
...ecfg,
icon: ecfg.icon === false ? false : (_f = (_e = ecfg.icon) != null ? _e : (_d = stateObj == null ? void 0 : stateObj.attributes) == null ? void 0 : _d.icon) != null ? _f : this._getDefaultEntityIcon(stateObj, ecfg.entity),
name: (_g = ecfg.name) != null ? _g : null
};
}
_getDefaultEntityIcon(stateObj, entityId = "") {
var _a, _b, _c;
const deviceClass = String((_b = (_a = stateObj == null ? void 0 : stateObj.attributes) == null ? void 0 : _a.device_class) != null ? _b : "").trim();
if (deviceClass) {
const deviceClassIcons = {
apparent_power: "mdi:flash",
battery: "mdi:battery",
carbon_dioxide: "mdi:molecule-co2",
current: "mdi:current-ac",
energy: "mdi:lightning-bolt",
gas: "mdi:meter-gas",
humidity: "mdi:water-percent",
monetary: "mdi:cash",
power: "mdi:flash",
pressure: "mdi:gauge",
temperature: "mdi:thermometer",
voltage: "mdi:sine-wave",
water: "mdi:water",
weight: "mdi:weight",
wind_speed: "mdi:weather-windy"
};
if (deviceClassIcons[deviceClass]) {
return deviceClassIcons[deviceClass];
}
}
const domain = String(entityId || "").split(".")[0];
const domainIcons = {
sensor: "mdi:eye",
binary_sensor: "mdi:radiobox-marked",
switch: "mdi:toggle-switch-variant",
light: "mdi:lightbulb"
};
return (_c = domainIcons[domain]) != null ? _c : null;
}
_shouldUpdate(oldHass, newHass) {
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
if (!this._config || !this._config.entities) return true;
for (const entityCfg of this._config.entities) {
const ecfg = this._resolve(entityCfg);
const entitiesToWatch = [
entityCfg.entity,
(_b = (_a = ecfg.scale) == null ? void 0 : _a.min) == null ? void 0 : _b.entity,
(_d = (_c = ecfg.scale) == null ? void 0 : _c.max) == null ? void 0 : _d.entity,
(_f = (_e = ecfg.baseline) == null ? void 0 : _e.at) == null ? void 0 : _f.entity,
(_h = (_g = ecfg.target_marker) == null ? void 0 : _g.source) == null ? void 0 : _h.entity
].filter(Boolean);
for (const ent of entitiesToWatch) {
const oldState = (_i = oldHass.states[ent]) != null ? _i : null;
const newState = (_j = newHass.states[ent]) != null ? _j : null;
if (oldState !== newState) {
return true;
}
}
}
return false;
}
_setStyleIfChanged(el, prop, value) {
var _a, _b;
if (!(el == null ? void 0 : el.style)) return false;
const nextValue = value == null ? "" : String(value);
if (prop.startsWith("--")) {
const currentValue2 = typeof el.style.getPropertyValue === "function" ? el.style.getPropertyValue(prop) : (_a = el.style[prop]) != null ? _a : "";
if (currentValue2 === nextValue) return false;
if (typeof el.style.setProperty === "function") {
el.style.setProperty(prop, nextValue);
} else {
el.style[prop] = nextValue;
}
return true;
}
const currentValue = (_b = el.style[prop]) != null ? _b : "";
if (currentValue === nextValue) return false;
el.style[prop] = nextValue;
return true;
}
_setStyleTextIfChanged(el, value) {
var _a;
if (!(el == null ? void 0 : el.style)) return false;
const nextValue = value == null ? "" : String(value);
const currentValue = (_a = el.style.cssText) != null ? _a : "";
if (currentValue === nextValue) return false;
el.style.cssText = nextValue;
return true;
}
_setTextIfChanged(el, value) {
var _a;
if (!el) return false;
const nextValue = value == null ? "" : String(value);
if (((_a = el.textContent) != null ? _a : "") === nextValue) return false;
el.textContent = nextValue;
return true;
}
_setDatasetIfChanged(el, key, value) {
var _a;
if (!(el == null ? void 0 : el.dataset)) return false;
const nextValue = value == null ? "" : String(value);
const currentValue = (_a = el.dataset[key]) != null ? _a : "";
if (currentValue === nextValue) return false;
el.dataset[key] = nextValue;
return true;
}
_setClassNameIfChanged(el, value) {
var _a;
if (!el) return false;
const nextValue = value == null ? "" : String(value);
if (((_a = el.className) != null ? _a : "") === nextValue) return false;
el.className = nextValue;
return true;
}
_repositionAllTargetLabels() {
if (!this.shadowRoot) return;
this.shadowRoot.querySelectorAll(".row[data-entity]").forEach((row) => {
this._positionTargetLabel(row);
});
}
_positionTargetLabel(row) {
const track = row.querySelector(".bar-track");
const label = row.querySelector(".target-value-label");
const marker = row.querySelector(".target-marker");
if (!track || !label || !marker) return;
if (marker.style.display === "none" || !label.textContent.trim()) {
this._setStyleIfChanged(label, "visibility", "hidden");
return;
}
const trackRect = track.getBoundingClientRect();
const maxLabelWidth = Math.max(0, Math.floor(trackRect.width - 4));
this._setStyleIfChanged(label, "maxWidth", `${maxLabelWidth}px`);
const labelRect = label.getBoundingClientRect();
const markerPercent = parseFloat(marker.style.left);
if (!Number.isFinite(markerPercent) || trackRect.width <= 0 || labelRect.width <= 0 || maxLabelWidth <= 10) {
this._setStyleIfChanged(label, "visibility", "hidden");
return;
}
const markerX = markerPercent / 100 * trackRect.width;
const halfLabel = labelRect.width / 2;
const clampedX = Math.max(halfLabel, Math.min(trackRect.width - halfLabel, markerX));
this._setStyleIfChanged(label, "left", `${clampedX}px`);
this._setStyleIfChanged(label, "transform", "translateX(-50%)");
this._setStyleIfChanged(label, "visibility", "visible");
}
_getEntityNumericValue(entityId) {
return getEntityNumericValue(this._hass, entityId);
}
_getNumericValue(value, entityId = null) {
return getNumericValue(this._hass, value, entityId);
}
_resolvePercentValue(percent, minValue, maxValue) {
return resolvePercentValue(percent, minValue, maxValue);
}
_getNormalizedResolvableNumericValue(resolvable, minValue = null, maxValue = null) {
return getNormalizedResolvableNumericValue(this._hass, resolvable, minValue, maxValue);
}
_hexToRgb(color) {
if (!color || typeof color !== "string") return null;
const hex = color.replace("#", "").trim();
const full = hex.length === 3 ? hex.split("").map((c) => c + c).join("") : hex;
if (!/^[0-9a-fA-F]{6}$/.test(full)) return null;
return {
r: parseInt(full.slice(0, 2), 16),
g: parseInt(full.slice(2, 4), 16),
b: parseInt(full.slice(4, 6), 16)
};
}
_getSeverityInterpolationStops(ecfg, minValue = 0, maxValue = 100) {
const bands = this._getSegmentsForRendering(ecfg, minValue, maxValue);
const sorted = bands.filter((s) => Number.isFinite(s == null ? void 0 : s.from) && Number.isFinite(s == null ? void 0 : s.to) && (s == null ? void 0 : s.color)).sort((a, b) => a.from - b.from);
if (!sorted.length) return [];
const stops = [];
for (let i = 0; i < sorted.length; i++) {
const band = sorted[i];
const rgb = this._hexToRgb(band.color);
if (!rgb) continue;
let anchor;
if (i === 0) {
anchor = band.from;
} else if (i === sorted.length - 1) {
anchor = band.to;
} else {
anchor = band.from + (band.to - band.from) / 2;
}
if (!stops.length || stops[stops.length - 1].p !== anchor) {
stops.push({ p: anchor, ...rgb });
}
}
return stops;
}
_getSeverityBandGradientCss(ecfg, minValue = 0, maxValue = 100) {
const bands = this._getSegmentsForRendering(ecfg, minValue, maxValue);
const sorted = bands.filter((s) => Number.isFinite(s == null ? void 0 : s.from) && Number.isFinite(s == null ? void 0 : s.to) && (s == null ? void 0 : s.color)).sort((a, b) => a.from - b.from);
if (!sorted.length) return null;
const stops = [];
for (const band of sorted) {
stops.push(`${band.color} ${band.from}%`, `${band.color} ${band.to}%`);
}
return `linear-gradient(to right, ${stops.join(", ")})`;
}
_getSoftBandBlendWidthPct() {
return 1.5;
}
_pushGradientColorStop(stops, pos, color) {
if (!Array.isArray(stops) || !color) return;
const clampedPos = Math.min(100, Math.max(0, pos));
const last = stops[stops.length - 1];
if (last && last.color === color && Math.abs(last.p - clampedPos) < 1e-4) return;
stops.push({ p: clampedPos, color });
}
_getSoftBandGradientStops(ecfg, minValue = 0, maxValue = 100) {
const bands = this._getSegmentsForRendering(ecfg, minValue, maxValue);
const sorted = bands.filter((s) => Number.isFinite(s == null ? void 0 : s.from) && Number.isFinite(s == null ? void 0 : s.to) && (s == null ? void 0 : s.color)).sort((a, b) => a.from - b.from);
if (!sorted.length) return [];
const blendWidth = this._getSoftBandBlendWidthPct();
const blendHalf = blendWidth / 2;
const stops = [];
this._pushGradientColorStop(stops, sorted[0].from, sorted[0].color);
for (let i = 0; i < sorted.length - 1; i++) {
const current = sorted[i];
const next = sorted[i + 1];
const boundary = current.to;
const currentWidth = current.to - current.from;
const nextWidth = next.to - next.from;
const soften = currentWidth >= blendWidth && nextWidth >= blendWidth;
if (soften) {
this._pushGradientColorStop(stops, Math.max(current.from, boundary - blendHalf), current.color);
this._pushGradientColorStop(stops, Math.min(next.to, boundary + blendHalf), next.color);
} else {
this._pushGradientColorStop(stops, boundary, current.color);
this._pushGradientColorStop(stops, boundary, next.color);
}
}
this._pushGradientColorStop(stops, sorted[sorted.length - 1].to, sorted[sorted.length - 1].color);
return stops;
}
_getSoftBandGradientCss(ecfg, minValue = 0, maxValue = 100) {
const stops = this._getSoftBandGradientStops(ecfg, minValue, maxValue);
if (!stops.length) return null;
return `linear-gradient(to right, ${stops.map((stop) => `${stop.color} ${stop.p}%`).join(", ")})`;
}
_resolveSegmentBoundaryPct(boundary, minValue, maxValue) {
if (boundary === null || boundary === void 0) return null;
if (typeof boundary === "object" && !Array.isArray(boundary)) {
const fixed2 = this._getFiniteNumber(boundary.fixed);
if (Number.isFinite(fixed2)) {
return this._toScalePct(fixed2, minValue, maxValue);
}
if (Number.isFinite(boundary.percent)) {
return boundary.percent;
}
return null;
}
const percent = this._parsePercentLiteral(boundary);
if (Number.isFinite(percent)) {
return percent;
}
const fixed = this._getFiniteNumber(boundary);
return Number.isFinite(fixed) ? this._toScalePct(fixed, minValue, maxValue) : null;
}
_getEffectiveFillStyle(ecfg) {
var _a, _b, _c, _d;
return (_d = (_c = (_a = ecfg == null ? void 0 : ecfg.bar) == null ? void 0 : _a.fill_style) != null ? _c : this._colorModeToFillStyle((_b = ecfg == null ? void 0 : ecfg.bar) == null ? void 0 : _b.color_mode)) != null ? _d : "bands";
}
_segmentsNeedBoundaryResolution(segments) {
return Array.isArray(segments) && segments.some((segment) => (segment == null ? void 0 : segment.from) && typeof segment.from === "object" && !Array.isArray(segment.from) || (segment == null ? void 0 : segment.to) && typeof segment.to === "object" && !Array.isArray(segment.to));
}
_getSegmentsForRendering(ecfg, minValue = 0, maxValue = 100) {
var _a, _b;
const safeMin = Number.isFinite(minValue) ? minValue : 0;
const safeMax = Number.isFinite(maxValue) ? maxValue : 100;
const rawSegments = Array.isArray((_a = ecfg.bar) == null ? void 0 : _a.segments) ? ecfg.bar.segments : [];
if (((_b = ecfg.bar) == null ? void 0 : _b.segment_space) === "scale" || this._segmentsNeedBoundaryResolution(rawSegments)) {
const resolvedSegments = rawSegments.map((segment) => {
var _a2;
return {
from: this._resolveSegmentBoundaryPct(segment.from, safeMin, safeMax),
to: this._resolveSegmentBoundaryPct(segment.to, safeMin, safeMax),
color: segment.color,
label: (_a2 = segment.label) != null ? _a2 : null
};
}).filter((segment) => Number.isFinite(segment.from) && segment.color);
return this.inferSegmentEndValues(resolvedSegments, 100).filter((segment) => Number.isFinite(segment.from) && Number.isFinite(segment.to) && segment.color);
}
return this.inferSegmentEndValues(rawSegments, 100).filter((segment) => Number.isFinite(segment.from) && Number.isFinite(segment.to) && segment.color);
}
_getColor(pct, ecfg, minValue = 0, maxValue = 100) {
const fillStyle = this._getEffectiveFillStyle(ecfg);
if (fillStyle === "solid") return ecfg.bar.color;
if (fillStyle === "gradient" || fillStyle === "band_gradient" || fillStyle === "soft_bands") {
let stops;
if (fillStyle === "band_gradient") {
stops = this._getSeverityInterpolationStops(ecfg, minValue, maxValue);
} else if (fillStyle === "soft_bands") {
stops = this._getSoftBandGradientStops(ecfg, minValue, maxValue).map((stop) => {
const rgb = this._hexToRgb(stop.color);
return rgb ? { p: stop.p, ...rgb } : null;
}).filter(Boolean);
} else if (ecfg.bar.gradient_stops && ecfg.bar.gradient_stops.length >= 2) {
stops = ecfg.bar.gradient_stops.map((s) => {
const hex = s.color.replace("#", "");
const full = hex.length === 3 ? hex.split("").map((c) => c + c).join("") : hex;
return { p: s.pos, r: parseInt(full.slice(0, 2), 16), g: parseInt(full.slice(2, 4), 16), b: parseInt(full.slice(4, 6), 16) };
});
stops.sort((a, b) => a.p - b.p);
} else {
stops = [
{ p: 0, r: 76, g: 175, b: 80 },
{ p: 50, r: 255, g: 152, b: 0 },
{ p: 100, r: 244, g: 67, b: 54 }
];
}
if (!stops || !stops.length) return ecfg.bar.color;
let lo = stops[0], hi = stops[stops.length - 1];
for (let i = 0; i < stops.length - 1; i++) {
if (pct >= stops[i].p && pct <= stops[i + 1].p) {
lo = stops[i];
hi = stops[i + 1];
break;
}
}
const t = lo.p === hi.p ? 0 : (pct - lo.p) / (hi.p - lo.p);
return `rgb(${Math.round(lo.r + t * (hi.r - lo.r))},${Math.round(lo.g + t * (hi.g - lo.g))},${Math.round(lo.b + t * (hi.b - lo.b))})`;
}
for (const s of this._getSegmentsForRendering(ecfg, minValue, maxValue)) {
if (pct >= s.from && pct <= s.to) return s.color;
}
return ecfg.bar.color;
}
_buildFullScaleGradientStyle(stops) {
if (!Array.isArray(stops) || !stops.length) return null;
const cssStops = stops.map((stop) => {
var _a;
const cssColor = (_a = stop.color) != null ? _a : this._rgbToCss(stop);
return cssColor ? `${cssColor} ${stop.p}%` : null;
}).filter(Boolean);
if (!cssStops.length) return null;
return `background:linear-gradient(to right,${cssStops.join(",")});background-repeat:no-repeat;`;
}
_getGradientInterpolationStops(ecfg, minValue = 0, maxValue = 100) {
const fillStyle = this._getEffectiveFillStyle(ecfg);
if (fillStyle === "band_gradient") {
return this._getSeverityInterpolationStops(ecfg, minValue, maxValue);
}
if (fillStyle === "soft_bands") {
return this._getSoftBandGradientStops(ecfg, minValue, maxValue).map((stop) => {
const rgb = this._hexToRgb(stop.color);
return rgb ? { p: stop.p, ...rgb } : null;
}).filter(Boolean).sort((a, b) => a.p - b.p);
}
if (ecfg.bar.gradient_stops && ecfg.bar.gradient_stops.length >= 2) {
return ecfg.bar.gradient_stops.map((s) => {
const rgb = this._hexToRgb(s.color);
return rgb ? { p: s.pos, ...rgb } : null;
}).filter(Boolean).sort((a, b) => a.p - b.p);
}
return [
{ p: 0, r: 76, g: 175, b: 80 },
{ p: 50, r: 255, g: 152, b: 0 },
{ p: 100, r: 244, g: 67, b: 54 }
];
}
_rgbToCss(rgb) {
if (!rgb) return null;
return `rgb(${rgb.r},${rgb.g},${rgb.b})`;
}
_buildSolidGradientStyle(color) {
return `linear-gradient(to right,${color} 0%,${color} 100%)`;
}
_getBasePaintGradient(color, ecfg, minValue = 0, maxValue = 100) {
var _a;
const fillStyle = this._getEffectiveFillStyle(ecfg);
if (ecfg.bar.solid_fill) {
return this._buildSolidGradientStyle(color);
}
if (fillStyle === "bands") {
return this._getSeverityBandGradientCss(ecfg, minValue, maxValue);
}
if (fillStyle === "soft_bands") {
return this._getSoftBandGradientCss(ecfg, minValue, maxValue);
}
if (fillStyle === "gradient" || fillStyle === "band_gradient") {
const stops = this._getGradientInterpolationStops(ecfg, minValue, maxValue);
return (_a = this._buildFullScaleGradientStyle(stops)) == null ? void 0 : _a.replace(/^background:/, "").replace(/;background-repeat:no-repeat;$/, "");
}
return this._buildSolidGradientStyle(color);
}
_getOverlayGradient(startPct, endPct, color) {
if (!color) return null;
const start = Math.min(100, Math.max(0, startPct));
const end = Math.min(100, Math.max(0, endPct));
if (end <= start) return null;
return `linear-gradient(to right,transparent 0%,transparent ${start}%,${color} ${start}%,${color} ${end}%,transparent ${end}%,transparent 100%)`;
}
_toScalePct(value, minValue, maxValue) {
if (!Number.isFinite(value)) return null;
const safeMin = Number.isFinite(minValue) ? minValue : 0;
const safeMax = Number.isFinite(maxValue) ? maxValue : 100;
const range = safeMax - safeMin || 1;
return Math.min(100, Math.max(0, (value - safeMin) / range * 100));
}
_resolveBaselinePct(ecfg, safeMin, safeMax) {
var _a, _b;
if (((_a = ecfg.baseline) == null ? void 0 : _a.enabled) === false) return null;
const baselineValue = this._getNormalizedResolvableNumericValue((_b = ecfg.baseline) == null ? void 0 : _b.at, safeMin, safeMax);
if (!Number.isFinite(baselineValue)) return null;
return this._toScalePct(baselineValue, safeMin, safeMax);
}
_formatNumericDisplay(rawVal, decimal = null) {
if (!Number.isFinite(rawVal)) return String(rawVal);
if (decimal !== null) {
return parseFloat(rawVal.toFixed(decimal)).toLocaleString();
}
return rawVal.toLocaleString();
}
_getNormalizedPercent(valuePct, baselinePct = null) {
const clampedValue = Math.min(100, Math.max(0, valuePct));
if (!Number.isFinite(baselinePct)) {
return {
usesBaseline: false,
start: 0,
end: clampedValue,
positive: true,
baseline: null,
hidden: clampedValue <= 0
};
}
const clampedBaseline = Math.min(100, Math.max(0, baselinePct));
return {
usesBaseline: true,
start: Math.min(clampedValue, clampedBaseline),
end: Math.max(clampedValue, clampedBaseline),
positive: clampedValue >= clampedBaseline,
baseline: clampedBaseline,
hidden: clampedValue === clampedBaseline
};
}
_getEndpointSemantics(geometry) {
if (geometry == null ? void 0 : geometry.endpointSemantics) {
return geometry.endpointSemantics;
}
if (!(geometry == null ? void 0 : geometry.usesBaseline)) {
return {
left: "scale",
right: "value"
};
}
return geometry.positive ? { left: "baseline", right: "value" } : { left: "value", right: "baseline" };
}
_getRevealCornerRadii(geometry) {
const endpoints = this._getEndpointSemantics(geometry);
const isRounded = (endpointType) => endpointType === "value" || endpointType === "range" || endpointType === "scale";
const leftRadius = isRounded(endpoints.left) ? "6px" : "0";
const rightRadius = isRounded(endpoints.right) ? "6px" : "0";
return `${leftRadius} ${rightRadius} ${rightRadius} ${leftRadius}`;
}
_getAboveTargetOverlayInterval(targetPct = null) {
if (!Number.isFinite(targetPct)) return null;
const start = Math.min(100, Math.max(0, targetPct));
if (start >= 100) return null;
return {
start,
end: 100
};
}
_getAboveTargetLayerGeometry(targetPct = null) {
const interval = this._getAboveTargetOverlayInterval(targetPct);
if (!interval) return null;
return {
start: interval.start,
end: interval.end,
hidden: false
};
}
_getFullScalePaintStyle(ecfg, color, targetPct = null, baselinePct = null, minValue = 0, maxValue = 100) {
var _a, _b, _c, _d, _e, _f;
const layers = [];
const basePaint = this._getBasePaintGradient(color, ecfg, minValue, maxValue);
const clampedBaseline = Number.isFinite(baselinePct) ? Math.min(100, Math.max(0, baselinePct)) : null;
if (Number.isFinite(clampedBaseline)) {
const belowColor = (_c = (_b = (_a = ecfg.baseline) == null ? void 0 : _a.below) == null ? void 0 : _b.color) != null ? _c : null;
const aboveColor = (_f = (_e = (_d = ecfg.baseline) == null ? void 0 : _d.above) == null ? void 0 : _e.color) != null ? _f : null;
const belowOverlay = this._getOverlayGradient(0, clampedBaseline, belowColor);
const aboveOverlay = this._getOverlayGradient(clampedBaseline, 100, aboveColor);
if (belowOverlay) layers.push(belowOverlay);
if (aboveOverlay) layers.push(aboveOverlay);
}
if (basePaint) layers.push(basePaint);
if (!layers.length) return "display:none;";
return `display:block;inset:0;background-image:${layers.join(",")};background-repeat:no-repeat;background-size:100% 100%;`;
}
_getRevealShapeStyle(geometry, h) {
var _a, _b;
const heightValue = typeof h === "number" ? `${h}px` : h;
const start = Math.min(100, Math.max(0, (_a = geometry == null ? void 0 : geometry.start) != null ? _a : 0));
const end = Math.min(100, Math.max(0, (_b = geometry == null ? void 0 : geometry.end) != null ? _b : 0));
if (geometry == null ? void 0 : geometry.hidden) {
return `display:none;height:${heightValue};clip-path:inset(0 100% 0 0 round 0);`;
}
const topInset = "0";
const rightInset = `${Math.max(0, 100 - end)}%`;
const bottomInset = "0";
const leftInset = `${start}%`;
const radii = this._getRevealCornerRadii(geometry);
return `display:block;height:${heightValue};clip-path:inset(${topInset} ${rightInset} ${bottomInset} ${leftInset} round ${radii});`;
}
_getStaticLayerRevealStyle(geometry) {
if (!(geometry == null ? void 0 : geometry.hidden) && Number.isFinite(geometry == null ? void 0 : geometry.start) && Number.isFinite(geometry == null ? void 0 : geometry.end) && geometry.end > geometry.start) {
const start = Math.min(100, Math.max(0, geometry.start));
const end = Math.min(100, Math.max(0, geometry.end));
return `display:block;clip-path:inset(0 ${Math.max(0, 100 - end)}% 0 ${start}% round 0);`;
}
return "display:none;clip-path:inset(0 100% 0 0 round 0);";
}
_getFillPaintLayers(geometry, h, ecfg, color, targetPct = null, baselinePct = null, minValue = 0, maxValue = 100) {
var _a, _b;
const basePaintStyle = this._getFullScalePaintStyle(ecfg, color, targetPct, baselinePct, minValue, maxValue);
const baseLayer = {
id: "base",
zIndex: 1,
visible: true,
paintStyle: basePaintStyle,
revealStyle: "display:block;"
};
const aboveTargetGeometry = this._getAboveTargetLayerGeometry(targetPct);
const aboveTargetLayer = {
id: "above-target",
zIndex: 2,
visible: !!(((_a = ecfg == null ? void 0 : ecfg.bar) == null ? void 0 : _a.above_target_color) && aboveTargetGeometry),
paintStyle: ((_b = ecfg == null ? void 0 : ecfg.bar) == null ? void 0 : _b.above_target_color) ? `display:block;inset:0;background:${ecfg.bar.above_target_color};` : "display:none;",
revealStyle: aboveTargetGeometry ? this._getStaticLayerRevealStyle(aboveTargetGeometry) : this._getStaticLayerRevealStyle({ start: 0, end: 0, hidden: true })
};
return [baseLayer, aboveTargetLayer];
}
_getFillRenderState(pct, h, ecfg, color, targetPct = null, baselinePct = null, minValue = 0, maxValue = 100, needleActive = false) {
var _a, _b;
const geometry = needleActive ? this._getNormalizedPercent(100, null) : this._getNormalizedPercent(pct, baselinePct);
const paintLayers = this._getFillPaintLayers(geometry, h, ecfg, color, targetPct, baselinePct, minValue, maxValue);
return {
geometry,
paintLayers,
paintStyle: (_b = (_a = paintLayers[0]) == null ? void 0 : _a.paintStyle) != null ? _b : "display:none;",
revealStyle: this._getRevealShapeStyle(geometry, h)
};
}
_getNeedleRenderState(rawValue, ecfg, minValue = 0, maxValue = 100, baselinePct = null) {
var _a, _b, _c, _d, _e, _f, _g, _h, _i;
const needle = (_a = ecfg == null ? void 0 : ecfg.bar) == null ? void 0 : _a.needle;
if (!(needle == null ? void 0 : needle.show)) {
return {
show: false,
pct: null,
color: (_b = needle == null ? void 0 : needle.color) != null ? _b : "#ffffff",
borderColor: this._getNeedleBorderColor((_c = needle == null ? void 0 : needle.color) != null ? _c : "#ffffff"),
edge: "middle"
};
}
if (Number.isFinite(baselinePct)) {
return {
show: false,
pct: null,
color: (_d = needle.color) != null ? _d : "#ffffff",
borderColor: this._getNeedleBorderColor((_e = needle.color) != null ? _e : "#ffffff"),
edge: "middle"
};
}
if (!Number.isFinite(rawValue)) {
return {
show: false,
pct: null,
color: (_f = needle.color) != null ? _f : "#ffffff",
borderColor: this._getNeedleBorderColor((_g = needle.color) != null ? _g : "#ffffff"),
edge: "middle"
};
}
const pct = Math.min(100, Math.max(0, this._toScalePct(rawValue, minValue, maxValue)));
return {
show: true,
pct,
color: (_h = needle.color) != null ? _h : "#ffffff",
borderColor: this._getNeedleBorderColor((_i = needle.color) != null ? _i : "#ffffff"),
edge: pct <= 0 ? "left" : pct >= 100 ? "right" : "middle"
};
}
_ensureBaseDom() {
if (this._baseDomReady) return;
if (this.shadowRoot.querySelector("ha-card")) {
this._baseDomReady = true;
return;
}
this.shadowRoot.innerHTML = `
<style>
:host {
display: block;
font-family: 'Segoe UI', system-ui, sans-serif;
position: relative;
z-index: 0;
isolation: isolate;
}
ha-card {
display: block;
background: var(--card-background-color, #fff);
border-radius: 12px;
box-shadow: var(--ha-card-box-shadow, 0 2px 8px rgba(0,0,0,0.08));
overflow: hidden;
padding: 16px;
box-sizing: border-box;
}
.card {
--sbcp-main-gap: 8px;
--sbcp-icon-width: 28px;
--sbcp-above-gap: 10px;
--sbcp-left-label-share: 25%;
--sbcp-value-width: 60px;
--sbcp-bar-min-width: 56px;
--sbcp-target-label-font-size: 12px;
--sbcp-inline-label-padding-x: 8px;
--sbcp-inline-label-padding-y: 2px;
--sbcp-inline-label-font-size: 12px;
min-width: 0;
}
.card[data-compact="compact"] {
--sbcp-main-gap: 6px;
--sbcp-icon-width: 26px;
--sbcp-above-gap: 8px;
--sbcp-left-label-share: 22%;
--sbcp-value-width: 54px;
--sbcp-bar-min-width: 52px;
--sbcp-target-label-font-size: 11px;
--sbcp-inline-label-padding-x: 7px;
--sbcp-inline-label-font-size: 11px;
}
.card[data-compact="tight"] {
--sbcp-main-gap: 5px;
--sbcp-icon-width: 24px;
--sbcp-above-gap: 6px;
--sbcp-left-label-share: 19%;
--sbcp-value-width: 50px;
--sbcp-bar-min-width: 48px;
--sbcp-target-label-font-size: 11px;
--sbcp-inline-label-padding-x: 6px;
--sbcp-inline-label-font-size: 11px;
}
.card[data-compact="dense"] {
--sbcp-main-gap: 4px;
--sbcp-icon-width: 23px;
--sbcp-above-gap: 5px;
--sbcp-left-label-share: 16%;
--sbcp-value-width: 46px;
--sbcp-bar-min-width: 44px;
--sbcp-target-label-font-size: 10px;
--sbcp-inline-label-padding-x: 5px;
--sbcp-inline-label-font-size: 10px;
}
.card[data-compact="compressed"] {
--sbcp-main-gap: 4px;
--sbcp-icon-width: 22px;
--sbcp-above-gap: 4px;
--sbcp-left-label-share: 14%;
--sbcp-value-width: 42px;
--sbcp-bar-min-width: 40px;
--sbcp-target-label-font-size: 10px;
--sbcp-inline-label-padding-x: 5px;
--sbcp-inline-label-font-size: 10px;
}
.card-title {
font-size: 13px;
font-weight: 600;
letter-spacing: 0.08em;
text-transform: uppercase;
color: var(--secondary-text-color, #888);
margin-bottom: 14px;
}
.row {
margin-bottom: 10px;
cursor: pointer;
border-radius: 8px;
padding: 2px 4px;
}
.row:last-child { margin-bottom: 0; }
.row-stack {
--sbcp-row-height: 38px;
display: flex;
flex-direction: column;
gap: 2px;
}
.row-stack[data-top-value="true"] .main-line.left-mode .value-right {
display: none;
}
.top-right-value {
display: none;
align-self: flex-end;
align-items: center;
justify-content: flex-end;
max-width: 100%;
min-width: 0;
font-size: 13px;
font-weight: 600;
color: var(--primary-text-color, #333);
font-variant-numeric: tabular-nums;
text-align: right;
line-height: 1.1;
margin-bottom: 1px;
}
.top-right-value[data-active="true"] {
display: flex;
}
.row:hover .bar-track { filter: brightness(0.95); transition: filter 0.15s; }
.main-line {
display: flex;
align-items: center;
gap: var(--sbcp-main-gap);
min-width: 0;
}
.main-line[data-row-density="tight"] {
gap: calc(var(--sbcp-main-gap) - 1px);
}
.main-line[data-row-density="dense"] {
gap: calc(var(--sbcp-main-gap) - 2px);
}
.main-line[data-row-density="compressed"] {
gap: calc(var(--sbcp-main-gap) - 2px);
}
.main-line:not(.left-mode)[data-row-density="compact"] {
--sbcp-value-width: 52px;
}
.main-line:not(.left-mode)[data-row-density="tight"] {
--sbcp-value-width: 48px;
}
.main-line:not(.left-mode)[data-row-density="dense"] {
--sbcp-value-width: 44px;
}
.main-line:not(.left-mode)[data-row-density="compressed"] {
--sbcp-value-width: 40px;
}
.main-line.off-mode[data-row-density="compressed"] .icon-wrap,
.main-line.above-mode[data-row-density="compressed"] .icon-wrap {
display: none;
}
.main-line.left-mode[data-hide-left-icon="true"] .icon-wrap,
.main-line.above-mode[data-hide-above-icon="true"] .icon-wrap,
.main-line.inside-mode[data-hide-inside-icon="true"] .icon-wrap,
.main-line.inside-mode[data-priority-hide-inside-icon="true"] .icon-wrap {
display: none;
}
.main-line.left-mode[data-left-density="normal"] {
--sbcp-left-label-share: 25%;
--sbcp-value-width: 58px;
}
.main-line.left-mode[data-left-density="compact"] {
--sbcp-left-label-share: 22%;
--sbcp-value-width: 53px;
}
.main-line.left-mode[data-left-density="tight"] {
--sbcp-left-label-share: 19%;
--sbcp-value-width: 49px;
}
.main-line.left-mode[data-left-density="dense"] {
--sbcp-left-label-share: 16%;
--sbcp-value-width: 46px;
}
.main-line.left-mode[data-left-density="compressed"] {
--sbcp-left-label-share: 14%;
--sbcp-value-width: 42px;
}
.icon-wrap {
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
width: var(--sbcp-icon-width);
height: var(--sbcp-row-height);
min-height: var(--sbcp-row-height);
color: var(--primary-text-color, #333);
line-height: 1;
}
.main-line.left-mode[data-left-density="compressed"] .icon-wrap {
display: none;
}
ha-icon {
--mdc-icon-size: 20px;
display: block;
}
.label-left {
flex: 1 1 auto;
height: var(--sbcp-row-height);
min-width: 0;
font-size: 13px;
font-weight: 500;
color: var(--primary-text-color, #333);
display: flex;
align-items: center;
}
.label-left[data-hidden="true"],
.label-left[data-priority-hidden="true"] {
display: none;
}
.label-left-text {
display: block;
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.bar-wrap {
flex: 1 1 var(--sbcp-bar-min-width);
min-width: var(--sbcp-bar-min-width);
position: relative;
}
.bar-track {
position: relative;
width: 100%;
height: var(--sbcp-row-height);
border-radius: 6px;
background: var(--secondary-background-color, #e8e8e8);
overflow: hidden;
}
.bar-fill-reveal {
position: absolute;
inset: 0;
pointer-events: none;
transition: clip-path 0.6s cubic-bezier(0.4,0,0.2,1);
z-index: 1;
}
.bar-paint-layer {
position: absolute;
inset: 0;
pointer-events: none;
z-index: 1;
}
.bar-paint-layer[data-layer="above-target"] {
z-index: 2;
}
.bar-fill-reveal.no-anim {
transition: none;
}
.row[data-bar-animated="false"] .bar-fill-reveal,
.row[data-bar-animated="false"] .needle-marker,
.row[data-bar-animated="false"] .target-marker,
.row[data-bar-animated="false"] .peak-marker,
.row[data-bar-animated="false"] .target-value-label {
transition: none;
}
.bar-inner-label {
position: absolute;
inset: 0;
display: flex;
align-items: center;
justify-content: space-between;
gap: 6px;
padding: 0 6px;
pointer-events: none;
z-index: 8;
}
.bar-inner-label[data-inside-density="compact"] {
gap: 5px;
padding: 0 5px;
}
.bar-inner-label[data-inside-density="tight"] {
gap: 4px;
padding: 0 4px;
}
.bar-inner-label[data-inside-density="dense"] {
gap: 0;
padding: 0 4px;
justify-content: flex-end;
}
.bar-inner-label[data-inside-density="compressed"] {
gap: 0;
padding: 0 4px;
justify-content: flex-end;
}
.bar-inner-label > span {
background: rgba(0,0,0,0.35);
backdrop-filter: blur(4px);
-webkit-backdrop-filter: blur(4px);
color: #fff;
font-size: var(--sbcp-inline-label-font-size);
font-weight: 600;
white-space: nowrap;
padding: var(--sbcp-inline-label-padding-y) var(--sbcp-inline-label-padding-x);
border-radius: 20px;
min-width: 0;
max-width: 100%;
overflow: hidden;
text-overflow: ellipsis;
}
.bar-inner-label .inside-name {
flex: 0 1 auto;
width: fit-content;
max-width: 60%;
display: inline-block;
}
.bar-inner-label[data-inside-density="compact"] .inside-name {
max-width: 56%;
}
.bar-inner-label[data-inside-density="tight"] .inside-name {
max-width: 48%;
}
.bar-inner-label[data-hide-name="true"] .inside-name,
.bar-inner-label[data-priority-hide-name="true"] .inside-name {
display: none;
}
.bar-inner-label .inside-value {
flex: 0 1 auto;
min-width: 0;
max-width: 56%;
display: inline-flex;
align-items: baseline;
}
.bar-inner-label .inside-value[data-hide-value="true"] {
display: none;
}
.main-line.inside-mode[data-hide-inside-icon="true"] .bar-inner-label .inside-value,
.main-line.inside-mode[data-priority-hide-inside-icon="true"] .bar-inner-label .inside-value,
.bar-inner-label[data-hide-name="true"] .inside-value,
.bar-inner-label[data-priority-hide-name="true"] .inside-value {
max-width: 100%;
}
.bar-inner-label[data-inside-density="dense"] .inside-value,
.bar-inner-label[data-inside-density="compressed"] .inside-value {
max-width: 100%;
}
.bar-inner-label .inside-value-text {
display: inline-flex;
align-items: baseline;
gap: 0;
max-width: 100%;
min-width: 0;
overflow: hidden;
white-space: nowrap;
background: transparent;
padding: 0;
border-radius: 0;
backdrop-filter: none;
-webkit-backdrop-filter: none;
}
.bar-inner-label .inside-value-text.has-unit {
gap: 2px;
}
.bar-inner-label .inside-value-text.tight-unit {
gap: 0;
}
.bar-inner-label .inside-number {
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
background: transparent;
padding: 0;
border-radius: 0;
}
.bar-inner-label .inside-unit {
flex: 0 1 auto;
min-width: 0;
overflow: hidden;
text-overflow: clip;
white-space: nowrap;
font-size: 11px;
font-weight: 400;
color: rgba(255, 255, 255, 0.72);
background: transparent;
padding: 0;
border-radius: 0;
}
.target-value-label {
position: absolute;
top: 100%;
margin-top: 3px;
font-size: var(--sbcp-target-label-font-size);
line-height: 1;
color: var(--secondary-text-color, #888);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
box-sizing: border-box;
pointer-events: none;
z-index: 6;
visibility: hidden;
transition: left 0.6s cubic-bezier(0.4,0,0.2,1);
}
.above-line {
display: grid;
grid-template-columns: var(--sbcp-icon-width) minmax(0, 1fr);
column-gap: var(--sbcp-main-gap);
min-width: 0;
align-items: flex-end;
}
.above-line[data-hide-above-icon="true"],
.above-line[data-above-density="compressed"] {
grid-template-columns: minmax(0, 1fr);
}
.above-bar-label[data-hide-name="true"] .above-bar-label-name,
.above-bar-label[data-priority-hide-name="true"] .above-bar-label-name,
.above-line[data-above-density="compressed"] .above-icon-spacer {
display: none;
}
.above-line[data-hide-above-icon="true"] .above-icon-spacer {
display: none;
}
.above-icon-spacer {
width: var(--sbcp-icon-width);
min-width: 0;
}
.above-bar-label {
flex: 1;
min-width: 0;
display: flex;
justify-content: flex-start;
align-items: center;
gap: var(--sbcp-main-gap);
margin-bottom: 2px;
min-height: 16px;
}
.above-bar-label-name {
flex: 1 1 auto;
min-width: 0;
font-size: 13px;
font-weight: 500;
color: var(--primary-text-color, #333);
line-height: 1.15;
}
.above-bar-label-value {
flex: 0 0 auto;
margin-left: auto;
display: inline-flex;
align-items: baseline;
justify-content: flex-end;
text-align: right;
min-width: 0;
max-width: 100%;
overflow: hidden;
font-size: 13px;
font-weight: 600;
color: var(--primary-text-color, #333);
font-variant-numeric: tabular-nums;
}
.hero-line {
--sbcp-hero-min-value-size: 10px;
--sbcp-hero-base-size: 84px;
--sbcp-hero-compact-size: clamp(50px, calc(var(--sbcp-hero-base-size) * 0.89), 100px);
--sbcp-hero-tight-size: clamp(42px, calc(var(--sbcp-hero-base-size) * 0.75), 84px);
--sbcp-hero-dense-size: clamp(29px, calc(var(--sbcp-hero-base-size) * 0.52), 58px);
--sbcp-hero-compressed-size: clamp(21px, calc(var(--sbcp-hero-base-size) * 0.38), 43px);
--sbcp-hero-xs-size: clamp(15px, calc(var(--sbcp-hero-base-size) * 0.26), 29px);
--sbcp-hero-fit-tight-size: clamp(15px, calc(var(--sbcp-hero-base-size) * 0.26), 29px);
--sbcp-hero-fit-minimum-size: 12px;
min-width: 0;
margin-bottom: 0;
}
.hero-line[data-hero-size="small"] {
--sbcp-hero-base-size: 56px;
}
.hero-line[data-hero-size="large"] {
--sbcp-hero-base-size: 112px;
}
.hero-header {
display: grid;
grid-template-columns: minmax(0, 1fr) minmax(0, auto);
align-items: baseline;
column-gap: var(--sbcp-main-gap);
min-width: 0;
overflow: hidden;
margin-bottom: clamp(2px, calc(var(--sbcp-row-height) * 0.08), 4px);
}
.hero-header[data-hide-name="true"] .hero-label,
.hero-header[data-priority-hide-name="true"] .hero-label {
display: none;
}
.hero-header[data-hide-name="true"],
.hero-header[data-priority-hide-name="true"] {
grid-template-columns: minmax(0, 1fr);
}
.hero-header[data-hide-name="true"] .hero-value,
.hero-header[data-priority-hide-name="true"] .hero-value {
grid-column: 1 / -1;
justify-self: stretch;
width: 100%;
}
.hero-label {
min-width: 0;
font-size: 13px;
font-weight: 500;
color: var(--primary-text-color, #333);
line-height: 1.15;
}
.hero-value {
min-width: 0;
max-width: 100%;
display: inline-flex;
align-items: baseline;
justify-content: flex-end;
justify-self: end;
overflow: hidden;
font-size: var(--sbcp-hero-base-size);
font-weight: 700;
color: var(--primary-text-color, #333);
font-variant-numeric: tabular-nums;
line-height: 0.95;
text-align: right;
}
.hero-line[data-hero-density="compact"] .hero-value {
font-size: var(--sbcp-hero-compact-size);
}
.hero-line[data-hero-density="tight"] .hero-value {
font-size: var(--sbcp-hero-tight-size);
}
.hero-line[data-hero-density="dense"] .hero-value {
font-size: var(--sbcp-hero-dense-size);
}
.hero-line[data-hero-density="compressed"] .hero-value {
font-size: var(--sbcp-hero-compressed-size);
}
.hero-line[data-hero-density="xs"] .hero-value {
font-size: var(--sbcp-hero-xs-size);
}
.hero-line[data-hero-value-fit="tight"] .hero-value {
font-size: var(--sbcp-hero-fit-tight-size);
}
.hero-line[data-hero-value-fit="minimum"] .hero-value {
font-size: var(--sbcp-hero-fit-minimum-size);
}
.hero-line[data-hero-value-fit="hidden"] .hero-value {
display: none;
}
.hero-line[data-hide-hero-unit="true"] .hero-value .unit-group {
display: none;
}
.hero-value .value-right-text {
display: inline-flex;
flex: 1 1 auto;
justify-content: flex-end;
gap: 4px;
align-items: baseline;
width: 100%;
min-width: 0;
max-width: 100%;
overflow: hidden;
text-overflow: clip;
white-space: nowrap;
}
.hero-value .value-right-text.tight-unit {
gap: 2px;
}
.hero-value .value-right-number {
flex: 0 1 auto;
min-width: 0;
overflow: hidden;
text-overflow: clip;
white-space: nowrap;
line-height: 0.95;
}
.hero-value .unit-group {
flex: 0 0 auto;
align-self: baseline;
line-height: 1;
overflow: visible;
text-overflow: clip;
}
.hero-value .unit {
font-size: clamp(10px, 0.42em, 16px);
font-weight: 500;
color: var(--secondary-text-color, #888);
line-height: 1;
overflow: visible;
text-overflow: clip;
}
/* \u2500\u2500 Shared marker base \u2500\u2500 */
.peak-marker, .target-marker {
position: absolute;
top: 0;
bottom: 0;
width: 0;
transform: translateX(-50%);
pointer-events: none;
transition: left 0.6s cubic-bezier(0.4,0,0.2,1);
--marker-color: #888;
--marker-contrast-color: #f3f4f6;
}
.target-marker {
z-index: 6;
}
.peak-marker {
z-index: 7;
}
.needle-layer {
position: absolute;
inset: 0;
overflow: hidden;
border-radius: inherit;
pointer-events: none;
z-index: 5;
}
.needle-marker {
position: absolute;
top: 0;
bottom: 0;
width: 7px;
transform: translateX(-50%);
pointer-events: none;
transition: left 0.6s cubic-bezier(0.4,0,0.2,1);
background: linear-gradient(
to right,
var(--needle-border-color, #000000) 0 1px,
var(--needle-color, #ffffff) 1px 6px,
var(--needle-border-color, #000000) 6px 7px
);
border-radius: 0;
box-shadow:
0 0 3px var(--needle-color, #ffffff),
0 0 6px var(--needle-color, #ffffff);
}
.needle-layer .needle-marker[data-edge="right"] {
transform: translateX(-100%);
}
.peak-marker .peak-inset,
.peak-marker .peak-outset,
.target-marker .target-inset,
.target-marker .target-outset {
position: absolute;
left: 50%;
transform: translateX(-50%);
width: 0;
height: 0;
}
/* Peak marker: large triangle intrudes into the bar, small one sits just above it. */
.peak-marker .peak-inset {
top: 0;
border-left: 7px solid transparent;
border-right: 7px solid transparent;
border-top: 11px solid var(--marker-color);
z-index: 2;
filter:
drop-shadow(0 0 1.2px var(--marker-contrast-color))
drop-shadow(0 0 3px color-mix(in srgb, var(--marker-contrast-color) 78%, transparent));
}
.peak-marker .peak-outset {
top: -4px;
border-left: 5px solid transparent;
border-right: 5px solid transparent;
border-bottom: 4px solid var(--marker-color);
z-index: 3;
}
/* Target marker: large triangle intrudes into the bar, small one sits just below it. */
.target-marker .target-inset {
bottom: 0;
border-left: 7px solid transparent;
border-right: 7px solid transparent;
border-bottom: 11px solid var(--marker-color);
z-index: 2;
filter:
drop-shadow(0 0 1.2px var(--marker-contrast-color))
drop-shadow(0 0 3px color-mix(in srgb, var(--marker-contrast-color) 78%, transparent));
}
.target-marker .target-outset {
bottom: -4px;
border-left: 5px solid transparent;
border-right: 5px solid transparent;
border-top: 4px solid var(--marker-color);
z-index: 3;
}
.value-right {
--sbcp-value-extra-width: 0px;
flex: 0 0 calc(var(--sbcp-value-width) + var(--sbcp-value-extra-width));
width: calc(var(--sbcp-value-width) + var(--sbcp-value-extra-width));
min-width: calc(var(--sbcp-value-width) + var(--sbcp-value-extra-width));
max-width: calc(var(--sbcp-value-width) + var(--sbcp-value-extra-width));
height: var(--sbcp-row-height);
text-align: right;
font-size: 13px;
font-weight: 600;
color: var(--primary-text-color, #333);
font-variant-numeric: tabular-nums;
display: flex;
align-items: center;
justify-content: flex-end;
overflow: hidden;
box-sizing: border-box;
padding-right: 1px;
min-width: 0;
}
.value-right-text {
display: inline-flex;
align-items: baseline;
justify-content: flex-end;
gap: 0;
width: 100%;
max-width: 100%;
min-width: 0;
overflow: hidden;
white-space: nowrap;
}
.value-right-text.has-unit {
gap: 2px;
}
.value-right-text.tight-unit {
gap: 0;
}
.value-right-number {
flex: 0 1 auto;
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
line-height: 1.1;
}
.value-right .unit-group,
.top-right-value .unit-group,
.above-bar-label-value .unit-group {
flex: 0 1 auto;
display: inline-flex;
align-items: baseline;
min-width: 0;
overflow: hidden;
white-space: nowrap;
line-height: 1.1;
}
.value-right .unit,
.top-right-value .unit,
.above-bar-label-value .unit {
flex: 0 1 auto;
min-width: 0;
display: inline-block;
overflow: hidden;
text-overflow: clip;
white-space: nowrap;
font-size: 11px;
font-weight: 400;
color: var(--secondary-text-color, #888);
line-height: 1.1;
}
.measure-layer {
position: fixed;
left: -9999px;
top: -9999px;
visibility: hidden;
pointer-events: none;
white-space: nowrap;
}
</style>
<ha-card>
<div class="card">
<div class="card-title" style="display:none;"></div>
<div class="rows"></div>
<div class="measure-layer"></div>
</div>
</ha-card>
`;
this._baseDomReady = true;
}
_render() {
const cfg = this._config;
this._ensureBaseDom();
const titleEl = this.shadowRoot.querySelector(".card-title");
if (titleEl) {
if (cfg.title) {
titleEl.textContent = cfg.title;
titleEl.style.display = "";
} else {
titleEl.textContent = "";
titleEl.style.display = "none";
}
}
this._disconnectResizeObserver();
this._resizeObserver = new ResizeObserver(() => {
this._applyCompactTier();
this._schedulePostLayoutDensityPass();
});
const surface = this.shadowRoot.querySelector("ha-card");
const card = this.shadowRoot.querySelector(".card");
if (surface && card) {
this._applyCompactTier();
this._resizeObserver.observe(surface);
this._resizeObserver.observe(this);
}
this._update();
this._schedulePostLayoutDensityPass();
}
_disconnectResizeObserver() {
if (!this._resizeObserver) return;
this._resizeObserver.disconnect();
this._resizeObserver = null;
}
_isReliableWidth(width, minWidth = 16) {
return Number.isFinite(width) && width >= minWidth;
}
_getHeroLabelReservedWidth(headerEl, labelEl, labelHidden) {
var _a, _b, _c;
if (labelHidden || !headerEl || !labelEl) return 0;
const headerWidth = Math.floor((_b = (_a = headerEl.getBoundingClientRect) == null ? void 0 : _a.call(headerEl).width) != null ? _b : 0);
const naturalLabelWidth = Math.ceil(labelEl.scrollWidth || ((_c = labelEl.getBoundingClientRect) == null ? void 0 : _c.call(labelEl).width) || 0);
if (!this._isReliableWidth(headerWidth, 8) || !Number.isFinite(naturalLabelWidth) || naturalLabelWidth <= 0) {
return 0;
}
return Math.min(naturalLabelWidth, headerWidth * 0.45);
}
_classifyCompactTier(width, currentTier = "normal") {
if (!this._isReliableWidth(width)) return currentTier || "normal";
if (width < 180) return "compressed";
if (width < 220) return "dense";
if (width < 280) return "tight";
if (width < 360) return "compact";
return "normal";
}
_classifyLeftDensity(width, currentDensity = "normal") {
if (!this._isReliableWidth(width)) return currentDensity || "normal";
if (width < 170) return "compressed";
if (width < 210) return "dense";
if (width < 255) return "tight";
if (width < 320) return "compact";
return "normal";
}
_classifyRowDensity(width, currentDensity = "normal") {
if (!this._isReliableWidth(width)) return currentDensity || "normal";
if (width < 150) return "compressed";
if (width < 190) return "dense";
if (width < 245) return "tight";
if (width < 300) return "compact";
return "normal";
}
_schedulePostLayoutDensityPass() {
if (!this.isConnected) return;
if (this._densityPassScheduled) {
this._densityPassDirty = true;
return;
}
this._densityPassScheduled = true;
this._densityPassFrame = requestAnimationFrame(() => {
var _a, _b;
this._densityPassScheduled = false;
this._densityPassFrame = null;
const runAgain = this._densityPassDirty;
this._densityPassDirty = false;
if (!this.isConnected) return;
const surface = (_a = this.shadowRoot) == null ? void 0 : _a.querySelector("ha-card");
const width = (_b = surface == null ? void 0 : surface.getBoundingClientRect().width) != null ? _b : 0;
if (!this._isReliableWidth(width)) {
if (this._densityPassRetries < 4) {
this._densityPassRetries += 1;
this._schedulePostLayoutDensityPass();
}
return;
}
this._densityPassRetries = 0;
this._applyCompactTier();
this._runPostLayoutPasses();
if (runAgain) {
this._schedulePostLayoutDensityPass();
}
});
}
_applyCompactTier() {
if (!this.shadowRoot) return;
const surface = this.shadowRoot.querySelector("ha-card");
const card = this.shadowRoot.querySelector(".card");
if (!surface || !card) return;
const width = surface.getBoundingClientRect().width;
if (!this._isReliableWidth(width)) {
this._schedulePostLayoutDensityPass();
if (!card.dataset.compact) card.dataset.compact = "normal";
return;
}
card.dataset.compact = this._classifyCompactTier(width, card.dataset.compact);
}
_applyLeftModeDensity() {
if (!this.shadowRoot) return;
const densities = ["normal", "compact", "tight", "dense", "compressed"];
this.shadowRoot.querySelectorAll(".main-line.left-mode").forEach((mainLine) => {
const width = mainLine.getBoundingClientRect().width;
if (!this._isReliableWidth(width)) {
this._schedulePostLayoutDensityPass();
if (!mainLine.dataset.leftDensity) mainLine.dataset.leftDensity = "normal";
return;
}
let density = this._classifyLeftDensity(width, mainLine.dataset.leftDensity);
const labelText = mainLine.querySelector(".label-left-text");
const fullLabelWidth = labelText ? labelText.scrollWidth : Number.POSITIVE_INFINITY;
const visibleLabelWidth = labelText ? labelText.clientWidth : Number.POSITIVE_INFINITY;
const labelIsTruncated = labelText ? fullLabelWidth > visibleLabelWidth + 1 : false;
const effectiveLabelWidth = labelIsTruncated ? visibleLabelWidth : fullLabelWidth;
let relaxBy = 0;
if (Number.isFinite(effectiveLabelWidth)) {
if (effectiveLabelWidth <= 72 && width >= 185) relaxBy = 1;
if (effectiveLabelWidth <= 44 && width >= 205) relaxBy = 2;
}
const currentIndex = densities.indexOf(density);
if (currentIndex !== -1 && relaxBy > 0) {
density = densities[Math.max(0, currentIndex - relaxBy)];
}
mainLine.dataset.leftDensity = density;
});
}
_applyInsideLabelDensity() {
if (!this.shadowRoot) return;
this.shadowRoot.querySelectorAll(".bar-inner-label").forEach((innerLabel) => {
var _a, _b, _c, _d, _e, _f;
const track = innerLabel.closest(".bar-track");
const mainLine = innerLabel.closest(".main-line");
const nameEl = innerLabel.querySelector(".inside-name");
const valueEl = innerLabel.querySelector(".inside-value");
if (!track || !nameEl || !valueEl) return;
const trackWidth = track.getBoundingClientRect().width;
const valueDisplay = this._decodeDataAttr(valueEl.dataset.display || valueEl.textContent || "");
const valueUnit = this._decodeDataAttr(valueEl.dataset.unit || ((_a = valueEl.querySelector(".inside-unit")) == null ? void 0 : _a.textContent) || "");
const valueWidth = this._measureInsideValueMarkupWidth(valueEl, valueDisplay, valueUnit, false);
const valueOnlyWidth = this._measureInsideValueMarkupWidth(valueEl, valueDisplay, valueUnit, true);
let density = this._classifyInsideDensity(trackWidth, valueWidth);
const rowWidth = typeof (mainLine == null ? void 0 : mainLine.getBoundingClientRect) === "function" ? mainLine.getBoundingClientRect().width : 0;
const rowDensity = this._isReliableWidth(rowWidth) ? this._classifyRowDensity(rowWidth, ((_b = mainLine == null ? void 0 : mainLine.dataset) == null ? void 0 : _b.rowDensity) || "normal") : ((_c = mainLine == null ? void 0 : mainLine.dataset) == null ? void 0 : _c.rowDensity) || "normal";
const iconWrap = (_e = (_d = mainLine == null ? void 0 : mainLine.querySelector) == null ? void 0 : _d.call(mainLine, ".icon-wrap")) != null ? _e : null;
let hideIcon = rowDensity === "dense" || rowDensity === "compressed";
const reclaimedWidth = iconWrap ? this._getLeftModeIconWidth(iconWrap, mainLine) + this._getLeftModeGap(mainLine) : 0;
if (!hideIcon && valueWidth > this._getInsideValueVisibleCap(trackWidth, density)) {
hideIcon = true;
}
if (iconWrap && hideIcon) {
density = this._classifyInsideDensity(trackWidth + reclaimedWidth, valueWidth);
}
const effectiveTrackWidth = trackWidth + (hideIcon ? reclaimedWidth : 0);
let hideName = false;
if (rowDensity === "compressed") {
density = "compressed";
hideIcon = true;
}
const rawValueCap = this._getInsideValueVisibleCap(trackWidth, density);
const innerPadding = this._getNumericStyleValue(innerLabel, "padding-left", 0) + this._getNumericStyleValue(innerLabel, "padding-right", 0);
const valueCap = Math.max(0, rawValueCap - innerPadding);
const hideUnit = !!valueUnit && valueWidth > valueCap;
const hideValue = valueOnlyWidth > valueCap;
const reservedValueWidth = hideValue ? 0 : Math.ceil(hideUnit ? valueOnlyWidth : valueWidth);
const labelGap = !hideValue ? this._getNumericStyleValue(innerLabel, "gap", 0) : 0;
if (!hideValue) {
const nameText = (nameEl.textContent || "").trim();
const nameFullWidth = nameEl.scrollWidth || ((_f = nameEl.getBoundingClientRect) == null ? void 0 : _f.call(nameEl).width) || this._measureTextWidthWithStyles(nameEl, nameText);
if (!nameText || !Number.isFinite(nameFullWidth) || nameFullWidth <= 0) {
hideName = density === "dense" || density === "compressed";
} else {
const usefulNameWidth = this._getInsideUsefulNameWidth(nameEl, nameText, nameFullWidth);
const availableNameWidth = Math.max(
0,
trackWidth - innerPadding - reservedValueWidth - labelGap
);
const visibleChars = this._measureVisibleLabelCharacters(nameEl, nameText, availableNameWidth);
const minUsefulChars = Math.min(4, nameText.length);
const nameNeedsTruncation = nameFullWidth > availableNameWidth + 1;
const hasUsefulRoom = availableNameWidth >= usefulNameWidth && (!nameNeedsTruncation || visibleChars >= minUsefulChars);
hideName = !hasUsefulRoom;
}
}
if (hideName && density === "normal") density = "dense";
innerLabel.dataset.insideDensity = density;
innerLabel.dataset.hideName = hideName ? "true" : "false";
valueEl.dataset.hideUnit = hideUnit ? "true" : "false";
valueEl.dataset.hideValue = hideValue ? "true" : "false";
if (mainLine) {
mainLine.dataset.hideInsideIcon = hideIcon ? "true" : "false";
}
});
}
_getInsideValueVisibleCap(trackWidth, density) {
if (density === "dense" || density === "compressed") {
return trackWidth;
}
return trackWidth * 0.56;
}
_classifyInsideDensity(trackWidth, valueWidth) {
if (trackWidth < Math.max(72, valueWidth + 12)) return "compressed";
if (trackWidth < valueWidth + 56) return "dense";
if (trackWidth < valueWidth + 92) return "tight";
if (trackWidth < valueWidth + 128) return "compact";
return "normal";
}
_applyRowDensity() {
if (!this.shadowRoot) return;
this.shadowRoot.querySelectorAll(".main-line").forEach((mainLine) => {
const width = mainLine.getBoundingClientRect().width;
if (!this._isReliableWidth(width)) {
this._schedulePostLayoutDensityPass();
if (!mainLine.dataset.rowDensity) mainLine.dataset.rowDensity = "normal";
return;
}
mainLine.dataset.rowDensity = this._classifyRowDensity(width, mainLine.dataset.rowDensity);
});
}
_applyAboveLabelDensity() {
if (!this.shadowRoot) return;
this.shadowRoot.querySelectorAll(".above-line, .hero-line").forEach((aboveLine) => {
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t;
const label = aboveLine.querySelector(".above-bar-label, .hero-header");
if (!label) return;
const isHeroLine = aboveLine.classList.contains("hero-line");
const width = isHeroLine ? this._getHeroDensityWidth(aboveLine) : label.getBoundingClientRect().width;
let density = "normal";
if (width < 90) density = "xs";
else if (width < 110) density = "compressed";
else if (width < 150) density = "dense";
else if (width < 210) density = "tight";
else if (width < 280) density = "compact";
if (isHeroLine) {
aboveLine.dataset.heroDensity = density;
label.dataset.hideName = density === "dense" || density === "compressed" || density === "xs" ? "true" : "false";
aboveLine.dataset.hideHeroIcon = density === "compressed" || density === "xs" ? "true" : "false";
return;
}
aboveLine.dataset.aboveDensity = density;
const labelText = typeof label.querySelector === "function" ? label.querySelector(".above-bar-label-name") : null;
const valueEl = typeof label.querySelector === "function" ? label.querySelector(".above-bar-label-value") : null;
const display = this._decodeDataAttr(((_a = valueEl == null ? void 0 : valueEl.dataset) == null ? void 0 : _a.display) || "");
const unit = this._decodeDataAttr(((_b = valueEl == null ? void 0 : valueEl.dataset) == null ? void 0 : _b.unit) || "");
const row = (_c = aboveLine.closest) == null ? void 0 : _c.call(aboveLine, ".row");
const mainLine = (_d = row == null ? void 0 : row.querySelector) == null ? void 0 : _d.call(row, ".main-line.above-mode");
const rowDensity = ((_e = mainLine == null ? void 0 : mainLine.dataset) == null ? void 0 : _e.rowDensity) || "normal";
const iconWrap = (_g = (_f = mainLine == null ? void 0 : mainLine.querySelector) == null ? void 0 : _f.call(mainLine, ".icon-wrap")) != null ? _g : null;
const iconRect = (_h = iconWrap == null ? void 0 : iconWrap.getBoundingClientRect) == null ? void 0 : _h.call(iconWrap);
const iconStyle = iconWrap && typeof getComputedStyle === "function" ? getComputedStyle(iconWrap) : null;
const mainIconVisible = !!iconWrap && rowDensity !== "compressed" && (iconStyle == null ? void 0 : iconStyle.display) !== "none" && ((_i = iconRect == null ? void 0 : iconRect.width) != null ? _i : 0) > 0 && ((_j = iconRect == null ? void 0 : iconRect.height) != null ? _j : 0) > 0;
let hideName = density === "dense" || density === "compressed";
let hideSpacer = !mainIconVisible;
if (labelText && valueEl && display) {
const rowStack = (_k = aboveLine.closest) == null ? void 0 : _k.call(aboveLine, ".row-stack");
const lineWidth = (_o = (_n = (_l = rowStack == null ? void 0 : rowStack.getBoundingClientRect) == null ? void 0 : _l.call(rowStack).width) != null ? _n : (_m = aboveLine.getBoundingClientRect) == null ? void 0 : _m.call(aboveLine).width) != null ? _o : width;
const spacerEl = typeof aboveLine.querySelector === "function" ? aboveLine.querySelector(".above-icon-spacer") : null;
const spacerWidth = (_q = (_p = spacerEl == null ? void 0 : spacerEl.getBoundingClientRect) == null ? void 0 : _p.call(spacerEl).width) != null ? _q : 0;
const lineGap = spacerEl ? this._getNumericStyleValue(aboveLine, "gap", 0) : 0;
const nameWidth = (_t = (_s = (_r = labelText.getBoundingClientRect) == null ? void 0 : _r.call(labelText).width) != null ? _s : labelText.clientWidth) != null ? _t : 0;
const labelGap = this._getNumericStyleValue(label, "gap", this._getLeftModeGap(aboveLine));
const fullValueWidth = Math.ceil(this._measureValueMarkupWidth(valueEl, display, unit, false) + 2);
const valueOnlyWidth = Math.ceil(this._measureValueMarkupWidth(valueEl, display, unit, true) + 2);
const text = (labelText.textContent || "").trim();
const visibleWidth = labelText.clientWidth;
const fullWidth = labelText.scrollWidth;
const visibleChars = this._measureVisibleLabelCharacters(labelText, text, visibleWidth);
const labelIsUnhelpful = this._shouldHideLeftLabel(text, fullWidth, visibleWidth, visibleChars);
const spacerReserve = mainIconVisible && spacerWidth > 0 ? spacerWidth + lineGap : 0;
const availableWithName = Math.max(0, lineWidth - spacerReserve - nameWidth - labelGap);
const availableValueOnly = Math.max(0, lineWidth);
hideName = labelIsUnhelpful;
if (!hideName && fullValueWidth <= availableWithName) {
hideSpacer = !mainIconVisible;
} else if (!hideName && valueOnlyWidth <= availableWithName) {
hideSpacer = !mainIconVisible;
} else {
hideName = true;
hideSpacer = true;
}
const availableWidth = hideName ? availableValueOnly : availableWithName;
const hideUnit = !!unit && fullValueWidth > availableWidth;
valueEl.dataset.hideUnit = hideUnit ? "true" : "false";
} else if (valueEl) {
valueEl.dataset.hideUnit = "false";
}
label.dataset.hideName = hideName ? "true" : "false";
aboveLine.dataset.hideAboveIcon = hideSpacer ? "true" : "false";
});
}
_getHeroDensityWidth(heroLine) {
var _a, _b, _c, _d, _e, _f, _g, _h, _i;
const row = (_a = heroLine == null ? void 0 : heroLine.closest) == null ? void 0 : _a.call(heroLine, ".row");
const rowStack = (_b = heroLine == null ? void 0 : heroLine.closest) == null ? void 0 : _b.call(heroLine, ".row-stack");
const mainLine = (_c = rowStack == null ? void 0 : rowStack.querySelector) == null ? void 0 : _c.call(rowStack, ".main-line.hero-mode");
const barWrap = (_d = mainLine == null ? void 0 : mainLine.querySelector) == null ? void 0 : _d.call(mainLine, ".bar-wrap");
const candidates = [
(_e = row == null ? void 0 : row.getBoundingClientRect) == null ? void 0 : _e.call(row).width,
(_f = rowStack == null ? void 0 : rowStack.getBoundingClientRect) == null ? void 0 : _f.call(rowStack).width,
(_g = mainLine == null ? void 0 : mainLine.getBoundingClientRect) == null ? void 0 : _g.call(mainLine).width,
(_h = barWrap == null ? void 0 : barWrap.getBoundingClientRect) == null ? void 0 : _h.call(barWrap).width,
(_i = heroLine == null ? void 0 : heroLine.getBoundingClientRect) == null ? void 0 : _i.call(heroLine).width
];
for (const width of candidates) {
if (this._isReliableWidth(width, 8)) return width;
}
return 0;
}
_measureHeroValueWidth(heroLine, valueEl, valueFit = "normal", hideUnit = false) {
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n;
const layer = (_a = this.shadowRoot) == null ? void 0 : _a.querySelector(".measure-layer");
if (!layer || !heroLine || !valueEl) return 0;
const display = this._decodeDataAttr(valueEl.dataset.display || valueEl.textContent || "");
const unit = this._decodeDataAttr(valueEl.dataset.unit || "");
if (!display) return 0;
const wrapper = document.createElement("div");
wrapper.className = "hero-line";
wrapper.dataset.heroSize = heroLine.dataset.heroSize || "medium";
wrapper.dataset.heroDensity = heroLine.dataset.heroDensity || "normal";
wrapper.dataset.heroValueFit = valueFit;
wrapper.dataset.hideHeroUnit = hideUnit ? "true" : "false";
wrapper.style.display = "inline-block";
this._setStyleIfChanged(
wrapper,
"--sbcp-hero-base-size",
((_c = (_b = heroLine.style) == null ? void 0 : _b.getPropertyValue) == null ? void 0 : _c.call(_b, "--sbcp-hero-base-size")) || null
);
const measureValue = document.createElement("span");
measureValue.className = "hero-value";
measureValue.dataset.display = valueEl.dataset.display || "";
measureValue.dataset.unit = valueEl.dataset.unit || "";
measureValue.innerHTML = this._formatRightValueMarkup(display, unit, hideUnit);
measureValue.style.display = "inline-flex";
measureValue.style.flex = "0 0 auto";
measureValue.style.width = "auto";
measureValue.style.minWidth = "0";
measureValue.style.maxWidth = "none";
measureValue.style.justifyContent = "flex-start";
measureValue.style.justifySelf = "start";
measureValue.style.overflow = "visible";
const text = measureValue.querySelector(".value-right-text");
if (text) {
text.style.display = "inline-flex";
text.style.flex = "0 0 auto";
text.style.width = "auto";
text.style.minWidth = "0";
text.style.maxWidth = "none";
text.style.justifyContent = "flex-start";
text.style.overflow = "visible";
}
const number = measureValue.querySelector(".value-right-number");
if (number) {
number.style.flex = "0 0 auto";
number.style.minWidth = "0";
number.style.overflow = "visible";
number.style.textOverflow = "clip";
}
const unitGroup = measureValue.querySelector(".unit-group");
if (unitGroup) {
unitGroup.style.flex = "0 0 auto";
unitGroup.style.minWidth = "0";
unitGroup.style.overflow = "visible";
}
wrapper.appendChild(measureValue);
layer.replaceChildren(wrapper);
return Math.max(
Math.ceil((_e = (_d = measureValue.getBoundingClientRect) == null ? void 0 : _d.call(measureValue).width) != null ? _e : 0),
Math.ceil(measureValue.scrollWidth || 0),
Math.ceil((_h = (_g = (_f = text == null ? void 0 : text.getBoundingClientRect) == null ? void 0 : _f.call(text).width) != null ? _g : text == null ? void 0 : text.scrollWidth) != null ? _h : 0),
Math.ceil((_k = (_j = (_i = number == null ? void 0 : number.getBoundingClientRect) == null ? void 0 : _i.call(number).width) != null ? _j : number == null ? void 0 : number.scrollWidth) != null ? _k : 0),
Math.ceil((_n = (_m = (_l = unitGroup == null ? void 0 : unitGroup.getBoundingClientRect) == null ? void 0 : _l.call(unitGroup).width) != null ? _m : unitGroup == null ? void 0 : unitGroup.scrollWidth) != null ? _n : 0)
);
}
_applyHeroValueFit() {
if (!this.shadowRoot) return;
this.shadowRoot.querySelectorAll(".hero-line").forEach((heroLine) => {
var _a, _b;
const headerEl = heroLine.querySelector(".hero-header");
const labelEl = heroLine.querySelector(".hero-label");
const valueEl = heroLine.querySelector(".hero-value");
const unitGroup = heroLine.querySelector(".unit-group");
if (!headerEl || !valueEl) return;
heroLine.dataset.hideHeroUnit = "false";
heroLine.dataset.heroValueFit = "normal";
delete headerEl.dataset.priorityHideName;
const headerWidth = Math.floor((_b = (_a = headerEl.getBoundingClientRect) == null ? void 0 : _a.call(headerEl).width) != null ? _b : 0);
if (!this._isReliableWidth(headerWidth, 8)) {
this._schedulePostLayoutDensityPass();
return;
}
const hasUnit = !!unitGroup && unitGroup.textContent.trim().length > 0;
const labelHiddenByDensity = headerEl.dataset.hideName === "true";
const visibleLabelGap = !labelHiddenByDensity && labelEl ? this._getNumericStyleValue(headerEl, "column-gap", 0) : 0;
const valueWidth = (valueFit = "normal", hideUnit = false) => this._measureHeroValueWidth(heroLine, valueEl, valueFit, hideUnit);
const availableWithLabel = Math.max(0, headerWidth - visibleLabelGap - 4);
const availableWithoutLabel = Math.max(0, headerWidth - 4);
if (!this._isReliableWidth(availableWithoutLabel, 8)) {
heroLine.dataset.hideHeroUnit = hasUnit ? "true" : "false";
heroLine.dataset.heroValueFit = "minimum";
this._schedulePostLayoutDensityPass();
return;
}
if (valueWidth("normal", false) <= availableWithLabel) return;
if (!labelHiddenByDensity && labelEl) {
headerEl.dataset.priorityHideName = "true";
if (valueWidth("normal", false) <= availableWithoutLabel) return;
}
if (hasUnit) {
heroLine.dataset.hideHeroUnit = "true";
if (valueWidth("normal", true) <= availableWithoutLabel) return;
}
heroLine.dataset.heroValueFit = "tight";
if (valueWidth("tight", hasUnit) <= availableWithoutLabel) return;
heroLine.dataset.heroValueFit = "minimum";
if (valueWidth("minimum", hasUnit) <= availableWithoutLabel) return;
heroLine.dataset.heroValueFit = "hidden";
});
}
_measureValueMarkupWidth(valueEl, display, unit, hideUnit) {
var _a;
const layer = (_a = this.shadowRoot) == null ? void 0 : _a.querySelector(".measure-layer");
if (!layer || !valueEl) return 0;
const clone = valueEl.cloneNode(false);
clone.removeAttribute("data-hide-unit");
clone.style.removeProperty("--sbcp-value-extra-width");
clone.style.width = "auto";
clone.style.minWidth = "0";
clone.style.maxWidth = "none";
clone.style.flex = "0 0 auto";
clone.innerHTML = this._formatRightValueMarkup(display, unit, hideUnit);
layer.replaceChildren(clone);
return clone.scrollWidth;
}
_measureInsideValueMarkupWidth(valueEl, display, unit, hideUnit = false) {
var _a;
const layer = (_a = this.shadowRoot) == null ? void 0 : _a.querySelector(".measure-layer");
if (!layer || !valueEl) return (valueEl == null ? void 0 : valueEl.scrollWidth) || 0;
const clone = valueEl.cloneNode(false);
clone.style.width = "auto";
clone.style.minWidth = "0";
clone.style.maxWidth = "none";
clone.style.flex = "0 0 auto";
clone.style.overflow = "visible";
clone.style.textOverflow = "clip";
clone.style.whiteSpace = "nowrap";
clone.innerHTML = this._formatInsideValueMarkup(display, unit, hideUnit);
layer.replaceChildren(clone);
let extraWidth = 0;
try {
const style = getComputedStyle(valueEl);
extraWidth += parseFloat(style.paddingLeft || "0") || 0;
extraWidth += parseFloat(style.paddingRight || "0") || 0;
extraWidth += parseFloat(style.borderLeftWidth || "0") || 0;
extraWidth += parseFloat(style.borderRightWidth || "0") || 0;
} catch (_err) {
}
return clone.getBoundingClientRect().width + extraWidth;
}
_measureTextWidthWithStyles(sourceEl, text) {
var _a;
const layer = (_a = this.shadowRoot) == null ? void 0 : _a.querySelector(".measure-layer");
if (!layer || !sourceEl) return 0;
const clone = sourceEl.cloneNode(false);
clone.textContent = text;
clone.style.width = "auto";
clone.style.minWidth = "0";
clone.style.maxWidth = "none";
clone.style.flex = "0 0 auto";
clone.style.overflow = "visible";
clone.style.textOverflow = "clip";
clone.style.whiteSpace = "nowrap";
layer.replaceChildren(clone);
return clone.scrollWidth;
}
_measureVisibleLabelCharacters(labelTextEl, text, visibleWidth) {
if (!labelTextEl || !text || !Number.isFinite(visibleWidth) || visibleWidth <= 0) return 0;
const ellipsisWidth = this._measureTextWidthWithStyles(labelTextEl, "...");
const availableTextWidth = Math.max(0, visibleWidth - ellipsisWidth);
if (availableTextWidth <= 0) return 0;
let low = 0;
let high = text.length;
while (low < high) {
const mid = Math.ceil((low + high) / 2);
const width = this._measureTextWidthWithStyles(labelTextEl, text.slice(0, mid));
if (width <= availableTextWidth) {
low = mid;
} else {
high = mid - 1;
}
}
return low;
}
_shouldHideLeftLabel(text, fullWidth, visibleWidth, visibleChars) {
if (!text) return false;
if (!Number.isFinite(fullWidth) || !Number.isFinite(visibleWidth)) return false;
const truncated = fullWidth > visibleWidth + 1;
return truncated && visibleChars < 5;
}
_getInsideUsefulNameWidth(labelTextEl, text, fullWidth = NaN) {
if (!text) return 0;
const naturalWidth = Number.isFinite(fullWidth) && fullWidth > 0 ? fullWidth : this._measureTextWidthWithStyles(labelTextEl, text);
const usefulChars = text.slice(0, Math.min(5, text.length));
const usefulWidth = this._measureTextWidthWithStyles(labelTextEl, usefulChars) + this._measureTextWidthWithStyles(labelTextEl, "...");
const minUsefulWidth = Math.max(36, Math.min(44, usefulWidth || 0));
return Math.min(naturalWidth || minUsefulWidth, minUsefulWidth);
}
_applyValueWidthReservation() {
if (!this.shadowRoot) return;
this.shadowRoot.querySelectorAll(".value-right").forEach((valueEl) => {
var _a, _b, _c;
const display = this._decodeDataAttr(valueEl.dataset.display || "");
const unit = this._decodeDataAttr(valueEl.dataset.unit || "");
if (!display) {
valueEl.style.setProperty("--sbcp-value-extra-width", "0px");
return;
}
const getStyle = typeof globalThis.getComputedStyle === "function" && globalThis.getComputedStyle.bind(globalThis) || typeof window !== "undefined" && typeof window.getComputedStyle === "function" && window.getComputedStyle.bind(window) || ((_c = (_b = (_a = valueEl == null ? void 0 : valueEl.ownerDocument) == null ? void 0 : _a.defaultView) == null ? void 0 : _b.getComputedStyle) == null ? void 0 : _c.bind(valueEl.ownerDocument.defaultView));
if (!getStyle) return;
const style = getStyle(valueEl);
const baseWidth = parseFloat(style.getPropertyValue("--sbcp-value-width")) || valueEl.clientWidth || 0;
const desiredWidth = Math.ceil(this._measureValueMarkupWidth(valueEl, display, unit, false) + 2);
const extraWidth = Math.max(0, desiredWidth - baseWidth);
valueEl.style.setProperty("--sbcp-value-extra-width", `${extraWidth}px`);
});
}
_applyValueVisibility() {
if (!this.shadowRoot) return;
this.shadowRoot.querySelectorAll(".value-right, .top-right-value, .above-bar-label-value").forEach((valueEl) => {
var _a, _b, _c, _d;
const display = this._decodeDataAttr(valueEl.dataset.display || "");
const unit = this._decodeDataAttr(valueEl.dataset.unit || "");
let hideUnit = valueEl.dataset.hideUnit === "true";
const isAboveValue = (_a = valueEl.classList) == null ? void 0 : _a.contains("above-bar-label-value");
if (!isAboveValue && display) {
const availableWidth = (_d = (_c = (_b = valueEl.getBoundingClientRect) == null ? void 0 : _b.call(valueEl).width) != null ? _c : valueEl.clientWidth) != null ? _d : 0;
const fullValueWidth = Math.ceil(this._measureValueMarkupWidth(valueEl, display, unit, false) + 2);
hideUnit = !!unit && availableWidth > 0 ? fullValueWidth > availableWidth : false;
valueEl.dataset.hideUnit = hideUnit ? "true" : "false";
}
if (valueEl.innerHTML !== this._formatRightValueMarkup(display, unit, hideUnit)) {
valueEl.innerHTML = this._formatRightValueMarkup(display, unit, hideUnit);
}
});
this.shadowRoot.querySelectorAll(".inside-value").forEach((valueEl) => {
const display = this._decodeDataAttr(valueEl.dataset.display || "");
const unit = this._decodeDataAttr(valueEl.dataset.unit || "");
const hideUnit = valueEl.dataset.hideUnit === "true";
const hideValue = valueEl.dataset.hideValue === "true";
if (!hideValue && !display) return;
if (!valueEl.dataset.hideUnit) valueEl.dataset.hideUnit = "false";
if (!valueEl.dataset.hideValue) valueEl.dataset.hideValue = "false";
const nextMarkup = this._formatInsideValueMarkup(display, unit, hideUnit);
if (valueEl.innerHTML !== nextMarkup) {
valueEl.innerHTML = nextMarkup;
}
});
}
_getMinimumBarShare() {
return 0.5;
}
_getMinimumBarShareHysteresis() {
return 0.02;
}
_getTopValueEnableShare() {
return this._getMinimumBarShare() - this._getMinimumBarShareHysteresis();
}
_getTopValueDisableShare() {
return this._getMinimumBarShare() + this._getMinimumBarShareHysteresis();
}
_getNumericStyleValue(el, propertyName, fallback = 0) {
if (!el) return fallback;
try {
const value = parseFloat(getComputedStyle(el).getPropertyValue(propertyName));
return Number.isFinite(value) ? value : fallback;
} catch (_err) {
return fallback;
}
}
_getLeftModeGap(mainLine) {
var _a;
const computedGap = this._getNumericStyleValue(mainLine, "gap", NaN);
if (Number.isFinite(computedGap)) return computedGap;
const density = ((_a = mainLine == null ? void 0 : mainLine.dataset) == null ? void 0 : _a.rowDensity) || "normal";
if (density === "tight") return 7;
if (density === "dense" || density === "compressed") return 6;
return 8;
}
_getLeftModeBarMinWidth(mainLine) {
var _a;
const computedMin = this._getNumericStyleValue(mainLine, "--sbcp-bar-min-width", NaN);
if (Number.isFinite(computedMin)) return computedMin;
const density = ((_a = mainLine == null ? void 0 : mainLine.dataset) == null ? void 0 : _a.leftDensity) || "normal";
if (density === "compact") return 52;
if (density === "tight") return 48;
if (density === "dense") return 44;
if (density === "compressed") return 40;
return 56;
}
_getLeftModeIconWidth(iconWrap, mainLine) {
var _a, _b;
const measured = (_a = iconWrap == null ? void 0 : iconWrap.getBoundingClientRect) == null ? void 0 : _a.call(iconWrap).width;
if (this._isReliableWidth(measured, 1)) return measured;
const computed = this._getNumericStyleValue(iconWrap || mainLine, "--sbcp-icon-width", NaN);
if (Number.isFinite(computed)) return computed;
const density = ((_b = mainLine == null ? void 0 : mainLine.dataset) == null ? void 0 : _b.leftDensity) || "normal";
if (density === "compact") return 26;
if (density === "tight") return 24;
if (density === "dense") return 23;
if (density === "compressed") return 22;
return 28;
}
_getReservedInlineValueWidth(valueEl) {
var _a, _b, _c;
if (!valueEl) return 0;
const display = this._decodeDataAttr(valueEl.dataset.display || "");
const unit = this._decodeDataAttr(valueEl.dataset.unit || "");
const baseWidth = this._getNumericStyleValue(valueEl, "--sbcp-value-width", valueEl.clientWidth || 0);
const inlineExtra = parseFloat(((_b = (_a = valueEl.style) == null ? void 0 : _a.getPropertyValue) == null ? void 0 : _b.call(_a, "--sbcp-value-extra-width")) || ((_c = valueEl.style) == null ? void 0 : _c["--sbcp-value-extra-width"]) || "0");
const extraWidth = Number.isFinite(inlineExtra) ? inlineExtra : this._getNumericStyleValue(valueEl, "--sbcp-value-extra-width", 0);
const reservedWidth = Math.max(0, baseWidth + extraWidth);
if (!display) return reservedWidth;
const fullMarkupWidth = Math.ceil(this._measureValueMarkupWidth(valueEl, display, unit, false) + 2);
return Math.max(reservedWidth, fullMarkupWidth);
}
_estimateLeftModeWidthBudget(row) {
var _a, _b, _c, _d, _e, _f;
const mainLine = row == null ? void 0 : row.querySelector(".main-line");
if (!mainLine) return null;
const rowWidth = (_b = (_a = mainLine.getBoundingClientRect) == null ? void 0 : _a.call(mainLine).width) != null ? _b : 0;
if (!this._isReliableWidth(rowWidth)) return null;
const labelWrap = row.querySelector(".label-left");
const iconWrap = row.querySelector(".icon-wrap");
const valueEl = row.querySelector(".value-right");
const labelMetrics = this._getLabelSacrificeMetrics(row, "left", { rowWidth });
const labelWidth = ((_c = labelWrap == null ? void 0 : labelWrap.dataset) == null ? void 0 : _c.hidden) === "true" ? 0 : (_f = (_e = (_d = labelWrap == null ? void 0 : labelWrap.getBoundingClientRect) == null ? void 0 : _d.call(labelWrap).width) != null ? _e : labelMetrics == null ? void 0 : labelMetrics.labelWidth) != null ? _f : 0;
const iconWidth = iconWrap ? this._getLeftModeIconWidth(iconWrap, mainLine) : 0;
const valueWidth = this._getReservedInlineValueWidth(valueEl);
const gap = this._getLeftModeGap(mainLine);
const barMinWidth = this._getLeftModeBarMinWidth(mainLine);
const baseLabelVisible = !!labelWrap && labelWrap.dataset.hidden !== "true";
const labelSacrificial = baseLabelVisible ? this._isLabelWorthSacrificing(row, "left", { rowWidth }) : true;
const hasIcon = !!iconWrap;
return {
rowWidth,
gap,
barMinWidth,
labelWidth: this._isReliableWidth(labelWidth, 0) ? labelWidth : 0,
iconWidth: this._isReliableWidth(iconWidth, 0) ? iconWidth : 0,
valueWidth: this._isReliableWidth(valueWidth, 0) ? valueWidth : 0,
baseLabelVisible,
labelSacrificial,
hasIcon,
mainLine,
labelWrap,
iconWrap,
valueEl,
rowStack: row.querySelector(".row-stack")
};
}
_predictLeftModeBarShareForState(row, state, budget = null) {
const effectiveBudget = budget || this._estimateLeftModeWidthBudget(row);
if (!effectiveBudget) return null;
const showLabel = effectiveBudget.baseLabelVisible && !state.hideLabel;
const showIcon = effectiveBudget.hasIcon && !state.hideIcon;
const showInlineValue = !state.topValue;
const visibleItems = 1 + (showIcon ? 1 : 0) + (showLabel ? 1 : 0) + (showInlineValue ? 1 : 0);
const gapCount = Math.max(0, visibleItems - 1);
const reservedWidth = (showIcon ? effectiveBudget.iconWidth : 0) + (showLabel ? effectiveBudget.labelWidth : 0) + (showInlineValue ? effectiveBudget.valueWidth : 0) + gapCount * effectiveBudget.gap;
const predictedBarWidth = Math.max(0, effectiveBudget.rowWidth - reservedWidth);
return {
rowWidth: effectiveBudget.rowWidth,
barWidth: predictedBarWidth,
share: predictedBarWidth / effectiveBudget.rowWidth,
showLabel,
showIcon,
showInlineValue,
reservedWidth,
gapCount
};
}
_getLeftModeCandidateStates(budget) {
const states = [
{ hideLabel: false, topValue: false, hideIcon: false }
];
if (budget == null ? void 0 : budget.labelSacrificial) {
states.push({ hideLabel: true, topValue: false, hideIcon: false });
}
states.push(
{ hideLabel: false, topValue: true, hideIcon: false },
{ hideLabel: true, topValue: true, hideIcon: false },
{ hideLabel: true, topValue: true, hideIcon: true }
);
return states;
}
_chooseFirstPredictedLeftModeState(row, states, threshold, budget) {
for (const state of states) {
const predicted = this._predictLeftModeBarShareForState(row, state, budget);
if (!predicted) continue;
if (predicted.share >= threshold) return { ...state, predicted };
}
return null;
}
_chooseFallbackPredictedLeftModeState(row, states, budget) {
let fallback = null;
for (const state of states) {
const predicted = this._predictLeftModeBarShareForState(row, state, budget);
if (!predicted) continue;
fallback = { ...state, predicted };
}
return fallback;
}
_chooseLeftModeResponsiveState(row) {
var _a, _b;
const budget = this._estimateLeftModeWidthBudget(row);
if (!budget) return null;
const minimumBarShare = this._getMinimumBarShare();
const states = this._getLeftModeCandidateStates(budget);
const previousTopValue = ((_b = (_a = budget.rowStack) == null ? void 0 : _a.dataset) == null ? void 0 : _b.forceTopValue) === "true";
const inlineStates = states.filter((state) => !state.topValue);
const topStates = states.filter((state) => state.topValue);
const enableShare = this._getTopValueEnableShare();
const disableShare = this._getTopValueDisableShare();
const inlineChoice = previousTopValue ? this._chooseFirstPredictedLeftModeState(row, inlineStates, disableShare, budget) : this._chooseFirstPredictedLeftModeState(row, inlineStates, enableShare, budget);
if (inlineChoice) return inlineChoice;
const topChoice = this._chooseFirstPredictedLeftModeState(row, topStates, minimumBarShare, budget) || this._chooseFallbackPredictedLeftModeState(row, topStates, budget);
return topChoice;
}
_applyLeftModeResponsiveState(row, state) {
const mainLine = row == null ? void 0 : row.querySelector(".main-line");
const rowStack = row == null ? void 0 : row.querySelector(".row-stack");
const leftLabel = row == null ? void 0 : row.querySelector(".label-left");
if (!mainLine || !rowStack) return;
delete rowStack.dataset.forceTopValue;
delete mainLine.dataset.hideLeftIcon;
if (leftLabel) delete leftLabel.dataset.priorityHidden;
if ((state == null ? void 0 : state.hideLabel) && leftLabel) {
leftLabel.dataset.priorityHidden = "true";
}
if (state == null ? void 0 : state.topValue) {
rowStack.dataset.forceTopValue = "true";
}
if (state == null ? void 0 : state.hideIcon) {
mainLine.dataset.hideLeftIcon = "true";
}
}
_getMeasuredBarShare(row) {
const mainLine = row == null ? void 0 : row.querySelector(".main-line");
const track = row == null ? void 0 : row.querySelector(".bar-track");
if (!mainLine || !track) return null;
const rowWidth = mainLine.getBoundingClientRect().width;
const barWidth = track.getBoundingClientRect().width;
if (!this._isReliableWidth(rowWidth) || !this._isReliableWidth(barWidth, 1)) return null;
return { rowWidth, barWidth, share: barWidth / rowWidth, mainLine, track };
}
_clearMinimumBarShareOverrides(row) {
const mainLine = row == null ? void 0 : row.querySelector(".main-line");
const rowStack = row == null ? void 0 : row.querySelector(".row-stack");
const leftLabel = row == null ? void 0 : row.querySelector(".label-left");
const aboveLabel = row == null ? void 0 : row.querySelector(".above-bar-label");
const innerLabel = row == null ? void 0 : row.querySelector(".bar-inner-label");
const aboveLine = row == null ? void 0 : row.querySelector(".above-line");
if (rowStack) delete rowStack.dataset.forceTopValue;
if (leftLabel) delete leftLabel.dataset.priorityHidden;
if (aboveLabel) delete aboveLabel.dataset.priorityHideName;
if (innerLabel) delete innerLabel.dataset.priorityHideName;
if (!mainLine) return;
delete mainLine.dataset.hideLeftIcon;
delete mainLine.dataset.hideAboveIcon;
delete mainLine.dataset.priorityHideInsideIcon;
}
_hideMinimumBarShareLabel(row, mode) {
if (mode === "left") {
const leftLabel = row.querySelector(".label-left");
if (leftLabel) leftLabel.dataset.priorityHidden = "true";
return;
}
if (mode === "above") {
const aboveLabel = row.querySelector(".above-bar-label");
if (aboveLabel) aboveLabel.dataset.priorityHideName = "true";
return;
}
if (mode === "inside") {
const innerLabel = row.querySelector(".bar-inner-label");
if (innerLabel) innerLabel.dataset.priorityHideName = "true";
}
}
_forceMinimumBarShareTopValue(row, mode) {
if (mode !== "left") return;
const rowStack = row.querySelector(".row-stack");
if (rowStack) rowStack.dataset.forceTopValue = "true";
}
_hideMinimumBarShareIcon(row, mode) {
const mainLine = row.querySelector(".main-line");
if (!mainLine) return;
if (mode === "left") {
mainLine.dataset.hideLeftIcon = "true";
return;
}
if (mode === "above") {
mainLine.dataset.hideAboveIcon = "true";
const aboveLine = row.querySelector(".above-line");
if (aboveLine) aboveLine.dataset.hideAboveIcon = "true";
return;
}
if (mode === "inside") {
mainLine.dataset.priorityHideInsideIcon = "true";
}
}
_getLabelSacrificeMetrics(row, mode, measurement) {
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
const rowWidth = (_d = (_c = measurement == null ? void 0 : measurement.rowWidth) != null ? _c : (_b = (_a = row == null ? void 0 : row.querySelector(".main-line")) == null ? void 0 : _a.getBoundingClientRect) == null ? void 0 : _b.call(_a).width) != null ? _d : 0;
if (!this._isReliableWidth(rowWidth)) return null;
if (mode === "left") {
const labelWrap = row.querySelector(".label-left");
const labelText = row.querySelector(".label-left-text");
if (!labelWrap || !labelText) return null;
const text = (labelText.textContent || "").trim();
const visibleWidth = labelText.clientWidth;
const fullWidth = labelText.scrollWidth;
const visibleChars = this._measureVisibleLabelCharacters(labelText, text, visibleWidth);
const labelWidth = (_f = (_e = labelWrap.getBoundingClientRect) == null ? void 0 : _e.call(labelWrap).width) != null ? _f : visibleWidth;
return { text, visibleWidth, fullWidth, visibleChars, labelWidth, rowWidth };
}
if (mode === "above") {
const labelText = row.querySelector(".above-bar-label-name");
if (!labelText) return null;
const text = (labelText.textContent || "").trim();
const visibleWidth = labelText.clientWidth;
const fullWidth = labelText.scrollWidth;
const visibleChars = this._measureVisibleLabelCharacters(labelText, text, visibleWidth);
const labelWidth = (_h = (_g = labelText.getBoundingClientRect) == null ? void 0 : _g.call(labelText).width) != null ? _h : visibleWidth;
return { text, visibleWidth, fullWidth, visibleChars, labelWidth, rowWidth };
}
if (mode === "inside") {
const labelText = row.querySelector(".inside-name");
if (!labelText) return null;
const text = (labelText.textContent || "").trim();
const visibleWidth = labelText.clientWidth;
const fullWidth = labelText.scrollWidth;
const visibleChars = this._measureVisibleLabelCharacters(labelText, text, visibleWidth);
const labelWidth = (_j = (_i = labelText.getBoundingClientRect) == null ? void 0 : _i.call(labelText).width) != null ? _j : visibleWidth;
return { text, visibleWidth, fullWidth, visibleChars, labelWidth, rowWidth };
}
return null;
}
_isLabelWorthSacrificing(row, mode, measurement) {
const metrics = this._getLabelSacrificeMetrics(row, mode, measurement);
if (!metrics || !metrics.text) return false;
return this._shouldHideLeftLabel(metrics.text, metrics.fullWidth, metrics.visibleWidth, metrics.visibleChars);
}
_ensureMinimumBarShare(rows = null) {
if (!this.shadowRoot) return;
const targetRows = rows || this.shadowRoot.querySelectorAll(".row[data-entity]");
const minimumBarShare = this._getMinimumBarShare();
targetRows.forEach((row) => {
const mainLine = row.querySelector(".main-line");
if (!mainLine) return;
const mode = mainLine.classList.contains("left-mode") ? "left" : mainLine.classList.contains("above-mode") ? "above" : mainLine.classList.contains("inside-mode") ? "inside" : "other";
if (mode === "other") return;
if (mode === "left") {
const state = this._chooseLeftModeResponsiveState(row);
if (state) this._applyLeftModeResponsiveState(row, state);
return;
}
this._clearMinimumBarShareOverrides(row);
let measurement = this._getMeasuredBarShare(row);
if (!measurement || measurement.share >= minimumBarShare) return;
if (this._isLabelWorthSacrificing(row, mode, measurement)) {
this._hideMinimumBarShareLabel(row, mode);
measurement = this._getMeasuredBarShare(row);
if (!measurement || measurement.share >= minimumBarShare) return;
}
this._forceMinimumBarShareTopValue(row, mode);
this._applyTopRightValueLayout();
measurement = this._getMeasuredBarShare(row);
if (!measurement || measurement.share >= minimumBarShare) return;
this._hideMinimumBarShareIcon(row, mode);
});
}
_shouldUseTopValueRow(mainLine) {
var _a, _b, _c;
if (!((_a = mainLine == null ? void 0 : mainLine.classList) == null ? void 0 : _a.contains("left-mode"))) return false;
return ((_c = (_b = mainLine.closest) == null ? void 0 : _b.call(mainLine, ".row-stack")) == null ? void 0 : _c.dataset.forceTopValue) === "true";
}
_getAdaptiveDensityForMainLine(mainLine) {
var _a;
if (!mainLine) return "normal";
if ((_a = mainLine.classList) == null ? void 0 : _a.contains("left-mode")) {
return mainLine.dataset.leftDensity || "normal";
}
return mainLine.dataset.rowDensity || "normal";
}
_getAdaptiveDefaultHeightForDensity(density) {
if (density === "compressed") return 24;
if (density === "dense") return 28;
return 38;
}
_getEffectiveRowHeight(baseHeight, heightExplicit, mainLine) {
if (heightExplicit) return this._clampSupportedRowHeight(baseHeight);
return this._clampSupportedRowHeight(this._getAdaptiveDefaultHeightForDensity(this._getAdaptiveDensityForMainLine(mainLine)));
}
_applyAdaptiveRowHeight() {
if (!this.shadowRoot) return;
this.shadowRoot.querySelectorAll(".row[data-entity]").forEach((row) => {
const mainLine = row.querySelector(".main-line");
const rowStack = row.querySelector(".row-stack");
if (!mainLine) return;
const baseHeight = parseFloat(row.dataset.baseHeight || "38") || 38;
const explicit = row.dataset.heightExplicit === "true";
const effectiveHeight = this._getEffectiveRowHeight(baseHeight, explicit, mainLine);
row.style.setProperty("--sbcp-row-height", `${effectiveHeight}px`);
if (rowStack) rowStack.style.setProperty("--sbcp-row-height", `${effectiveHeight}px`);
mainLine.style.height = `${effectiveHeight}px`;
const labelLeft = mainLine.querySelector(".label-left");
if (labelLeft) labelLeft.style.height = `${effectiveHeight}px`;
const iconWrap = mainLine.querySelector(".icon-wrap");
if (iconWrap) {
iconWrap.style.height = `${effectiveHeight}px`;
iconWrap.style.minHeight = `${effectiveHeight}px`;
}
const track = mainLine.querySelector(".bar-track");
if (track) track.style.height = `${effectiveHeight}px`;
const inlineValue = mainLine.querySelector(".value-right");
if (inlineValue) inlineValue.style.height = `${effectiveHeight}px`;
});
}
_applyTopRightValueLayout() {
if (!this.shadowRoot) return;
this.shadowRoot.querySelectorAll(".main-line.left-mode").forEach((mainLine) => {
var _a, _b, _c, _d, _e;
const rowStack = mainLine.closest(".row-stack");
const inlineValue = mainLine.querySelector(".value-right");
const topValue = rowStack == null ? void 0 : rowStack.querySelector(".top-right-value");
if (!rowStack || !inlineValue || !topValue) return;
const active = this._shouldUseTopValueRow(mainLine);
rowStack.dataset.topValue = active ? "true" : "false";
topValue.dataset.active = active ? "true" : "false";
const display = this._decodeDataAttr(inlineValue.dataset.display || "");
const unit = this._decodeDataAttr(inlineValue.dataset.unit || "");
topValue.dataset.display = inlineValue.dataset.display || "";
topValue.dataset.unit = inlineValue.dataset.unit || "";
topValue.dataset.hideUnit = "false";
const availableWidth = (_e = (_d = (_c = (_a = rowStack.getBoundingClientRect) == null ? void 0 : _a.call(rowStack).width) != null ? _c : (_b = topValue.getBoundingClientRect) == null ? void 0 : _b.call(topValue).width) != null ? _d : topValue.clientWidth) != null ? _e : 0;
const fullValueWidth = display ? Math.ceil(this._measureValueMarkupWidth(topValue, display, unit, false) + 2) : 0;
const hideUnit = !!unit && availableWidth > 0 && fullValueWidth > availableWidth;
topValue.dataset.hideUnit = hideUnit ? "true" : "false";
topValue.innerHTML = this._formatRightValueMarkup(display, unit, hideUnit);
});
}
_applyLeftLabelUsefulness() {
if (!this.shadowRoot) return;
this.shadowRoot.querySelectorAll(".main-line.left-mode").forEach((mainLine) => {
const labelWrap = mainLine.querySelector(".label-left");
const labelText = mainLine.querySelector(".label-left-text");
if (!labelWrap || !labelText) return;
labelWrap.dataset.hidden = "false";
const text = (labelText.textContent || "").trim();
const fullWidth = labelText.scrollWidth;
const visibleWidth = labelText.clientWidth;
const visibleChars = this._measureVisibleLabelCharacters(labelText, text, visibleWidth);
const shouldHide = this._shouldHideLeftLabel(text, fullWidth, visibleWidth, visibleChars);
labelWrap.dataset.hidden = shouldHide ? "true" : "false";
});
}
_runPostLayoutPasses(rows = null) {
requestAnimationFrame(() => {
this._applyRowDensity();
this._applyLeftModeDensity();
this._applyAboveLabelDensity();
this._applyHeroValueFit();
this._applyInsideLabelDensity();
this._applyValueWidthReservation();
requestAnimationFrame(() => {
var _a;
this._applyAdaptiveRowHeight();
this._applyValueVisibility();
this._applyLeftLabelUsefulness();
this._applyTopRightValueLayout();
this._ensureMinimumBarShare(rows);
this._applyTopRightValueLayout();
this._applyLeftLabelUsefulness();
const targetRows = rows || ((_a = this.shadowRoot) == null ? void 0 : _a.querySelectorAll(".row[data-entity]")) || [];
targetRows.forEach((row) => {
this._positionTargetLabel(row);
});
});
});
}
_isTightUnit(unit) {
return ["h", "m", "s"].includes(String(unit || "").trim());
}
_encodeDataAttr(value) {
return encodeURIComponent(String(value != null ? value : ""));
}
_decodeDataAttr(value) {
const raw = String(value != null ? value : "");
try {
return decodeURIComponent(raw);
} catch (_err) {
return raw;
}
}
_parseColorToRgb(color) {
const value = String(color || "").trim();
if (!value) return null;
const hexMatch = value.match(/^#([0-9a-f]{3}|[0-9a-f]{6})$/i);
if (hexMatch) {
const hex = hexMatch[1];
const full = hex.length === 3 ? hex.split("").map((c) => c + c).join("") : hex;
return {
r: parseInt(full.slice(0, 2), 16),
g: parseInt(full.slice(2, 4), 16),
b: parseInt(full.slice(4, 6), 16)
};
}
const rgbMatch = value.match(/^rgba?\(([^)]+)\)$/i);
if (rgbMatch) {
const parts = rgbMatch[1].split(",").map((p) => p.trim());
if (parts.length >= 3) {
return {
r: Math.max(0, Math.min(255, parseFloat(parts[0]))),
g: Math.max(0, Math.min(255, parseFloat(parts[1]))),
b: Math.max(0, Math.min(255, parseFloat(parts[2])))
};
}
}
return null;
}
_rgbToHsl({ r, g, b }) {
const rn = r / 255;
const gn = g / 255;
const bn = b / 255;
const max = Math.max(rn, gn, bn);
const min = Math.min(rn, gn, bn);
const l = (max + min) / 2;
if (max === min) {
return { h: 0, s: 0, l: l * 100 };
}
const d = max - min;
const s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
let h;
switch (max) {
case rn:
h = ((gn - bn) / d + (gn < bn ? 6 : 0)) / 6;
break;
case gn:
h = ((bn - rn) / d + 2) / 6;
break;
default:
h = ((rn - gn) / d + 4) / 6;
break;
}
return { h: h * 360, s: s * 100, l: l * 100 };
}
_getMarkerContrastColor(color) {
const rgb = this._parseColorToRgb(color);
if (!rgb) return "#f3f4f6";
const { h, s, l } = this._rgbToHsl(rgb);
const contrastL = Math.abs(l - 90) >= Math.abs(l - 10) ? 90 : 10;
const contrastS = Math.max(40, Math.min(100, s));
return `hsl(${Math.round(h)} ${Math.round(contrastS)}% ${Math.round(contrastL)}%)`;
}
_getNeedleBorderColor(color) {
const rgb = this._parseColorToRgb(color);
if (!rgb) return "#000000";
const toLinear = (channel) => {
const srgb = channel / 255;
return srgb <= 0.04045 ? srgb / 12.92 : ((srgb + 0.055) / 1.055) ** 2.4;
};
const luminance = 0.2126 * toLinear(rgb.r) + 0.7152 * toLinear(rgb.g) + 0.0722 * toLinear(rgb.b);
return luminance < 0.22 ? "#ffffff" : "#000000";
}
_formatDisplayWithUnit(display, unit) {
if (!unit) return String(display);
const cleanUnit = String(unit);
return `${display}${this._isTightUnit(cleanUnit) ? "" : " "}${cleanUnit}`;
}
_formatRightValueMarkup(display, unit, hideUnit = false) {
const escapedDisplay = escapeHtml(display);
if (!unit || hideUnit) {
return `<span class="value-right-text"><span class="value-right-number">${escapedDisplay}</span></span>`;
}
const cleanUnit = String(unit);
const escapedUnit = escapeHtml(cleanUnit);
const tightUnit = this._isTightUnit(cleanUnit);
const textClass = tightUnit ? "value-right-text tight-unit" : "value-right-text has-unit";
return `<span class="${textClass}"><span class="value-right-number">${escapedDisplay}</span><span class="unit-group"><span class="unit">${escapedUnit}</span></span></span>`;
}
_formatAboveValueMarkup(display, unit, hideUnit = false) {
return `<span class="above-bar-label-value" data-display="${this._encodeDataAttr(display)}" data-unit="${this._encodeDataAttr(unit)}" data-hide-unit="${hideUnit ? "true" : "false"}">${this._formatRightValueMarkup(display, unit, hideUnit)}</span>`;
}
_formatInsideValueMarkup(display, unit, hideUnit = false) {
const escapedDisplay = escapeHtml(display);
if (!unit || hideUnit) return `<span class="inside-value-text"><span class="inside-number">${escapedDisplay}</span></span>`;
const cleanUnit = String(unit);
const escapedUnit = escapeHtml(cleanUnit);
const unitModeClass = this._isTightUnit(cleanUnit) ? "tight-unit" : "has-unit";
return `<span class="inside-value-text ${unitModeClass}"><span class="inside-number">${escapedDisplay}</span><span class="inside-unit">${escapedUnit}</span></span>`;
}
_buildRow(entityCfg, stateDisplay, unit, pct, color, peakPct, peakDisplay, targetPct, targetDisplay, peakColor, targetColor, minValue, maxValue) {
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u;
const ecfg = this._resolve(entityCfg);
const stateObj = (_c = (_b = (_a = this._hass) == null ? void 0 : _a.states) == null ? void 0 : _b[entityCfg.entity]) != null ? _c : null;
const rowViewModel = stateObj ? buildRowViewModel({
hass: this._hass,
cardConfig: this._config,
entityConfig: ecfg,
entityState: stateObj,
peaks: this._peaks
}) : null;
const layout = ecfg.layout;
const bar = ecfg.bar;
const targetMarkerCfg = ecfg.target_marker;
const peakMarkerCfg = ecfg.peak_marker;
const safeMin = Number.isFinite(minValue) ? minValue : 0;
const safeMax = Number.isFinite(maxValue) ? maxValue : 100;
const baselinePct = (_d = rowViewModel == null ? void 0 : rowViewModel.baselinePercent) != null ? _d : this._resolveBaselinePct(ecfg, safeMin, safeMax);
const lp = layout.label.position;
const h = (_f = (_e = rowViewModel == null ? void 0 : rowViewModel.attributes) == null ? void 0 : _e.baseHeight) != null ? _f : layout.height;
const name = (_j = (_i = (_g = rowViewModel == null ? void 0 : rowViewModel.name) != null ? _g : ecfg.name) != null ? _i : (_h = stateObj == null ? void 0 : stateObj.attributes) == null ? void 0 : _h.friendly_name) != null ? _j : entityCfg.entity;
const escapedEntityId = escapeHtml((_k = rowViewModel == null ? void 0 : rowViewModel.entityId) != null ? _k : entityCfg.entity);
const escapedName = escapeHtml(name);
const targetEnabled = (targetMarkerCfg == null ? void 0 : targetMarkerCfg.enabled) !== false;
const peakMarkerColor = peakColor || "#888";
const targetMarkerColor = targetColor || "#888";
const peakContrastColor = this._getMarkerContrastColor(peakMarkerColor);
const targetContrastColor = this._getMarkerContrastColor(targetMarkerColor);
const rawValue = (_l = rowViewModel == null ? void 0 : rowViewModel.numericValue) != null ? _l : this._getFiniteNumber(stateDisplay);
const needleState = (_m = rowViewModel == null ? void 0 : rowViewModel.needle) != null ? _m : this._getNeedleRenderState(rawValue, ecfg, safeMin, safeMax, baselinePct);
const fillState = this._getFillRenderState(pct, "var(--sbcp-row-height)", ecfg, color, targetPct, baselinePct, safeMin, safeMax, needleState.show);
const peakMarker = peakMarkerCfg.show && peakPct !== null ? `
<div class="peak-marker" style="left:${peakPct}%;--marker-color:${peakMarkerColor};--marker-contrast-color:${peakContrastColor};">
<div class="peak-outset"></div>
<div class="peak-inset"></div>
</div>` : "";
const targetMarker = `
<div class="target-marker" style="left:${targetPct !== null ? targetPct : 0}%;--marker-color:${targetMarkerColor};--marker-contrast-color:${targetContrastColor};display:${targetPct !== null ? "" : "none"};">
<div class="target-inset"></div>
<div class="target-outset"></div>
</div>`;
const targetValueLabel = targetEnabled && targetMarkerCfg.show_label ? `
<div class="target-value-label" style="left:${targetPct !== null ? targetPct : 0}%;">
${targetDisplay !== null ? escapeHtml(targetDisplay) : ""}
</div>` : "";
const needleMarker = ((_o = (_n = ecfg.bar) == null ? void 0 : _n.needle) == null ? void 0 : _o.show) && !Number.isFinite(baselinePct) ? `
<div class="needle-layer">
<div class="needle-marker" data-edge="${needleState.edge}" style="left:${(_p = needleState.pct) != null ? _p : 0}%;--needle-color:${needleState.color};--needle-border-color:${needleState.borderColor};display:${needleState.show ? "block" : "none"};"></div>
</div>` : "";
const paintLayers = fillState.paintLayers.map((layer) => `
<div class="bar-paint-layer" data-layer="${layer.id}" style="z-index:${layer.zIndex};${layer.paintStyle}${layer.revealStyle}"></div>`).join("");
const aboveLabel = lp === "above" ? `
<div class="above-line">
${ecfg.icon && ecfg.icon !== false ? `<div class="above-icon-spacer"></div>` : ""}
<div class="above-bar-label">
<span class="above-bar-label-name label-left-text">${escapedName}</span>
${this._formatAboveValueMarkup(stateDisplay, unit, false)}
</div>
</div>` : "";
const heroSize = (_q = layout.hero.size) != null ? _q : "small";
const heroFontSize = layout.hero.value_size;
const heroHeader = lp === "hero" ? `
<div class="hero-line" data-hero-size="${heroSize}"${Number.isFinite(heroFontSize) ? ` style="--sbcp-hero-base-size:${heroFontSize}px"` : ""}>
<div class="hero-header">
<span class="hero-label label-left-text">${escapedName}</span>
<span class="hero-value" data-display="${this._encodeDataAttr(stateDisplay)}" data-unit="${this._encodeDataAttr(unit)}">${this._formatRightValueMarkup(stateDisplay, unit, false)}</span>
</div>
</div>` : "";
const innerLabel = lp === "inside" ? `
<div class="bar-inner-label">
<span class="inside-name">${escapedName}</span>
<span class="inside-value" data-display="${this._encodeDataAttr(stateDisplay)}" data-unit="${this._encodeDataAttr(unit)}" data-hide-unit="false" data-hide-value="false">${this._formatInsideValueMarkup(stateDisplay, unit, false)}</span>
</div>` : "";
const leftLabel = lp === "left" ? `<div class="label-left" style="flex:0 1 min(${layout.label.width}px, var(--sbcp-left-label-share));max-width:min(${layout.label.width}px, var(--sbcp-left-label-share));"><span class="label-left-text">${escapedName}</span></div>` : "";
const rightValue = lp !== "inside" && lp !== "above" && lp !== "hero" ? `<div class="value-right" data-display="${this._encodeDataAttr(stateDisplay)}" data-unit="${this._encodeDataAttr(unit)}" data-hide-unit="false">${this._formatRightValueMarkup(stateDisplay, unit, false)}</div>` : "";
const topRightValue = lp === "left" ? `<div class="top-right-value" data-display="${this._encodeDataAttr(stateDisplay)}" data-unit="${this._encodeDataAttr(unit)}" data-hide-unit="false" data-active="false">${this._formatRightValueMarkup(stateDisplay, unit, false)}</div>` : "";
const escapedIcon = ecfg.icon && ecfg.icon !== false ? escapeHtml(ecfg.icon) : "";
const mainIcon = escapedIcon && lp !== "hero" ? `<div class="icon-wrap"><ha-icon icon="${escapedIcon}"></ha-icon></div>` : "";
return `
<div class="row" data-entity="${escapedEntityId}" data-base-height="${h}" data-height-explicit="${((_s = (_r = rowViewModel == null ? void 0 : rowViewModel.attributes) == null ? void 0 : _r.heightExplicit) != null ? _s : layout.height_explicit) ? "true" : "false"}" data-bar-animated="${((_u = (_t = rowViewModel == null ? void 0 : rowViewModel.attributes) == null ? void 0 : _t.barAnimated) != null ? _u : bar.animated) ? "true" : "false"}">
<div class="row-stack" style="--sbcp-row-height:${h}px;">
${aboveLabel}
${heroHeader}
${topRightValue}
<div class="main-line ${lp}-mode" style="height:${h}px;">
${mainIcon}
${leftLabel}
<div class="bar-wrap">
<div class="bar-track">
<div class="bar-fill-reveal${bar.animated ? "" : " no-anim"}" style="${fillState.revealStyle}">
${paintLayers}
</div>
${innerLabel}
${peakMarker}
${targetMarker}
${needleMarker}
</div>
${targetValueLabel}
</div>
${rightValue}
</div>
</div>
</div>`;
}
_patchRow(row, entityCfg, stateObj) {
var _a;
if (!row || !stateObj) return;
const ecfg = this._resolve(entityCfg);
const rowViewModel = buildRowViewModel({
hass: this._hass,
cardConfig: this._config,
entityConfig: ecfg,
entityState: stateObj,
peaks: this._peaks
});
const rawVal = rowViewModel.numericValue;
const safeMin = rowViewModel.min;
const safeMax = rowViewModel.max;
const targetVal = rowViewModel.target;
const pct = rowViewModel.percent;
const color = this._getColor(pct, ecfg, safeMin, safeMax);
const display = rowViewModel.displayValue;
const displayUnit = rowViewModel.displayUnit;
const fillReveal = row.querySelector(".bar-fill-reveal");
const paintLayer = row.querySelector('.bar-paint-layer[data-layer="base"]');
const liveTargetPct = rowViewModel.targetPercent;
const liveBaselinePct = rowViewModel.baselinePercent;
const needleState = rowViewModel.needle;
const fillState = this._getFillRenderState(pct, "var(--sbcp-row-height)", ecfg, color, liveTargetPct, liveBaselinePct, safeMin, safeMax, needleState.show);
if (fillReveal) {
this._setStyleTextIfChanged(fillReveal, fillState.revealStyle);
this._setClassNameIfChanged(fillReveal, `bar-fill-reveal${ecfg.bar.animated ? "" : " no-anim"}`);
}
if (paintLayer) {
const baseLayerState = fillState.paintLayers.find((layer) => layer.id === "base");
if (baseLayerState) {
this._setStyleTextIfChanged(paintLayer, `z-index:${baseLayerState.zIndex};${baseLayerState.paintStyle}${baseLayerState.revealStyle}`);
}
}
const aboveTargetLayer = row.querySelector('.bar-paint-layer[data-layer="above-target"]');
if (aboveTargetLayer) {
const aboveTargetState = fillState.paintLayers.find((layer) => layer.id === "above-target");
if (aboveTargetState) {
this._setStyleTextIfChanged(aboveTargetLayer, `z-index:${aboveTargetState.zIndex};${aboveTargetState.paintStyle}${aboveTargetState.revealStyle}`);
}
}
const needleEl = row.querySelector(".needle-marker");
if (needleEl) {
this._setStyleIfChanged(needleEl, "display", needleState.show ? "block" : "none");
this._setStyleIfChanged(needleEl, "left", `${(_a = needleState.pct) != null ? _a : 0}%`);
this._setStyleIfChanged(needleEl, "--needle-color", needleState.color);
this._setStyleIfChanged(needleEl, "--needle-border-color", needleState.borderColor);
this._setDatasetIfChanged(needleEl, "edge", needleState.edge);
}
this._setDatasetIfChanged(row, "baseHeight", rowViewModel.attributes.baseHeight);
this._setDatasetIfChanged(row, "heightExplicit", rowViewModel.attributes.heightExplicit ? "true" : "false");
this._setDatasetIfChanged(row, "barAnimated", rowViewModel.attributes.barAnimated ? "true" : "false");
const valueEl = row.querySelector(".value-right");
if (valueEl) {
valueEl.dataset.display = this._encodeDataAttr(display);
valueEl.dataset.unit = this._encodeDataAttr(displayUnit);
valueEl.dataset.hideUnit = "false";
valueEl.innerHTML = this._formatRightValueMarkup(display, displayUnit, false);
}
const topValueEl = row.querySelector(".top-right-value");
if (topValueEl) {
topValueEl.dataset.display = this._encodeDataAttr(display);
topValueEl.dataset.unit = this._encodeDataAttr(displayUnit);
topValueEl.dataset.hideUnit = "false";
topValueEl.innerHTML = this._formatRightValueMarkup(display, displayUnit, false);
}
const innerLabel = row.querySelector(".bar-inner-label");
if (innerLabel) {
const valueSpan = innerLabel.querySelector(".inside-value");
if (valueSpan) {
valueSpan.dataset.display = this._encodeDataAttr(display);
valueSpan.dataset.unit = this._encodeDataAttr(displayUnit);
valueSpan.dataset.hideUnit = "false";
valueSpan.dataset.hideValue = "false";
valueSpan.innerHTML = this._formatInsideValueMarkup(display, displayUnit, false);
}
}
const heroHeader = row.querySelector(".hero-header");
if (heroHeader) {
const heroLine = row.querySelector(".hero-line");
this._setStyleIfChanged(
heroLine,
"--sbcp-hero-base-size",
Number.isFinite(ecfg.layout.hero.value_size) ? `${ecfg.layout.hero.value_size}px` : null
);
heroHeader.innerHTML = `<span class="hero-label label-left-text">${escapeHtml(rowViewModel.name)}</span><span class="hero-value" data-display="${this._encodeDataAttr(display)}" data-unit="${this._encodeDataAttr(displayUnit)}">${this._formatRightValueMarkup(display, displayUnit, false)}</span>`;
}
const aboveLabel = heroHeader ? null : row.querySelector(".above-bar-label");
if (aboveLabel) {
aboveLabel.innerHTML = `<span class="above-bar-label-name label-left-text">${escapeHtml(rowViewModel.name)}</span>${this._formatAboveValueMarkup(display, displayUnit, false)}`;
}
if (ecfg.peak_marker.show && Number.isFinite(rawVal)) {
const key = entityCfg.entity;
if (this._peaks[key] === void 0 || rawVal > this._peaks[key]) {
this._peaks[key] = rawVal;
}
const peakVal = this._peaks[key];
const peakPct = this._toScalePct(peakVal, safeMin, safeMax);
const peakEl = row.querySelector(".peak-marker");
if (peakEl) {
if (Number.isFinite(peakPct)) {
this._setStyleIfChanged(peakEl, "left", `${peakPct}%`);
}
this._setStyleIfChanged(peakEl, "--marker-color", ecfg.peak_marker.color);
this._setStyleIfChanged(peakEl, "--marker-contrast-color", this._getMarkerContrastColor(ecfg.peak_marker.color));
}
}
const targetEl = row.querySelector(".target-marker");
const targetLabelEl = row.querySelector(".target-value-label");
if (targetVal !== null) {
const targetPct = rowViewModel.targetPercent;
if (targetEl) {
this._setStyleIfChanged(targetEl, "display", "");
this._setStyleIfChanged(targetEl, "left", `${targetPct}%`);
this._setStyleIfChanged(targetEl, "--marker-color", ecfg.target_marker.color);
this._setStyleIfChanged(targetEl, "--marker-contrast-color", this._getMarkerContrastColor(ecfg.target_marker.color));
}
if (targetLabelEl) {
this._setTextIfChanged(targetLabelEl, rowViewModel.targetDisplay);
}
} else {
if (targetEl) this._setStyleIfChanged(targetEl, "display", "none");
if (targetLabelEl) this._setStyleIfChanged(targetLabelEl, "visibility", "hidden");
}
}
_update() {
if (!this._hass || !this._config) return;
const rowsEl = this.shadowRoot.querySelector(".rows");
if (!rowsEl) return;
const entities = this._config.entities;
if (!this._rendered) {
let html = "";
for (let entityIndex = 0; entityIndex < entities.length; entityIndex++) {
const entityCfg = entities[entityIndex];
const stateObj = this._hass.states[entityCfg.entity];
if (!stateObj) {
html += `<div class="row"><span style="color:var(--error-color,red);font-size:12px;">Entity not found: ${escapeHtml(entityCfg.entity)}</span></div>`;
continue;
}
const ecfg = this._resolve(entityCfg);
const rowViewModel = buildRowViewModel({
hass: this._hass,
cardConfig: this._config,
entityConfig: ecfg,
entityState: stateObj,
peaks: this._peaks
});
const rawVal = rowViewModel.numericValue;
const safeMin = rowViewModel.min;
const safeMax = rowViewModel.max;
const targetVal = rowViewModel.target;
const pct = rowViewModel.percent;
const color = this._getColor(pct, ecfg, safeMin, safeMax);
const display = rowViewModel.displayValue;
const displayUnit = rowViewModel.displayUnit;
const targetPct = rowViewModel.targetPercent;
const targetDisplay = rowViewModel.targetDisplay;
let peakPct = null, peakDisplay = null;
if (ecfg.peak_marker.show && Number.isFinite(rawVal)) {
if (this._peaks[entityCfg.entity] === void 0 || rawVal > this._peaks[entityCfg.entity]) {
this._peaks[entityCfg.entity] = rawVal;
}
const peakVal = this._peaks[entityCfg.entity];
peakPct = this._toScalePct(peakVal, safeMin, safeMax);
peakDisplay = this._formatNumericDisplay(peakVal, ecfg.formatting.decimal);
}
html += this._buildRow(entityCfg, display, displayUnit, pct, color, peakPct, peakDisplay, targetPct, targetDisplay, ecfg.peak_marker.color, ecfg.target_marker.color, safeMin, safeMax);
}
rowsEl.innerHTML = html;
this._rendered = true;
const builtRows = rowsEl.querySelectorAll(".row[data-entity]");
builtRows.forEach((row, idx) => {
const entityCfg = entities[idx];
const stateObj = entityCfg ? this._hass.states[entityCfg.entity] : null;
if (entityCfg && stateObj) {
this._patchRow(row, entityCfg, stateObj);
}
});
this._runPostLayoutPasses(builtRows);
builtRows.forEach((row) => {
row.addEventListener("click", () => {
const entityId = row.dataset.entity;
const event = new CustomEvent("hass-more-info", { composed: true, detail: { entityId } });
this.dispatchEvent(event);
});
});
return;
}
const rows = rowsEl.querySelectorAll(".row[data-entity]");
let rowIdx = 0;
for (const entityCfg of entities) {
const stateObj = this._hass.states[entityCfg.entity];
if (!stateObj) {
rowIdx++;
continue;
}
const row = rows[rowIdx];
if (!row) {
rowIdx++;
continue;
}
this._patchRow(row, entityCfg, stateObj);
rowIdx++;
}
this._runPostLayoutPasses(rows);
}
};
}
});
// src/editor/SensorBarCardPlusEditor.js
var SensorBarCardPlusEditor;
var init_SensorBarCardPlusEditor = __esm({
"src/editor/SensorBarCardPlusEditor.js"() {
SensorBarCardPlusEditor = class extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: "open" });
this._config = {};
this._draftConfig = {};
this._hass = null;
this._isRendering = false;
this._renderScheduled = false;
this._lastRenderedConfigJson = null;
this._lastEmittedConfigJson = null;
this._shadowListenersAttached = false;
this._expandedEntityOverrides = /* @__PURE__ */ new Set();
this._expandedOverrideGroups = /* @__PURE__ */ new Set();
this._expandedCardGroups = /* @__PURE__ */ new Set();
this._gradientStopsDrafts = /* @__PURE__ */ new Map();
this._gradientStopsUiRows = /* @__PURE__ */ new Map();
this._gradientStopPosTexts = /* @__PURE__ */ new Map();
this._gradientStopValidationMessages = /* @__PURE__ */ new Map();
this._segmentDrafts = /* @__PURE__ */ new Map();
this._segmentUiRows = /* @__PURE__ */ new Map();
this._segmentBoundaryTexts = /* @__PURE__ */ new Map();
this._targetAboveFillDrafts = /* @__PURE__ */ new Map();
this._baselineColorDrafts = /* @__PURE__ */ new Map();
this._pendingFocusSelector = null;
this._boundHandleClick = (event) => this._handleClick(event);
this._boundHandleChange = (event) => this._handleChange(event);
this._boundHandleInput = (event) => this._handleInput(event);
this._boundHandleValueChanged = (event) => this._handleValueChanged(event);
this._boundHandleKeydown = (event) => this._handleKeydown(event);
}
setConfig(config) {
var _a;
const nextConfig = this._cloneDeep(config != null ? config : {});
const nextConfigJson = this._serializeConfig(nextConfig);
const currentConfigJson = this._serializeConfig(this._config);
const currentDraftJson = this._serializeConfig(this._draftConfig);
if (nextConfigJson === currentConfigJson) {
return;
}
if (nextConfigJson === currentDraftJson) {
this._config = nextConfig;
return;
}
const shouldRender = !((_a = this.shadowRoot) == null ? void 0 : _a.innerHTML) || nextConfigJson !== this._lastRenderedConfigJson;
this._config = nextConfig;
this._draftConfig = this._cloneDeep(nextConfig);
this._gradientStopsDrafts = /* @__PURE__ */ new Map();
this._gradientStopsUiRows = /* @__PURE__ */ new Map();
this._gradientStopPosTexts = /* @__PURE__ */ new Map();
this._gradientStopValidationMessages = /* @__PURE__ */ new Map();
this._segmentDrafts = /* @__PURE__ */ new Map();
this._segmentUiRows = /* @__PURE__ */ new Map();
this._segmentBoundaryTexts = /* @__PURE__ */ new Map();
this._targetAboveFillDrafts = /* @__PURE__ */ new Map();
this._baselineColorDrafts = /* @__PURE__ */ new Map();
if (shouldRender) {
this._render();
}
}
set hass(hass) {
var _a;
this._hass = hass;
if (!((_a = this.shadowRoot) == null ? void 0 : _a.innerHTML)) {
this._render();
return;
}
this._syncEntityPickers();
}
_cloneContainer(value) {
return Array.isArray(value) ? [...value] : { ...value != null ? value : {} };
}
_cloneDeep(value) {
if (Array.isArray(value)) {
return value.map((entry) => this._cloneDeep(entry));
}
if (this._isObject(value)) {
const clone = {};
for (const [key, entry] of Object.entries(value)) {
clone[key] = this._cloneDeep(entry);
}
return clone;
}
return value;
}
_serializeConfig(value) {
const normalize = (input) => {
if (Array.isArray(input)) {
return input.map((entry) => normalize(entry));
}
if (this._isObject(input)) {
return Object.keys(input).sort().reduce((acc, key) => {
acc[key] = normalize(input[key]);
return acc;
}, {});
}
return input;
};
return JSON.stringify(normalize(value != null ? value : null));
}
_isObject(value) {
return !!value && typeof value === "object" && !Array.isArray(value);
}
_setPathValue(target, path, value) {
if (!path.length) {
return value;
}
const root = this._cloneContainer(target != null ? target : {});
let cursor = root;
let sourceCursor = target;
for (let index = 0; index < path.length - 1; index++) {
const key = path[index];
const nextSource = this._isObject(sourceCursor == null ? void 0 : sourceCursor[key]) || Array.isArray(sourceCursor == null ? void 0 : sourceCursor[key]) ? sourceCursor[key] : {};
cursor[key] = this._cloneContainer(nextSource);
cursor = cursor[key];
sourceCursor = nextSource;
}
cursor[path[path.length - 1]] = value;
return root;
}
_deletePathValue(target, path) {
if (!path.length || !this._isObject(target)) {
return target;
}
const [key, ...rest] = path;
if (!(key in target)) {
return target;
}
const cloned = this._cloneContainer(target);
if (!rest.length) {
delete cloned[key];
return cloned;
}
const nextValue = this._deletePathValue(cloned[key], rest);
if (nextValue === cloned[key]) {
return target;
}
if (this._isObject(nextValue) && !Object.keys(nextValue).length) {
delete cloned[key];
return cloned;
}
cloned[key] = nextValue;
return cloned;
}
_getPathValue(target, path) {
let cursor = target;
for (const key of path) {
if (cursor == null) return void 0;
cursor = cursor[key];
}
return cursor;
}
_hasPath(target, path) {
let cursor = target;
for (const key of path) {
if (!this._isObject(cursor) && !Array.isArray(cursor)) return false;
if (!(key in cursor)) return false;
cursor = cursor[key];
}
return true;
}
_normalizeTextValue(value) {
return typeof value === "string" ? value : value == null ? "" : String(value);
}
_normalizeOptionalEnabled(value) {
return value === true ? true : value === false ? false : null;
}
_normalizeNumberValue(value) {
if (value === "" || value === null || value === void 0) {
return null;
}
const parsed = Number(value);
return Number.isFinite(parsed) ? parsed : null;
}
_normalizeDecimalValue(value) {
if (value === "" || value === null || value === void 0) {
return null;
}
const parsed = Number(value);
if (!Number.isFinite(parsed) || parsed < 0 || !Number.isInteger(parsed)) {
return null;
}
return parsed;
}
_preferStructuredPath(structuredPath, legacyPath = null) {
if (this._hasPath(this._draftConfig, structuredPath.slice(0, -1))) {
return structuredPath;
}
if (this._hasPath(this._draftConfig, structuredPath)) {
return structuredPath;
}
if (legacyPath && this._hasPath(this._draftConfig, legacyPath)) {
return legacyPath;
}
return structuredPath;
}
_getEntitiesValue() {
var _a, _b;
if (Array.isArray(this._draftConfig.entities)) {
return this._draftConfig.entities.map((entry) => {
var _a2, _b2, _c;
return typeof entry === "string" ? { entity: entry } : {
entity: (_a2 = entry == null ? void 0 : entry.entity) != null ? _a2 : "",
name: (_b2 = entry == null ? void 0 : entry.name) != null ? _b2 : "",
icon: (_c = entry == null ? void 0 : entry.icon) != null ? _c : ""
};
});
}
if (this._draftConfig.entity) {
return [{
entity: this._draftConfig.entity,
name: (_a = this._draftConfig.name) != null ? _a : "",
icon: (_b = this._draftConfig.icon) != null ? _b : ""
}];
}
return [];
}
_getRawEntityRows() {
if (Array.isArray(this._draftConfig.entities)) {
return this._cloneDeep(this._draftConfig.entities);
}
if (this._draftConfig.entity !== void 0) {
const hasTopLevelIdentity = this._draftConfig.name !== void 0 || this._draftConfig.icon !== void 0;
if (!hasTopLevelIdentity) {
return [this._draftConfig.entity];
}
return [{
entity: this._draftConfig.entity,
...this._draftConfig.name !== void 0 ? { name: this._draftConfig.name } : {},
...this._draftConfig.icon !== void 0 ? { icon: this._draftConfig.icon } : {}
}];
}
return [];
}
_buildEntityConfigEntries(entities) {
const usesShorthand = !Array.isArray(this._draftConfig.entities) && this._draftConfig.entity !== void 0;
const source = Array.isArray(this._draftConfig.entities) ? this._draftConfig.entities : this._draftConfig.entity !== void 0 ? [{
entity: this._draftConfig.entity,
...this._draftConfig.name !== void 0 ? { name: this._draftConfig.name } : {},
...this._draftConfig.icon !== void 0 ? { icon: this._draftConfig.icon } : {}
}] : [];
const entries = entities.map((entry, index) => {
const rawEntry = source[index];
if (this._isObject(rawEntry)) {
const mergedEntry = {
...rawEntry,
entity: entry.entity
};
const normalizedName2 = this._normalizeTextValue(entry.name).trim();
if (normalizedName2) {
mergedEntry.name = normalizedName2;
} else {
delete mergedEntry.name;
}
const rawIconValue = entry == null ? void 0 : entry.icon;
const normalizedIcon2 = typeof rawIconValue === "string" ? rawIconValue.trim() : rawIconValue;
if (normalizedIcon2 === false) {
mergedEntry.icon = false;
} else if (typeof normalizedIcon2 === "string" && normalizedIcon2) {
mergedEntry.icon = normalizedIcon2;
} else if (rawEntry.icon === false) {
mergedEntry.icon = false;
} else {
delete mergedEntry.icon;
}
return mergedEntry;
}
const nextEntry = {
entity: entry.entity
};
const normalizedName = this._normalizeTextValue(entry.name).trim();
if (normalizedName) {
nextEntry.name = normalizedName;
}
const normalizedIcon = typeof (entry == null ? void 0 : entry.icon) === "string" ? entry.icon.trim() : entry == null ? void 0 : entry.icon;
if (normalizedIcon === false) {
nextEntry.icon = false;
} else if (typeof normalizedIcon === "string" && normalizedIcon) {
nextEntry.icon = normalizedIcon;
}
return nextEntry;
});
if (!usesShorthand) {
return entries.map((entry) => {
if (this._isObject(entry) && Object.keys(entry).length === 1 && entry.entity !== void 0) {
return entry.entity;
}
return entry;
});
}
return entries;
}
_updateConfig(nextConfig) {
this._draftConfig = this._cloneDeep(nextConfig);
}
_emitConfigChanged() {
const emittedConfig = this._cleanupEditorEmittedConfig(this._cloneDeep(this._draftConfig));
const nextConfigJson = this._serializeConfig(emittedConfig);
if (nextConfigJson === this._lastEmittedConfigJson) {
return false;
}
this._lastEmittedConfigJson = nextConfigJson;
this.dispatchEvent(new CustomEvent("config-changed", {
detail: { config: emittedConfig },
bubbles: true,
composed: true
}));
return true;
}
_scheduleRender() {
if (this._renderScheduled || this._isRendering) return;
this._renderScheduled = true;
setTimeout(() => {
this._renderScheduled = false;
this._render();
}, 0);
}
_applyUserConfig(nextConfig, options = {}) {
const { rerender = false } = options;
const nextConfigJson = this._serializeConfig(nextConfig);
const currentDraftJson = this._serializeConfig(this._draftConfig);
if (nextConfigJson === currentDraftJson) {
return false;
}
this._updateConfig(nextConfig);
this._emitConfigChanged();
this._refreshDerivedEditorUi();
if (rerender) {
this._scheduleRender();
}
return true;
}
_getShadowElementById(id) {
var _a, _b, _c, _d, _e, _f;
if (!this.shadowRoot) {
return null;
}
return (_f = (_e = (_b = (_a = this.shadowRoot).getElementById) == null ? void 0 : _b.call(_a, id)) != null ? _e : (_d = (_c = this.shadowRoot).querySelector) == null ? void 0 : _d.call(_c, `#${id}`)) != null ? _f : null;
}
_setElementChecked(id, checked) {
const element = this._getShadowElementById(id);
if (element) {
element.checked = !!checked;
}
}
_setElementText(id, value) {
const element = this._getShadowElementById(id);
if (element) {
element.textContent = value;
}
}
_refreshDerivedEditorUi() {
if (!this.shadowRoot) {
return;
}
this._refreshCardDerivedUi();
this._refreshEntityDerivedUi();
}
_refreshCardDerivedUi() {
this._setElementText("card-group-segments-summary", this._getSegmentsSummary({ type: "card" }));
this._setElementText("card-group-gradient-stops-summary", this._getGradientStopsSummary({ type: "card" }));
this._setElementChecked("target-above-fill-enabled", this._isTargetAboveFillEnabled({ type: "card" }));
this._setElementChecked("baseline-above-color-enabled", this._isBaselineDirectionalColorEnabled({ type: "card" }, "above"));
this._setElementChecked("baseline-below-color-enabled", this._isBaselineDirectionalColorEnabled({ type: "card" }, "below"));
this._refreshSegmentUi({ type: "card" });
}
_refreshEntityDerivedUi() {
const count = this._getEntitiesValue().length;
for (let index = 0; index < count; index += 1) {
const scope = { type: "entity", index };
this._setElementChecked(`entity-${index}-scale-inherit`, !this._hasResolvableOverride(this._getResolvableScopedValue(scope, "min")) && !this._hasResolvableOverride(this._getResolvableScopedValue(scope, "max")));
this._setElementChecked(`entity-${index}-target-inherit`, !this._hasTargetOverride(scope));
this._setElementChecked(`entity-${index}-baseline-inherit`, !this._hasBaselineOverride(scope));
this._setElementChecked(`entity-${index}-needle-inherit`, !this._hasNeedleOverride(scope));
this._setElementChecked(`entity-${index}-peak-inherit`, !this._hasPeakOverride(scope));
this._setElementChecked(`entity-${index}-bar-inherit`, !this._hasEntityBarAppearanceOverride(scope));
this._setElementChecked(`entity-${index}-segments-inherit`, !this._hasSegmentsOverride(scope));
this._setElementChecked(`entity-${index}-gradient-stops-inherit`, !this._hasGradientStopsOverride(scope));
this._setElementChecked(`entity-${index}-layout-inherit`, !this._hasLayoutOverride(scope));
this._setElementChecked(`entity-${index}-formatting-inherit`, !this._hasFormattingOverride(scope));
this._setElementChecked(`entity-${index}-target-above-fill-enabled`, this._isTargetAboveFillEnabled(scope));
this._setElementChecked(`entity-${index}-baseline-above-color-enabled`, this._isBaselineDirectionalColorEnabled(scope, "above"));
this._setElementChecked(`entity-${index}-baseline-below-color-enabled`, this._isBaselineDirectionalColorEnabled(scope, "below"));
this._setElementText(`entity-${index}-group-scale-summary`, this._getScaleOverrideSummary(scope));
this._setElementText(`entity-${index}-group-target-summary`, this._getTargetOverrideSummary(scope));
this._setElementText(`entity-${index}-group-baseline-summary`, this._getBaselineOverrideSummary(scope));
this._setElementText(`entity-${index}-group-needle-summary`, this._getNeedleSummary(scope));
this._setElementText(`entity-${index}-group-peak-summary`, this._getPeakSummary(scope));
this._setElementText(`entity-${index}-group-bar-summary`, this._getBarAppearanceSummary(scope));
this._setElementText(`entity-${index}-group-segments-summary`, this._getSegmentsSummary(scope));
this._setElementText(`entity-${index}-group-gradient-stops-summary`, this._getGradientStopsSummary(scope));
this._setElementText(`entity-${index}-group-layout-summary`, this._getLayoutSummary(scope));
this._setElementText(`entity-${index}-group-formatting-summary`, this._getFormattingSummary(scope));
this._refreshSegmentUi(scope);
}
}
_queuePostRenderFocus(selector) {
this._pendingFocusSelector = selector || null;
}
_applyPendingFocus() {
if (!this._pendingFocusSelector || !this.shadowRoot) {
return;
}
const selector = this._pendingFocusSelector;
this._pendingFocusSelector = null;
setTimeout(() => {
var _a, _b;
const element = (_b = (_a = this.shadowRoot) == null ? void 0 : _a.querySelector) == null ? void 0 : _b.call(_a, selector);
if (!element || typeof element.focus !== "function") {
return;
}
try {
element.focus({ preventScroll: true });
} catch (_error) {
element.focus();
}
}, 0);
}
_setValueAtPath(path, value, options = {}) {
const nextConfig = value === void 0 ? this._deletePathValue(this._draftConfig, path) : this._setPathValue(this._draftConfig, path, value);
return this._applyUserConfig(nextConfig, options);
}
_setTitle(value) {
this._setValueAtPath(["title"], value);
}
_setEntityField(index, key, value) {
const normalizedValue = this._normalizeTextValue(value);
if (!Array.isArray(this._draftConfig.entities) && this._draftConfig.entity !== void 0 && index === 0) {
if (!normalizedValue.trim()) {
return this._setValueAtPath([key], void 0);
}
return this._setValueAtPath([key], normalizedValue.trim());
}
const nextConfig = this._withEntityScopeConfig((entries) => {
var _a;
const rawEntry = entries[index];
const nextEntry = this._isObject(rawEntry) ? this._cloneDeep(rawEntry) : { entity: (_a = rawEntry == null ? void 0 : rawEntry.entity) != null ? _a : "" };
if (!normalizedValue.trim()) {
delete nextEntry[key];
} else {
nextEntry[key] = normalizedValue.trim();
}
entries[index] = nextEntry;
return entries;
});
return this._applyUserConfig(nextConfig);
}
_cleanupEntityIdentityForEmit(target) {
if (!this._isObject(target)) {
return target;
}
const nextTarget = this._cloneDeep(target);
const normalizedName = this._normalizeTextValue(nextTarget.name).trim();
if (!normalizedName) {
delete nextTarget.name;
} else {
nextTarget.name = normalizedName;
}
if (nextTarget.icon === false) {
return nextTarget;
}
const normalizedIcon = this._normalizeTextValue(nextTarget.icon).trim();
if (!normalizedIcon) {
delete nextTarget.icon;
} else {
nextTarget.icon = normalizedIcon;
}
return nextTarget;
}
_cleanupNeedleForEmit(target, scope = { type: "card" }) {
var _a;
if (!this._isObject(target) || !this._isObject(target.bar)) {
return target;
}
const nextTarget = this._cloneDeep(target);
const rawNeedle = (_a = nextTarget.bar) == null ? void 0 : _a.needle;
if (rawNeedle === void 0) {
return nextTarget;
}
const defaultColor = this._normalizeColorComparisonValue("#ffffff");
let nextNeedle = null;
if (rawNeedle === true) {
nextNeedle = { show: true };
} else if (rawNeedle === false) {
nextNeedle = (scope == null ? void 0 : scope.type) === "entity" ? { show: false } : null;
} else if (this._isObject(rawNeedle)) {
const color = this._normalizeTextValue(rawNeedle.color).trim();
if (rawNeedle.show === true) {
nextNeedle = { show: true };
} else if (rawNeedle.show === false) {
nextNeedle = (scope == null ? void 0 : scope.type) === "entity" ? { show: false } : null;
} else if ((scope == null ? void 0 : scope.type) === "entity" && color && this._normalizeColorComparisonValue(color) !== defaultColor) {
nextNeedle = {};
}
if (nextNeedle && color && this._normalizeColorComparisonValue(color) !== defaultColor) {
nextNeedle.color = color;
}
} else {
nextNeedle = null;
}
if (nextNeedle) {
nextTarget.bar.needle = nextNeedle;
} else {
delete nextTarget.bar.needle;
if (!Object.keys(nextTarget.bar).length) {
delete nextTarget.bar;
}
}
return nextTarget;
}
_cleanupResolvableValueForEmit(value) {
const nextValue = {};
if (this._isObject(value)) {
const fixed = this._normalizeNumberValue(value.fixed);
const entity = this._normalizeTextValue(value.entity).trim();
if (fixed !== null) {
nextValue.fixed = fixed;
}
if (entity) {
nextValue.entity = entity;
}
} else {
const fixed = this._normalizeNumberValue(value);
if (fixed !== null) {
nextValue.fixed = fixed;
}
}
return Object.keys(nextValue).length ? nextValue : null;
}
_cleanupScaleForEmit(target) {
if (!this._isObject(target) || !this._isObject(target.scale)) {
return target;
}
const nextTarget = this._cloneDeep(target);
const nextScale = this._cloneDeep(nextTarget.scale);
["min", "max"].forEach((key) => {
if (!Object.prototype.hasOwnProperty.call(nextScale, key)) {
return;
}
const cleanedValue = this._cleanupResolvableValueForEmit(nextScale[key]);
if (cleanedValue) {
nextScale[key] = cleanedValue;
delete nextTarget[key];
delete nextTarget[`${key}_entity`];
} else {
delete nextScale[key];
}
});
if (Object.keys(nextScale).length) {
nextTarget.scale = nextScale;
} else {
delete nextTarget.scale;
}
return nextTarget;
}
_cleanupFormattingForEmit(target) {
if (!this._isObject(target) || !this._isObject(target.formatting)) {
return target;
}
const nextTarget = this._cloneDeep(target);
const nextFormatting = this._cloneDeep(nextTarget.formatting);
const unit = this._normalizeTextValue(nextFormatting.unit).trim();
const decimal = this._normalizeDecimalValue(nextFormatting.decimal);
if (unit) {
nextFormatting.unit = unit;
delete nextTarget.unit;
} else {
delete nextFormatting.unit;
}
if (decimal !== null) {
nextFormatting.decimal = decimal;
delete nextTarget.decimal;
} else {
delete nextFormatting.decimal;
}
if (Object.keys(nextFormatting).length) {
nextTarget.formatting = nextFormatting;
} else {
delete nextTarget.formatting;
}
return nextTarget;
}
_cleanupLayoutForEmit(target) {
if (!this._isObject(target) || !this._isObject(target.layout)) {
return target;
}
const nextTarget = this._cloneDeep(target);
const nextLayout = this._cloneDeep(nextTarget.layout);
const nextLabel = this._isObject(nextLayout.label) ? this._cloneDeep(nextLayout.label) : null;
const nextHero = this._isObject(nextLayout.hero) ? this._cloneDeep(nextLayout.hero) : null;
const height = this._normalizeNumberValue(nextLayout.height);
const width = this._normalizeNumberValue(nextLabel == null ? void 0 : nextLabel.width);
const valueSize = this._normalizeHeroValueSizeValue(nextHero == null ? void 0 : nextHero.value_size);
const position = this._normalizeTextValue(nextLabel == null ? void 0 : nextLabel.position).trim();
if (height !== null && height >= 24) {
nextLayout.height = height;
delete nextTarget.height;
} else {
delete nextLayout.height;
}
if (nextLabel) {
if (position) {
nextLabel.position = position;
delete nextTarget.label_position;
} else {
delete nextLabel.position;
}
if (width !== null) {
nextLabel.width = width;
delete nextTarget.label_width;
} else {
delete nextLabel.width;
}
if (Object.keys(nextLabel).length) {
nextLayout.label = nextLabel;
} else {
delete nextLayout.label;
}
}
if (nextHero) {
if (valueSize !== null) {
nextHero.value_size = valueSize;
} else {
delete nextHero.value_size;
}
if (Object.keys(nextHero).length) {
nextLayout.hero = nextHero;
} else {
delete nextLayout.hero;
}
}
if (Object.keys(nextLayout).length) {
nextTarget.layout = nextLayout;
} else {
delete nextTarget.layout;
}
return nextTarget;
}
_cleanupTargetForEmit(target) {
var _a, _b;
if (!this._isObject(target) || !this._isObject(target.target)) {
return target;
}
const nextTarget = this._cloneDeep(target);
const nextMarker = this._cloneDeep(nextTarget.target);
const cleanedAt = this._cleanupResolvableValueForEmit(nextMarker.at);
const color = this._normalizeTextValue(nextMarker.color).trim();
const labelShow = ((_a = nextMarker.label) == null ? void 0 : _a.show) === true;
const fillColor = this._normalizeTextValue((_b = nextMarker.when_exceeded) == null ? void 0 : _b.fill_color).trim();
if (typeof nextMarker.enabled !== "boolean") {
delete nextMarker.enabled;
}
if (cleanedAt) {
nextMarker.at = cleanedAt;
delete nextTarget.target_entity;
} else {
delete nextMarker.at;
}
if (color && this._normalizeColorComparisonValue(color) !== this._normalizeColorComparisonValue("#888")) {
nextMarker.color = color;
delete nextTarget.target_color;
} else {
delete nextMarker.color;
}
if (labelShow) {
nextMarker.label = { ...this._isObject(nextMarker.label) ? nextMarker.label : {}, show: true };
delete nextTarget.show_target_label;
} else {
delete nextMarker.label;
}
if (fillColor) {
nextMarker.when_exceeded = {
...this._isObject(nextMarker.when_exceeded) ? nextMarker.when_exceeded : {},
fill_color: fillColor
};
delete nextTarget.above_target_color;
} else {
delete nextMarker.when_exceeded;
}
if (Object.keys(nextMarker).length) {
nextTarget.target = nextMarker;
} else {
delete nextTarget.target;
}
return nextTarget;
}
_cleanupBaselineForEmit(target) {
if (!this._isObject(target) || !this._isObject(target.baseline)) {
return target;
}
const nextTarget = this._cloneDeep(target);
const nextBaseline = this._cloneDeep(nextTarget.baseline);
const cleanedAt = this._cleanupResolvableValueForEmit(nextBaseline.at);
if (typeof nextBaseline.enabled !== "boolean") {
delete nextBaseline.enabled;
}
if (cleanedAt) {
nextBaseline.at = cleanedAt;
} else {
delete nextBaseline.at;
}
["above", "below"].forEach((direction) => {
if (!this._isObject(nextBaseline[direction])) {
delete nextBaseline[direction];
return;
}
const color = this._normalizeTextValue(nextBaseline[direction].color).trim();
if (color) {
nextBaseline[direction] = { ...nextBaseline[direction], color };
} else {
delete nextBaseline[direction];
}
});
if (Object.keys(nextBaseline).length) {
nextTarget.baseline = nextBaseline;
} else {
delete nextTarget.baseline;
}
return nextTarget;
}
_cleanupPeakForEmit(target) {
if (!this._isObject(target) || !this._isObject(target.peak)) {
return target;
}
const nextTarget = this._cloneDeep(target);
const nextPeak = this._cloneDeep(nextTarget.peak);
const color = this._normalizeTextValue(nextPeak.color).trim();
if (typeof nextPeak.enabled !== "boolean") {
delete nextPeak.enabled;
}
if (color && this._normalizeColorComparisonValue(color) !== this._normalizeColorComparisonValue("#888")) {
nextPeak.color = color;
delete nextTarget.peak_color;
} else {
delete nextPeak.color;
}
if (Object.keys(nextPeak).length) {
nextTarget.peak = nextPeak;
} else {
delete nextTarget.peak;
}
return nextTarget;
}
_cleanupBarForEmit(target) {
if (!this._isObject(target) || !this._isObject(target.bar)) {
return target;
}
const nextTarget = this._cloneDeep(target);
const nextBar = this._cloneDeep(nextTarget.bar);
const fillStyle = this._normalizeTextValue(nextBar.fill_style).trim();
const color = this._normalizeTextValue(nextBar.color).trim();
const segments = Array.isArray(nextBar.segments) ? nextBar.segments : null;
const gradientStops = Array.isArray(nextBar.gradient_stops) ? nextBar.gradient_stops : null;
if (fillStyle && fillStyle !== "bands") {
nextBar.fill_style = fillStyle;
delete nextTarget.color_mode;
} else {
delete nextBar.fill_style;
}
if (color && this._normalizeColorComparisonValue(color) !== this._normalizeColorComparisonValue("#4a9eff")) {
nextBar.color = color;
delete nextTarget.color;
} else {
delete nextBar.color;
}
if (nextBar.solid_fill === true) {
nextBar.solid_fill = true;
} else {
delete nextBar.solid_fill;
}
if (segments && segments.length && !this._segmentsEqualForEditor(segments, this._getDefaultSegments())) {
nextBar.segments = segments;
delete nextTarget.segments;
delete nextTarget.severity;
} else {
delete nextBar.segments;
}
if (gradientStops && gradientStops.length >= 2 && !this._isDefaultGradientStops(gradientStops)) {
nextBar.gradient_stops = this._sanitizeGradientStopsForEmit(gradientStops);
delete nextTarget.gradient_stops;
} else {
delete nextBar.gradient_stops;
}
if (Object.keys(nextBar).length) {
nextTarget.bar = nextBar;
} else {
delete nextTarget.bar;
}
return nextTarget;
}
_getEditorKnownKeyOrder(path = []) {
const pathKey = path.join(".");
switch (pathKey) {
case "":
return ["type", "title", "entities", "scale", "target", "baseline", "peak", "layout", "formatting", "bar"];
case "entities.*":
return ["entity", "name", "icon", "scale", "target", "baseline", "peak", "layout", "formatting", "bar"];
case "scale":
return ["min", "max"];
case "scale.min":
case "scale.max":
case "target.at":
case "baseline.at":
return ["fixed", "entity"];
case "target":
return ["enabled", "at", "color", "label", "when_exceeded"];
case "target.label":
return ["show"];
case "target.when_exceeded":
return ["fill_color"];
case "baseline":
return ["enabled", "at", "above", "below"];
case "baseline.above":
case "baseline.below":
return ["color"];
case "peak":
return ["enabled", "color"];
case "layout":
return ["height", "label", "hero"];
case "layout.label":
return ["position", "hero_size", "width"];
case "layout.hero":
return ["size", "value_size"];
case "formatting":
return ["unit", "decimal"];
case "bar":
return ["fill_style", "color", "solid_fill", "needle", "segments", "gradient_stops"];
case "bar.needle":
return ["show", "color"];
default:
return null;
}
}
_orderEditorConfigKeys(value, path = []) {
var _a;
if (Array.isArray(value)) {
const nextPath = path[0] === "entities" ? ["entities", "*"] : path;
return value.map((entry) => this._orderEditorConfigKeys(entry, nextPath));
}
if (!this._isObject(value)) {
return value;
}
const orderedValue = {};
const knownOrder = (_a = this._getEditorKnownKeyOrder(path)) != null ? _a : [];
const seenKeys = /* @__PURE__ */ new Set();
knownOrder.forEach((key) => {
if (!Object.prototype.hasOwnProperty.call(value, key)) {
return;
}
orderedValue[key] = this._orderEditorConfigKeys(value[key], [...path, key]);
seenKeys.add(key);
});
Object.keys(value).forEach((key) => {
if (seenKeys.has(key)) {
return;
}
orderedValue[key] = this._orderEditorConfigKeys(value[key], [...path, key]);
});
return orderedValue;
}
_cleanupEditorEmittedConfig(config) {
if (!this._isObject(config)) {
return config;
}
let nextConfig = this._cleanupEntityIdentityForEmit(config);
nextConfig = this._cleanupScaleForEmit(nextConfig);
nextConfig = this._cleanupTargetForEmit(nextConfig);
nextConfig = this._cleanupBaselineForEmit(nextConfig);
nextConfig = this._cleanupPeakForEmit(nextConfig);
nextConfig = this._cleanupLayoutForEmit(nextConfig);
nextConfig = this._cleanupFormattingForEmit(nextConfig);
nextConfig = this._cleanupNeedleForEmit(nextConfig, { type: "card" });
nextConfig = this._cleanupBarForEmit(nextConfig);
if (Array.isArray(nextConfig.entities)) {
nextConfig.entities = nextConfig.entities.map((entry) => {
if (!this._isObject(entry)) {
return entry;
}
let cleanedEntry = this._cleanupEntityIdentityForEmit(entry);
cleanedEntry = this._cleanupScaleForEmit(cleanedEntry);
cleanedEntry = this._cleanupTargetForEmit(cleanedEntry);
cleanedEntry = this._cleanupBaselineForEmit(cleanedEntry);
cleanedEntry = this._cleanupPeakForEmit(cleanedEntry);
cleanedEntry = this._cleanupLayoutForEmit(cleanedEntry);
cleanedEntry = this._cleanupFormattingForEmit(cleanedEntry);
cleanedEntry = this._cleanupNeedleForEmit(cleanedEntry, { type: "entity" });
cleanedEntry = this._cleanupBarForEmit(cleanedEntry);
return cleanedEntry;
});
}
return this._orderEditorConfigKeys(nextConfig);
}
_getScopedPath(scope, keyPath) {
const normalizedPath = Array.isArray(keyPath) ? keyPath : [keyPath];
if (!scope || scope.type === "card") {
return normalizedPath;
}
if (scope.type === "entity") {
return ["entities", scope.index, ...normalizedPath];
}
return normalizedPath;
}
_normalizePath(keyPath) {
return Array.isArray(keyPath) ? keyPath : [keyPath];
}
_getEntityRawEntries() {
if (Array.isArray(this._draftConfig.entities)) {
return this._draftConfig.entities.map((entry) => this._isObject(entry) ? this._cloneDeep(entry) : { entity: entry });
}
if (this._draftConfig.entity !== void 0) {
return [{
entity: this._draftConfig.entity,
...this._draftConfig.name !== void 0 ? { name: this._draftConfig.name } : {},
...this._draftConfig.icon !== void 0 ? { icon: this._draftConfig.icon } : {}
}];
}
return [];
}
_withEntityScopeConfig(mutator) {
const rawEntries = this._getEntityRawEntries();
const nextEntries = mutator(rawEntries.map((entry) => this._cloneDeep(entry)));
let nextConfig = this._setPathValue(this._draftConfig, ["entities"], nextEntries);
if (!Array.isArray(this._draftConfig.entities) && this._draftConfig.entity !== void 0) {
nextConfig = this._deletePathValue(nextConfig, ["entity"]);
if (this._draftConfig.name !== void 0) {
nextConfig = this._deletePathValue(nextConfig, ["name"]);
}
if (this._draftConfig.icon !== void 0) {
nextConfig = this._deletePathValue(nextConfig, ["icon"]);
}
}
return nextConfig;
}
_setEntityRowsRaw(nextRows, options = {}) {
var _a;
const normalizedRows = this._cloneDeep(nextRows);
if (Array.isArray(this._draftConfig.entities) || this._draftConfig.entity === void 0 || normalizedRows.length !== 1) {
let nextConfig2 = this._setPathValue(this._draftConfig, ["entities"], normalizedRows);
if (!Array.isArray(this._draftConfig.entities) && this._draftConfig.entity !== void 0) {
nextConfig2 = this._deletePathValue(nextConfig2, ["entity"]);
nextConfig2 = this._deletePathValue(nextConfig2, ["name"]);
nextConfig2 = this._deletePathValue(nextConfig2, ["icon"]);
}
return this._applyUserConfig(nextConfig2, options);
}
const [row] = normalizedRows;
if (typeof row === "string") {
let nextConfig2 = this._setPathValue(this._draftConfig, ["entity"], row);
nextConfig2 = this._deletePathValue(nextConfig2, ["name"]);
nextConfig2 = this._deletePathValue(nextConfig2, ["icon"]);
return this._applyUserConfig(nextConfig2, options);
}
let nextConfig = this._setPathValue(this._draftConfig, ["entity"], (_a = row == null ? void 0 : row.entity) != null ? _a : "");
if (row && Object.prototype.hasOwnProperty.call(row, "name")) {
nextConfig = this._setPathValue(nextConfig, ["name"], row.name);
} else {
nextConfig = this._deletePathValue(nextConfig, ["name"]);
}
if (row && Object.prototype.hasOwnProperty.call(row, "icon")) {
nextConfig = this._setPathValue(nextConfig, ["icon"], row.icon);
} else {
nextConfig = this._deletePathValue(nextConfig, ["icon"]);
}
return this._applyUserConfig(nextConfig, options);
}
_moveEntityRow(index, direction) {
const rows = this._getRawEntityRows();
const nextIndex = index + direction;
if (index < 0 || index >= rows.length || nextIndex < 0 || nextIndex >= rows.length) {
return false;
}
const nextRows = this._cloneDeep(rows);
[nextRows[index], nextRows[nextIndex]] = [nextRows[nextIndex], nextRows[index]];
return this._setEntityRowsRaw(nextRows, { rerender: true });
}
_duplicateEntityRow(index) {
const rows = this._getRawEntityRows();
if (index < 0 || index >= rows.length) {
return false;
}
const sourceRow = this._cloneDeep(rows[index]);
const duplicateRow = typeof sourceRow === "string" ? { entity: sourceRow } : this._cloneDeep(sourceRow);
if (this._isObject(duplicateRow) && typeof duplicateRow.name === "string" && duplicateRow.name.trim()) {
duplicateRow.name = `${duplicateRow.name.trim()} copy`;
}
const nextRows = this._cloneDeep(rows);
nextRows.splice(index + 1, 0, duplicateRow);
return this._setEntityRowsRaw(nextRows, { rerender: true });
}
_removeEntityRow(index) {
const rows = this._getRawEntityRows();
if (rows.length <= 1 || index < 0 || index >= rows.length) {
return false;
}
const nextRows = rows.filter((_, rowIndex) => rowIndex !== index);
return this._setEntityRowsRaw(nextRows, { rerender: true });
}
_getScopedValue(scope, keyPath) {
if ((scope == null ? void 0 : scope.type) === "entity") {
const entry = this._getEntityRawEntries()[scope.index];
return this._getPathValue(entry, this._normalizePath(keyPath));
}
return this._getPathValue(this._draftConfig, this._getScopedPath(scope, keyPath));
}
_removeScopedValue(scope, keyPath, options = {}) {
if ((scope == null ? void 0 : scope.type) === "entity") {
const nextConfig = this._withEntityScopeConfig((entries) => {
var _a, _b;
const entry = this._isObject(entries[scope.index]) ? { ...entries[scope.index] } : { entity: (_b = (_a = entries[scope.index]) == null ? void 0 : _a.entity) != null ? _b : "" };
entries[scope.index] = this._deletePathValue(entry, this._normalizePath(keyPath));
return entries;
});
return this._applyUserConfig(nextConfig, options);
}
return this._setValueAtPath(this._getScopedPath(scope, keyPath), void 0, options);
}
_applyScopedMutation(scope, mutator, options = {}) {
if ((scope == null ? void 0 : scope.type) === "entity") {
const nextConfig2 = this._withEntityScopeConfig((entries) => {
var _a;
const rawEntry = entries[scope.index];
const entry = this._isObject(rawEntry) ? this._cloneDeep(rawEntry) : { entity: (_a = rawEntry == null ? void 0 : rawEntry.entity) != null ? _a : "" };
entries[scope.index] = mutator(entry);
return entries;
});
return this._applyUserConfig(nextConfig2, options);
}
const nextConfig = mutator(this._cloneDeep(this._draftConfig));
return this._applyUserConfig(nextConfig, options);
}
_setScopedValue(scope, keyPath, value, options = {}) {
return this._applyScopedMutation(scope, (target) => this._setPathValue(target, this._normalizePath(keyPath), value), options);
}
_removePathsFromTarget(target, keyPaths = []) {
return keyPaths.reduce((nextTarget, keyPath) => this._deletePathValue(nextTarget, this._normalizePath(keyPath)), target);
}
_pruneEmptyObjectsInTarget(target, keyPath) {
let nextTarget = target;
const normalizedPath = this._normalizePath(keyPath);
for (let index = normalizedPath.length; index > 0; index--) {
const currentPath = normalizedPath.slice(0, index);
const currentValue = this._getPathValue(nextTarget, currentPath);
if (!this._isObject(currentValue) || Object.keys(currentValue).length) {
break;
}
nextTarget = this._deletePathValue(nextTarget, currentPath);
}
return nextTarget;
}
_setCanonicalScopedValue(scope, canonicalPath, value, options = {}) {
const { deprecatedKeys = [], prunePaths = [] } = options;
return this._applyScopedMutation(scope, (target) => {
let nextTarget = this._setPathValue(target, this._normalizePath(canonicalPath), value);
nextTarget = this._removePathsFromTarget(nextTarget, deprecatedKeys);
const pathsToPrune = [this._normalizePath(canonicalPath).slice(0, -1), ...prunePaths.map((path) => this._normalizePath(path))];
pathsToPrune.forEach((path) => {
if (path.length) {
nextTarget = this._pruneEmptyObjectsInTarget(nextTarget, path);
}
});
return nextTarget;
}, options);
}
_removeCanonicalScopedValue(scope, canonicalPath, options = {}) {
const { deprecatedKeys = [], prunePaths = [] } = options;
return this._applyScopedMutation(scope, (target) => {
let nextTarget = this._deletePathValue(target, this._normalizePath(canonicalPath));
nextTarget = this._removePathsFromTarget(nextTarget, deprecatedKeys);
const pathsToPrune = [this._normalizePath(canonicalPath).slice(0, -1), ...prunePaths.map((path) => this._normalizePath(path))];
pathsToPrune.forEach((path) => {
if (path.length) {
nextTarget = this._pruneEmptyObjectsInTarget(nextTarget, path);
}
});
return nextTarget;
}, options);
}
_setScopedNumericOverride(scope, keyPath, rawValue, options = {}) {
const normalizedValue = this._normalizeNumberValue(rawValue);
if (rawValue === "" || rawValue === null || rawValue === void 0) {
return this._removeScopedValue(scope, keyPath, options);
}
if (normalizedValue === null) {
return false;
}
return this._setScopedValue(scope, keyPath, normalizedValue, options);
}
_setScopedTextOverride(scope, keyPath, rawValue, options = {}) {
const normalizedValue = this._normalizeTextValue(rawValue).trim();
if (!normalizedValue) {
return this._removeScopedValue(scope, keyPath, options);
}
return this._setScopedValue(scope, keyPath, normalizedValue, options);
}
_setCanonicalScopedNumericOverride(scope, canonicalPath, rawValue, options = {}) {
const normalizedValue = this._normalizeNumberValue(rawValue);
if (rawValue === "" || rawValue === null || rawValue === void 0 || normalizedValue === null) {
return this._removeCanonicalScopedValue(scope, canonicalPath, options);
}
return this._setCanonicalScopedValue(scope, canonicalPath, normalizedValue, options);
}
_setCanonicalScopedTextOverride(scope, canonicalPath, rawValue, options = {}) {
const normalizedValue = this._normalizeTextValue(rawValue).trim();
if (!normalizedValue) {
return this._removeCanonicalScopedValue(scope, canonicalPath, options);
}
return this._setCanonicalScopedValue(scope, canonicalPath, normalizedValue, options);
}
_getResolvablePartsFromTarget(target, field, options = {}) {
var _a, _b, _c, _d;
const canonicalBasePath = (_a = options.canonicalBasePath) != null ? _a : ["scale", field];
const legacyFixedPath = (_b = options.legacyFixedPath) != null ? _b : [field];
const legacyEntityPath = (_c = options.legacyEntityPath) != null ? _c : [`${field}_entity`];
const structuredValue = this._getPathValue(target, canonicalBasePath);
const legacyFixedValue = this._getPathValue(target, legacyFixedPath);
const legacyEntityValue = this._getPathValue(target, legacyEntityPath);
const structuredFixedValue = this._isObject(structuredValue) ? structuredValue == null ? void 0 : structuredValue.fixed : structuredValue;
const structuredEntityValue = this._isObject(structuredValue) ? structuredValue == null ? void 0 : structuredValue.entity : void 0;
return {
fixed: structuredFixedValue != null ? structuredFixedValue : !this._isObject(legacyFixedValue) && legacyFixedValue !== void 0 ? legacyFixedValue : "",
entity: (_d = structuredEntityValue != null ? structuredEntityValue : legacyEntityValue) != null ? _d : ""
};
}
_getResolvableScopedValue(scope, field, options = {}) {
const target = (scope == null ? void 0 : scope.type) === "entity" ? this._getEntityRawEntries()[scope.index] : this._draftConfig;
return this._getResolvablePartsFromTarget(target != null ? target : {}, field, options);
}
_getEffectiveResolvableScopedValue(scope, field, options = {}) {
const localValue = this._getResolvableScopedValue(scope, field, options);
if ((scope == null ? void 0 : scope.type) !== "entity") {
return localValue;
}
const inheritedValue = this._getResolvableScopedValue({ type: "card" }, field, options);
return {
fixed: this._hasExplicitOverrideValue(localValue.fixed) ? localValue.fixed : inheritedValue.fixed,
entity: this._hasExplicitOverrideValue(localValue.entity) ? localValue.entity : inheritedValue.entity
};
}
_setCanonicalResolvablePart(scope, field, part, rawValue, options = {}) {
var _a, _b, _c, _d;
const canonicalBasePath = (_a = options.canonicalBasePath) != null ? _a : ["scale", field];
const legacyFixedPath = (_b = options.legacyFixedPath) != null ? _b : [field];
const legacyEntityPath = (_c = options.legacyEntityPath) != null ? _c : [`${field}_entity`];
const prunePaths = (_d = options.prunePaths) != null ? _d : [canonicalBasePath, canonicalBasePath.slice(0, -1)];
const normalizedValue = part === "fixed" ? this._normalizeNumberValue(rawValue) : this._normalizeTextValue(rawValue).trim();
return this._applyScopedMutation(scope, (target) => {
const currentParts = this._getResolvablePartsFromTarget(target != null ? target : {}, field, {
canonicalBasePath,
legacyFixedPath,
legacyEntityPath
});
const nextParts = { ...currentParts };
if (part === "fixed") {
if (rawValue === "" || rawValue === null || rawValue === void 0 || normalizedValue === null) {
delete nextParts.fixed;
} else {
nextParts.fixed = normalizedValue;
}
} else if (!normalizedValue) {
delete nextParts.entity;
} else {
nextParts.entity = normalizedValue;
}
let nextTarget = this._cloneDeep(target);
nextTarget = this._deletePathValue(nextTarget, legacyEntityPath);
const legacyFixedValue = this._getPathValue(nextTarget, legacyFixedPath);
if (!this._isObject(legacyFixedValue)) {
nextTarget = this._deletePathValue(nextTarget, legacyFixedPath);
}
nextTarget = this._deletePathValue(nextTarget, canonicalBasePath);
const hasFixed = nextParts.fixed !== void 0 && nextParts.fixed !== null && nextParts.fixed !== "";
const hasEntity = nextParts.entity !== void 0 && nextParts.entity !== null && nextParts.entity !== "";
if (hasFixed || hasEntity) {
const nextValue = {};
if (hasFixed) nextValue.fixed = nextParts.fixed;
if (hasEntity) nextValue.entity = nextParts.entity;
nextTarget = this._setPathValue(nextTarget, canonicalBasePath, nextValue);
}
prunePaths.forEach((path) => {
if (path.length) {
nextTarget = this._pruneEmptyObjectsInTarget(nextTarget, path);
}
});
return nextTarget;
}, options);
}
_clearCanonicalResolvableValue(scope, field, options = {}) {
var _a, _b, _c, _d;
const canonicalBasePath = (_a = options.canonicalBasePath) != null ? _a : ["scale", field];
const legacyFixedPath = (_b = options.legacyFixedPath) != null ? _b : [field];
const legacyEntityPath = (_c = options.legacyEntityPath) != null ? _c : [`${field}_entity`];
const prunePaths = (_d = options.prunePaths) != null ? _d : [canonicalBasePath, canonicalBasePath.slice(0, -1)];
return this._applyScopedMutation(scope, (target) => {
let nextTarget = this._deletePathValue(target, canonicalBasePath);
nextTarget = this._deletePathValue(nextTarget, legacyEntityPath);
const legacyFixedValue = this._getPathValue(nextTarget, legacyFixedPath);
if (!this._isObject(legacyFixedValue)) {
nextTarget = this._deletePathValue(nextTarget, legacyFixedPath);
}
prunePaths.forEach((path) => {
if (path.length) {
nextTarget = this._pruneEmptyObjectsInTarget(nextTarget, path);
}
});
return nextTarget;
}, options);
}
_getScopedDisplayValue(scope, canonicalPath, fallbackPaths = []) {
const valuesToTry = [canonicalPath, ...fallbackPaths];
for (const path of valuesToTry) {
const value = this._getScopedValue(scope, path);
if (value !== void 0 && value !== null && value !== "") {
return value;
}
}
return "";
}
_getEffectiveScopedDisplayValue(scope, canonicalPath, fallbackPaths = []) {
const valuesToTry = [canonicalPath, ...fallbackPaths];
for (const path of valuesToTry) {
const value = this._getScopedValue(scope, path);
if (value !== void 0 && value !== null && value !== "") {
return value;
}
}
if ((scope == null ? void 0 : scope.type) === "entity") {
for (const path of valuesToTry) {
const value = this._getScopedValue({ type: "card" }, path);
if (value !== void 0 && value !== null && value !== "") {
return value;
}
}
}
return "";
}
_getScopedFormattingValue(scope, key) {
var _a, _b;
return (_b = (_a = this._getScopedValue(scope, ["formatting", key])) != null ? _a : this._getScopedValue(scope, [key])) != null ? _b : "";
}
_getEffectiveScopedFormattingValue(scope, key) {
return this._getEffectiveScopedDisplayValue(scope, ["formatting", key], [[key]]);
}
_setScopedFormattingUnit(scope, rawValue) {
return this._setCanonicalScopedTextOverride(scope, ["formatting", "unit"], rawValue, {
deprecatedKeys: [["unit"]],
prunePaths: [["formatting"]]
});
}
_setScopedFormattingDecimal(scope, rawValue) {
const normalizedValue = this._normalizeDecimalValue(rawValue);
if (rawValue === "" || rawValue === null || rawValue === void 0) {
return this._removeCanonicalScopedValue(scope, ["formatting", "decimal"], {
deprecatedKeys: [["decimal"]],
prunePaths: [["formatting"]]
});
}
if (normalizedValue === null) {
return false;
}
return this._setCanonicalScopedValue(scope, ["formatting", "decimal"], normalizedValue, {
deprecatedKeys: [["decimal"]],
prunePaths: [["formatting"]]
});
}
_clearFormattingOverride(scope) {
return this._applyScopedMutation(scope, (target) => {
let nextTarget = this._deletePathValue(target, ["formatting", "unit"]);
nextTarget = this._deletePathValue(nextTarget, ["formatting", "decimal"]);
nextTarget = this._deletePathValue(nextTarget, ["unit"]);
nextTarget = this._deletePathValue(nextTarget, ["decimal"]);
nextTarget = this._pruneEmptyObjectsInTarget(nextTarget, ["formatting"]);
return nextTarget;
}, { rerender: true });
}
_hasFormattingOverride(scope) {
var _a;
const formattingValue = (_a = this._getScopedValue(scope, ["formatting"])) != null ? _a : {};
if (this._isObject(formattingValue) && (Object.prototype.hasOwnProperty.call(formattingValue, "unit") || Object.prototype.hasOwnProperty.call(formattingValue, "decimal"))) {
return true;
}
return this._getScopedValue(scope, ["unit"]) !== void 0 || this._getScopedValue(scope, ["decimal"]) !== void 0;
}
_getScopedLayoutValue(scope, key) {
var _a, _b, _c, _d, _e, _f, _g, _h, _i;
if (key === "height") {
return (_b = (_a = this._getScopedValue(scope, ["layout", "height"])) != null ? _a : this._getScopedValue(scope, ["height"])) != null ? _b : "";
}
if (key === "position") {
return (_d = (_c = this._getScopedValue(scope, ["layout", "label", "position"])) != null ? _c : this._getScopedValue(scope, ["label_position"])) != null ? _d : "";
}
if (key === "width") {
return (_f = (_e = this._getScopedValue(scope, ["layout", "label", "width"])) != null ? _e : this._getScopedValue(scope, ["label_width"])) != null ? _f : "";
}
if (key === "hero_size") {
return (_h = (_g = this._getScopedValue(scope, ["layout", "hero", "size"])) != null ? _g : this._getScopedValue(scope, ["layout", "label", "hero_size"])) != null ? _h : "";
}
if (key === "value_size") {
return (_i = this._getScopedValue(scope, ["layout", "hero", "value_size"])) != null ? _i : "";
}
return "";
}
_getEffectiveScopedLayoutValue(scope, key) {
if (key === "height") {
return this._getEffectiveScopedDisplayValue(scope, ["layout", "height"], [["height"]]);
}
if (key === "position") {
return this._getEffectiveScopedDisplayValue(scope, ["layout", "label", "position"], [["label_position"]]);
}
if (key === "width") {
return this._getEffectiveScopedDisplayValue(scope, ["layout", "label", "width"], [["label_width"]]);
}
if (key === "hero_size") {
return this._getEffectiveScopedDisplayValue(scope, ["layout", "hero", "size"], [["layout", "label", "hero_size"]]);
}
if (key === "value_size") {
return this._getEffectiveScopedDisplayValue(scope, ["layout", "hero", "value_size"]);
}
return "";
}
_setScopedLayoutLabelPosition(scope, value) {
if (!value) {
return this._removeCanonicalScopedValue(scope, ["layout", "label", "position"], {
deprecatedKeys: [["label_position"]],
prunePaths: [["layout", "label"], ["layout"]],
rerender: true
});
}
const didSet = this._setCanonicalScopedValue(scope, ["layout", "label", "position"], value, {
deprecatedKeys: [["label_position"]],
prunePaths: [["layout", "label"], ["layout"]],
rerender: true
});
if (!didSet || value === "hero") return didSet;
this._removeCanonicalScopedValue(scope, ["layout", "label", "hero_size"], {
prunePaths: [["layout", "label"], ["layout"]],
rerender: true
});
this._removeCanonicalScopedValue(scope, ["layout", "hero"], {
prunePaths: [["layout"]],
rerender: true
});
return true;
}
_setLayoutLabelPosition(value) {
return this._setScopedLayoutLabelPosition({ type: "card" }, value);
}
_setScopedLayoutHeroSize(scope, value) {
if (!value) {
return this._removeCanonicalScopedValue(scope, ["layout", "hero", "size"], {
deprecatedKeys: [["layout", "label", "hero_size"]],
prunePaths: [["layout", "hero"], ["layout"]]
});
}
return this._setCanonicalScopedValue(scope, ["layout", "hero", "size"], value, {
deprecatedKeys: [["layout", "label", "hero_size"]],
prunePaths: [["layout", "hero"], ["layout"]]
});
}
_setLayoutHeroSize(value) {
return this._setScopedLayoutHeroSize({ type: "card" }, value);
}
_normalizeHeroValueSizeValue(value) {
const numericValue = this._normalizeNumberValue(value);
if (numericValue === null) return null;
return Math.min(112, Math.max(12, numericValue));
}
_setScopedLayoutHeroValueSize(scope, value) {
if (value === "" || value === null || value === void 0) {
return this._removeCanonicalScopedValue(scope, ["layout", "hero", "value_size"], {
prunePaths: [["layout", "hero"], ["layout"]]
});
}
const valueSize = this._normalizeHeroValueSizeValue(value);
if (valueSize === null) return false;
return this._setCanonicalScopedValue(scope, ["layout", "hero", "value_size"], valueSize, {
prunePaths: [["layout", "hero"], ["layout"]]
});
}
_setLayoutHeroValueSize(value) {
return this._setScopedLayoutHeroValueSize({ type: "card" }, value);
}
_setScopedLayoutHeight(scope, value) {
const numericValue = this._normalizeNumberValue(value);
if (value === "" || value === null || value === void 0) {
return this._removeCanonicalScopedValue(scope, ["layout", "height"], {
deprecatedKeys: [["height"]],
prunePaths: [["layout"]]
});
}
if (numericValue === null || numericValue < 24) {
return false;
}
return this._setCanonicalScopedValue(scope, ["layout", "height"], numericValue, {
deprecatedKeys: [["height"]],
prunePaths: [["layout"]]
});
}
_setLayoutHeight(value) {
return this._setScopedLayoutHeight({ type: "card" }, value);
}
_setScopedLayoutLabelWidth(scope, value) {
const numericValue = this._normalizeNumberValue(value);
if (value === "" || value === null || value === void 0) {
return this._removeCanonicalScopedValue(scope, ["layout", "label", "width"], {
deprecatedKeys: [["label_width"]],
prunePaths: [["layout", "label"], ["layout"]]
});
}
if (numericValue === null) {
return false;
}
return this._setCanonicalScopedValue(scope, ["layout", "label", "width"], numericValue, {
deprecatedKeys: [["label_width"]],
prunePaths: [["layout", "label"], ["layout"]]
});
}
_clearLayoutOverride(scope) {
return this._applyScopedMutation(scope, (target) => {
let nextTarget = this._deletePathValue(target, ["layout", "height"]);
nextTarget = this._deletePathValue(nextTarget, ["layout", "label", "position"]);
nextTarget = this._deletePathValue(nextTarget, ["layout", "label", "hero_size"]);
nextTarget = this._deletePathValue(nextTarget, ["layout", "label", "width"]);
nextTarget = this._deletePathValue(nextTarget, ["layout", "hero"]);
nextTarget = this._deletePathValue(nextTarget, ["height"]);
nextTarget = this._deletePathValue(nextTarget, ["label_position"]);
nextTarget = this._deletePathValue(nextTarget, ["label_width"]);
nextTarget = this._pruneEmptyObjectsInTarget(nextTarget, ["layout", "label"]);
nextTarget = this._pruneEmptyObjectsInTarget(nextTarget, ["layout"]);
return nextTarget;
}, { rerender: true });
}
_hasLayoutOverride(scope) {
var _a, _b;
const layoutValue = (_a = this._getScopedValue(scope, ["layout"])) != null ? _a : {};
const labelValue = this._isObject(layoutValue) ? (_b = layoutValue.label) != null ? _b : {} : {};
if (this._isObject(layoutValue) && (Object.prototype.hasOwnProperty.call(layoutValue, "height") || this._isObject(labelValue) && (Object.prototype.hasOwnProperty.call(labelValue, "position") || Object.prototype.hasOwnProperty.call(labelValue, "hero_size") || Object.prototype.hasOwnProperty.call(labelValue, "width")))) {
return true;
}
if (this._isObject(layoutValue) && this._isObject(layoutValue.hero) && Object.keys(layoutValue.hero).length) {
return true;
}
return this._getScopedValue(scope, ["height"]) !== void 0 || this._getScopedValue(scope, ["label_position"]) !== void 0 || this._getScopedValue(scope, ["label_width"]) !== void 0;
}
_setScaleBound(key, value) {
return this._setCanonicalResolvablePart({ type: "card" }, key, "fixed", value);
}
_clearScaleOverride(scope) {
return this._applyScopedMutation(scope, (target) => {
let nextTarget = this._deletePathValue(target, ["scale", "min"]);
nextTarget = this._deletePathValue(nextTarget, ["scale", "max"]);
nextTarget = this._deletePathValue(nextTarget, ["min"]);
nextTarget = this._deletePathValue(nextTarget, ["max"]);
nextTarget = this._deletePathValue(nextTarget, ["min_entity"]);
nextTarget = this._deletePathValue(nextTarget, ["max_entity"]);
nextTarget = this._pruneEmptyObjectsInTarget(nextTarget, ["scale"]);
return nextTarget;
}, { rerender: true });
}
_setBarFillStyle(value) {
return this._setScopedBarFillStyle({ type: "card" }, value);
}
_setBarColor(value) {
return this._setScopedBarColor({ type: "card" }, value);
}
_setGradientStops(stops, options = {}) {
return this._setScopedGradientStops({ type: "card" }, stops, options);
}
_setSegments(segments, options = {}) {
return this._setScopedSegments({ type: "card" }, segments, options);
}
_getDefaultGradientStops() {
return [
{ pos: 0, color: "#4CAF50" },
{ pos: 50, color: "#FF9800" },
{ pos: 100, color: "#F44336" }
];
}
_normalizeGradientStopPosValue(rawValue) {
const numericValue = this._normalizeNumberValue(rawValue);
if (numericValue === null || !Number.isFinite(numericValue)) {
return null;
}
if (numericValue < 0 || numericValue > 100) {
return null;
}
return numericValue;
}
_sanitizeGradientStopsForEmit(stops) {
if (!Array.isArray(stops)) {
return [];
}
return stops.map((stop) => {
if (!this._isObject(stop)) {
return null;
}
const pos = this._normalizeGradientStopPosValue(stop.pos);
const color = this._normalizeTextValue(stop.color).trim();
if (pos === null || !color) {
return null;
}
return {
...stop,
pos,
color
};
}).filter(Boolean).sort((left, right) => left.pos - right.pos);
}
_getGradientStopDraftColorDefault(scope = { type: "card" }) {
var _a;
const committedStops = this._sanitizeGradientStopsForEmit(this._getScopedGradientStopsValue(scope));
if (committedStops.length) {
return (_a = committedStops[committedStops.length - 1].color) != null ? _a : "#4CAF50";
}
return this._getDefaultGradientStops()[0].color;
}
_getNextSuggestedGradientStopPos(scope = { type: "card" }) {
const committedStops = this._sanitizeGradientStopsForEmit(this._getScopedGradientStopsValue(scope));
if (!committedStops.length) {
return 0;
}
const highest = committedStops[committedStops.length - 1];
if (highest.pos >= 100) {
return "";
}
let suggestedPos;
if (committedStops.length === 1) {
suggestedPos = highest.pos + 25;
} else {
const previous = committedStops[committedStops.length - 2];
suggestedPos = highest.pos + (highest.pos - previous.pos);
}
const clampedPos = Math.min(100, Math.max(0, suggestedPos));
if (committedStops.some((stop) => stop.pos === clampedPos)) {
return "";
}
return clampedPos;
}
_getGradientStopsDraftKey(scope) {
return (scope == null ? void 0 : scope.type) === "entity" ? `entity:${scope.index}` : "card";
}
_getGradientStopPosTextKey(scope, stopIndex) {
return `${this._getGradientStopsDraftKey(scope)}:pos:${stopIndex}`;
}
_getGradientStopPosText(scope = { type: "card" }, stopIndex, fallbackValue = "") {
const key = this._getGradientStopPosTextKey(scope, stopIndex);
if (this._gradientStopPosTexts.has(key)) {
return this._gradientStopPosTexts.get(key);
}
if (fallbackValue === "" || fallbackValue === null || fallbackValue === void 0) {
return "";
}
return String(fallbackValue);
}
_setGradientStopPosText(scope, stopIndex, rawValue) {
this._gradientStopPosTexts.set(
this._getGradientStopPosTextKey(scope, stopIndex),
this._normalizeTextValue(rawValue)
);
}
_clearGradientStopPosText(scope, stopIndex) {
this._gradientStopPosTexts.delete(this._getGradientStopPosTextKey(scope, stopIndex));
}
_clearGradientStopScopeTextState(scope) {
const prefix = `${this._getGradientStopsDraftKey(scope)}:pos:`;
for (const key of this._gradientStopPosTexts.keys()) {
if (key.startsWith(prefix)) {
this._gradientStopPosTexts.delete(key);
}
}
for (const key of this._gradientStopValidationMessages.keys()) {
if (key.startsWith(prefix)) {
this._gradientStopValidationMessages.delete(key);
}
}
}
_getGradientStopsUiRows(scope = { type: "card" }) {
const key = this._getGradientStopsDraftKey(scope);
if (this._gradientStopsUiRows.has(key)) {
return this._cloneDeep(this._gradientStopsUiRows.get(key));
}
return null;
}
_setGradientStopsUiRows(scope, stops) {
this._gradientStopsUiRows.set(this._getGradientStopsDraftKey(scope), this._cloneDeep(stops));
}
_getStoredScopedGradientStops(scope = { type: "card" }) {
const structuredValue = this._getScopedValue(scope, ["bar", "gradient_stops"]);
if (structuredValue !== void 0) {
return structuredValue;
}
const legacyValue = this._getScopedValue(scope, ["gradient_stops"]);
if (legacyValue !== void 0) {
return legacyValue;
}
return null;
}
_getFallbackGradientStops(scope = { type: "card" }) {
if ((scope == null ? void 0 : scope.type) === "entity") {
const inheritedStops = this._sanitizeGradientStopsForEmit(this._getScopedGradientStopsValue({ type: "card" }));
return inheritedStops.length ? inheritedStops : this._getDefaultGradientStops();
}
return this._getDefaultGradientStops();
}
_createGradientStopDraftState(scope = { type: "card" }) {
const suggestedPos = this._getNextSuggestedGradientStopPos(scope);
return {
pos: suggestedPos === "" ? "" : String(suggestedPos),
color: this._getGradientStopDraftColorDefault(scope)
};
}
_getGradientStopsDraftState(scope = { type: "card" }) {
const key = this._getGradientStopsDraftKey(scope);
if (!this._gradientStopsDrafts.has(key)) {
this._gradientStopsDrafts.set(key, this._createGradientStopDraftState(scope));
}
return this._cloneDeep(this._gradientStopsDrafts.get(key));
}
_setGradientStopsDraftState(scope, nextDraft, options = {}) {
var _a, _b;
this._gradientStopsDrafts.set(this._getGradientStopsDraftKey(scope), {
pos: (_a = nextDraft == null ? void 0 : nextDraft.pos) != null ? _a : "",
color: (_b = nextDraft == null ? void 0 : nextDraft.color) != null ? _b : this._getGradientStopDraftColorDefault(scope)
});
if (options == null ? void 0 : options.refreshOnly) {
this._refreshGradientDraftUi(scope);
return;
}
this._render();
}
_setGradientStopsDraftField(scope, field, rawValue) {
const currentDraft = this._getGradientStopsDraftState(scope);
const nextValue = field === "color" ? this._normalizeTextValue(rawValue).trim() : this._normalizeTextValue(rawValue);
this._setGradientStopsDraftState(scope, {
...currentDraft,
[field]: nextValue
}, { refreshOnly: field === "pos" });
}
_getValidGradientDraftStop(scope = { type: "card" }) {
const draft = this._getGradientStopsDraftState(scope);
const pos = this._normalizeGradientStopPosValue(draft.pos);
const color = this._normalizeTextValue(draft.color).trim();
if (pos === null || !color) {
return null;
}
return { pos, color };
}
_hasGradientStopDuplicate(scope = { type: "card" }, candidatePos, excludeIndex = null) {
return this._sanitizeGradientStopsForEmit(this._getScopedGradientStopsValue(scope)).some((stop, index) => index !== excludeIndex && stop.pos === candidatePos);
}
_canAddGradientStop(scope = { type: "card" }) {
const draftStop = this._getValidGradientDraftStop(scope);
if (!draftStop) {
return false;
}
return !this._hasGradientStopDuplicate(scope, draftStop.pos);
}
_getGradientDraftValidationMessage(scope = { type: "card" }) {
const draft = this._getGradientStopsDraftState(scope);
const normalizedPosText = this._normalizeTextValue(draft.pos).trim();
const normalizedColor = this._normalizeTextValue(draft.color).trim();
if (!normalizedPosText) {
return "Enter a position to add a stop.";
}
if (this._normalizeGradientStopPosValue(draft.pos) === null) {
return "Enter a value from 0 to 100.";
}
if (!normalizedColor) {
return "Choose a color to add a stop.";
}
if (this._hasGradientStopDuplicate(scope, this._normalizeGradientStopPosValue(draft.pos))) {
return "Position already exists.";
}
return "";
}
_isDefaultGradientStops(stops) {
const sanitizedStops = this._sanitizeGradientStopsForEmit(stops);
const defaultStops = this._getDefaultGradientStops();
if (sanitizedStops.length !== defaultStops.length) {
return false;
}
return sanitizedStops.every((stop, index) => stop.pos === defaultStops[index].pos && this._normalizeColorComparisonValue(stop.color) === this._normalizeColorComparisonValue(defaultStops[index].color));
}
_setScopedGradientStops(scope, stops, options = {}) {
var _a;
const sanitizedStops = this._sanitizeGradientStopsForEmit(stops);
const shouldRemove = sanitizedStops.length < 2 || this._isDefaultGradientStops(sanitizedStops);
const previousUiRowsJson = this._serializeConfig((_a = this._getGradientStopsUiRows(scope)) != null ? _a : []);
this._clearGradientStopScopeTextState(scope);
this._setGradientStopsUiRows(scope, sanitizedStops);
const applied = this._applyScopedMutation(scope, (target) => {
let nextTarget = this._deletePathValue(target, ["gradient_stops"]);
nextTarget = this._deletePathValue(nextTarget, ["bar", "gradient_stops"]);
if (!shouldRemove) {
nextTarget = this._setPathValue(nextTarget, ["bar", "gradient_stops"], sanitizedStops);
}
nextTarget = this._pruneEmptyObjectsInTarget(nextTarget, ["bar"]);
return nextTarget;
}, options);
if (applied === false && (options == null ? void 0 : options.rerender) && this._serializeConfig(sanitizedStops) !== previousUiRowsJson) {
this._render();
}
if (applied !== false && !(options == null ? void 0 : options.rerender)) {
this._refreshGradientDraftUi(scope);
}
return applied;
}
_clearGradientStopsOverride(scope) {
var _a;
const previousUiRowsJson = this._serializeConfig((_a = this._getGradientStopsUiRows(scope)) != null ? _a : []);
this._gradientStopsDrafts.delete(this._getGradientStopsDraftKey(scope));
this._gradientStopsUiRows.delete(this._getGradientStopsDraftKey(scope));
this._clearGradientStopScopeTextState(scope);
const applied = this._applyScopedMutation(scope, (target) => {
let nextTarget = this._deletePathValue(target, ["bar", "gradient_stops"]);
nextTarget = this._deletePathValue(nextTarget, ["gradient_stops"]);
nextTarget = this._pruneEmptyObjectsInTarget(nextTarget, ["bar"]);
return nextTarget;
}, { rerender: true });
if (applied === false && previousUiRowsJson !== this._serializeConfig([])) {
this._render();
}
return applied;
}
_setScopedSegments(scope, segments, options = {}) {
const nextSegments = (options == null ? void 0 : options.sort) === false ? this._cloneDeep(segments) : this._sortSegmentsForEditor(segments);
const fallbackSegments = this._getFallbackSegments(scope);
const shouldRemove = !Array.isArray(nextSegments) || !nextSegments.length || fallbackSegments.length > 0 && this._segmentsEqualForEditor(nextSegments, fallbackSegments);
this._setSegmentsUiRows(scope, nextSegments);
const applied = this._applyScopedMutation(scope, (target) => {
let nextTarget = this._deletePathValue(target, ["bar", "segments"]);
nextTarget = this._deletePathValue(nextTarget, ["segments"]);
nextTarget = this._deletePathValue(nextTarget, ["severity"]);
if (!shouldRemove) {
nextTarget = this._setPathValue(nextTarget, ["bar", "segments"], nextSegments);
}
nextTarget = this._pruneEmptyObjectsInTarget(nextTarget, ["bar"]);
return nextTarget;
}, options);
if (applied !== false) {
this._refreshSegmentUi(scope);
}
return applied;
}
_clearSegmentsOverride(scope) {
this._segmentDrafts.delete(this._getSegmentsScopeKey(scope));
this._segmentUiRows.delete(this._getSegmentsScopeKey(scope));
this._clearSegmentScopeTextState(scope);
return this._applyScopedMutation(scope, (target) => {
let nextTarget = this._deletePathValue(target, ["bar", "segments"]);
nextTarget = this._deletePathValue(nextTarget, ["segments"]);
nextTarget = this._deletePathValue(nextTarget, ["severity"]);
nextTarget = this._pruneEmptyObjectsInTarget(nextTarget, ["bar"]);
return nextTarget;
}, { rerender: true });
}
_setNeedle(value) {
return this._setScopedNeedleMode({ type: "card" }, value ? "enabled" : "disabled");
}
_getScopedPeakConfig(scope) {
var _a, _b;
const rawPeak = this._getScopedValue(scope, ["peak"]);
const rawPeakMarker = this._getScopedValue(scope, ["peak_marker"]);
const rawLegacyShow = this._getScopedValue(scope, ["show_peak"]);
const rawLegacyColor = this._getScopedValue(scope, ["peak_color"]);
const defaultColor = "#888";
let mode = (scope == null ? void 0 : scope.type) === "entity" ? "inherit" : "disabled";
let color = "";
if (this._isObject(rawPeak)) {
if (rawPeak.enabled === true) {
mode = "enabled";
} else if (rawPeak.enabled === false) {
mode = "disabled";
}
color = (_a = rawPeak.color) != null ? _a : color;
}
if (this._isObject(rawPeakMarker)) {
if (rawPeakMarker.show === true) {
mode = "enabled";
} else if (rawPeakMarker.show === false) {
mode = "disabled";
} else if ((scope == null ? void 0 : scope.type) !== "entity") {
mode = "disabled";
}
color = (_b = rawPeakMarker.color) != null ? _b : color;
}
if (rawLegacyShow === true) {
mode = "enabled";
} else if (rawLegacyShow === false) {
mode = "disabled";
}
color = color || rawLegacyColor || "";
if (color && this._normalizeColorComparisonValue(color) === this._normalizeColorComparisonValue(defaultColor)) {
color = "";
}
return { mode, color };
}
_getEffectiveScopedPeakConfig(scope) {
const localPeak = this._getScopedPeakConfig(scope);
if ((scope == null ? void 0 : scope.type) !== "entity") {
return localPeak;
}
if (!this._hasPeakOverride(scope)) {
return this._getScopedPeakConfig({ type: "card" });
}
const inheritedPeak = this._getScopedPeakConfig({ type: "card" });
return {
mode: localPeak.mode === "inherit" ? inheritedPeak.mode : localPeak.mode,
color: localPeak.color || inheritedPeak.color
};
}
_hasPeakOverride(scope) {
var _a, _b;
const peakValue = (_a = this._getScopedValue(scope, ["peak"])) != null ? _a : {};
if (this._isObject(peakValue) && (Object.prototype.hasOwnProperty.call(peakValue, "enabled") || Object.prototype.hasOwnProperty.call(peakValue, "color"))) {
return true;
}
const peakMarkerValue = (_b = this._getScopedValue(scope, ["peak_marker"])) != null ? _b : {};
if (this._isObject(peakMarkerValue) && (Object.prototype.hasOwnProperty.call(peakMarkerValue, "show") || Object.prototype.hasOwnProperty.call(peakMarkerValue, "color"))) {
return true;
}
return this._getScopedValue(scope, ["show_peak"]) !== void 0 || this._getScopedValue(scope, ["peak_color"]) !== void 0;
}
_getPeakSummary(scope) {
if ((scope == null ? void 0 : scope.type) === "entity" && !this._hasPeakOverride(scope)) return "Inherited";
const peak = this._getScopedPeakConfig(scope);
if (peak.mode === "disabled") return peak.color ? "Disabled \u2022 Custom color" : "Disabled";
if (peak.mode === "enabled") return peak.color ? "Enabled \u2022 Custom color" : "Enabled";
if (peak.color) return "Custom color";
return "Inherited";
}
_clearPeakOverride(scope) {
return this._applyScopedMutation(scope, (target) => {
let nextTarget = this._deletePathValue(target, ["peak", "enabled"]);
nextTarget = this._deletePathValue(nextTarget, ["peak", "color"]);
nextTarget = this._deletePathValue(nextTarget, ["show_peak"]);
nextTarget = this._deletePathValue(nextTarget, ["peak_color"]);
nextTarget = this._deletePathValue(nextTarget, ["peak_marker"]);
nextTarget = this._pruneEmptyObjectsInTarget(nextTarget, ["peak"]);
return nextTarget;
}, { rerender: true });
}
_setScopedPeakEnabled(scope, value) {
const boolValue = !!value;
const defaultColor = "#888";
return this._applyScopedMutation(scope, (target) => {
var _a, _b, _c;
let nextTarget = this._cloneDeep(target);
const currentPeak = this._isObject(this._getPathValue(nextTarget, ["peak"])) ? this._cloneDeep(this._getPathValue(nextTarget, ["peak"])) : {};
const currentColor = (_c = (_b = (_a = currentPeak.color) != null ? _a : this._isObject(this._getPathValue(nextTarget, ["peak_marker"])) ? this._getPathValue(nextTarget, ["peak_marker", "color"]) : void 0) != null ? _b : this._getPathValue(nextTarget, ["peak_color"])) != null ? _c : defaultColor;
if ((scope == null ? void 0 : scope.type) === "entity" || boolValue) {
currentPeak.enabled = boolValue;
} else {
delete currentPeak.enabled;
}
if (currentColor && this._normalizeColorComparisonValue(currentColor) !== this._normalizeColorComparisonValue(defaultColor)) {
currentPeak.color = currentColor;
} else {
delete currentPeak.color;
}
if (Object.keys(currentPeak).length) {
nextTarget = this._setPathValue(nextTarget, ["peak"], currentPeak);
} else {
nextTarget = this._deletePathValue(nextTarget, ["peak"]);
}
nextTarget = this._deletePathValue(nextTarget, ["show_peak"]);
nextTarget = this._deletePathValue(nextTarget, ["peak_color"]);
nextTarget = this._deletePathValue(nextTarget, ["peak_marker"]);
nextTarget = this._pruneEmptyObjectsInTarget(nextTarget, ["peak"]);
return nextTarget;
});
}
_setScopedPeakColor(scope, rawValue) {
const normalizedValue = this._normalizeTextValue(rawValue).trim();
const defaultColor = "#888";
return this._applyScopedMutation(scope, (target) => {
let nextTarget = this._cloneDeep(target);
const currentPeak = this._isObject(this._getPathValue(nextTarget, ["peak"])) ? this._cloneDeep(this._getPathValue(nextTarget, ["peak"])) : {};
const currentConfig = this._getScopedPeakConfig(scope);
delete currentPeak.color;
if (normalizedValue && this._normalizeColorComparisonValue(normalizedValue) !== this._normalizeColorComparisonValue(defaultColor)) {
currentPeak.color = normalizedValue;
}
if ((scope == null ? void 0 : scope.type) === "entity") {
if (currentConfig.mode === "enabled") currentPeak.enabled = true;
if (currentConfig.mode === "disabled") currentPeak.enabled = false;
} else if (currentConfig.mode === "enabled") {
currentPeak.enabled = true;
}
if (Object.keys(currentPeak).length) {
nextTarget = this._setPathValue(nextTarget, ["peak"], currentPeak);
} else {
nextTarget = this._deletePathValue(nextTarget, ["peak"]);
}
nextTarget = this._deletePathValue(nextTarget, ["show_peak"]);
nextTarget = this._deletePathValue(nextTarget, ["peak_color"]);
nextTarget = this._deletePathValue(nextTarget, ["peak_marker"]);
nextTarget = this._pruneEmptyObjectsInTarget(nextTarget, ["peak"]);
return nextTarget;
});
}
_setFixedMarkerValue(rootKey, enabled, value) {
const numericValue = this._normalizeNumberValue(value);
if (!enabled || numericValue === null) {
return this._removeCanonicalScopedValue({ type: "card" }, [rootKey, "at", "fixed"], {
deprecatedKeys: rootKey === "target" ? [["target_entity"]] : [],
prunePaths: [[rootKey, "at"], [rootKey]]
});
}
return this._setCanonicalScopedValue({ type: "card" }, [rootKey, "at", "fixed"], numericValue, {
deprecatedKeys: rootKey === "target" ? [["target_entity"]] : [],
prunePaths: [[rootKey, "at"], [rootKey]]
});
}
_setPeakShow(value) {
return this._setScopedPeakEnabled({ type: "card" }, value);
}
_readFixedMarker(rootKey) {
const rawValue = this._draftConfig[rootKey];
if (this._isObject(rawValue)) {
const fixed = this._isObject(rawValue == null ? void 0 : rawValue.at) ? rawValue.at.fixed : rawValue == null ? void 0 : rawValue.at;
return {
enabled: fixed !== void 0 && fixed !== null && fixed !== "",
value: fixed != null ? fixed : ""
};
}
return {
enabled: rawValue !== void 0 && rawValue !== null && rawValue !== "",
value: rawValue != null ? rawValue : ""
};
}
_getGradientStopsValue() {
return this._getScopedGradientStopsValue({ type: "card" });
}
_getSegmentsValue() {
return this._getScopedSegmentsValue({ type: "card" });
}
_getSegmentsScopeKey(scope = { type: "card" }) {
return (scope == null ? void 0 : scope.type) === "entity" ? `entity:${scope.index}` : "card";
}
_getSegmentBoundaryTextKey(scope, segmentIndex, field) {
return `${this._getSegmentsScopeKey(scope)}:${segmentIndex}:${field}`;
}
_getSegmentBoundaryText(scope = { type: "card" }, segmentIndex, field, fallbackValue = "") {
const key = this._getSegmentBoundaryTextKey(scope, segmentIndex, field);
if (this._segmentBoundaryTexts.has(key)) {
return this._segmentBoundaryTexts.get(key);
}
return this._formatSegmentBoundaryValue(fallbackValue);
}
_setSegmentBoundaryText(scope, segmentIndex, field, rawValue) {
this._segmentBoundaryTexts.set(
this._getSegmentBoundaryTextKey(scope, segmentIndex, field),
this._normalizeTextValue(rawValue)
);
}
_clearSegmentBoundaryText(scope, segmentIndex, field) {
this._segmentBoundaryTexts.delete(this._getSegmentBoundaryTextKey(scope, segmentIndex, field));
}
_clearSegmentScopeTextState(scope) {
const prefix = `${this._getSegmentsScopeKey(scope)}:`;
for (const key of this._segmentBoundaryTexts.keys()) {
if (key.startsWith(prefix)) {
this._segmentBoundaryTexts.delete(key);
}
}
}
_getSegmentsUiRows(scope = { type: "card" }) {
const key = this._getSegmentsScopeKey(scope);
if (this._segmentUiRows.has(key)) {
return this._cloneDeep(this._segmentUiRows.get(key));
}
return null;
}
_setSegmentsUiRows(scope, rows) {
this._segmentUiRows.set(this._getSegmentsScopeKey(scope), this._cloneDeep(rows));
}
_getSegmentDraftState(scope = { type: "card" }) {
const key = this._getSegmentsScopeKey(scope);
if (!this._segmentDrafts.has(key)) {
this._segmentDrafts.set(key, this._createSegmentDraftState(scope));
}
return this._cloneDeep(this._segmentDrafts.get(key));
}
_setSegmentDraftState(scope, nextDraft, options = {}) {
var _a, _b, _c;
this._segmentDrafts.set(this._getSegmentsScopeKey(scope), {
from: (_a = nextDraft == null ? void 0 : nextDraft.from) != null ? _a : "",
to: (_b = nextDraft == null ? void 0 : nextDraft.to) != null ? _b : "",
color: (_c = nextDraft == null ? void 0 : nextDraft.color) != null ? _c : this._getSegmentDraftColorDefault(scope)
});
if (options == null ? void 0 : options.refreshOnly) {
this._refreshSegmentUi(scope);
return;
}
this._render();
}
_setSegmentDraftField(scope, field, rawValue) {
const currentDraft = this._getSegmentDraftState(scope);
const nextValue = field === "color" ? this._normalizeTextValue(rawValue).trim() : this._normalizeTextValue(rawValue);
this._setSegmentDraftState(scope, {
...currentDraft,
[field]: nextValue
}, { refreshOnly: true });
}
_isSegmentFillStyle(fillStyle) {
return ["bands", "soft_bands", "band_gradient"].includes(fillStyle);
}
_getDefaultSegments() {
return [
{ from: "0%", to: "33%", color: "#4CAF50" },
{ from: "33%", to: "75%", color: "#FF9800" },
{ from: "75%", to: "100%", color: "#F44336" }
];
}
_getStoredScopedSegments(scope = { type: "card" }) {
const structuredValue = this._getScopedValue(scope, ["bar", "segments"]);
if (structuredValue !== void 0) {
return structuredValue;
}
const legacySegments = this._getScopedValue(scope, ["segments"]);
if (legacySegments !== void 0) {
return legacySegments;
}
const legacySeverity = this._getScopedValue(scope, ["severity"]);
if (legacySeverity !== void 0) {
return legacySeverity;
}
return null;
}
_parseSegmentBoundaryInput(rawValue) {
const normalizedValue = this._normalizeTextValue(rawValue).trim();
if (!normalizedValue) {
return null;
}
const percentMatch = normalizedValue.match(/^\s*([+-]?(?:\d+(?:\.\d+)?|\.\d+))\s*%\s*$/);
const percent = percentMatch ? parseFloat(percentMatch[1]) : null;
if (Number.isFinite(percent)) {
return `${percent}%`;
}
const numericValue = this._normalizeNumberValue(normalizedValue);
return numericValue === null ? null : numericValue;
}
_formatSegmentBoundaryValue(value) {
if (typeof value === "string") {
return value;
}
if (typeof value === "number" && Number.isFinite(value)) {
return String(value);
}
if (this._isObject(value)) {
if (Number.isFinite(value.percent)) {
return `${value.percent}%`;
}
if (Number.isFinite(this._getFiniteNumber(value.fixed))) {
return String(this._getFiniteNumber(value.fixed));
}
}
return "";
}
_getSegmentDraftColorDefault(scope = { type: "card" }) {
var _a;
const segments = this._getScopedSegmentsValue(scope);
if (segments.length) {
return this._normalizeTextValue((_a = segments[segments.length - 1]) == null ? void 0 : _a.color).trim() || "#4a9eff";
}
return "#4CAF50";
}
_getNewSegmentDefaults(scope = { type: "card" }) {
var _a;
const segments = this._getScopedSegmentsValue(scope);
const previous = segments[segments.length - 1];
const previousTo = (_a = previous == null ? void 0 : previous.to) != null ? _a : null;
return {
from: previousTo != null ? previousTo : "0%",
to: "100%",
color: "#4a9eff"
};
}
_createSegmentDraftState(scope = { type: "card" }) {
var _a;
const defaults = this._getNewSegmentDefaults(scope);
const formattedFrom = this._formatSegmentBoundaryValue(defaults.from);
const formattedTo = this._formatSegmentBoundaryValue(defaults.to);
const draftFrom = formattedFrom === "100%" || formattedFrom === "100" ? "" : formattedFrom;
const draftTo = draftFrom ? formattedTo : "";
return {
from: draftFrom,
to: draftTo,
color: (_a = defaults.color) != null ? _a : this._getSegmentDraftColorDefault(scope)
};
}
_normalizeSegmentForEditorComparison(segment) {
if (!this._isObject(segment)) {
return null;
}
const from = this._formatSegmentBoundaryValue(segment.from).trim();
const to = this._formatSegmentBoundaryValue(segment.to).trim();
const color = this._normalizeColorComparisonValue(segment.color);
if (!from || !to || !color) {
return null;
}
return { from, to, color };
}
_segmentsEqualForEditor(leftSegments, rightSegments) {
const left = Array.isArray(leftSegments) ? leftSegments.map((segment) => this._normalizeSegmentForEditorComparison(segment)).filter(Boolean) : [];
const right = Array.isArray(rightSegments) ? rightSegments.map((segment) => this._normalizeSegmentForEditorComparison(segment)).filter(Boolean) : [];
if (left.length !== right.length) {
return false;
}
return left.every((segment, index) => segment.from === right[index].from && segment.to === right[index].to && segment.color === right[index].color);
}
_getFallbackSegments(scope = { type: "card" }) {
if ((scope == null ? void 0 : scope.type) === "entity") {
const cardStoredSegments = this._getStoredScopedSegments({ type: "card" });
if (cardStoredSegments !== null) {
return this._cloneDeep(this._getScopedSegmentsValue({ type: "card" }));
}
}
if (!this._isSegmentFillStyle(this._getEffectiveFillStyleValue(scope))) {
return [];
}
return this._cloneDeep(this._getDefaultSegments());
}
_parseSegmentBoundaryText(rawValue) {
const normalizedValue = this._normalizeTextValue(rawValue).trim();
if (!normalizedValue) {
return { state: "empty", value: null };
}
const parsed = this._parseSegmentBoundaryInput(normalizedValue);
if (parsed === null) {
return { state: "invalid", value: null };
}
return { state: "valid", value: parsed };
}
_compareSegmentBoundaries(left, right) {
const leftValue = this._getSegmentPreviewBoundaryValue(left);
const rightValue = this._getSegmentPreviewBoundaryValue(right);
if (leftValue === null || rightValue === null) {
return null;
}
if (leftValue < rightValue) return -1;
if (leftValue > rightValue) return 1;
return 0;
}
_buildSegmentValidationRows(scope = { type: "card" }) {
var _a;
const rows = (_a = this._getSegmentsUiRows(scope)) != null ? _a : this._getScopedSegmentsValue(scope);
return rows.map((segment, index) => {
const rawFrom = this._getSegmentBoundaryText(scope, index, "from", segment == null ? void 0 : segment.from);
const rawTo = this._getSegmentBoundaryText(scope, index, "to", segment == null ? void 0 : segment.to);
const parsedFrom = this._parseSegmentBoundaryText(rawFrom);
const parsedTo = this._parseSegmentBoundaryText(rawTo);
return {
index,
rawFrom,
rawTo,
parsedFrom,
parsedTo
};
});
}
_getSegmentRowValidationMessage(scope = { type: "card" }, segmentIndex) {
const rows = this._buildSegmentValidationRows(scope);
const row = rows[segmentIndex];
if (!row) {
return "";
}
if (row.parsedFrom.state === "invalid" || row.parsedTo.state === "invalid" || row.parsedFrom.state === "empty" || row.parsedTo.state === "empty") {
return "Enter valid from/to values.";
}
if (this._compareSegmentBoundaries(row.parsedFrom.value, row.parsedTo.value) !== -1) {
return "From must be below To.";
}
const candidateFrom = this._getSegmentPreviewBoundaryValue(row.parsedFrom.value);
const candidateTo = this._getSegmentPreviewBoundaryValue(row.parsedTo.value);
for (const other of rows) {
if (other.index === segmentIndex) continue;
if (other.parsedFrom.state !== "valid" || other.parsedTo.state !== "valid") continue;
const otherFrom = this._getSegmentPreviewBoundaryValue(other.parsedFrom.value);
const otherTo = this._getSegmentPreviewBoundaryValue(other.parsedTo.value);
if (candidateFrom === otherFrom) {
return "Duplicate segment start.";
}
if (candidateFrom < otherTo && candidateTo > otherFrom) {
return "Segments overlap.";
}
}
return "";
}
_getValidSegmentDraft(scope = { type: "card" }) {
const draft = this._getSegmentDraftState(scope);
const parsedFrom = this._parseSegmentBoundaryText(draft.from);
const parsedTo = this._parseSegmentBoundaryText(draft.to);
const color = this._normalizeTextValue(draft.color).trim();
if (parsedFrom.state !== "valid" || parsedTo.state !== "valid" || !color) {
return null;
}
if (this._compareSegmentBoundaries(parsedFrom.value, parsedTo.value) !== -1) {
return null;
}
const candidateFrom = this._getSegmentPreviewBoundaryValue(parsedFrom.value);
const candidateTo = this._getSegmentPreviewBoundaryValue(parsedTo.value);
const rows = this._buildSegmentValidationRows(scope);
for (const row of rows) {
if (row.parsedFrom.state !== "valid" || row.parsedTo.state !== "valid") continue;
const otherFrom = this._getSegmentPreviewBoundaryValue(row.parsedFrom.value);
const otherTo = this._getSegmentPreviewBoundaryValue(row.parsedTo.value);
if (candidateFrom === otherFrom || candidateFrom < otherTo && candidateTo > otherFrom) {
return null;
}
}
return {
from: parsedFrom.value,
to: parsedTo.value,
color
};
}
_canAddSegment(scope = { type: "card" }) {
return !!this._getValidSegmentDraft(scope);
}
_getSegmentDraftValidationMessage(scope = { type: "card" }) {
const draft = this._getSegmentDraftState(scope);
const parsedFrom = this._parseSegmentBoundaryText(draft.from);
const parsedTo = this._parseSegmentBoundaryText(draft.to);
const color = this._normalizeTextValue(draft.color).trim();
if (!this._normalizeTextValue(draft.from).trim() && !this._normalizeTextValue(draft.to).trim()) {
return "";
}
if (parsedFrom.state !== "valid" || parsedTo.state !== "valid") {
return "Enter valid from/to values.";
}
if (this._compareSegmentBoundaries(parsedFrom.value, parsedTo.value) !== -1) {
return "From must be below To.";
}
if (!color) {
return "Choose a color to add a segment.";
}
const candidateFrom = this._getSegmentPreviewBoundaryValue(parsedFrom.value);
const candidateTo = this._getSegmentPreviewBoundaryValue(parsedTo.value);
const rows = this._buildSegmentValidationRows(scope);
for (const row of rows) {
if (row.parsedFrom.state !== "valid" || row.parsedTo.state !== "valid") continue;
const otherFrom = this._getSegmentPreviewBoundaryValue(row.parsedFrom.value);
const otherTo = this._getSegmentPreviewBoundaryValue(row.parsedTo.value);
if (candidateFrom === otherFrom) {
return "Duplicate segment start.";
}
if (candidateFrom < otherTo && candidateTo > otherFrom) {
return "Segments overlap.";
}
}
return "";
}
_getSegmentPreviewBoundaryValue(value) {
if (typeof value === "string") {
const match = value.trim().match(/^([+-]?(?:\d+(?:\.\d+)?|\.\d+))%$/);
if (match) {
const parsed = parseFloat(match[1]);
return Number.isFinite(parsed) ? parsed : null;
}
}
if (typeof value === "number" && Number.isFinite(value)) {
return value;
}
if (this._isObject(value)) {
if (Number.isFinite(value.percent)) {
return value.percent;
}
const fixedValue = this._getFiniteNumber(value.fixed);
if (Number.isFinite(fixedValue)) {
return fixedValue;
}
}
return null;
}
_sortSegmentsForEditor(segments) {
if (!Array.isArray(segments)) {
return [];
}
return this._cloneDeep(segments).sort((left, right) => {
const leftFrom = this._getSegmentPreviewBoundaryValue(left == null ? void 0 : left.from);
const rightFrom = this._getSegmentPreviewBoundaryValue(right == null ? void 0 : right.from);
if (leftFrom === null && rightFrom === null) return 0;
if (leftFrom === null) return 1;
if (rightFrom === null) return -1;
return leftFrom - rightFrom;
});
}
_getSegmentPreviewRows(scope = { type: "card" }) {
var _a;
const baseSegments = (_a = this._getSegmentsUiRows(scope)) != null ? _a : this._getScopedSegmentsValue(scope);
const previewSegments = this._sortSegmentsForEditor(baseSegments);
const validDraft = this._getValidSegmentDraft(scope);
if (validDraft) {
previewSegments.push(validDraft);
}
return this._sortSegmentsForEditor(previewSegments).filter((segment) => {
const from = this._getSegmentPreviewBoundaryValue(segment == null ? void 0 : segment.from);
const to = this._getSegmentPreviewBoundaryValue(segment == null ? void 0 : segment.to);
return from !== null && to !== null && typeof (segment == null ? void 0 : segment.color) === "string" && segment.color.trim();
});
}
_buildEditorSegmentPreviewStyle(scope = { type: "card" }) {
const segments = this._getSegmentPreviewRows(scope);
if (!segments.length) {
return "";
}
const fillStyle = this._getEffectiveFillStyleValue(scope);
const stops = [];
segments.forEach((segment) => {
const from = Math.max(0, Math.min(100, this._getSegmentPreviewBoundaryValue(segment.from)));
const to = Math.max(0, Math.min(100, this._getSegmentPreviewBoundaryValue(segment.to)));
stops.push(`${segment.color} ${from}%`, `${segment.color} ${to}%`);
});
if (fillStyle === "bands") {
return `background:linear-gradient(to right,${stops.join(",")});background-repeat:no-repeat;`;
}
return `background:linear-gradient(to right,${stops.join(",")});background-repeat:no-repeat;`;
}
_getSegmentPreviewDomIds(scope = { type: "card" }) {
if ((scope == null ? void 0 : scope.type) === "entity") {
return {
previewId: `entity-${scope.index}-segment-preview`,
trackId: `entity-${scope.index}-segment-preview-track`
};
}
return {
previewId: "card-segment-preview",
trackId: "card-segment-preview-track"
};
}
_renderSegmentPreview(scope = { type: "card" }) {
var _a;
const { previewId, trackId } = this._getSegmentPreviewDomIds(scope);
const segments = this._getSegmentPreviewRows(scope);
const markers = [];
segments.forEach((segment) => {
const from = this._getSegmentPreviewBoundaryValue(segment.from);
const to = this._getSegmentPreviewBoundaryValue(segment.to);
if (from !== null) markers.push(from);
if (to !== null) markers.push(to);
});
const uniqueMarkers = [...new Set(markers)].sort((left, right) => left - right);
return `
<div id="${previewId}" class="gradient-preview segment-preview">
<div id="${trackId}" class="gradient-preview-track segment-preview-track" style="${this._escapeAttribute((_a = this._buildEditorSegmentPreviewStyle(scope)) != null ? _a : "")}">
${uniqueMarkers.map((marker, index) => `
<span
id="${previewId}-stop-${index}"
class="gradient-preview-stop"
style="left:${this._escapeAttribute(String(marker))}%"
title="${this._escapeAttribute(`${marker}%`)}"
></span>
`).join("")}
</div>
</div>
`;
}
_refreshSegmentPreview(scope = { type: "card" }) {
var _a;
const { previewId, trackId } = this._getSegmentPreviewDomIds(scope);
const track = this._getShadowElementById(trackId);
if (!track) {
return;
}
track.setAttribute("style", (_a = this._buildEditorSegmentPreviewStyle(scope)) != null ? _a : "");
const segments = this._getSegmentPreviewRows(scope);
const markers = [];
segments.forEach((segment) => {
const from = this._getSegmentPreviewBoundaryValue(segment.from);
const to = this._getSegmentPreviewBoundaryValue(segment.to);
if (from !== null) markers.push(from);
if (to !== null) markers.push(to);
});
const uniqueMarkers = [...new Set(markers)].sort((left, right) => left - right);
track.innerHTML = uniqueMarkers.map((marker, index) => `
<span
id="${previewId}-stop-${index}"
class="gradient-preview-stop"
style="left:${this._escapeAttribute(String(marker))}%"
title="${this._escapeAttribute(`${marker}%`)}"
></span>
`).join("");
}
_getSegmentDomIds(scope = { type: "card" }) {
if ((scope == null ? void 0 : scope.type) === "entity") {
return {
hintPrefix: `entity-${scope.index}-segment-row-hint-`,
draftHintId: `entity-${scope.index}-segment-draft-hint`,
addSelector: `button[data-action="add-entity-segment"][data-index="${scope.index}"]`
};
}
return {
hintPrefix: "segment-row-hint-",
draftHintId: "segment-draft-hint",
addSelector: 'button[data-action="add-segment"]'
};
}
_refreshSegmentUi(scope = { type: "card" }) {
var _a, _b;
this._refreshSegmentPreview(scope);
if (!this.shadowRoot) {
return;
}
const { hintPrefix, draftHintId, addSelector } = this._getSegmentDomIds(scope);
const addButton = this.shadowRoot.querySelector(addSelector);
if (addButton) {
addButton.disabled = !this._canAddSegment(scope);
}
const rows = (_a = this._getSegmentsUiRows(scope)) != null ? _a : this._getScopedSegmentsValue(scope);
rows.forEach((_, index) => {
var _a2;
const hint = this._getShadowElementById(`${hintPrefix}${index}`);
const message = this._getSegmentRowValidationMessage(scope, index);
if (hint) {
hint.textContent = message;
(_a2 = hint.setAttribute) == null ? void 0 : _a2.call(hint, "style", message ? "" : "display:none");
}
});
const draftHint = this._getShadowElementById(draftHintId);
if (draftHint) {
const message = this._getSegmentDraftValidationMessage(scope);
draftHint.textContent = message;
(_b = draftHint.setAttribute) == null ? void 0 : _b.call(draftHint, "style", message ? "" : "display:none");
}
}
_commitSegmentDraft(scope = { type: "card" }) {
var _a;
const draftSegment = this._getValidSegmentDraft(scope);
if (!draftSegment) {
this._refreshSegmentUi(scope);
return false;
}
const committedSegments = (_a = this._getSegmentsUiRows(scope)) != null ? _a : this._getScopedSegmentsValue(scope);
const nextSegments = this._sortSegmentsForEditor([...committedSegments, draftSegment]);
const applied = this._setScopedSegments(scope, nextSegments, { rerender: true });
if (applied !== false) {
this._segmentDrafts.set(this._getSegmentsScopeKey(scope), this._createSegmentDraftState(scope));
}
return applied;
}
_commitSegmentBoundaryEdit(scope = { type: "card" }, segmentIndex, field, rawValue, inputEl = null) {
var _a, _b;
this._setSegmentBoundaryText(scope, segmentIndex, field, rawValue);
const normalizedText = this._normalizeTextValue(rawValue).trim();
const parsedValue = this._parseSegmentBoundaryInput(rawValue);
const nextValue = parsedValue === null ? normalizedText : parsedValue;
const currentSegments = (_a = this._getSegmentsUiRows(scope)) != null ? _a : this._getScopedSegmentsValue(scope);
const nextSegments = currentSegments.map((segment, currentIndex) => currentIndex === segmentIndex ? { ...segment, [field]: nextValue } : segment);
this._clearSegmentBoundaryText(scope, segmentIndex, field);
const applied = this._setScopedSegments(scope, nextSegments, { rerender: true });
const message = this._getSegmentRowValidationMessage(scope, segmentIndex);
if (inputEl == null ? void 0 : inputEl.setCustomValidity) {
inputEl.setCustomValidity(message || "");
if (message) {
(_b = inputEl.reportValidity) == null ? void 0 : _b.call(inputEl);
}
}
return applied;
}
_commitGradientStopDraft(scope = { type: "card" }) {
const draftStop = this._getValidGradientDraftStop(scope);
if (!draftStop || this._hasGradientStopDuplicate(scope, draftStop.pos)) {
this._refreshGradientDraftUi(scope);
return false;
}
const committedStops = this._sanitizeGradientStopsForEmit(this._getScopedGradientStopsValue(scope));
const nextStops = [...committedStops, draftStop].sort((left, right) => left.pos - right.pos);
const applied = this._setScopedGradientStops(scope, nextStops, { rerender: true });
if (applied !== false) {
this._gradientStopsDrafts.set(this._getGradientStopsDraftKey(scope), {
pos: (() => {
const suggestion = this._getNextSuggestedGradientStopPos(scope);
return suggestion === "" ? "" : String(suggestion);
})(),
color: draftStop.color
});
}
return applied;
}
_getGradientPreviewDomIds(scope = { type: "card" }) {
if ((scope == null ? void 0 : scope.type) === "entity") {
return {
previewId: `entity-${scope.index}-gradient-preview`,
trackId: `entity-${scope.index}-gradient-preview-track`,
hintId: `entity-${scope.index}-gradient-draft-hint`,
addSelector: `button[data-action="add-entity-gradient-stop"][data-index="${scope.index}"]`,
draftInputId: `entity-${scope.index}-gradient-draft-pos`
};
}
return {
previewId: "card-gradient-preview",
trackId: "card-gradient-preview-track",
hintId: "gradient-draft-hint",
addSelector: 'button[data-action="add-gradient-stop"]',
draftInputId: "gradient-draft-pos"
};
}
_refreshGradientDraftUi(scope = { type: "card" }) {
var _a, _b, _c;
if (!this.shadowRoot) {
return;
}
const getById = (_b = (_a = this.shadowRoot.getElementById) == null ? void 0 : _a.bind(this.shadowRoot)) != null ? _b : ((id) => {
var _a2, _b2, _c2;
return (_c2 = (_b2 = (_a2 = this.shadowRoot).querySelector) == null ? void 0 : _b2.call(_a2, `#${id}`)) != null ? _c2 : null;
});
const { previewId, trackId, hintId, addSelector, draftInputId } = this._getGradientPreviewDomIds(scope);
const addButton = this.shadowRoot.querySelector(addSelector);
if (addButton) {
addButton.disabled = !this._canAddGradientStop(scope);
}
const draftInput = getById(draftInputId);
if (draftInput && typeof draftInput.closest !== "function") {
this._render();
return;
}
const draftContainer = draftInput == null ? void 0 : draftInput.closest(".gradient-stop-draft");
const nextMessage = this._getGradientDraftValidationMessage(scope);
const existingHint = getById(hintId);
if (nextMessage) {
if (existingHint) {
existingHint.textContent = nextMessage;
} else if (draftContainer) {
const hint = document.createElement("div");
hint.id = hintId;
hint.className = "section-note";
hint.textContent = nextMessage;
draftContainer.appendChild(hint);
}
} else if (existingHint) {
existingHint.remove();
}
const preview = getById(previewId);
const track = getById(trackId);
if (!preview || !track) {
return;
}
track.setAttribute("style", (_c = this._getGradientPreviewStyle(scope)) != null ? _c : "");
const markerStops = this._buildGradientPreviewEffectiveStops(scope);
const renderedStops = markerStops.length ? markerStops : this._getDefaultGradientStops();
track.innerHTML = renderedStops.map((stop, index) => `
<span
id="${previewId}-stop-${index}"
class="gradient-preview-stop"
style="left:${this._escapeAttribute(String(stop.pos))}%"
title="${this._escapeAttribute(`${stop.pos}%`)}"
></span>
`).join("");
}
_commitGradientStopPosEdit(scope = { type: "card" }, stopIndex, rawValue, inputEl = null) {
const nextPos = this._normalizeGradientStopPosValue(rawValue);
if (nextPos === null || this._hasGradientStopDuplicate(scope, nextPos, stopIndex)) {
if (inputEl == null ? void 0 : inputEl.setCustomValidity) {
inputEl.setCustomValidity(nextPos === null ? "Enter a value from 0 to 100." : "Position already exists.");
if (inputEl.reportValidity) {
inputEl.reportValidity();
}
}
return false;
}
if (inputEl == null ? void 0 : inputEl.setCustomValidity) {
inputEl.setCustomValidity("");
}
const currentStops = this._getScopedGradientStopsValue(scope);
const nextStops = currentStops.map((stop, currentStopIndex) => currentStopIndex === stopIndex ? { ...stop, pos: nextPos } : stop);
this._clearGradientStopPosText(scope, stopIndex);
return this._setScopedGradientStops(scope, nextStops, { rerender: true });
}
_getFillStyleValue() {
return this._getScopedFillStyleValue({ type: "card" });
}
_getFillStyleFromColorMode(colorMode) {
switch (colorMode) {
case "single":
return "solid";
case "gradient":
return "gradient";
case "severity":
return "bands";
case "severity_gradient":
return "band_gradient";
default:
return "bands";
}
}
_getScopedFillStyleValue(scope) {
var _a;
const fillStyle = this._getScopedValue(scope, ["bar", "fill_style"]);
if (fillStyle) return fillStyle;
const colorMode = (_a = this._getScopedValue(scope, ["bar", "color_mode"])) != null ? _a : this._getScopedValue(scope, ["color_mode"]);
return this._getFillStyleFromColorMode(colorMode);
}
_getEffectiveScopedFillStyleValue(scope) {
if ((scope == null ? void 0 : scope.type) !== "entity") {
return this._getScopedFillStyleValue(scope);
}
return this._getEffectiveFillStyleValue(scope);
}
_setScopedBarFillStyle(scope, rawValue) {
const normalizedValue = this._normalizeTextValue(rawValue).trim();
if (!normalizedValue || normalizedValue === "bands") {
return this._removeCanonicalScopedValue(scope, ["bar", "fill_style"], {
deprecatedKeys: [["color_mode"]],
prunePaths: [["bar"]]
});
}
return this._setCanonicalScopedTextOverride(scope, ["bar", "fill_style"], normalizedValue, {
deprecatedKeys: [["color_mode"]],
prunePaths: [["bar"]]
});
}
_getScopedBarColorValue(scope) {
var _a, _b;
return (_b = (_a = this._getScopedValue(scope, ["bar", "color"])) != null ? _a : this._getScopedValue(scope, ["color"])) != null ? _b : "#4a9eff";
}
_getEffectiveScopedBarColorValue(scope) {
const value = this._getEffectiveScopedDisplayValue(scope, ["bar", "color"], [["color"]]);
return value || "#4a9eff";
}
_setScopedBarColor(scope, rawValue) {
const normalizedValue = this._normalizeTextValue(rawValue).trim();
if (!normalizedValue || this._normalizeColorComparisonValue(normalizedValue) === this._normalizeColorComparisonValue("#4a9eff")) {
return this._removeCanonicalScopedValue(scope, ["bar", "color"], {
deprecatedKeys: [["color"]],
prunePaths: [["bar"]]
});
}
return this._setCanonicalScopedTextOverride(scope, ["bar", "color"], normalizedValue, {
deprecatedKeys: [["color"]],
prunePaths: [["bar"]]
});
}
_getScopedBarSolidFillValue(scope) {
return !!this._getScopedValue(scope, ["bar", "solid_fill"]);
}
_getEffectiveScopedBarSolidFillValue(scope) {
if ((scope == null ? void 0 : scope.type) !== "entity") {
return this._getScopedBarSolidFillValue(scope);
}
const localValue = this._getScopedValue(scope, ["bar", "solid_fill"]);
if (localValue !== void 0) {
return !!localValue;
}
return this._getScopedBarSolidFillValue({ type: "card" });
}
_setScopedBarSolidFill(scope, value) {
if (!value) {
return this._removeCanonicalScopedValue(scope, ["bar", "solid_fill"], {
prunePaths: [["bar"]]
});
}
return this._setCanonicalScopedValue(scope, ["bar", "solid_fill"], true, {
prunePaths: [["bar"]]
});
}
_clearEntityBarAppearance(scope) {
return this._applyScopedMutation(scope, (target) => {
let nextTarget = this._deletePathValue(target, ["bar", "fill_style"]);
nextTarget = this._deletePathValue(nextTarget, ["bar", "color"]);
nextTarget = this._deletePathValue(nextTarget, ["bar", "solid_fill"]);
nextTarget = this._deletePathValue(nextTarget, ["color_mode"]);
nextTarget = this._deletePathValue(nextTarget, ["color"]);
nextTarget = this._pruneEmptyObjectsInTarget(nextTarget, ["bar"]);
return nextTarget;
}, { rerender: true });
}
_hasEntityBarAppearanceOverride(scope) {
var _a;
const barValue = (_a = this._getScopedValue(scope, ["bar"])) != null ? _a : {};
if (this._isObject(barValue) && (Object.prototype.hasOwnProperty.call(barValue, "fill_style") || Object.prototype.hasOwnProperty.call(barValue, "color") || Object.prototype.hasOwnProperty.call(barValue, "solid_fill"))) {
return true;
}
return this._getScopedValue(scope, ["color_mode"]) !== void 0 || this._getScopedValue(scope, ["color"]) !== void 0;
}
_getScopedNeedleConfig(scope) {
var _a;
const rawNeedle = this._getScopedValue(scope, ["bar", "needle"]);
const defaultColor = "#ffffff";
let mode = (scope == null ? void 0 : scope.type) === "entity" ? "inherit" : "disabled";
let color = "";
if (typeof rawNeedle === "boolean") {
mode = rawNeedle ? "enabled" : "disabled";
} else if (this._isObject(rawNeedle)) {
if (rawNeedle.show === true) {
mode = "enabled";
} else if (rawNeedle.show === false) {
mode = "disabled";
} else if ((scope == null ? void 0 : scope.type) !== "entity") {
mode = "disabled";
}
color = (_a = rawNeedle.color) != null ? _a : "";
}
if (color === defaultColor) {
color = "";
}
return { mode, color };
}
_hasNeedleOverride(scope) {
return this._getScopedValue(scope, ["bar", "needle"]) !== void 0;
}
_getEffectiveScopedNeedleConfig(scope) {
const localNeedle = this._getScopedNeedleConfig(scope);
if ((scope == null ? void 0 : scope.type) !== "entity") {
return localNeedle;
}
if (!this._hasNeedleOverride(scope)) {
return this._getScopedNeedleConfig({ type: "card" });
}
const inheritedNeedle = this._getScopedNeedleConfig({ type: "card" });
return {
mode: localNeedle.mode === "inherit" ? inheritedNeedle.mode : localNeedle.mode,
color: localNeedle.color || inheritedNeedle.color
};
}
_setScopedNeedleMode(scope, mode) {
return this._applyScopedMutation(scope, (target) => {
let nextTarget = this._cloneDeep(target);
const existingNeedle = this._getPathValue(nextTarget, ["bar", "needle"]);
const existingColor = this._isObject(existingNeedle) ? existingNeedle.color : void 0;
nextTarget = this._deletePathValue(nextTarget, ["bar", "needle"]);
if ((scope == null ? void 0 : scope.type) === "entity" && mode === "inherit") {
nextTarget = this._pruneEmptyObjectsInTarget(nextTarget, ["bar"]);
return nextTarget;
}
if (mode === "disabled") {
if ((scope == null ? void 0 : scope.type) === "entity") {
nextTarget = this._setPathValue(nextTarget, ["bar", "needle"], { show: false });
}
nextTarget = this._pruneEmptyObjectsInTarget(nextTarget, ["bar"]);
return nextTarget;
}
const nextNeedle = { show: true };
if (existingColor && existingColor !== "#ffffff") {
nextNeedle.color = existingColor;
}
nextTarget = this._setPathValue(nextTarget, ["bar", "needle"], nextNeedle);
const baselineEnabled = this._getPathValue(nextTarget, ["baseline", "enabled"]);
const baselineParts = this._getResolvablePartsFromTarget(nextTarget != null ? nextTarget : {}, "baseline", {
canonicalBasePath: ["baseline", "at"],
legacyFixedPath: ["baseline"],
legacyEntityPath: ["baseline", "at", "entity"]
});
const baselineActive = baselineEnabled === true || baselineEnabled !== false && this._hasResolvableOverride(baselineParts);
if (baselineActive) {
nextTarget = this._deletePathValue(nextTarget, ["baseline"]);
}
nextTarget = this._pruneEmptyObjectsInTarget(nextTarget, ["bar"]);
return nextTarget;
});
}
_setScopedNeedleColor(scope, rawValue) {
const normalizedValue = this._normalizeTextValue(rawValue).trim();
return this._applyScopedMutation(scope, (target) => {
let nextTarget = this._cloneDeep(target);
const current = this._getScopedNeedleConfig(scope);
const hasCustomColor = normalizedValue && this._normalizeColorComparisonValue(normalizedValue) !== this._normalizeColorComparisonValue("#ffffff");
nextTarget = this._deletePathValue(nextTarget, ["bar", "needle", "color"]);
if ((scope == null ? void 0 : scope.type) !== "entity" && current.mode === "disabled") {
nextTarget = this._pruneEmptyObjectsInTarget(nextTarget, ["bar", "needle"]);
nextTarget = this._pruneEmptyObjectsInTarget(nextTarget, ["bar"]);
return nextTarget;
}
const showValue = current.mode === "enabled" ? true : current.mode === "disabled" ? false : void 0;
const nextNeedle = {};
if (showValue !== void 0) {
nextNeedle.show = showValue;
}
if (hasCustomColor) {
nextNeedle.color = normalizedValue;
}
if (Object.keys(nextNeedle).length) {
nextTarget = this._setPathValue(nextTarget, ["bar", "needle"], nextNeedle);
} else {
nextTarget = this._deletePathValue(nextTarget, ["bar", "needle"]);
}
nextTarget = this._pruneEmptyObjectsInTarget(nextTarget, ["bar", "needle"]);
nextTarget = this._pruneEmptyObjectsInTarget(nextTarget, ["bar"]);
return nextTarget;
});
}
_getNeedleValue() {
return this._getScopedNeedleConfig({ type: "card" }).mode === "enabled";
}
_getPeakShowValue() {
return this._getScopedPeakConfig({ type: "card" }).mode === "enabled";
}
_getScaleFixedValue(key, fallbackKey) {
return this._getResolvableScopedValue({ type: "card" }, key).fixed;
}
_getScaleEntityValue(key) {
return this._getResolvableScopedValue({ type: "card" }, key).entity;
}
_getTargetResolvableValue(scope) {
return this._getResolvableScopedValue(scope, "target", {
canonicalBasePath: ["target", "at"],
legacyFixedPath: ["target"],
legacyEntityPath: ["target_entity"]
});
}
_getEffectiveTargetResolvableValue(scope) {
return this._getEffectiveResolvableScopedValue(scope, "target", {
canonicalBasePath: ["target", "at"],
legacyFixedPath: ["target"],
legacyEntityPath: ["target_entity"]
});
}
_getTargetMode(scope) {
const enabled = this._getScopedValue(scope, ["target", "enabled"]);
if ((scope == null ? void 0 : scope.type) === "entity") {
if (enabled === false) return "disabled";
if (enabled === true || this._hasTargetOverride(scope)) return "enabled";
return "inherit";
}
if (enabled === true) return "enabled";
if (enabled === false) return "disabled";
return "auto";
}
_getEffectiveTargetMode(scope) {
const mode = this._getTargetMode(scope);
if ((scope == null ? void 0 : scope.type) !== "entity" || mode !== "inherit") {
return mode;
}
const cardMode = this._getTargetMode({ type: "card" });
if (cardMode === "disabled") return "disabled";
if (cardMode === "enabled") return "enabled";
const cardTarget = this._getTargetResolvableValue({ type: "card" });
return this._hasResolvableOverride(cardTarget) || this._hasCustomTargetColor({ type: "card" }) || this._getTargetLabelShowValue({ type: "card" }) || !!this._getTargetAboveFillColorValue({ type: "card" }) ? "enabled" : "disabled";
}
_setTargetMode(scope, mode) {
if ((scope == null ? void 0 : scope.type) === "entity" && mode === "inherit") {
return this._clearTargetOverride(scope);
}
if (mode === "auto") {
return this._removeCanonicalScopedValue(scope, ["target", "enabled"], {
prunePaths: [["target"]]
});
}
return this._setCanonicalScopedValue(scope, ["target", "enabled"], mode === "enabled", {
prunePaths: [["target"]]
});
}
_setTargetResolvablePart(scope, part, rawValue) {
return this._setCanonicalResolvablePart(scope, "target", part, rawValue, {
canonicalBasePath: ["target", "at"],
legacyFixedPath: ["target"],
legacyEntityPath: ["target_entity"],
prunePaths: [["target", "at"], ["target"]]
});
}
_clearTargetOverride(scope) {
return this._applyScopedMutation(scope, (target) => {
let nextTarget = this._cloneDeep(target);
const rawTarget = this._getPathValue(nextTarget, ["target"]);
if (this._isObject(rawTarget)) {
nextTarget = this._deletePathValue(nextTarget, ["target", "enabled"]);
nextTarget = this._deletePathValue(nextTarget, ["target", "at"]);
nextTarget = this._deletePathValue(nextTarget, ["target", "color"]);
nextTarget = this._deletePathValue(nextTarget, ["target", "label", "show"]);
nextTarget = this._deletePathValue(nextTarget, ["target", "when_exceeded", "fill_color"]);
} else {
nextTarget = this._deletePathValue(nextTarget, ["target"]);
}
nextTarget = this._deletePathValue(nextTarget, ["target_entity"]);
nextTarget = this._deletePathValue(nextTarget, ["target_color"]);
nextTarget = this._deletePathValue(nextTarget, ["show_target_label"]);
nextTarget = this._deletePathValue(nextTarget, ["above_target_color"]);
nextTarget = this._pruneEmptyObjectsInTarget(nextTarget, ["target", "label"]);
nextTarget = this._pruneEmptyObjectsInTarget(nextTarget, ["target", "when_exceeded"]);
nextTarget = this._pruneEmptyObjectsInTarget(nextTarget, ["target"]);
return nextTarget;
}, { rerender: true });
}
_getTargetColorValue(scope) {
var _a, _b;
return (_b = (_a = this._getScopedValue(scope, ["target", "color"])) != null ? _a : this._getScopedValue(scope, ["target_color"])) != null ? _b : "";
}
_getEffectiveTargetColorValue(scope) {
return this._getEffectiveScopedDisplayValue(scope, ["target", "color"], [["target_color"]]);
}
_hasCustomTargetColor(scope) {
const color = this._getTargetColorValue(scope);
return !!color && this._normalizeColorComparisonValue(color) !== this._normalizeColorComparisonValue("#888");
}
_setTargetColor(scope, rawValue) {
const normalizedValue = this._normalizeTextValue(rawValue).trim();
if (!normalizedValue || this._normalizeColorComparisonValue(normalizedValue) === this._normalizeColorComparisonValue("#888")) {
return this._removeCanonicalScopedValue(scope, ["target", "color"], {
deprecatedKeys: [["target_color"]],
prunePaths: [["target"]]
});
}
return this._setCanonicalScopedTextOverride(scope, ["target", "color"], normalizedValue, {
deprecatedKeys: [["target_color"]],
prunePaths: [["target"]]
});
}
_getTargetLabelShowValue(scope) {
const structuredValue = this._getScopedValue(scope, ["target", "label", "show"]);
if (structuredValue !== void 0) {
return !!structuredValue;
}
return !!this._getScopedValue(scope, ["show_target_label"]);
}
_getEffectiveTargetLabelShowValue(scope) {
const structuredValue = this._getScopedValue(scope, ["target", "label", "show"]);
if (structuredValue !== void 0) {
return !!structuredValue;
}
const legacyValue = this._getScopedValue(scope, ["show_target_label"]);
if (legacyValue !== void 0) {
return !!legacyValue;
}
if ((scope == null ? void 0 : scope.type) === "entity") {
return this._getTargetLabelShowValue({ type: "card" });
}
return false;
}
_setTargetLabelShow(scope, value) {
if (!value) {
return this._removeCanonicalScopedValue(scope, ["target", "label", "show"], {
deprecatedKeys: [["show_target_label"]],
prunePaths: [["target", "label"], ["target"]]
});
}
return this._setCanonicalScopedValue(scope, ["target", "label", "show"], true, {
deprecatedKeys: [["show_target_label"]],
prunePaths: [["target", "label"], ["target"]]
});
}
_getTargetAboveFillColorValue(scope) {
var _a, _b;
return (_b = (_a = this._getScopedValue(scope, ["target", "when_exceeded", "fill_color"])) != null ? _a : this._getScopedValue(scope, ["above_target_color"])) != null ? _b : "";
}
_getTargetAboveFillDraftKey(scope = { type: "card" }) {
return (scope == null ? void 0 : scope.type) === "entity" ? `entity:${scope.index}` : "card";
}
_setTargetAboveFillDraft(scope, rawValue) {
const normalizedValue = this._normalizeTextValue(rawValue).trim();
const key = this._getTargetAboveFillDraftKey(scope);
if (normalizedValue) {
this._targetAboveFillDrafts.set(key, normalizedValue);
} else {
this._targetAboveFillDrafts.delete(key);
}
}
_getTargetAboveFillDraft(scope) {
var _a;
return (_a = this._targetAboveFillDrafts.get(this._getTargetAboveFillDraftKey(scope))) != null ? _a : "";
}
_getBaselineColorDraftKey(scope = { type: "card" }, direction = "above") {
const scopeKey = (scope == null ? void 0 : scope.type) === "entity" ? `entity:${scope.index}` : "card";
return `${scopeKey}:${direction}`;
}
_setBaselineColorDraft(scope, direction, rawValue) {
const normalizedValue = this._normalizeTextValue(rawValue).trim();
const key = this._getBaselineColorDraftKey(scope, direction);
if (normalizedValue) {
this._baselineColorDrafts.set(key, normalizedValue);
} else {
this._baselineColorDrafts.delete(key);
}
}
_getBaselineColorDraft(scope, direction) {
var _a;
return (_a = this._baselineColorDrafts.get(this._getBaselineColorDraftKey(scope, direction))) != null ? _a : "";
}
_getEffectiveTargetAboveFillColorValue(scope) {
return this._getEffectiveScopedDisplayValue(scope, ["target", "when_exceeded", "fill_color"], [["above_target_color"]]);
}
_setTargetAboveFillColor(scope, rawValue) {
const normalizedValue = this._normalizeTextValue(rawValue).trim();
this._setTargetAboveFillDraft(scope, normalizedValue);
if (!this._isTargetAboveFillEnabled(scope)) {
return false;
}
if (!normalizedValue) {
return this._removeCanonicalScopedValue(scope, ["target", "when_exceeded", "fill_color"], {
deprecatedKeys: [["above_target_color"]],
prunePaths: [["target", "when_exceeded"], ["target"]]
});
}
return this._setCanonicalScopedTextOverride(scope, ["target", "when_exceeded", "fill_color"], normalizedValue, {
deprecatedKeys: [["above_target_color"]],
prunePaths: [["target", "when_exceeded"], ["target"]]
});
}
_isTargetAboveFillEnabled(scope) {
return !!this._normalizeTextValue(this._getTargetAboveFillColorValue(scope)).trim();
}
_setTargetAboveFillEnabled(scope, value) {
const currentValue = this._normalizeTextValue(this._getTargetAboveFillColorValue(scope)).trim();
if (!value) {
if (currentValue) {
this._setTargetAboveFillDraft(scope, currentValue);
}
return this._removeCanonicalScopedValue(scope, ["target", "when_exceeded", "fill_color"], {
deprecatedKeys: [["above_target_color"]],
prunePaths: [["target", "when_exceeded"], ["target"]]
});
}
const nextValue = this._getTargetAboveFillDraft(scope) || this._normalizeTextValue(this._getEffectiveTargetAboveFillColorValue(scope)).trim() || currentValue || "#000000";
return this._setCanonicalScopedTextOverride(scope, ["target", "when_exceeded", "fill_color"], nextValue, {
deprecatedKeys: [["above_target_color"]],
prunePaths: [["target", "when_exceeded"], ["target"]]
});
}
_isBaselineDirectionalColorEnabled(scope, direction) {
return !!this._normalizeTextValue(this._getBaselineDirectionalColorValue(scope, direction)).trim();
}
_setBaselineDirectionalColorEnabled(scope, direction, value) {
const currentValue = this._normalizeTextValue(this._getBaselineDirectionalColorValue(scope, direction)).trim();
if (!value) {
if (currentValue) {
this._setBaselineColorDraft(scope, direction, currentValue);
}
return this._removeCanonicalScopedValue(scope, ["baseline", direction, "color"], {
prunePaths: [["baseline", direction], ["baseline"]]
});
}
const nextValue = this._getBaselineColorDraft(scope, direction) || this._normalizeTextValue(this._getEffectiveBaselineDirectionalColorValue(scope, direction)).trim() || currentValue || "#000000";
return this._setCanonicalScopedTextOverride(scope, ["baseline", direction, "color"], nextValue, {
prunePaths: [["baseline", direction], ["baseline"]]
});
}
_hasTargetOverride(scope) {
const targetValue = this._getScopedValue(scope, ["target"]);
if (this._isObject(targetValue) && Object.keys(targetValue).length) {
return true;
}
if (!this._isObject(targetValue) && targetValue !== void 0 && targetValue !== null && targetValue !== "") {
return true;
}
return ["target_entity", "target_color", "show_target_label", "above_target_color"].some((key) => {
const value = this._getScopedValue(scope, [key]);
return value !== void 0 && value !== null && value !== "" && value !== false;
});
}
_getBaselineResolvableValue(scope) {
return this._getResolvableScopedValue(scope, "baseline", {
canonicalBasePath: ["baseline", "at"],
legacyFixedPath: ["baseline"],
legacyEntityPath: ["baseline", "at", "entity"]
});
}
_getEffectiveBaselineResolvableValue(scope) {
return this._getEffectiveResolvableScopedValue(scope, "baseline", {
canonicalBasePath: ["baseline", "at"],
legacyFixedPath: ["baseline"],
legacyEntityPath: ["baseline", "at", "entity"]
});
}
_getBaselineMode(scope) {
const enabled = this._getScopedValue(scope, ["baseline", "enabled"]);
if ((scope == null ? void 0 : scope.type) === "entity") {
if (enabled === false) return "disabled";
if (enabled === true || this._hasBaselineOverride(scope)) return "enabled";
return "inherit";
}
if (enabled === true) return "enabled";
if (enabled === false) return "disabled";
return "auto";
}
_getEffectiveBaselineMode(scope) {
const mode = this._getBaselineMode(scope);
if ((scope == null ? void 0 : scope.type) !== "entity" || mode !== "inherit") {
return mode;
}
const cardMode = this._getBaselineMode({ type: "card" });
if (cardMode === "disabled") return "disabled";
if (cardMode === "enabled") return "enabled";
const cardBaseline = this._getBaselineResolvableValue({ type: "card" });
return this._hasResolvableOverride(cardBaseline) || !!this._getBaselineDirectionalColorValue({ type: "card" }, "above") || !!this._getBaselineDirectionalColorValue({ type: "card" }, "below") ? "enabled" : "disabled";
}
_setBaselineMode(scope, mode) {
if ((scope == null ? void 0 : scope.type) === "entity" && mode === "inherit") {
return this._clearBaselineOverride(scope);
}
return this._applyScopedMutation(scope, (target) => {
let nextTarget = this._cloneDeep(target);
if (mode === "auto") {
nextTarget = this._deletePathValue(nextTarget, ["baseline", "enabled"]);
} else {
nextTarget = this._setPathValue(nextTarget, ["baseline", "enabled"], mode === "enabled");
}
nextTarget = this._pruneEmptyObjectsInTarget(nextTarget, ["baseline"]);
return nextTarget;
});
}
_setBaselineResolvablePart(scope, part, rawValue) {
const normalizedValue = part === "fixed" ? this._normalizeNumberValue(rawValue) : this._normalizeTextValue(rawValue).trim();
return this._applyScopedMutation(scope, (target) => {
const currentParts = this._getResolvablePartsFromTarget(target != null ? target : {}, "baseline", {
canonicalBasePath: ["baseline", "at"],
legacyFixedPath: ["baseline"],
legacyEntityPath: ["baseline", "at", "entity"]
});
const nextParts = { ...currentParts };
if (part === "fixed") {
if (rawValue === "" || rawValue === null || rawValue === void 0 || normalizedValue === null) {
delete nextParts.fixed;
} else {
nextParts.fixed = normalizedValue;
}
} else if (!normalizedValue) {
delete nextParts.entity;
} else {
nextParts.entity = normalizedValue;
}
let nextTarget = this._cloneDeep(target);
nextTarget = this._deletePathValue(nextTarget, ["baseline", "at"]);
const hasFixed = nextParts.fixed !== void 0 && nextParts.fixed !== null && nextParts.fixed !== "";
const hasEntity = nextParts.entity !== void 0 && nextParts.entity !== null && nextParts.entity !== "";
if (hasFixed || hasEntity) {
const nextValue = {};
if (hasFixed) nextValue.fixed = nextParts.fixed;
if (hasEntity) nextValue.entity = nextParts.entity;
nextTarget = this._setPathValue(nextTarget, ["baseline", "at"], nextValue);
}
nextTarget = this._pruneEmptyObjectsInTarget(nextTarget, ["baseline", "at"]);
nextTarget = this._pruneEmptyObjectsInTarget(nextTarget, ["baseline"]);
return nextTarget;
});
}
_removeScopedNeedle(scope) {
return this._applyScopedMutation(scope, (target) => {
let nextTarget = this._deletePathValue(target, ["bar", "needle"]);
nextTarget = this._pruneEmptyObjectsInTarget(nextTarget, ["bar"]);
return nextTarget;
});
}
_setBaselineDirectionalColor(scope, direction, rawValue) {
const normalizedValue = this._normalizeTextValue(rawValue).trim();
this._setBaselineColorDraft(scope, direction, normalizedValue);
const path = ["baseline", direction, "color"];
if (!normalizedValue) {
return this._removeCanonicalScopedValue(scope, path, {
prunePaths: [["baseline", direction], ["baseline"]]
});
}
if (!this._isBaselineDirectionalColorEnabled(scope, direction)) {
return this._setBaselineDirectionalColorEnabled(scope, direction, true);
}
return this._applyScopedMutation(scope, (target) => {
return this._setPathValue(target, path, normalizedValue);
});
}
_getBaselineDirectionalColorValue(scope, direction) {
var _a;
return (_a = this._getScopedValue(scope, ["baseline", direction, "color"])) != null ? _a : "";
}
_getEffectiveBaselineDirectionalColorValue(scope, direction) {
return this._getEffectiveScopedDisplayValue(scope, ["baseline", direction, "color"]);
}
_clearBaselineOverride(scope) {
return this._applyScopedMutation(scope, (target) => {
let nextTarget = this._cloneDeep(target);
const rawBaseline = this._getPathValue(nextTarget, ["baseline"]);
if (this._isObject(rawBaseline)) {
nextTarget = this._deletePathValue(nextTarget, ["baseline", "enabled"]);
nextTarget = this._deletePathValue(nextTarget, ["baseline", "at"]);
nextTarget = this._deletePathValue(nextTarget, ["baseline", "above", "color"]);
nextTarget = this._deletePathValue(nextTarget, ["baseline", "below", "color"]);
} else {
nextTarget = this._deletePathValue(nextTarget, ["baseline"]);
}
nextTarget = this._pruneEmptyObjectsInTarget(nextTarget, ["baseline", "above"]);
nextTarget = this._pruneEmptyObjectsInTarget(nextTarget, ["baseline", "below"]);
nextTarget = this._pruneEmptyObjectsInTarget(nextTarget, ["baseline"]);
return nextTarget;
}, { rerender: true });
}
_hasBaselineOverride(scope) {
const baselineValue = this._getScopedValue(scope, ["baseline"]);
if (this._isObject(baselineValue) && Object.keys(baselineValue).length) {
return true;
}
return !this._isObject(baselineValue) && baselineValue !== void 0 && baselineValue !== null && baselineValue !== "";
}
_isEntityOverrideExpanded(index) {
return this._expandedEntityOverrides.has(index);
}
_toggleEntityOverrideExpanded(index) {
if (this._expandedEntityOverrides.has(index)) {
this._expandedEntityOverrides.delete(index);
} else {
this._expandedEntityOverrides.add(index);
}
this._render();
}
_syncExpandedEntityOverrides(entityCount) {
const nextExpanded = /* @__PURE__ */ new Set();
this._expandedEntityOverrides.forEach((index) => {
if (index < entityCount) nextExpanded.add(index);
});
this._expandedEntityOverrides = nextExpanded;
const nextGroups = /* @__PURE__ */ new Set();
this._expandedOverrideGroups.forEach((key) => {
const [indexText, group] = String(key).split(":");
const index = Number(indexText);
if (Number.isInteger(index) && index < entityCount && group) {
nextGroups.add(`${index}:${group}`);
}
});
this._expandedOverrideGroups = nextGroups;
}
_isCardGroupExpanded(group) {
return this._expandedCardGroups.has(group);
}
_toggleCardGroupExpanded(group) {
if (this._expandedCardGroups.has(group)) {
this._expandedCardGroups.delete(group);
} else {
this._expandedCardGroups.add(group);
}
this._render();
}
_getOverrideGroupKey(index, group) {
return `${index}:${group}`;
}
_isOverrideGroupExpanded(index, group) {
return this._expandedOverrideGroups.has(this._getOverrideGroupKey(index, group));
}
_toggleOverrideGroupExpanded(index, group) {
const key = this._getOverrideGroupKey(index, group);
if (this._expandedOverrideGroups.has(key)) {
this._expandedOverrideGroups.delete(key);
} else {
this._expandedOverrideGroups.add(key);
}
this._render();
}
_hasExplicitOverrideValue(value) {
return value !== "" && value !== void 0 && value !== null;
}
_hasResolvableOverride(parts) {
return this._hasExplicitOverrideValue(parts == null ? void 0 : parts.fixed) || this._hasExplicitOverrideValue(parts == null ? void 0 : parts.entity);
}
_getScaleOverrideSummary(scope) {
const parts = [];
const min = this._getResolvableScopedValue(scope, "min");
const max = this._getResolvableScopedValue(scope, "max");
if (min.entity) parts.push("Min entity");
else if (min.fixed !== "" && min.fixed !== void 0) parts.push(`Min ${min.fixed}`);
if (max.entity) parts.push("Max entity");
else if (max.fixed !== "" && max.fixed !== void 0) parts.push(`Max ${max.fixed}`);
return parts.length ? parts.join(" \u2022 ") : "Inherited";
}
_getLayoutSummary(scope) {
const parts = [];
const height = this._getScopedLayoutValue(scope, "height");
const position = this._getScopedLayoutValue(scope, "position");
const width = this._getScopedLayoutValue(scope, "width");
if (height !== "") parts.push(`Height ${height}`);
if (position !== "") parts.push(`${position}`);
if (width !== "") parts.push(`Width ${width}`);
return parts.length ? parts.join(" \u2022 ") : "Inherited";
}
_getTargetOverrideSummary(scope) {
const mode = this._getTargetMode(scope);
if (mode === "disabled") return "Disabled";
const parts = [];
const target = this._getTargetResolvableValue(scope);
if (target.fixed !== "" && target.fixed !== void 0) parts.push(`Target ${target.fixed}`);
if (target.entity) parts.push("Entity");
if (this._hasCustomTargetColor(scope)) parts.push("Custom color");
if (this._getTargetLabelShowValue(scope)) parts.push("Label");
if (this._getTargetAboveFillColorValue(scope)) parts.push("Above");
return parts.length ? parts.join(" \u2022 ") : "Inherited";
}
_getBaselineOverrideSummary(scope) {
const mode = this._getBaselineMode(scope);
if (mode === "disabled") return "Disabled";
const parts = [];
const baseline = this._getBaselineResolvableValue(scope);
if (baseline.fixed !== "" && baseline.fixed !== void 0) parts.push(`Baseline ${baseline.fixed}`);
if (baseline.entity) parts.push("Entity");
if (this._getBaselineDirectionalColorValue(scope, "above")) parts.push("Above");
if (this._getBaselineDirectionalColorValue(scope, "below")) parts.push("Below");
return parts.length ? parts.join(" \u2022 ") : "Inherited";
}
_getBarAppearanceSummary(scope) {
var _a;
const parts = [];
const fillStyle = this._getScopedFillStyleValue(scope);
const color = (_a = this._getScopedValue(scope, ["bar", "color"])) != null ? _a : this._getScopedValue(scope, ["color"]);
if (fillStyle && fillStyle !== "bands") parts.push(fillStyle.replace(/_/g, " "));
if (color && this._normalizeColorComparisonValue(color) !== this._normalizeColorComparisonValue("#4a9eff")) {
parts.push("Custom color");
}
return parts.length ? parts.join(" \u2022 ") : "Inherited";
}
_getScopedSegmentsValue(scope) {
const uiRows = this._getSegmentsUiRows(scope);
if (uiRows !== null) {
return this._cloneDeep(uiRows);
}
const storedSegments = this._getStoredScopedSegments(scope);
if (storedSegments !== null) {
return this._sortSegmentsForEditor(storedSegments);
}
return this._sortSegmentsForEditor(this._getFallbackSegments(scope));
}
_hasSegmentsOverride(scope) {
return this._getStoredScopedSegments(scope) !== null;
}
_getSegmentsSummary(scope) {
const segments = this._getScopedSegmentsValue(scope);
if (!Array.isArray(segments) || segments.length === 0) {
return "Inherited";
}
if ((scope == null ? void 0 : scope.type) !== "entity" && !this._hasSegmentsOverride(scope) && this._isSegmentFillStyle(this._getEffectiveFillStyleValue(scope))) {
return "Default bands";
}
return `${segments.length} segments`;
}
_getEffectiveFillStyleValue(scope) {
if ((scope == null ? void 0 : scope.type) === "entity") {
const hasEntityFillStyle = this._getScopedValue(scope, ["bar", "fill_style"]) !== void 0 || this._getScopedValue(scope, ["bar", "color_mode"]) !== void 0 || this._getScopedValue(scope, ["color_mode"]) !== void 0;
if (hasEntityFillStyle) {
return this._getScopedFillStyleValue(scope);
}
return this._getFillStyleValue();
}
return this._getScopedFillStyleValue(scope);
}
_getScopedGradientStopsValue(scope) {
const localRows = this._getGradientStopsUiRows(scope);
if (Array.isArray(localRows)) {
return localRows;
}
const storedStops = this._getStoredScopedGradientStops(scope);
if (storedStops !== null) {
return this._sanitizeGradientStopsForEmit(storedStops);
}
return this._cloneDeep(this._getFallbackGradientStops(scope));
}
_hasGradientStopsOverride(scope) {
if (this._getStoredScopedGradientStops(scope) !== null) {
return true;
}
const localRows = this._getGradientStopsUiRows(scope);
if (!Array.isArray(localRows)) {
return false;
}
return this._serializeConfig(this._sanitizeGradientStopsForEmit(localRows)) !== this._serializeConfig(this._sanitizeGradientStopsForEmit(this._getFallbackGradientStops(scope)));
}
_getGradientStopsSummary(scope) {
if ((scope == null ? void 0 : scope.type) === "entity" && !this._hasGradientStopsOverride(scope)) {
return "Inherited";
}
const gradientStops = this._sanitizeGradientStopsForEmit(this._getScopedGradientStopsValue(scope));
if (this._getEffectiveFillStyleValue(scope) !== "gradient") {
return "Inactive fill style";
}
if (!gradientStops.length) {
return (scope == null ? void 0 : scope.type) === "entity" ? "Inherited" : "Default gradient";
}
if (this._isDefaultGradientStops(gradientStops)) {
return "Default gradient";
}
return `${gradientStops.length} stops`;
}
_buildGradientPreviewEffectiveStops(scope = { type: "card" }) {
const committedStops = this._sanitizeGradientStopsForEmit(this._getScopedGradientStopsValue(scope));
const draftStop = this._getValidGradientDraftStop(scope);
const previewStops = [...committedStops];
if (draftStop && !this._hasGradientStopDuplicate(scope, draftStop.pos)) {
previewStops.push(draftStop);
}
return previewStops.sort((left, right) => left.pos - right.pos);
}
_buildEditorGradientPreviewStyle(stops) {
if (!Array.isArray(stops) || !stops.length) {
return "";
}
const cssStops = stops.map((stop) => {
var _a;
const color = this._normalizeTextValue(stop.color).trim();
const pos = this._normalizeGradientStopPosValue((_a = stop.p) != null ? _a : stop.pos);
if (!color || pos === null) {
return null;
}
return `${color} ${pos}%`;
}).filter(Boolean);
if (!cssStops.length) {
return "";
}
return `background:linear-gradient(to right,${cssStops.join(",")});background-repeat:no-repeat;`;
}
_getGradientPreviewStyle(scope = { type: "card" }) {
const previewStops = this._buildGradientPreviewEffectiveStops(scope);
const resolvedStops = previewStops.length >= 2 ? previewStops.map((stop) => ({ p: stop.pos, color: stop.color })) : this._getDefaultGradientStops().map((stop) => ({ p: stop.pos, color: stop.color }));
return this._buildEditorGradientPreviewStyle(resolvedStops);
}
_renderGradientPreview(scope = { type: "card" }, options = {}) {
var _a, _b, _c;
const previewId = (_a = options.previewId) != null ? _a : "gradient-preview";
const trackId = (_b = options.trackId) != null ? _b : `${previewId}-track`;
const effectiveStops = this._buildGradientPreviewEffectiveStops(scope);
const markerStops = effectiveStops.length ? effectiveStops : this._getDefaultGradientStops();
return `
<div id="${previewId}" class="gradient-preview">
<div id="${trackId}" class="gradient-preview-track" style="${this._escapeAttribute((_c = this._getGradientPreviewStyle(scope)) != null ? _c : "")}">
${markerStops.map((stop, index) => `
<span
id="${previewId}-stop-${index}"
class="gradient-preview-stop"
style="left:${this._escapeAttribute(String(stop.pos))}%"
title="${this._escapeAttribute(`${stop.pos}%`)}"
></span>
`).join("")}
</div>
</div>
`;
}
_getNeedleSummary(scope) {
if ((scope == null ? void 0 : scope.type) === "entity" && !this._hasNeedleOverride(scope)) return "Inherited";
const needle = this._getScopedNeedleConfig(scope);
if (needle.mode === "disabled") return needle.color ? "Disabled \u2022 Custom color" : "Disabled";
if (needle.mode === "enabled") return needle.color ? "Enabled \u2022 Custom color" : "Enabled";
if (needle.color) return "Custom color";
return "Inherited";
}
_getFormattingSummary(scope) {
const parts = [];
const unit = this._getScopedFormattingValue(scope, "unit");
const decimal = this._getScopedFormattingValue(scope, "decimal");
if (unit !== "") parts.push(`Unit ${unit}`);
if (decimal !== "") parts.push(`${decimal} ${Number(decimal) === 1 ? "decimal" : "decimals"}`);
return parts.length ? parts.join(" \u2022 ") : "Inherited";
}
_renderOverrideGroup({ index, group, title, summary, content }) {
const expanded = this._isOverrideGroupExpanded(index, group);
return `
<div class="override-group" data-group="${group}" data-expanded="${expanded ? "true" : "false"}">
<button
type="button"
id="entity-${index}-group-${group}"
class="override-group-toggle"
data-action="toggle-override-group"
data-index="${index}"
data-group="${group}"
aria-expanded="${expanded ? "true" : "false"}"
>
<span
id="entity-${index}-group-${group}-title"
class="override-group-title"
data-action="toggle-override-group"
data-index="${index}"
data-group="${group}"
>${expanded ? "\u25BE" : "\u25B8"} ${title}</span>
<span
id="entity-${index}-group-${group}-summary"
class="override-group-summary"
data-action="toggle-override-group"
data-index="${index}"
data-group="${group}"
>${this._escapeAttribute(summary)}</span>
</button>
<div class="override-group-body" style="display:${expanded ? "grid" : "none"};">
${content}
</div>
</div>
`;
}
_renderCardGroup({ group, title, summary, content, inactive = false }) {
const expanded = this._isCardGroupExpanded(group);
return `
<div class="override-group card-subgroup${inactive ? " is-inactive" : ""}" data-group="${group}" data-expanded="${expanded ? "true" : "false"}">
<button
type="button"
id="card-group-${group}"
class="override-group-toggle"
data-action="toggle-card-group"
data-group="${group}"
aria-expanded="${expanded ? "true" : "false"}"
>
<span id="card-group-${group}-title" class="override-group-title">${expanded ? "\u25BE" : "\u25B8"} ${title}</span>
<span id="card-group-${group}-summary" class="override-group-summary">${this._escapeAttribute(summary)}</span>
</button>
<div class="override-group-body" style="display:${expanded ? "grid" : "none"};">
${content}
</div>
</div>
`;
}
_renderEntityInput(entry, index) {
if (customElements.get("ha-entity-picker")) {
return `<ha-entity-picker data-kind="entity-picker" data-index="${index}"></ha-entity-picker>`;
}
return `<input type="text" data-kind="entity-input" data-index="${index}" value="${this._escapeAttribute(entry.entity)}" placeholder="sensor.example" autocapitalize="none" autocomplete="off" autocorrect="off" spellcheck="false">`;
}
_renderEntitySourceInput(kind, index, value, placeholder = "sensor.example") {
if (customElements.get("ha-entity-picker")) {
return `<ha-entity-picker data-kind="${kind}" data-index="${index}"></ha-entity-picker>`;
}
return `<input type="text" data-kind="${kind}" data-index="${index}" value="${this._escapeAttribute(value)}" placeholder="${this._escapeAttribute(placeholder)}" autocapitalize="none" autocomplete="off" autocorrect="off" spellcheck="false">`;
}
_escapeAttribute(value) {
return this._normalizeTextValue(value).replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
}
_isHexColorValue(value) {
return typeof value === "string" && /^#(?:[0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/.test(value.trim());
}
_expandHexColor(value) {
if (!this._isHexColorValue(value)) {
return null;
}
const normalized = value.trim().toLowerCase();
if (normalized.length === 7) {
return normalized;
}
return `#${normalized.slice(1).split("").map((char) => char + char).join("")}`;
}
_normalizeColorComparisonValue(value) {
var _a;
const normalizedText = this._normalizeTextValue(value).trim().toLowerCase();
if (!normalizedText) {
return "";
}
return (_a = this._expandHexColor(normalizedText)) != null ? _a : normalizedText;
}
_getColorPickerValue(value, fallbackHex = "#000000") {
var _a, _b;
return (_b = (_a = this._expandHexColor(value)) != null ? _a : this._expandHexColor(fallbackHex)) != null ? _b : "#000000";
}
_renderColorInput({ id, field = null, kind = null, index = null, value = "", fallbackHex = "#000000", placeholder = "", extraDataset = {} }) {
const controlValue = this._normalizeTextValue(value).trim();
const pickerValue = this._getColorPickerValue(controlValue, fallbackHex);
const extraAttrs = Object.entries(extraDataset).map(([key, entry]) => `data-${key}="${this._escapeAttribute(entry)}"`).join(" ");
const baseAttrs = field ? `data-field="${field}"${extraAttrs ? ` ${extraAttrs}` : ""}` : `data-kind="${kind}" data-index="${index}"${extraAttrs ? ` ${extraAttrs}` : ""}`;
const fallbackAttrs = field ? `data-field="${field}-text-fallback"${extraAttrs ? ` ${extraAttrs}` : ""}` : `data-kind="${kind}-text-fallback" data-index="${index}"${extraAttrs ? ` ${extraAttrs}` : ""}`;
return `
<div class="field-grid">
<input id="${id}" type="color" ${baseAttrs} value="${this._escapeAttribute(pickerValue)}">
${controlValue && !this._isHexColorValue(controlValue) ? `<input type="text" ${fallbackAttrs} value="${this._escapeAttribute(controlValue)}" placeholder="${this._escapeAttribute(placeholder || "CSS color value")}">` : ""}
</div>
`;
}
_renderListRows(items, renderItem) {
return items.map((item, index) => renderItem(item, index)).join("");
}
_render() {
var _a;
if (!this.shadowRoot || this._isRendering) return;
this._isRendering = true;
try {
const entities = this._getEntitiesValue();
const fillStyle = this._getFillStyleValue();
const layoutLabelPosition = this._getScopedLayoutValue({ type: "card" }, "position") || "left";
const layoutHeroSize = this._getScopedLayoutValue({ type: "card" }, "hero_size") || "medium";
const layoutHeroValueSize = this._getScopedLayoutValue({ type: "card" }, "value_size");
const layoutHeight = this._getScopedLayoutValue({ type: "card" }, "height");
const layoutLabelWidth = this._getScopedLayoutValue({ type: "card" }, "width");
const barColor = this._getScopedBarColorValue({ type: "card" });
const barSolidFill = this._getScopedBarSolidFillValue({ type: "card" });
const cardNeedle = this._getScopedNeedleConfig({ type: "card" });
const gradientStops = this._getGradientStopsValue();
const gradientDraft = this._getGradientStopsDraftState({ type: "card" });
const gradientDraftMessage = this._getGradientDraftValidationMessage({ type: "card" });
const segments = this._getSegmentsValue();
const baseline = this._getBaselineResolvableValue({ type: "card" });
const baselineMode = this._getBaselineMode({ type: "card" });
const baselineAboveColor = this._getBaselineDirectionalColorValue({ type: "card" }, "above");
const baselineBelowColor = this._getBaselineDirectionalColorValue({ type: "card" }, "below");
const target = this._getTargetResolvableValue({ type: "card" });
const targetMode = this._getTargetMode({ type: "card" });
const targetColor = this._getTargetColorValue({ type: "card" });
const targetLabelShow = this._getTargetLabelShowValue({ type: "card" });
const targetAboveFillColor = this._getTargetAboveFillColorValue({ type: "card" });
const formattingUnit = this._getScopedFormattingValue({ type: "card" }, "unit");
const formattingDecimal = this._getScopedFormattingValue({ type: "card" }, "decimal");
const cardPeak = this._getScopedPeakConfig({ type: "card" });
const scaleMin = this._getScaleFixedValue("min", "min");
const scaleMax = this._getScaleFixedValue("max", "max");
const scaleMinEntity = this._getScaleEntityValue("min");
const scaleMaxEntity = this._getScaleEntityValue("max");
const gradientStopsSummary = this._getGradientStopsSummary({ type: "card" });
const gradientStopsInactive = this._getEffectiveFillStyleValue({ type: "card" }) !== "gradient";
const defaultSegmentsVisible = !this._hasSegmentsOverride({ type: "card" }) && this._isSegmentFillStyle(this._getEffectiveFillStyleValue({ type: "card" }));
this._syncExpandedEntityOverrides(entities.length);
this.shadowRoot.innerHTML = `
<style>
:host {
display: block;
}
.editor {
display: grid;
gap: 18px;
padding: 10px 0 14px;
}
.section {
display: grid;
gap: 14px;
padding: 14px;
background: color-mix(in srgb, var(--card-background-color, #fff) 88%, transparent);
border: 1px solid color-mix(in srgb, var(--divider-color, #888) 35%, transparent);
border-radius: 14px;
box-shadow: 0 1px 0 color-mix(in srgb, var(--divider-color, #888) 20%, transparent);
}
.section-head {
display: grid;
gap: 4px;
}
.section h3 {
margin: 0;
font-size: 1rem;
font-weight: 700;
letter-spacing: 0.01em;
color: var(--primary-text-color, #111);
}
.section-note {
font-size: 0.82rem;
color: var(--secondary-text-color, #666);
}
.field-grid {
display: grid;
gap: 12px;
}
.editor-grid,
.field-row {
display: grid;
gap: 8px;
min-width: 0;
}
.inline-row {
display: grid;
gap: 12px;
grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
align-items: end;
}
label {
font-size: 0.9rem;
font-weight: 500;
color: var(--primary-text-color, #111);
min-width: 0;
}
input,
select,
button {
font: inherit;
}
input[type="text"],
input[type="number"],
input[type="color"],
select {
width: 100%;
box-sizing: border-box;
min-height: 42px;
padding: 8px 10px;
color: var(--primary-text-color, #111);
background: color-mix(in srgb, var(--secondary-background-color, var(--card-background-color, #fff)) 82%, transparent);
border: 1px solid color-mix(in srgb, var(--divider-color, #888) 38%, transparent);
border-radius: 10px;
}
input[type="color"] {
padding: 4px;
cursor: pointer;
}
input[type="text"]:focus,
input[type="number"]:focus,
input[type="color"]:focus,
select:focus {
outline: 2px solid color-mix(in srgb, var(--accent-color, var(--primary-color, #03a9f4)) 55%, transparent);
outline-offset: 1px;
}
input[type="checkbox"] {
width: 18px;
height: 18px;
}
.toggle {
display: flex;
gap: 8px;
align-items: center;
flex-wrap: wrap;
}
.list {
display: grid;
gap: 10px;
min-width: 0;
}
.list-row {
display: grid;
gap: 10px;
grid-template-columns: minmax(0, 1fr) auto;
align-items: end;
min-width: 0;
}
.list-row.triple {
grid-template-columns: repeat(3, minmax(120px, 1fr)) auto;
}
.list-row.segment-row {
grid-template-columns: minmax(72px, 1fr) minmax(72px, 1fr) minmax(52px, 64px) 40px;
align-items: center;
}
.list-row.segment-row > * {
min-width: 0;
}
.list-row.segment-row > button {
width: 40px;
min-width: 40px;
padding: 6px;
justify-self: end;
}
.list-row.gradient-stop-row {
grid-template-columns: minmax(110px, 1fr) minmax(120px, 1fr) auto;
}
.gradient-stop-list {
display: grid;
gap: 10px;
min-width: 0;
}
.gradient-stop-draft {
padding-top: 10px;
border-top: 1px dashed color-mix(in srgb, var(--divider-color, #888) 34%, transparent);
}
.segment-editor-row {
display: grid;
gap: 6px;
min-width: 0;
}
.segment-draft {
display: grid;
gap: 6px;
padding-top: 10px;
border-top: 1px dashed color-mix(in srgb, var(--divider-color, #888) 34%, transparent);
}
.gradient-preview {
display: grid;
gap: 8px;
min-width: 0;
}
.gradient-preview-track {
position: relative;
width: 100%;
min-height: 28px;
min-width: 0;
border-radius: 999px;
border: 1px solid color-mix(in srgb, var(--divider-color, #888) 28%, transparent);
background: linear-gradient(to right, #4CAF50 0%, #FF9800 50%, #F44336 100%);
box-shadow: inset 0 1px 0 color-mix(in srgb, var(--card-background-color, #fff) 35%, transparent);
overflow: hidden;
}
.gradient-preview-stop {
position: absolute;
top: 3px;
bottom: 3px;
width: 2px;
margin-left: -1px;
border-radius: 999px;
background: color-mix(in srgb, var(--primary-text-color, #111) 72%, transparent);
box-shadow: 0 0 0 1px color-mix(in srgb, var(--card-background-color, #fff) 52%, transparent);
}
.entity-shell {
display: grid;
gap: 10px;
padding: 12px;
min-width: 0;
background: color-mix(in srgb, var(--secondary-background-color, var(--card-background-color, #fff)) 68%, transparent);
border: 1px solid color-mix(in srgb, var(--divider-color, #888) 30%, transparent);
border-radius: 14px;
}
.entity-main {
display: grid;
gap: 10px;
padding: 10px 12px 12px;
min-width: 0;
border-radius: 12px;
background: color-mix(in srgb, var(--card-background-color, #fff) 90%, transparent);
border: 1px solid color-mix(in srgb, var(--divider-color, #888) 22%, transparent);
}
.entity-header {
display: grid;
gap: 12px;
grid-template-columns: minmax(0, 1fr) auto;
align-items: start;
padding-bottom: 4px;
border-bottom: 1px solid color-mix(in srgb, var(--divider-color, #888) 24%, transparent);
}
.entity-header-main {
display: grid;
gap: 4px;
min-width: 0;
flex: 1 1 auto;
}
.entity-title {
font-size: 0.95rem;
font-weight: 700;
color: var(--primary-text-color, #111);
}
.entity-subtitle {
font-size: 0.8rem;
color: var(--secondary-text-color, #666);
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.entity-actions {
display: flex;
flex-wrap: wrap;
justify-content: flex-end;
align-items: center;
gap: 8px;
flex: 0 0 auto;
min-width: min(100%, 240px);
}
.entity-actions button {
min-height: 34px;
padding: 6px 10px;
flex: 0 1 auto;
}
.entity-fields {
display: grid;
gap: 10px;
min-width: 0;
}
.override-toggle {
display: inline-flex;
align-items: center;
gap: 8px;
justify-self: start;
padding: 8px 10px;
border-radius: 10px;
border: 1px solid color-mix(in srgb, var(--divider-color, #888) 28%, transparent);
background: color-mix(in srgb, var(--card-background-color, #fff) 84%, transparent);
color: var(--secondary-text-color, #666);
transition: background 120ms ease, border-color 120ms ease, color 120ms ease;
}
.override-toggle:hover,
.override-toggle:focus {
background: color-mix(in srgb, var(--secondary-background-color, var(--card-background-color, #fff)) 74%, transparent);
border-color: color-mix(in srgb, var(--accent-color, var(--primary-color, #03a9f4)) 28%, var(--divider-color, #888));
color: var(--primary-text-color, #111);
}
.override-toggle[aria-expanded="true"] {
color: var(--primary-text-color, #111);
border-color: color-mix(in srgb, var(--accent-color, var(--primary-color, #03a9f4)) 40%, transparent);
box-shadow: inset 3px 0 0 color-mix(in srgb, var(--accent-color, var(--primary-color, #03a9f4)) 70%, transparent);
}
.override-panel {
display: grid;
gap: 12px;
padding: 12px 14px;
min-width: 0;
border-radius: 12px;
border: 1px solid color-mix(in srgb, var(--divider-color, #888) 28%, transparent);
border-left: 4px solid color-mix(in srgb, var(--accent-color, var(--primary-color, #03a9f4)) 65%, transparent);
background: color-mix(in srgb, var(--secondary-background-color, var(--card-background-color, #ffffff)) 82%, transparent);
}
.override-panel::before {
content: "Overrides";
font-size: 0.78rem;
font-weight: 700;
letter-spacing: 0.04em;
text-transform: uppercase;
color: var(--secondary-text-color, #666);
}
.override-group {
display: grid;
gap: 10px;
min-width: 0;
--override-group-accent: var(--accent-color, var(--primary-color, #03a9f4));
border-radius: 12px;
border: 1px solid color-mix(in srgb, var(--divider-color, #888) 24%, transparent);
background: color-mix(in srgb, var(--card-background-color, #fff) 78%, transparent);
overflow: hidden;
}
.override-group[data-group="scale"] {
--override-group-accent: #4f8dff;
}
.override-group[data-group="target"] {
--override-group-accent: #ff9b3d;
}
.override-group[data-group="baseline"] {
--override-group-accent: #5bbd6d;
}
.override-group[data-group="bar"] {
--override-group-accent: #34c6d3;
}
.override-group[data-group="needle"] {
--override-group-accent: #9b6bff;
}
.override-group[data-group="formatting"] {
--override-group-accent: #d46be3;
}
.override-group[data-group="layout"] {
--override-group-accent: #6e90ff;
}
.override-group[data-group="peak"] {
--override-group-accent: #f08b3e;
}
.override-group[data-group="segments"] {
--override-group-accent: #d2a53a;
}
.override-group[data-group="gradient-stops"] {
--override-group-accent: #48b978;
}
.card-subgroup {
margin-top: 2px;
}
.override-group.is-inactive .override-group-summary,
.override-group.is-inactive .section-note {
color: var(--secondary-text-color, #666);
}
.override-group.is-inactive .override-group-body {
opacity: 0.92;
}
.override-group-toggle {
display: flex;
justify-content: space-between;
align-items: flex-start;
gap: 12px;
width: 100%;
text-align: left;
border: 0;
border-radius: 0;
background: transparent;
padding: 10px 12px;
min-width: 0;
}
.override-group-toggle:hover,
.override-group-toggle:focus {
background: color-mix(in srgb, var(--secondary-background-color, var(--card-background-color, #fff)) 72%, transparent);
}
.override-group[data-expanded="true"] {
border-color: color-mix(in srgb, var(--override-group-accent) 34%, transparent);
box-shadow: inset 3px 0 0 color-mix(in srgb, var(--override-group-accent) 70%, transparent);
}
.override-group-title {
font-weight: 700;
color: var(--primary-text-color, #111);
min-width: 0;
overflow-wrap: anywhere;
}
.override-group-summary {
font-size: 0.82rem;
color: var(--secondary-text-color, #666);
text-align: right;
min-width: 0;
max-width: 42%;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.override-group-body {
display: grid;
gap: 12px;
padding: 0 12px 12px;
min-width: 0;
background: color-mix(in srgb, var(--secondary-background-color, var(--card-background-color, #fff)) 78%, transparent);
}
button {
min-height: 40px;
padding: 8px 12px;
cursor: pointer;
color: var(--primary-text-color, #111);
background: color-mix(in srgb, var(--secondary-background-color, var(--card-background-color, #fff)) 78%, transparent);
border: 1px solid color-mix(in srgb, var(--divider-color, #888) 30%, transparent);
border-radius: 10px;
}
button:hover,
button:focus {
background: color-mix(in srgb, var(--secondary-background-color, var(--card-background-color, #fff)) 60%, transparent);
}
button:disabled {
cursor: not-allowed;
opacity: 0.58;
color: var(--secondary-text-color, #666);
background: color-mix(in srgb, var(--secondary-background-color, var(--card-background-color, #fff)) 86%, transparent);
border-color: color-mix(in srgb, var(--divider-color, #888) 22%, transparent);
box-shadow: none;
}
button:disabled:hover,
button:disabled:focus {
background: color-mix(in srgb, var(--secondary-background-color, var(--card-background-color, #fff)) 86%, transparent);
}
.field-row .field-grid {
gap: 8px;
grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
align-items: end;
}
.field-row .field-grid > * {
min-width: 0;
}
ha-entity-picker {
min-width: 0;
width: 100%;
}
@media (max-width: 720px) {
.section {
gap: 12px;
}
.inline-row {
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
}
.override-group-toggle {
flex-wrap: wrap;
}
.override-group-summary {
max-width: 100%;
flex: 1 1 100%;
text-align: left;
}
.entity-actions {
min-width: 0;
justify-content: flex-start;
}
.list-row.triple,
.list-row.gradient-stop-row {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.list-row.segment-row {
grid-template-columns: repeat(3, minmax(0, 1fr)) 40px;
}
.list-row.triple > button,
.list-row.gradient-stop-row > button {
grid-column: 1 / -1;
width: 100%;
}
.list-row.segment-row > button {
grid-column: auto;
width: 40px;
}
}
@media (max-width: 480px) {
.section {
padding: 12px;
}
.inline-row {
grid-template-columns: minmax(0, 1fr);
}
.entity-shell,
.entity-main,
.override-panel {
padding-left: 10px;
padding-right: 10px;
}
.entity-header {
grid-template-columns: minmax(0, 1fr);
}
.entity-actions {
width: 100%;
}
.entity-actions button {
flex: 1 1 120px;
}
.list-row {
grid-template-columns: minmax(0, 1fr);
}
.list-row.triple,
.list-row.gradient-stop-row {
grid-template-columns: minmax(0, 1fr);
}
.list-row.segment-row {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.list-row > button,
.list-row.triple > button,
.list-row.gradient-stop-row > button {
width: 100%;
}
.list-row.segment-row > button {
grid-column: 1 / -1;
width: 100%;
}
}
</style>
<div class="editor">
<div class="section">
<div class="section-head">
<h3>Basics</h3>
</div>
<div class="inline-row editor-grid">
<div class="field-row">
<label for="title">Title</label>
<input id="title" type="text" data-field="title" value="${this._escapeAttribute((_a = this._draftConfig.title) != null ? _a : "")}">
</div>
</div>
</div>
<div class="section">
<div class="section-head">
<h3>Entities</h3>
<div class="section-note">Overrides replace card defaults only for this entity.</div>
</div>
<div class="field-grid">
<div class="list">
${this._renderListRows(entities, (entry, index) => {
var _a2, _b;
return `
<div class="entity-shell" data-entity-shell-index="${index}">
<div class="entity-main">
<div class="entity-header">
<div class="entity-header-main">
<div class="entity-title">Entity ${index + 1}</div>
<div class="entity-subtitle">${this._escapeAttribute(entry.entity || "Configure entity")}</div>
</div>
<div class="entity-actions">
<button type="button" data-action="move-entity-up" data-index="${index}"${index === 0 ? " disabled" : ""} aria-label="Move entity ${index + 1} up">\u2191</button>
<button type="button" data-action="move-entity-down" data-index="${index}"${index === entities.length - 1 ? " disabled" : ""} aria-label="Move entity ${index + 1} down">\u2193</button>
<button type="button" data-action="duplicate-entity" data-index="${index}">Duplicate</button>
<button type="button" data-action="remove-entity" data-index="${index}"${entities.length <= 1 ? " disabled" : ""} aria-label="Remove" title="Remove">\u{1F5D1}</button>
</div>
</div>
<div class="entity-fields">
${this._renderEntityInput(entry, index)}
<input type="text" data-kind="entity-name" data-index="${index}" value="${this._escapeAttribute((_a2 = entry.name) != null ? _a2 : "")}" placeholder="Name">
<input type="text" data-kind="entity-icon" data-index="${index}" value="${this._escapeAttribute((_b = entry.icon) != null ? _b : "")}" placeholder="mdi:flash" autocapitalize="none" autocomplete="off" autocorrect="off" spellcheck="false">
</div>
</div>
<button type="button" class="override-toggle" data-action="toggle-entity-overrides" data-index="${index}" aria-expanded="${this._isEntityOverrideExpanded(index) ? "true" : "false"}">
${this._isEntityOverrideExpanded(index) ? "\u25BE" : "\u25B8"} Overrides
</button>
<div class="override-panel" style="display:${this._isEntityOverrideExpanded(index) ? "grid" : "none"};">
<div class="section-note">Overrides replace card defaults only for this entity.</div>
${(() => {
const scope = { type: "entity", index };
const minParts = this._getEffectiveResolvableScopedValue(scope, "min");
const maxParts = this._getEffectiveResolvableScopedValue(scope, "max");
const barAppearanceInherited = !this._hasEntityBarAppearanceOverride(scope);
const needleInherited = !this._hasNeedleOverride(scope);
const entityNeedle = this._getEffectiveScopedNeedleConfig(scope);
const baselineInherited = !this._hasBaselineOverride(scope);
const baselineParts = this._getEffectiveBaselineResolvableValue(scope);
const baselineMode2 = this._getEffectiveBaselineMode(scope);
const targetInherited = !this._hasTargetOverride(scope);
const targetParts = this._getEffectiveTargetResolvableValue(scope);
const targetMode2 = this._getEffectiveTargetMode(scope);
const formattingInherited = !this._hasFormattingOverride(scope);
const layoutInherited = !this._hasLayoutOverride(scope);
const peakInherited = !this._hasPeakOverride(scope);
const gradientStopsInherited = !this._hasGradientStopsOverride(scope);
const segmentsInherited = !this._hasSegmentsOverride(scope);
const scaleInherited = !this._hasResolvableOverride(this._getResolvableScopedValue(scope, "min")) && !this._hasResolvableOverride(this._getResolvableScopedValue(scope, "max"));
const entityPeak = this._getEffectiveScopedPeakConfig(scope);
const entityGradientStops = this._getScopedGradientStopsValue(scope);
const entityGradientDraft = this._getGradientStopsDraftState(scope);
const entityGradientDraftMessage = this._getGradientDraftValidationMessage(scope);
const entitySegments = this._getScopedSegmentsValue(scope);
const scaleGroup = this._renderOverrideGroup({
index,
group: "scale",
title: "Scale",
summary: this._getScaleOverrideSummary(scope),
content: `
<div class="field-row">
<div class="toggle">
<input id="entity-${index}-scale-inherit" type="checkbox" data-kind="entity-scale-inherit" data-index="${index}"${scaleInherited ? " checked" : ""}>
<label for="entity-${index}-scale-inherit">Inherit card settings</label>
</div>
</div>
<div class="section-note">Fixed values are used as fallback when entity values are unavailable.</div>
<div class="field-row">
<label for="entity-${index}-min">Min fallback</label>
<input id="entity-${index}-min" type="number" step="any" data-kind="entity-override-min" data-index="${index}" value="${this._escapeAttribute(minParts.fixed)}" placeholder="inherit card default">
</div>
<div class="field-row">
<label>Min entity</label>
${this._renderEntitySourceInput("entity-override-min-entity-source", index, minParts.entity, "inherit card default")}
</div>
<div class="field-row">
<label for="entity-${index}-max">Max fallback</label>
<input id="entity-${index}-max" type="number" step="any" data-kind="entity-override-max" data-index="${index}" value="${this._escapeAttribute(maxParts.fixed)}" placeholder="inherit card default">
</div>
<div class="field-row">
<label>Max entity</label>
${this._renderEntitySourceInput("entity-override-max-entity-source", index, maxParts.entity, "inherit card default")}
</div>
`
});
const layoutGroup = this._renderOverrideGroup({
index,
group: "layout",
title: "Layout",
summary: this._getLayoutSummary(scope),
content: `
<div class="field-row">
<div class="toggle">
<input id="entity-${index}-layout-inherit" type="checkbox" data-kind="entity-layout-inherit" data-index="${index}"${layoutInherited ? " checked" : ""}>
<label for="entity-${index}-layout-inherit">Inherit card settings</label>
</div>
</div>
<div class="field-row">
<label for="entity-${index}-height">Row height</label>
<input id="entity-${index}-height" type="number" min="24" step="1" data-kind="entity-override-height" data-index="${index}" value="${this._escapeAttribute(this._getEffectiveScopedLayoutValue(scope, "height"))}" placeholder="inherit card default">
</div>
<div class="field-row">
<label for="entity-${index}-label-position">Label position</label>
<select id="entity-${index}-label-position" data-kind="entity-layout-label-position" data-index="${index}" value="${this._escapeAttribute(this._getEffectiveScopedLayoutValue(scope, "position"))}">
<option value=""${this._getEffectiveScopedLayoutValue(scope, "position") === "" ? " selected" : ""}>inherit card default</option>
<option value="left"${this._getEffectiveScopedLayoutValue(scope, "position") === "left" ? " selected" : ""}>left</option>
<option value="above"${this._getEffectiveScopedLayoutValue(scope, "position") === "above" ? " selected" : ""}>above</option>
<option value="inside"${this._getEffectiveScopedLayoutValue(scope, "position") === "inside" ? " selected" : ""}>inside</option>
<option value="hero"${this._getEffectiveScopedLayoutValue(scope, "position") === "hero" ? " selected" : ""}>hero</option>
<option value="off"${this._getEffectiveScopedLayoutValue(scope, "position") === "off" ? " selected" : ""}>off</option>
</select>
</div>
${(this._getEffectiveScopedLayoutValue(scope, "position") || "") === "hero" ? `
<div class="field-row">
<label for="entity-${index}-label-hero-size">Hero size</label>
<select id="entity-${index}-label-hero-size" data-kind="entity-layout-label-hero-size" data-index="${index}" value="${this._escapeAttribute(this._getEffectiveScopedLayoutValue(scope, "hero_size") || "medium")}">
<option value="small"${(this._getEffectiveScopedLayoutValue(scope, "hero_size") || "medium") === "small" ? " selected" : ""}>small</option>
<option value="medium"${(this._getEffectiveScopedLayoutValue(scope, "hero_size") || "medium") === "medium" ? " selected" : ""}>medium</option>
<option value="large"${(this._getEffectiveScopedLayoutValue(scope, "hero_size") || "medium") === "large" ? " selected" : ""}>large</option>
</select>
</div>
<div class="field-row">
<label for="entity-${index}-hero-value-size">Maximum font size</label>
<input id="entity-${index}-hero-value-size" type="number" min="12" max="112" step="1" data-kind="entity-layout-hero-value-size" data-index="${index}" value="${this._escapeAttribute(this._getEffectiveScopedLayoutValue(scope, "value_size"))}" placeholder="use Hero size preset">
<div class="section-note">The hero value may render smaller when needed to fit. A custom value overrides the Hero size preset.</div>
</div>
` : ""}
<div class="field-row">
<label for="entity-${index}-label-width">Label width</label>
<input id="entity-${index}-label-width" type="number" step="1" data-kind="entity-layout-label-width" data-index="${index}" value="${this._escapeAttribute(this._getEffectiveScopedLayoutValue(scope, "width"))}" placeholder="inherit card default">
</div>
`
});
const barGroup = this._renderOverrideGroup({
index,
group: "bar",
title: "Bar Appearance",
summary: this._getBarAppearanceSummary(scope),
content: `
<div class="field-row">
<div class="toggle">
<input id="entity-${index}-bar-inherit" type="checkbox" data-kind="entity-bar-inherit" data-index="${index}"${barAppearanceInherited ? " checked" : ""}>
<label for="entity-${index}-bar-inherit">Inherit card settings</label>
</div>
</div>
<div class="field-row">
<label for="entity-${index}-bar-fill-style">Fill style</label>
<select id="entity-${index}-bar-fill-style" data-kind="entity-bar-fill-style" data-index="${index}" value="${this._escapeAttribute(this._getEffectiveScopedFillStyleValue(scope))}">
<option value="bands"${this._getEffectiveScopedFillStyleValue(scope) === "bands" ? " selected" : ""}>bands</option>
<option value="solid"${this._getEffectiveScopedFillStyleValue(scope) === "solid" ? " selected" : ""}>solid</option>
<option value="gradient"${this._getEffectiveScopedFillStyleValue(scope) === "gradient" ? " selected" : ""}>gradient</option>
<option value="soft_bands"${this._getEffectiveScopedFillStyleValue(scope) === "soft_bands" ? " selected" : ""}>soft_bands</option>
<option value="band_gradient"${this._getEffectiveScopedFillStyleValue(scope) === "band_gradient" ? " selected" : ""}>band_gradient</option>
</select>
</div>
<div class="field-row">
<div class="toggle">
<input id="entity-${index}-bar-solid-fill" type="checkbox" data-kind="entity-bar-solid-fill" data-index="${index}"${this._getEffectiveScopedBarSolidFillValue(scope) ? " checked" : ""}>
<label for="entity-${index}-bar-solid-fill">Solid fill</label>
</div>
</div>
<div class="field-row">
<label for="entity-${index}-bar-color">Bar color</label>
${this._renderColorInput({
id: `entity-${index}-bar-color`,
kind: "entity-bar-color",
index,
value: this._getEffectiveScopedBarColorValue(scope),
fallbackHex: "#4a9eff",
placeholder: "inherit card default"
})}
</div>
`
});
const needleGroup = this._renderOverrideGroup({
index,
group: "needle",
title: "Needle",
summary: this._getNeedleSummary(scope),
content: `
<div class="field-row">
<div class="toggle">
<input id="entity-${index}-needle-inherit" type="checkbox" data-kind="entity-needle-inherit" data-index="${index}"${needleInherited ? " checked" : ""}>
<label for="entity-${index}-needle-inherit">Inherit card settings</label>
</div>
</div>
<div class="field-row">
<label for="entity-${index}-needle-mode">Needle mode</label>
<select id="entity-${index}-needle-mode" data-kind="entity-needle-mode" data-index="${index}" value="${this._escapeAttribute(entityNeedle.mode)}">
<option value="enabled"${entityNeedle.mode === "enabled" ? " selected" : ""}>enabled</option>
<option value="disabled"${entityNeedle.mode === "disabled" ? " selected" : ""}>disabled</option>
</select>
</div>
<div class="field-row">
<label for="entity-${index}-needle-color">Needle color</label>
${this._renderColorInput({
id: `entity-${index}-needle-color`,
kind: "entity-needle-color",
index,
value: entityNeedle.color,
fallbackHex: "#ffffff",
placeholder: "#ffffff"
})}
</div>
`
});
const formattingGroup = this._renderOverrideGroup({
index,
group: "formatting",
title: "Formatting",
summary: this._getFormattingSummary(scope),
content: `
<div class="field-row">
<div class="toggle">
<input id="entity-${index}-formatting-inherit" type="checkbox" data-kind="entity-formatting-inherit" data-index="${index}"${formattingInherited ? " checked" : ""}>
<label for="entity-${index}-formatting-inherit">Inherit card settings</label>
</div>
</div>
<div class="field-row">
<label for="entity-${index}-formatting-unit">Unit</label>
<input id="entity-${index}-formatting-unit" type="text" data-kind="entity-formatting-unit" data-index="${index}" value="${this._escapeAttribute(this._getEffectiveScopedFormattingValue(scope, "unit"))}" placeholder="inherit card default">
</div>
<div class="field-row">
<label for="entity-${index}-formatting-decimal">Decimals</label>
<input id="entity-${index}-formatting-decimal" type="number" min="0" step="1" data-kind="entity-formatting-decimal" data-index="${index}" value="${this._escapeAttribute(this._getEffectiveScopedFormattingValue(scope, "decimal"))}" placeholder="inherit card default">
</div>
`
});
const peakGroup = this._renderOverrideGroup({
index,
group: "peak",
title: "Peak",
summary: this._getPeakSummary(scope),
content: `
<div class="field-row">
<div class="toggle">
<input id="entity-${index}-peak-inherit" type="checkbox" data-kind="entity-peak-inherit" data-index="${index}"${peakInherited ? " checked" : ""}>
<label for="entity-${index}-peak-inherit">Inherit card settings</label>
</div>
</div>
<div class="field-row">
<div class="toggle">
<input id="entity-${index}-peak-enabled" type="checkbox" data-kind="entity-peak-enabled" data-index="${index}"${entityPeak.mode === "enabled" ? " checked" : ""}>
<label for="entity-${index}-peak-enabled">Peak enabled</label>
</div>
</div>
<div class="field-row">
<label for="entity-${index}-peak-color">Peak color</label>
${this._renderColorInput({
id: `entity-${index}-peak-color`,
kind: "entity-peak-color",
index,
value: entityPeak.color,
fallbackHex: "#888",
placeholder: "inherit card default"
})}
</div>
`
});
const segmentsGroup = this._renderOverrideGroup({
index,
group: "segments",
title: "Segments",
summary: this._getSegmentsSummary(scope),
content: `
<div class="field-row">
<div class="toggle">
<input id="entity-${index}-segments-inherit" type="checkbox" data-kind="entity-segments-inherit" data-index="${index}"${segmentsInherited ? " checked" : ""}>
<label for="entity-${index}-segments-inherit">Inherit card settings</label>
</div>
</div>
${this._isSegmentFillStyle(this._getEffectiveFillStyleValue(scope)) ? "" : '<div class="section-note">Only used with segment-based fill styles.</div>'}
${this._renderSegmentPreview(scope)}
<div class="field-row">
<label>Segments</label>
<div class="list">
${this._renderListRows(entitySegments, (segment, segmentIndex) => {
var _a3;
return `
<div class="segment-editor-row">
<div class="list-row triple segment-row">
<input type="text" data-kind="entity-segment-from" data-index="${index}" data-segment-index="${segmentIndex}" value="${this._escapeAttribute(this._getSegmentBoundaryText(scope, segmentIndex, "from", segment == null ? void 0 : segment.from))}" placeholder="0%">
<input type="text" data-kind="entity-segment-to" data-index="${index}" data-segment-index="${segmentIndex}" value="${this._escapeAttribute(this._getSegmentBoundaryText(scope, segmentIndex, "to", segment == null ? void 0 : segment.to))}" placeholder="100%">
<input type="color" data-kind="entity-segment-color" data-index="${index}" data-segment-index="${segmentIndex}" value="${this._escapeAttribute((_a3 = segment == null ? void 0 : segment.color) != null ? _a3 : "#4a9eff")}">
<button type="button" data-action="remove-entity-segment" data-index="${index}" data-segment-index="${segmentIndex}" aria-label="Remove" title="Remove">\u{1F5D1}</button>
</div>
<div id="entity-${index}-segment-row-hint-${segmentIndex}" class="section-note"${this._getSegmentRowValidationMessage(scope, segmentIndex) ? "" : ' style="display:none"'}>${this._escapeAttribute(this._getSegmentRowValidationMessage(scope, segmentIndex))}</div>
</div>
`;
})}
<div class="segment-draft">
<div class="list-row triple segment-row">
<input id="entity-${index}-segment-draft-from" type="text" data-kind="entity-segment-draft-from" data-index="${index}" value="${this._escapeAttribute(this._getSegmentDraftState(scope).from)}" placeholder="0%">
<input id="entity-${index}-segment-draft-to" type="text" data-kind="entity-segment-draft-to" data-index="${index}" value="${this._escapeAttribute(this._getSegmentDraftState(scope).to)}" placeholder="100%">
<input type="color" data-kind="entity-segment-draft-color" data-index="${index}" value="${this._escapeAttribute(this._getSegmentDraftState(scope).color || "#4a9eff")}">
<button type="button" data-action="add-entity-segment" data-index="${index}"${this._canAddSegment(scope) ? "" : " disabled"}>Add</button>
</div>
<div id="entity-${index}-segment-draft-hint" class="section-note"${this._getSegmentDraftValidationMessage(scope) ? "" : ' style="display:none"'}>${this._escapeAttribute(this._getSegmentDraftValidationMessage(scope))}</div>
</div>
</div>
</div>
`
});
const gradientStopsGroup = this._renderOverrideGroup({
index,
group: "gradient-stops",
title: "Gradient Stops",
summary: this._getGradientStopsSummary(scope),
content: `
<div class="field-row">
<div class="toggle">
<input id="entity-${index}-gradient-stops-inherit" type="checkbox" data-kind="entity-gradient-stops-inherit" data-index="${index}"${gradientStopsInherited ? " checked" : ""}>
<label for="entity-${index}-gradient-stops-inherit">Inherit card settings</label>
</div>
</div>
${this._getEffectiveFillStyleValue(scope) !== "gradient" ? '<div class="section-note">Only used with Gradient fill style</div>' : ""}
${this._renderGradientPreview(scope, {
previewId: `entity-${index}-gradient-preview`,
trackId: `entity-${index}-gradient-preview-track`
})}
<div class="field-row">
<label>Gradient stops</label>
<div class="list gradient-stop-list">
${this._renderListRows(entityGradientStops, (stop, stopIndex) => {
var _a3, _b2;
return `
<div class="list-row gradient-stop-row">
<input type="number" min="0" max="100" step="any" data-kind="entity-gradient-pos" data-index="${index}" data-stop-index="${stopIndex}" value="${this._escapeAttribute(this._getGradientStopPosText(scope, stopIndex, (_a3 = stop == null ? void 0 : stop.pos) != null ? _a3 : ""))}" placeholder="0">
${this._renderColorInput({
id: `entity-${index}-gradient-color-${stopIndex}`,
kind: "entity-gradient-color",
index,
value: (_b2 = stop == null ? void 0 : stop.color) != null ? _b2 : "#4a9eff",
fallbackHex: "#4CAF50",
placeholder: "CSS color value",
extraDataset: { "stop-index": stopIndex }
})}
<button type="button" data-action="remove-entity-gradient-stop" data-index="${index}" data-stop-index="${stopIndex}" aria-label="Remove" title="Remove">\u{1F5D1}</button>
</div>
`;
})}
<div class="gradient-stop-draft">
<div class="list-row gradient-stop-row">
<input id="entity-${index}-gradient-draft-pos" type="number" min="0" max="100" step="any" data-kind="entity-gradient-draft-pos" data-index="${index}" value="${this._escapeAttribute(entityGradientDraft.pos)}" placeholder="0">
${this._renderColorInput({
id: `entity-${index}-gradient-draft-color`,
kind: "entity-gradient-draft-color",
index,
value: entityGradientDraft.color,
fallbackHex: "#4CAF50",
placeholder: "CSS color value"
})}
<button type="button" data-action="add-entity-gradient-stop" data-index="${index}"${this._canAddGradientStop(scope) ? "" : " disabled"}>Add</button>
</div>
${entityGradientDraftMessage ? `<div id="entity-${index}-gradient-draft-hint" class="section-note">${this._escapeAttribute(entityGradientDraftMessage)}</div>` : ""}
</div>
</div>
</div>
`
});
const baselineGroup = this._renderOverrideGroup({
index,
group: "baseline",
title: "Baseline",
summary: this._getBaselineOverrideSummary(scope),
content: `
<div class="field-row">
<div class="toggle">
<input id="entity-${index}-baseline-inherit" type="checkbox" data-kind="entity-baseline-inherit" data-index="${index}"${baselineInherited ? " checked" : ""}>
<label for="entity-${index}-baseline-inherit">Inherit card settings</label>
</div>
</div>
<div class="field-row">
<label for="entity-${index}-baseline-mode">Baseline mode</label>
<select id="entity-${index}-baseline-mode" data-kind="entity-baseline-mode" data-index="${index}" value="${this._escapeAttribute(baselineMode2)}">
<option value="enabled"${baselineMode2 === "enabled" ? " selected" : ""}>enabled</option>
<option value="disabled"${baselineMode2 === "disabled" ? " selected" : ""}>disabled</option>
</select>
</div>
<div class="field-row">
<label for="entity-${index}-baseline-value">Baseline fallback</label>
<input id="entity-${index}-baseline-value" type="number" step="any" data-kind="entity-baseline-value" data-index="${index}" value="${this._escapeAttribute(baselineParts.fixed)}" placeholder="inherit card default">
</div>
<div class="field-row">
<label>Baseline entity</label>
${this._renderEntitySourceInput("entity-baseline-entity-source", index, baselineParts.entity, "inherit card default")}
</div>
<div class="field-row">
<div class="toggle">
<input id="entity-${index}-baseline-above-color-enabled" type="checkbox" data-kind="entity-baseline-above-color-enabled" data-index="${index}"${this._isBaselineDirectionalColorEnabled(scope, "above") ? " checked" : ""}>
<label for="entity-${index}-baseline-above-color-enabled">Above-baseline color enabled</label>
</div>
</div>
<div class="field-row">
<label for="entity-${index}-baseline-above-color">Above-baseline color</label>
${this._renderColorInput({
id: `entity-${index}-baseline-above-color`,
kind: "entity-baseline-above-color",
index,
value: this._getEffectiveBaselineDirectionalColorValue(scope, "above"),
fallbackHex: "#000000",
placeholder: "inherit card default"
})}
</div>
<div class="field-row">
<div class="toggle">
<input id="entity-${index}-baseline-below-color-enabled" type="checkbox" data-kind="entity-baseline-below-color-enabled" data-index="${index}"${this._isBaselineDirectionalColorEnabled(scope, "below") ? " checked" : ""}>
<label for="entity-${index}-baseline-below-color-enabled">Below-baseline color enabled</label>
</div>
</div>
<div class="field-row">
<label for="entity-${index}-baseline-below-color">Below-baseline color</label>
${this._renderColorInput({
id: `entity-${index}-baseline-below-color`,
kind: "entity-baseline-below-color",
index,
value: this._getEffectiveBaselineDirectionalColorValue(scope, "below"),
fallbackHex: "#000000",
placeholder: "inherit card default"
})}
</div>
`
});
const targetGroup = this._renderOverrideGroup({
index,
group: "target",
title: "Target",
summary: this._getTargetOverrideSummary(scope),
content: `
<div class="field-row">
<div class="toggle">
<input id="entity-${index}-target-inherit" type="checkbox" data-kind="entity-target-inherit" data-index="${index}"${targetInherited ? " checked" : ""}>
<label for="entity-${index}-target-inherit">Inherit card settings</label>
</div>
</div>
<div class="field-row">
<label for="entity-${index}-target-mode">Target mode</label>
<select id="entity-${index}-target-mode" data-kind="entity-target-mode" data-index="${index}" value="${this._escapeAttribute(targetMode2)}">
<option value="enabled"${targetMode2 === "enabled" ? " selected" : ""}>enabled</option>
<option value="disabled"${targetMode2 === "disabled" ? " selected" : ""}>disabled</option>
</select>
</div>
<div class="field-row">
<label for="entity-${index}-target-value">Target fallback</label>
<input id="entity-${index}-target-value" type="number" step="any" data-kind="entity-target-value" data-index="${index}" value="${this._escapeAttribute(targetParts.fixed)}" placeholder="inherit card default">
</div>
<div class="field-row">
<label>Target entity</label>
${this._renderEntitySourceInput("entity-target-entity-source", index, targetParts.entity, "inherit card default")}
</div>
<div class="field-row">
<label for="entity-${index}-target-color">Target color</label>
${this._renderColorInput({
id: `entity-${index}-target-color`,
kind: "entity-target-color",
index,
value: this._getEffectiveTargetColorValue(scope),
fallbackHex: "#888",
placeholder: "inherit card default"
})}
</div>
<div class="field-row">
<div class="toggle">
<input id="entity-${index}-target-label-show" type="checkbox" data-kind="entity-target-label-show" data-index="${index}"${this._getEffectiveTargetLabelShowValue(scope) ? " checked" : ""}>
<label for="entity-${index}-target-label-show">Show target label</label>
</div>
</div>
<div class="field-row">
<div class="toggle">
<input id="entity-${index}-target-above-fill-enabled" type="checkbox" data-kind="entity-target-above-fill-enabled" data-index="${index}"${this._isTargetAboveFillEnabled(scope) ? " checked" : ""}>
<label for="entity-${index}-target-above-fill-enabled">Above-target color enabled</label>
</div>
</div>
<div class="field-row">
<label for="entity-${index}-target-above-fill">Above-target color</label>
${this._renderColorInput({
id: `entity-${index}-target-above-fill`,
kind: "entity-target-above-fill-color",
index,
value: this._getEffectiveTargetAboveFillColorValue(scope),
fallbackHex: "#000000",
placeholder: "inherit card default"
})}
</div>
`
});
return `
${scaleGroup}
${targetGroup}
${baselineGroup}
${needleGroup}
${peakGroup}
${barGroup}
${segmentsGroup}
${gradientStopsGroup}
${layoutGroup}
${formattingGroup}
`;
})()}
</div>
</div>
`;
})}
<button type="button" data-action="add-entity">Add entity</button>
</div>
</div>
</div>
<div class="section">
<div class="section-head">
<h3>Scale</h3>
<div class="section-note">Entity values take precedence. Fixed values are used as fallback.</div>
</div>
<div class="inline-row editor-grid">
<div class="field-row">
<label for="scale-min">Min fallback</label>
<input id="scale-min" type="number" step="any" data-field="scale-min" value="${this._escapeAttribute(scaleMin)}">
</div>
<div class="field-row">
<label>Min entity</label>
${this._renderEntitySourceInput("scale-min-entity-source", "card", scaleMinEntity)}
</div>
<div class="field-row">
<label for="scale-max">Max fallback</label>
<input id="scale-max" type="number" step="any" data-field="scale-max" value="${this._escapeAttribute(scaleMax)}">
</div>
<div class="field-row">
<label>Max entity</label>
${this._renderEntitySourceInput("scale-max-entity-source", "card", scaleMaxEntity)}
</div>
</div>
</div>
<div class="section">
<div class="section-head">
<h3>Markers</h3>
<div class="section-note">Target, baseline, and peak markers help compare the current value against reference points.</div>
</div>
<div class="field-grid">
<div class="field-row">
<label for="target-mode">Target mode</label>
<select id="target-mode" data-field="target-mode" value="${this._escapeAttribute(targetMode)}">
<option value="auto"${targetMode === "auto" ? " selected" : ""}>auto</option>
<option value="enabled"${targetMode === "enabled" ? " selected" : ""}>enabled</option>
<option value="disabled"${targetMode === "disabled" ? " selected" : ""}>disabled</option>
</select>
</div>
<div class="field-row">
<label for="target-value">Target fallback</label>
<input id="target-value" type="number" step="any" data-field="target-value" value="${this._escapeAttribute(target.fixed)}">
</div>
<div class="field-row">
<label>Target entity</label>
${this._renderEntitySourceInput("target-entity-source", "card", target.entity)}
</div>
<div class="field-row">
<label for="target-color">Target color</label>
${this._renderColorInput({
id: "target-color",
field: "target-color",
value: targetColor,
fallbackHex: "#888",
placeholder: "#888"
})}
</div>
<div class="field-row">
<div class="toggle">
<input id="target-label-show" type="checkbox" data-field="target-label-show"${targetLabelShow ? " checked" : ""}>
<label for="target-label-show">Show target label</label>
</div>
</div>
<div class="field-row">
<div class="toggle">
<input id="target-above-fill-enabled" type="checkbox" data-field="target-above-fill-enabled"${this._isTargetAboveFillEnabled({ type: "card" }) ? " checked" : ""}>
<label for="target-above-fill-enabled">Above-target color enabled</label>
</div>
</div>
<div class="field-row">
<label for="target-above-fill-color">Above-target color</label>
${this._renderColorInput({
id: "target-above-fill-color",
field: "target-above-fill-color",
value: targetAboveFillColor,
fallbackHex: "#000000"
})}
</div>
<div class="field-row">
<label for="baseline-mode">Baseline mode</label>
<select id="baseline-mode" data-field="baseline-mode" value="${this._escapeAttribute(baselineMode)}">
<option value="auto"${baselineMode === "auto" ? " selected" : ""}>auto</option>
<option value="enabled"${baselineMode === "enabled" ? " selected" : ""}>enabled</option>
<option value="disabled"${baselineMode === "disabled" ? " selected" : ""}>disabled</option>
</select>
</div>
<div class="field-row">
<div class="section-note">Auto shows the baseline when a baseline value is configured.</div>
</div>
<div class="field-row">
<label for="baseline-value">Baseline fallback</label>
<input id="baseline-value" type="number" step="any" data-field="baseline-value" value="${this._escapeAttribute(baseline.fixed)}">
</div>
<div class="field-row">
<label>Baseline entity</label>
${this._renderEntitySourceInput("baseline-entity-source", "card", baseline.entity)}
</div>
<div class="field-row">
<div class="toggle">
<input id="baseline-above-color-enabled" type="checkbox" data-field="baseline-above-color-enabled"${this._isBaselineDirectionalColorEnabled({ type: "card" }, "above") ? " checked" : ""}>
<label for="baseline-above-color-enabled">Above-baseline color enabled</label>
</div>
</div>
<div class="field-row">
<label for="baseline-above-color">Above-baseline color</label>
${this._renderColorInput({
id: "baseline-above-color",
field: "baseline-above-color",
value: baselineAboveColor,
fallbackHex: "#000000"
})}
</div>
<div class="field-row">
<div class="toggle">
<input id="baseline-below-color-enabled" type="checkbox" data-field="baseline-below-color-enabled"${this._isBaselineDirectionalColorEnabled({ type: "card" }, "below") ? " checked" : ""}>
<label for="baseline-below-color-enabled">Below-baseline color enabled</label>
</div>
</div>
<div class="field-row">
<label for="baseline-below-color">Below-baseline color</label>
${this._renderColorInput({
id: "baseline-below-color",
field: "baseline-below-color",
value: baselineBelowColor,
fallbackHex: "#000000"
})}
</div>
<div class="field-row">
<div class="toggle">
<input id="peak-show" type="checkbox" data-field="peak-show"${cardPeak.mode === "enabled" ? " checked" : ""}>
<label for="peak-show">Peak enabled</label>
</div>
</div>
<div class="field-row">
<label for="peak-color">Peak color</label>
${this._renderColorInput({
id: "peak-color",
field: "peak-color",
value: cardPeak.color,
fallbackHex: "#888",
placeholder: "#888"
})}
</div>
</div>
</div>
<div class="section">
<div class="section-head">
<h3>Bar Appearance</h3>
<div class="section-note">Choose the bar rendering mode and base bar colors.</div>
</div>
<div class="inline-row editor-grid">
<div class="field-row">
<label for="bar-fill-style">Fill style</label>
<select id="bar-fill-style" data-field="bar-fill-style" value="${this._escapeAttribute(fillStyle)}">
<option value="solid"${fillStyle === "solid" ? " selected" : ""}>solid</option>
<option value="gradient"${fillStyle === "gradient" ? " selected" : ""}>gradient</option>
<option value="bands"${fillStyle === "bands" ? " selected" : ""}>bands</option>
<option value="band_gradient"${fillStyle === "band_gradient" ? " selected" : ""}>band_gradient</option>
<option value="soft_bands"${fillStyle === "soft_bands" ? " selected" : ""}>soft_bands</option>
</select>
</div>
<div class="field-row">
<div class="toggle">
<input id="bar-solid-fill" type="checkbox" data-field="bar-solid-fill"${barSolidFill ? " checked" : ""}>
<label for="bar-solid-fill">Solid fill</label>
</div>
</div>
<div class="field-row">
<label for="bar-color">Bar color</label>
${this._renderColorInput({
id: "bar-color",
field: "bar-color",
value: barColor,
fallbackHex: "#4a9eff",
placeholder: "#4a9eff"
})}
</div>
<div class="field-row">
<label for="bar-needle-mode">Needle enabled</label>
<select id="bar-needle-mode" data-field="bar-needle-mode" value="${this._escapeAttribute(cardNeedle.mode)}">
<option value="disabled"${cardNeedle.mode === "disabled" ? " selected" : ""}>disabled</option>
<option value="enabled"${cardNeedle.mode === "enabled" ? " selected" : ""}>enabled</option>
</select>
</div>
<div class="field-row">
<label for="bar-needle-color">Needle color</label>
${this._renderColorInput({
id: "bar-needle-color",
field: "bar-needle-color",
value: cardNeedle.color,
fallbackHex: "#ffffff",
placeholder: "#ffffff"
})}
</div>
</div>
</div>
<div class="section">
<div class="section-head">
<h3>Segments</h3>
<div class="section-note">Segments define colored value ranges.</div>
</div>
${this._renderCardGroup({
group: "segments",
title: "Segments",
summary: this._getSegmentsSummary({ type: "card" }),
inactive: !this._isSegmentFillStyle(fillStyle),
content: `
${this._isSegmentFillStyle(fillStyle) ? "" : '<div class="section-note">Only used with segment-based fill styles.</div>'}
${this._renderSegmentPreview({ type: "card" })}
<div class="field-row">
<label>Segments</label>
<div class="list">
${defaultSegmentsVisible ? '<div class="section-note">Default bands</div>' : ""}
${this._renderListRows(segments, (segment, index) => {
var _a2;
return `
<div class="segment-editor-row">
<div class="list-row triple segment-row">
<input type="text" data-kind="segment-from" data-index="${index}" value="${this._escapeAttribute(this._getSegmentBoundaryText({ type: "card" }, index, "from", segment == null ? void 0 : segment.from))}" placeholder="0%">
<input type="text" data-kind="segment-to" data-index="${index}" value="${this._escapeAttribute(this._getSegmentBoundaryText({ type: "card" }, index, "to", segment == null ? void 0 : segment.to))}" placeholder="100%">
<input type="color" data-kind="segment-color" data-index="${index}" value="${this._escapeAttribute((_a2 = segment == null ? void 0 : segment.color) != null ? _a2 : "#4a9eff")}">
<button type="button" data-action="remove-segment" data-index="${index}" aria-label="Remove" title="Remove">\u{1F5D1}</button>
</div>
<div id="segment-row-hint-${index}" class="section-note"${this._getSegmentRowValidationMessage({ type: "card" }, index) ? "" : ' style="display:none"'}>${this._escapeAttribute(this._getSegmentRowValidationMessage({ type: "card" }, index))}</div>
</div>
`;
})}
<div class="segment-draft">
<div class="list-row triple segment-row">
<input id="segment-draft-from" type="text" data-kind="segment-draft-from" value="${this._escapeAttribute(this._getSegmentDraftState({ type: "card" }).from)}" placeholder="0%">
<input id="segment-draft-to" type="text" data-kind="segment-draft-to" value="${this._escapeAttribute(this._getSegmentDraftState({ type: "card" }).to)}" placeholder="100%">
<input type="color" data-kind="segment-draft-color" value="${this._escapeAttribute(this._getSegmentDraftState({ type: "card" }).color || "#4a9eff")}">
<button type="button" data-action="add-segment"${this._canAddSegment({ type: "card" }) ? "" : " disabled"}>Add</button>
</div>
<div id="segment-draft-hint" class="section-note"${this._getSegmentDraftValidationMessage({ type: "card" }) ? "" : ' style="display:none"'}>${this._escapeAttribute(this._getSegmentDraftValidationMessage({ type: "card" }))}</div>
</div>
</div>
</div>
`
})}
</div>
<div class="section">
<div class="section-head">
<h3>Gradient Stops</h3>
<div class="section-note">Gradient stops define a smooth color transition from 0 to 100%.</div>
</div>
${this._renderCardGroup({
group: "gradient-stops",
title: "Gradient Stops",
summary: gradientStopsSummary,
inactive: gradientStopsInactive,
content: `
${gradientStopsInactive ? '<div class="section-note">Only used with Gradient fill style</div>' : ""}
${this._renderGradientPreview({ type: "card" }, {
previewId: "card-gradient-preview",
trackId: "card-gradient-preview-track"
})}
<div class="field-row">
<label>Gradient stops</label>
<div class="list gradient-stop-list">
${this._renderListRows(gradientStops, (stop, index) => {
var _a2, _b;
return `
<div class="list-row gradient-stop-row">
<input type="number" min="0" max="100" step="any" data-kind="gradient-pos" data-index="${index}" value="${this._escapeAttribute(this._getGradientStopPosText({ type: "card" }, index, (_a2 = stop == null ? void 0 : stop.pos) != null ? _a2 : ""))}" placeholder="0">
${this._renderColorInput({
id: `gradient-color-${index}`,
kind: "gradient-color",
index,
value: (_b = stop == null ? void 0 : stop.color) != null ? _b : "#4a9eff",
fallbackHex: "#4CAF50",
placeholder: "CSS color value"
})}
<button type="button" data-action="remove-gradient-stop" data-index="${index}" aria-label="Remove" title="Remove">\u{1F5D1}</button>
</div>
`;
})}
<div class="gradient-stop-draft">
<div class="list-row gradient-stop-row">
<input id="gradient-draft-pos" type="number" min="0" max="100" step="any" data-kind="gradient-draft-pos" value="${this._escapeAttribute(gradientDraft.pos)}" placeholder="0">
${this._renderColorInput({
id: "gradient-draft-color",
kind: "gradient-draft-color",
index: "card",
value: gradientDraft.color,
fallbackHex: "#4CAF50",
placeholder: "CSS color value"
})}
<button type="button" data-action="add-gradient-stop"${this._canAddGradientStop({ type: "card" }) ? "" : " disabled"}>Add</button>
</div>
${gradientDraftMessage ? `<div id="gradient-draft-hint" class="section-note">${this._escapeAttribute(gradientDraftMessage)}</div>` : ""}
</div>
</div>
</div>
`
})}
</div>
<div class="section">
<div class="section-head">
<h3>Layout</h3>
</div>
<div class="inline-row editor-grid">
<div class="field-row">
<label for="layout-height">Row height</label>
<input id="layout-height" type="number" min="24" step="1" data-field="layout-height" value="${this._escapeAttribute(layoutHeight)}">
</div>
<div class="field-row">
<label for="layout-label-position">Label position</label>
<select id="layout-label-position" data-field="layout-label-position" value="${this._escapeAttribute(layoutLabelPosition)}">
<option value="left"${layoutLabelPosition === "left" ? " selected" : ""}>left</option>
<option value="above"${layoutLabelPosition === "above" ? " selected" : ""}>above</option>
<option value="inside"${layoutLabelPosition === "inside" ? " selected" : ""}>inside</option>
<option value="hero"${layoutLabelPosition === "hero" ? " selected" : ""}>hero</option>
<option value="off"${layoutLabelPosition === "off" ? " selected" : ""}>off</option>
</select>
</div>
${layoutLabelPosition === "hero" ? `
<div class="field-row">
<label for="layout-label-hero-size">Hero size</label>
<select id="layout-label-hero-size" data-field="layout-label-hero-size" value="${this._escapeAttribute(layoutHeroSize)}">
<option value="small"${layoutHeroSize === "small" ? " selected" : ""}>small</option>
<option value="medium"${layoutHeroSize === "medium" ? " selected" : ""}>medium</option>
<option value="large"${layoutHeroSize === "large" ? " selected" : ""}>large</option>
</select>
</div>
<div class="field-row">
<label for="layout-hero-value-size">Maximum font size</label>
<input id="layout-hero-value-size" type="number" min="12" max="112" step="1" data-field="layout-hero-value-size" value="${this._escapeAttribute(layoutHeroValueSize)}" placeholder="use Hero size preset">
<div class="section-note">The hero value may render smaller when needed to fit. A custom value overrides the Hero size preset.</div>
</div>
` : ""}
<div class="field-row">
<label for="layout-label-width">Label width</label>
<input id="layout-label-width" type="number" step="1" data-field="layout-label-width" value="${this._escapeAttribute(layoutLabelWidth)}">
</div>
</div>
</div>
<div class="section">
<div class="section-head">
<h3>Formatting</h3>
</div>
<div class="inline-row editor-grid">
<div class="field-row">
<label for="formatting-unit">Unit</label>
<input id="formatting-unit" type="text" data-field="formatting-unit" value="${this._escapeAttribute(formattingUnit)}">
</div>
<div class="field-row">
<label for="formatting-decimal">Decimals</label>
<input id="formatting-decimal" type="number" min="0" step="1" data-field="formatting-decimal" value="${this._escapeAttribute(formattingDecimal)}">
</div>
</div>
</div>
</div>
`;
this._bindShadowListeners();
this._syncEntityPickers();
this._lastRenderedConfigJson = this._serializeConfig(this._draftConfig);
this._applyPendingFocus();
} finally {
this._isRendering = false;
}
}
_bindShadowListeners() {
if (!this.shadowRoot || this._shadowListenersAttached) return;
this.shadowRoot.addEventListener("click", this._boundHandleClick);
this.shadowRoot.addEventListener("change", this._boundHandleChange);
this.shadowRoot.addEventListener("input", this._boundHandleInput);
this.shadowRoot.addEventListener("value-changed", this._boundHandleValueChanged);
this.shadowRoot.addEventListener("keydown", this._boundHandleKeydown);
this._shadowListenersAttached = true;
}
_syncEntityPickers() {
if (!this.shadowRoot) return;
const entities = this._getEntitiesValue();
const syncPicker = (picker) => {
var _a;
const kind = picker.dataset.kind;
const indexValue = picker.dataset.index;
const index = Number(indexValue);
picker.hass = this._hass;
picker.allowCustomEntity = true;
if (kind === "entity-picker") {
const entry = entities[index];
picker.value = (_a = entry == null ? void 0 : entry.entity) != null ? _a : "";
picker.label = `Entity ${index + 1}`;
return;
}
if (kind === "scale-min-entity-source") {
picker.value = this._getScaleEntityValue("min");
picker.label = "Min entity";
return;
}
if (kind === "scale-max-entity-source") {
picker.value = this._getScaleEntityValue("max");
picker.label = "Max entity";
return;
}
if (kind === "baseline-entity-source") {
picker.value = this._getBaselineResolvableValue({ type: "card" }).entity;
picker.label = "Baseline entity";
return;
}
if (kind === "target-entity-source") {
picker.value = this._getTargetResolvableValue({ type: "card" }).entity;
picker.label = "Target entity";
return;
}
if (kind === "entity-override-min-entity-source") {
picker.value = this._getEffectiveResolvableScopedValue({ type: "entity", index }, "min").entity;
picker.label = `Entity ${index + 1} min entity`;
return;
}
if (kind === "entity-override-max-entity-source") {
picker.value = this._getEffectiveResolvableScopedValue({ type: "entity", index }, "max").entity;
picker.label = `Entity ${index + 1} max entity`;
return;
}
if (kind === "entity-baseline-entity-source") {
picker.value = this._getEffectiveBaselineResolvableValue({ type: "entity", index }).entity;
picker.label = `Entity ${index + 1} baseline entity`;
return;
}
if (kind === "entity-target-entity-source") {
picker.value = this._getEffectiveTargetResolvableValue({ type: "entity", index }).entity;
picker.label = `Entity ${index + 1} target entity`;
}
};
[
'ha-entity-picker[data-kind="entity-picker"]',
'ha-entity-picker[data-kind="scale-min-entity-source"]',
'ha-entity-picker[data-kind="scale-max-entity-source"]',
'ha-entity-picker[data-kind="baseline-entity-source"]',
'ha-entity-picker[data-kind="target-entity-source"]',
'ha-entity-picker[data-kind="entity-override-min-entity-source"]',
'ha-entity-picker[data-kind="entity-override-max-entity-source"]',
'ha-entity-picker[data-kind="entity-baseline-entity-source"]',
'ha-entity-picker[data-kind="entity-target-entity-source"]'
].forEach((selector) => {
this.shadowRoot.querySelectorAll(selector).forEach(syncPicker);
});
if (customElements.whenDefined) {
customElements.whenDefined("ha-entity-picker").then(() => {
[
'ha-entity-picker[data-kind="entity-picker"]',
'ha-entity-picker[data-kind="scale-min-entity-source"]',
'ha-entity-picker[data-kind="scale-max-entity-source"]',
'ha-entity-picker[data-kind="baseline-entity-source"]',
'ha-entity-picker[data-kind="target-entity-source"]',
'ha-entity-picker[data-kind="entity-override-min-entity-source"]',
'ha-entity-picker[data-kind="entity-override-max-entity-source"]',
'ha-entity-picker[data-kind="entity-baseline-entity-source"]',
'ha-entity-picker[data-kind="entity-target-entity-source"]'
].forEach((selector) => {
var _a;
(_a = this.shadowRoot) == null ? void 0 : _a.querySelectorAll(selector).forEach(syncPicker);
});
}).catch(() => {
});
}
}
_handleClick(event) {
var _a, _b, _c, _d, _e, _f;
const target = (_c = (_b = (_a = event.target) == null ? void 0 : _a.closest) == null ? void 0 : _b.call(_a, "[data-action]")) != null ? _c : event.target;
const action = (_d = target == null ? void 0 : target.dataset) == null ? void 0 : _d.action;
if (!action) return;
if (target == null ? void 0 : target.disabled) return;
if (action === "add-entity") {
const nextEntities = [...this._getEntitiesValue(), { entity: "" }];
const nextEntries = this._buildEntityConfigEntries(nextEntities);
this._queuePostRenderFocus(`[data-kind="entity-picker"][data-index="${nextEntities.length - 1}"], [data-kind="entity-input"][data-index="${nextEntities.length - 1}"]`);
if (Array.isArray(this._draftConfig.entities) || nextEntries.length > 1 || !this._draftConfig.entity) {
let nextConfig = this._setPathValue(this._draftConfig, ["entities"], nextEntries);
if (!Array.isArray(this._draftConfig.entities) && this._draftConfig.entity !== void 0) {
nextConfig = this._deletePathValue(nextConfig, ["entity"]);
if (this._draftConfig.name !== void 0) {
nextConfig = this._deletePathValue(nextConfig, ["name"]);
}
if (this._draftConfig.icon !== void 0) {
nextConfig = this._deletePathValue(nextConfig, ["icon"]);
}
}
this._applyUserConfig(nextConfig, { rerender: true });
} else {
this._setValueAtPath(["entity"], (_f = (_e = nextEntities[0]) == null ? void 0 : _e.entity) != null ? _f : "", { rerender: true });
}
return;
}
if (action === "move-entity-up") {
this._moveEntityRow(Number(target.dataset.index), -1);
return;
}
if (action === "move-entity-down") {
this._moveEntityRow(Number(target.dataset.index), 1);
return;
}
if (action === "duplicate-entity") {
const sourceIndex = Number(target.dataset.index);
this._queuePostRenderFocus(`[data-kind="entity-name"][data-index="${sourceIndex + 1}"], [data-kind="entity-picker"][data-index="${sourceIndex + 1}"], [data-kind="entity-input"][data-index="${sourceIndex + 1}"]`);
this._duplicateEntityRow(sourceIndex);
return;
}
if (action === "toggle-entity-overrides") {
this._toggleEntityOverrideExpanded(Number(target.dataset.index));
return;
}
if (action === "toggle-override-group") {
this._toggleOverrideGroupExpanded(Number(target.dataset.index), target.dataset.group);
return;
}
if (action === "toggle-card-group") {
this._toggleCardGroupExpanded(target.dataset.group);
return;
}
if (action === "remove-entity") {
this._removeEntityRow(Number(target.dataset.index));
return;
}
if (action === "add-gradient-stop") {
this._queuePostRenderFocus("#gradient-draft-pos");
this._commitGradientStopDraft({ type: "card" });
return;
}
if (action === "remove-gradient-stop") {
const index = Number(target.dataset.index);
this._setGradientStops(this._getGradientStopsValue().filter((_, stopIndex) => stopIndex !== index), { rerender: true });
return;
}
if (action === "add-entity-gradient-stop") {
const entityIndex = Number(target.dataset.index);
this._queuePostRenderFocus(`#entity-${entityIndex}-gradient-draft-pos`);
this._commitGradientStopDraft({ type: "entity", index: entityIndex });
return;
}
if (action === "remove-entity-gradient-stop") {
const scope = { type: "entity", index: Number(target.dataset.index) };
const stopIndex = Number(target.dataset.stopIndex);
this._setScopedGradientStops(scope, this._getScopedGradientStopsValue(scope).filter((_, index) => index !== stopIndex), { rerender: true });
return;
}
if (action === "add-segment") {
this._queuePostRenderFocus("#segment-draft-from");
this._commitSegmentDraft({ type: "card" });
return;
}
if (action === "remove-segment") {
const index = Number(target.dataset.index);
this._setSegments(this._getSegmentsValue().filter((_, segmentIndex) => segmentIndex !== index), { rerender: true, sort: true });
return;
}
if (action === "add-entity-segment") {
const entityIndex = Number(target.dataset.index);
this._queuePostRenderFocus(`#entity-${entityIndex}-segment-draft-from`);
this._commitSegmentDraft({ type: "entity", index: entityIndex });
return;
}
if (action === "remove-entity-segment") {
const scope = { type: "entity", index: Number(target.dataset.index) };
const segmentIndex = Number(target.dataset.segmentIndex);
this._setScopedSegments(scope, this._getScopedSegmentsValue(scope).filter((_, index) => index !== segmentIndex), { rerender: true, sort: true });
return;
}
}
_handleChange(event) {
var _a, _b;
const kind = (_b = (_a = event.target) == null ? void 0 : _a.dataset) == null ? void 0 : _b.kind;
if (kind === "gradient-pos") {
const stopIndex = Number(event.target.dataset.index);
this._commitGradientStopPosEdit({ type: "card" }, stopIndex, event.target.value, event.target);
return;
}
if (kind === "entity-gradient-pos") {
const scope = { type: "entity", index: Number(event.target.dataset.index) };
const stopIndex = Number(event.target.dataset.stopIndex);
this._commitGradientStopPosEdit(scope, stopIndex, event.target.value, event.target);
return;
}
if (kind === "segment-from" || kind === "segment-to") {
this._commitSegmentBoundaryEdit({ type: "card" }, Number(event.target.dataset.index), kind === "segment-from" ? "from" : "to", event.target.value, event.target);
return;
}
if (kind === "entity-segment-from" || kind === "entity-segment-to") {
this._commitSegmentBoundaryEdit({ type: "entity", index: Number(event.target.dataset.index) }, Number(event.target.dataset.segmentIndex), kind === "entity-segment-from" ? "from" : "to", event.target.value, event.target);
return;
}
this._handleFieldEvent(event);
}
_handleInput(event) {
var _a;
const target = event.target;
if (!target) return;
if (target.tagName === "HA-ENTITY-PICKER") return;
if (target.tagName === "INPUT" && target.type === "checkbox") return;
const kind = (_a = target.dataset) == null ? void 0 : _a.kind;
if (kind === "gradient-pos") {
this._setGradientStopPosText({ type: "card" }, Number(target.dataset.index), target.value);
return;
}
if (kind === "entity-gradient-pos") {
this._setGradientStopPosText({ type: "entity", index: Number(target.dataset.index) }, Number(target.dataset.stopIndex), target.value);
return;
}
if (kind === "segment-from" || kind === "segment-to") {
this._setSegmentBoundaryText({ type: "card" }, Number(target.dataset.index), kind === "segment-from" ? "from" : "to", target.value);
this._refreshSegmentUi({ type: "card" });
return;
}
if (kind === "entity-segment-from" || kind === "entity-segment-to") {
const scope = { type: "entity", index: Number(target.dataset.index) };
this._setSegmentBoundaryText(scope, Number(target.dataset.segmentIndex), kind === "entity-segment-from" ? "from" : "to", target.value);
this._refreshSegmentUi(scope);
return;
}
this._handleFieldEvent(event);
}
_handleValueChanged(event) {
var _a;
if (((_a = event.target) == null ? void 0 : _a.tagName) === "HA-ENTITY-PICKER") {
this._handleFieldEvent(event);
}
}
_handleKeydown(event) {
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p;
const kind = (_b = (_a = event.target) == null ? void 0 : _a.dataset) == null ? void 0 : _b.kind;
if (event.key === "Escape") {
if (kind === "gradient-draft-pos" || kind === "gradient-draft-color") {
(_c = event.preventDefault) == null ? void 0 : _c.call(event);
this._gradientStopsDrafts.set(this._getGradientStopsDraftKey({ type: "card" }), this._createGradientStopDraftState({ type: "card" }));
this._render();
return;
}
if (kind === "entity-gradient-draft-pos" || kind === "entity-gradient-draft-color") {
(_d = event.preventDefault) == null ? void 0 : _d.call(event);
const scope = { type: "entity", index: Number(event.target.dataset.index) };
this._gradientStopsDrafts.set(this._getGradientStopsDraftKey(scope), this._createGradientStopDraftState(scope));
this._render();
}
if (kind === "segment-draft-from" || kind === "segment-draft-to" || kind === "segment-draft-color") {
(_e = event.preventDefault) == null ? void 0 : _e.call(event);
this._segmentDrafts.set(this._getSegmentsScopeKey({ type: "card" }), this._createSegmentDraftState({ type: "card" }));
this._render();
return;
}
if (kind === "entity-segment-draft-from" || kind === "entity-segment-draft-to" || kind === "entity-segment-draft-color") {
(_f = event.preventDefault) == null ? void 0 : _f.call(event);
const scope = { type: "entity", index: Number(event.target.dataset.index) };
this._segmentDrafts.set(this._getSegmentsScopeKey(scope), this._createSegmentDraftState(scope));
this._render();
return;
}
return;
}
if (event.key !== "Enter") {
return;
}
if (kind === "gradient-pos") {
(_g = event.preventDefault) == null ? void 0 : _g.call(event);
const stopIndex = Number(event.target.dataset.index);
this._commitGradientStopPosEdit({ type: "card" }, stopIndex, event.target.value, event.target);
return;
}
if (kind === "entity-gradient-pos") {
(_h = event.preventDefault) == null ? void 0 : _h.call(event);
const scope = { type: "entity", index: Number(event.target.dataset.index) };
const stopIndex = Number(event.target.dataset.stopIndex);
this._commitGradientStopPosEdit(scope, stopIndex, event.target.value, event.target);
return;
}
if (kind === "gradient-draft-pos") {
(_i = event.preventDefault) == null ? void 0 : _i.call(event);
this._commitGradientStopDraft({ type: "card" });
return;
}
if (kind === "gradient-draft-color") {
(_j = event.preventDefault) == null ? void 0 : _j.call(event);
this._commitGradientStopDraft({ type: "card" });
return;
}
if (kind === "entity-gradient-draft-pos") {
(_k = event.preventDefault) == null ? void 0 : _k.call(event);
this._commitGradientStopDraft({ type: "entity", index: Number(event.target.dataset.index) });
return;
}
if (kind === "entity-gradient-draft-color") {
(_l = event.preventDefault) == null ? void 0 : _l.call(event);
this._commitGradientStopDraft({ type: "entity", index: Number(event.target.dataset.index) });
return;
}
if (kind === "segment-from" || kind === "segment-to") {
(_m = event.preventDefault) == null ? void 0 : _m.call(event);
this._commitSegmentBoundaryEdit({ type: "card" }, Number(event.target.dataset.index), kind === "segment-from" ? "from" : "to", event.target.value, event.target);
return;
}
if (kind === "entity-segment-from" || kind === "entity-segment-to") {
(_n = event.preventDefault) == null ? void 0 : _n.call(event);
this._commitSegmentBoundaryEdit({ type: "entity", index: Number(event.target.dataset.index) }, Number(event.target.dataset.segmentIndex), kind === "entity-segment-from" ? "from" : "to", event.target.value, event.target);
return;
}
if (kind === "segment-draft-from" || kind === "segment-draft-to" || kind === "segment-draft-color") {
(_o = event.preventDefault) == null ? void 0 : _o.call(event);
this._commitSegmentDraft({ type: "card" });
return;
}
if (kind === "entity-segment-draft-from" || kind === "entity-segment-draft-to" || kind === "entity-segment-draft-color") {
(_p = event.preventDefault) == null ? void 0 : _p.call(event);
this._commitSegmentDraft({ type: "entity", index: Number(event.target.dataset.index) });
}
}
_handleFieldEvent(event) {
var _a, _b, _c, _d, _e, _f, _g;
const target = event.target;
const rawField = (_a = target == null ? void 0 : target.dataset) == null ? void 0 : _a.field;
const rawKind = (_b = target == null ? void 0 : target.dataset) == null ? void 0 : _b.kind;
const field = (rawField == null ? void 0 : rawField.endsWith("-text-fallback")) ? rawField.slice(0, -14) : rawField;
const kind = (rawKind == null ? void 0 : rawKind.endsWith("-text-fallback")) ? rawKind.slice(0, -14) : rawKind;
const detailValue = (_c = event.detail) == null ? void 0 : _c.value;
const value = detailValue != null ? detailValue : (target == null ? void 0 : target.type) === "checkbox" ? target.checked : target == null ? void 0 : target.value;
if (field === "title") return void this._setTitle(value);
if (field === "formatting-unit") return void this._setScopedFormattingUnit({ type: "card" }, value);
if (field === "formatting-decimal") return void this._setScopedFormattingDecimal({ type: "card" }, value);
if (field === "layout-label-position") return void this._setLayoutLabelPosition(value);
if (field === "layout-label-hero-size") return void this._setLayoutHeroSize(value);
if (field === "layout-hero-value-size") return void this._setLayoutHeroValueSize(value);
if (field === "layout-height") return void this._setLayoutHeight(value);
if (field === "layout-label-width") return void this._setScopedLayoutLabelWidth({ type: "card" }, value);
if (field === "scale-min") return void this._setScaleBound("min", value);
if (field === "scale-max") return void this._setScaleBound("max", value);
if (field === "bar-fill-style") return void this._setBarFillStyle(value);
if (field === "bar-color") return void this._setBarColor(value);
if (field === "bar-solid-fill") return void this._setScopedBarSolidFill({ type: "card" }, value);
if (field === "bar-needle-mode") return void this._setScopedNeedleMode({ type: "card" }, value);
if (field === "bar-needle-color") return void this._setScopedNeedleColor({ type: "card" }, value);
if (field === "baseline-mode") return void this._setBaselineMode({ type: "card" }, value);
if (field === "baseline-value") {
return void this._setBaselineResolvablePart({ type: "card" }, "fixed", value);
}
if (field === "baseline-above-color") return void this._setBaselineDirectionalColor({ type: "card" }, "above", value);
if (field === "baseline-below-color") return void this._setBaselineDirectionalColor({ type: "card" }, "below", value);
if (field === "baseline-above-color-enabled") return void this._setBaselineDirectionalColorEnabled({ type: "card" }, "above", value);
if (field === "baseline-below-color-enabled") return void this._setBaselineDirectionalColorEnabled({ type: "card" }, "below", value);
if (field === "target-mode") return void this._setTargetMode({ type: "card" }, value);
if (field === "target-value") {
return void this._setTargetResolvablePart({ type: "card" }, "fixed", value);
}
if (field === "target-color") return void this._setTargetColor({ type: "card" }, value);
if (field === "target-label-show") return void this._setTargetLabelShow({ type: "card" }, value);
if (field === "target-above-fill-enabled") return void this._setTargetAboveFillEnabled({ type: "card" }, value);
if (field === "target-above-fill-color") return void this._setTargetAboveFillColor({ type: "card" }, value);
if (field === "peak-show") return void this._setPeakShow(value);
if (field === "peak-color") return void this._setScopedPeakColor({ type: "card" }, value);
if (kind === "entity-picker" || kind === "entity-input") {
const index = Number(target.dataset.index);
const nextEntities = this._getEntitiesValue().map((entry, entryIndex) => entryIndex === index ? { ...entry, entity: this._normalizeTextValue(value) } : entry);
const nextEntries = this._buildEntityConfigEntries(nextEntities);
if (Array.isArray(this._draftConfig.entities) || nextEntries.length > 1 || !this._draftConfig.entity) {
this._setValueAtPath(["entities"], nextEntries);
} else {
this._setValueAtPath(["entity"], (_e = (_d = nextEntities[0]) == null ? void 0 : _d.entity) != null ? _e : "");
}
return;
}
if (kind === "entity-name") {
return void this._setEntityField(Number(target.dataset.index), "name", value);
}
if (kind === "entity-icon") {
return void this._setEntityField(Number(target.dataset.index), "icon", value);
}
if (kind === "scale-min-entity-source") {
return void this._setCanonicalResolvablePart({ type: "card" }, "min", "entity", value);
}
if (kind === "scale-max-entity-source") {
return void this._setCanonicalResolvablePart({ type: "card" }, "max", "entity", value);
}
if (kind === "baseline-entity-source") {
return void this._setBaselineResolvablePart({ type: "card" }, "entity", value);
}
if (kind === "target-entity-source") {
return void this._setTargetResolvablePart({ type: "card" }, "entity", value);
}
if (kind === "entity-scale-inherit") {
if (value) {
return void this._clearScaleOverride({ type: "entity", index: Number(target.dataset.index) });
}
return;
}
if (kind === "entity-override-min") {
return void this._setCanonicalResolvablePart({ type: "entity", index: Number(target.dataset.index) }, "min", "fixed", value);
}
if (kind === "entity-override-max") {
return void this._setCanonicalResolvablePart({ type: "entity", index: Number(target.dataset.index) }, "max", "fixed", value);
}
if (kind === "entity-override-min-entity-source") {
return void this._setCanonicalResolvablePart({ type: "entity", index: Number(target.dataset.index) }, "min", "entity", value);
}
if (kind === "entity-override-max-entity-source") {
return void this._setCanonicalResolvablePart({ type: "entity", index: Number(target.dataset.index) }, "max", "entity", value);
}
if (kind === "entity-override-height") {
return void this._setScopedLayoutHeight({ type: "entity", index: Number(target.dataset.index) }, value);
}
if (kind === "entity-layout-inherit") {
if (value) {
return void this._clearLayoutOverride({ type: "entity", index: Number(target.dataset.index) });
}
return;
}
if (kind === "entity-layout-label-position") {
return void this._setScopedLayoutLabelPosition({ type: "entity", index: Number(target.dataset.index) }, value);
}
if (kind === "entity-layout-label-hero-size") {
return void this._setScopedLayoutHeroSize({ type: "entity", index: Number(target.dataset.index) }, value);
}
if (kind === "entity-layout-hero-value-size") {
return void this._setScopedLayoutHeroValueSize({ type: "entity", index: Number(target.dataset.index) }, value);
}
if (kind === "entity-layout-label-width") {
return void this._setScopedLayoutLabelWidth({ type: "entity", index: Number(target.dataset.index) }, value);
}
if (kind === "entity-formatting-inherit") {
if (value) {
return void this._clearFormattingOverride({ type: "entity", index: Number(target.dataset.index) });
}
return;
}
if (kind === "entity-formatting-unit") {
return void this._setScopedFormattingUnit({ type: "entity", index: Number(target.dataset.index) }, value);
}
if (kind === "entity-formatting-decimal") {
return void this._setScopedFormattingDecimal({ type: "entity", index: Number(target.dataset.index) }, value);
}
if (kind === "entity-peak-inherit") {
if (value) {
return void this._clearPeakOverride({ type: "entity", index: Number(target.dataset.index) });
}
return;
}
if (kind === "entity-peak-enabled") {
return void this._setScopedPeakEnabled({ type: "entity", index: Number(target.dataset.index) }, value);
}
if (kind === "entity-peak-color") {
return void this._setScopedPeakColor({ type: "entity", index: Number(target.dataset.index) }, value);
}
if (kind === "entity-segments-inherit") {
if (value) {
return void this._clearSegmentsOverride({ type: "entity", index: Number(target.dataset.index) });
}
return;
}
if (kind === "entity-gradient-stops-inherit") {
if (value) {
return void this._clearGradientStopsOverride({ type: "entity", index: Number(target.dataset.index) });
}
return;
}
if (kind === "entity-bar-inherit") {
if (value) {
return void this._clearEntityBarAppearance({ type: "entity", index: Number(target.dataset.index) });
}
return;
}
if (kind === "entity-needle-inherit") {
if (value) {
return void this._removeScopedNeedle({ type: "entity", index: Number(target.dataset.index) });
}
return;
}
if (kind === "entity-bar-fill-style") {
return void this._setScopedBarFillStyle({ type: "entity", index: Number(target.dataset.index) }, value);
}
if (kind === "entity-bar-color") {
return void this._setScopedBarColor({ type: "entity", index: Number(target.dataset.index) }, value);
}
if (kind === "entity-bar-solid-fill") {
return void this._setScopedBarSolidFill({ type: "entity", index: Number(target.dataset.index) }, value);
}
if (kind === "entity-needle-mode") {
return void this._setScopedNeedleMode({ type: "entity", index: Number(target.dataset.index) }, value);
}
if (kind === "entity-needle-color") {
return void this._setScopedNeedleColor({ type: "entity", index: Number(target.dataset.index) }, value);
}
if (kind === "entity-baseline-mode") {
return void this._setBaselineMode({ type: "entity", index: Number(target.dataset.index) }, value);
}
if (kind === "entity-baseline-inherit") {
if (value) {
return void this._clearBaselineOverride({ type: "entity", index: Number(target.dataset.index) });
}
return;
}
if (kind === "entity-baseline-value") {
return void this._setBaselineResolvablePart({ type: "entity", index: Number(target.dataset.index) }, "fixed", value);
}
if (kind === "entity-baseline-entity-source") {
return void this._setBaselineResolvablePart({ type: "entity", index: Number(target.dataset.index) }, "entity", value);
}
if (kind === "entity-baseline-above-color") {
return void this._setBaselineDirectionalColor({ type: "entity", index: Number(target.dataset.index) }, "above", value);
}
if (kind === "entity-baseline-below-color") {
return void this._setBaselineDirectionalColor({ type: "entity", index: Number(target.dataset.index) }, "below", value);
}
if (kind === "entity-baseline-above-color-enabled") {
return void this._setBaselineDirectionalColorEnabled({ type: "entity", index: Number(target.dataset.index) }, "above", value);
}
if (kind === "entity-baseline-below-color-enabled") {
return void this._setBaselineDirectionalColorEnabled({ type: "entity", index: Number(target.dataset.index) }, "below", value);
}
if (kind === "entity-target-mode") {
return void this._setTargetMode({ type: "entity", index: Number(target.dataset.index) }, value);
}
if (kind === "entity-target-inherit") {
if (value) {
return void this._clearTargetOverride({ type: "entity", index: Number(target.dataset.index) });
}
return;
}
if (kind === "entity-target-value") {
return void this._setTargetResolvablePart({ type: "entity", index: Number(target.dataset.index) }, "fixed", value);
}
if (kind === "entity-target-entity-source") {
return void this._setTargetResolvablePart({ type: "entity", index: Number(target.dataset.index) }, "entity", value);
}
if (kind === "entity-target-color") {
return void this._setTargetColor({ type: "entity", index: Number(target.dataset.index) }, value);
}
if (kind === "entity-target-label-show") {
return void this._setTargetLabelShow({ type: "entity", index: Number(target.dataset.index) }, value);
}
if (kind === "entity-target-above-fill-enabled") {
return void this._setTargetAboveFillEnabled({ type: "entity", index: Number(target.dataset.index) }, value);
}
if (kind === "entity-target-above-fill-color") {
return void this._setTargetAboveFillColor({ type: "entity", index: Number(target.dataset.index) }, value);
}
if (kind === "gradient-draft-pos") {
this._setGradientStopsDraftField({ type: "card" }, "pos", value);
return;
}
if (kind === "gradient-draft-color") {
this._setGradientStopsDraftField({ type: "card" }, "color", value);
return;
}
if (kind === "entity-gradient-draft-pos") {
this._setGradientStopsDraftField({ type: "entity", index: Number(target.dataset.index) }, "pos", value);
return;
}
if (kind === "entity-gradient-draft-color") {
this._setGradientStopsDraftField({ type: "entity", index: Number(target.dataset.index) }, "color", value);
return;
}
if (kind === "segment-draft-from") {
this._setSegmentDraftField({ type: "card" }, "from", value);
return;
}
if (kind === "segment-draft-to") {
this._setSegmentDraftField({ type: "card" }, "to", value);
return;
}
if (kind === "segment-draft-color") {
this._setSegmentDraftField({ type: "card" }, "color", value);
return;
}
if (kind === "entity-segment-draft-from") {
this._setSegmentDraftField({ type: "entity", index: Number(target.dataset.index) }, "from", value);
return;
}
if (kind === "entity-segment-draft-to") {
this._setSegmentDraftField({ type: "entity", index: Number(target.dataset.index) }, "to", value);
return;
}
if (kind === "entity-segment-draft-color") {
this._setSegmentDraftField({ type: "entity", index: Number(target.dataset.index) }, "color", value);
return;
}
if (kind == null ? void 0 : kind.startsWith("gradient-")) {
const index = Number(target.dataset.index);
const currentStops = this._sanitizeGradientStopsForEmit(this._getGradientStopsValue());
const nextStops = this._getGradientStopsValue().map((stop, stopIndex) => {
var _a2;
if (stopIndex !== index) return stop;
const nextPos = this._normalizeGradientStopPosValue(stop == null ? void 0 : stop.pos);
return {
...stop,
pos: nextPos != null ? nextPos : 0,
color: kind === "gradient-color" ? value : (_a2 = stop == null ? void 0 : stop.color) != null ? _a2 : "#4a9eff"
};
});
if (this._serializeConfig(nextStops) !== this._serializeConfig(currentStops)) {
this._setGradientStops(nextStops);
}
return;
}
if (kind == null ? void 0 : kind.startsWith("entity-gradient-")) {
const scope = { type: "entity", index: Number(target.dataset.index) };
const stopIndex = Number(target.dataset.stopIndex);
const currentStops = this._sanitizeGradientStopsForEmit(this._getScopedGradientStopsValue(scope));
const nextStops = this._getScopedGradientStopsValue(scope).map((stop, currentStopIndex) => {
var _a2;
if (currentStopIndex !== stopIndex) return stop;
const nextPos = this._normalizeGradientStopPosValue(stop == null ? void 0 : stop.pos);
return {
...stop,
pos: nextPos != null ? nextPos : 0,
color: kind === "entity-gradient-color" ? value : (_a2 = stop == null ? void 0 : stop.color) != null ? _a2 : "#4a9eff"
};
});
if (this._serializeConfig(nextStops) !== this._serializeConfig(currentStops)) {
this._setScopedGradientStops(scope, nextStops);
}
return;
}
if (kind === "segment-color") {
const index = Number(target.dataset.index);
const nextSegments = ((_f = this._getSegmentsUiRows({ type: "card" })) != null ? _f : this._getSegmentsValue()).map((segment, segmentIndex) => {
if (segmentIndex !== index) return segment;
return {
...segment,
color: value
};
});
this._setSegments(nextSegments, { sort: false });
return;
}
if (kind === "entity-segment-color") {
const scope = { type: "entity", index: Number(target.dataset.index) };
const segmentIndex = Number(target.dataset.segmentIndex);
const nextSegments = ((_g = this._getSegmentsUiRows(scope)) != null ? _g : this._getScopedSegmentsValue(scope)).map((segment, currentSegmentIndex) => {
if (currentSegmentIndex !== segmentIndex) return segment;
return {
...segment,
color: value
};
});
this._setScopedSegments(scope, nextSegments, { sort: false });
return;
}
}
};
}
});
// src/sensor-bar-card-plus.js
var require_sensor_bar_card_plus = __commonJS({
"src/sensor-bar-card-plus.js"() {
init_SensorBarCard();
init_SensorBarCardPlusEditor();
customElements.define("sensor-bar-card-plus", SensorBarCard);
customElements.define("sensor-bar-card-plus-editor", SensorBarCardPlusEditor);
window.customCards = window.customCards || [];
window.customCards.push({
type: "sensor-bar-card-plus",
name: "Sensor Bar Card Plus",
description: "Animated, colour-coded horizontal bar card for Home Assistant with extended target and layout features."
});
}
});
require_sensor_bar_card_plus();
})();