taxonium-component
Version:
React component for exploring large phylogenetic trees in the browser
659 lines (658 loc) • 24.3 kB
JavaScript
import { jsx as a, jsxs as $, Fragment as P } from "react/jsx-runtime";
import * as C from "react";
import { useState as S, Suspense as se, lazy as V } from "react";
import { z as I, A as H, au as ie, E as U, G as Q, aQ as L, H as J, a$ as le, I as K, aR as de, bv as ce, b_ as W, aN as ue, T as _, u as X, c as pe, b$ as fe, c0 as ge, a as ve, o as Y, P as me, aG as he } from "./JBrowsePanel-BNE3gNW1.js";
import { F as be } from "./FeatureDetails-BEUoAeO7.js";
import { B as q } from "./BaseCard-uve71KMy.js";
import { D as Z } from "./DataGridFlexContainer-fD_l1wuy.js";
import { F as ee } from "./FormControlLabel-CfHqydvH.js";
import { C as te } from "./Checkbox-D7_LksK2.js";
import { D as oe } from "./DataGrid-cokHFdGI.js";
import { p as E, c as ne } from "./index-CoM8QAjP.js";
import r from "prop-types";
function ye(e) {
return C.Children.toArray(e).filter((t) => /* @__PURE__ */ C.isValidElement(t));
}
function Ce(e) {
return H("MuiToggleButton", e);
}
const R = I("MuiToggleButton", ["root", "disabled", "selected", "standard", "primary", "secondary", "sizeSmall", "sizeMedium", "sizeLarge", "fullWidth"]), j = /* @__PURE__ */ C.createContext({});
E.env.NODE_ENV !== "production" && (j.displayName = "ToggleButtonGroupContext");
const M = /* @__PURE__ */ C.createContext(void 0);
E.env.NODE_ENV !== "production" && (M.displayName = "ToggleButtonGroupButtonContext");
function Te(e, t) {
return t === void 0 || e === void 0 ? !1 : Array.isArray(t) ? t.includes(e) : e === t;
}
const Be = (e) => {
const {
classes: t,
fullWidth: o,
selected: n,
disabled: d,
size: s,
color: c
} = e, l = {
root: ["root", n && "selected", d && "disabled", o && "fullWidth", `size${L(s)}`, c]
};
return J(l, Ce, t);
}, $e = Q(le, {
name: "MuiToggleButton",
slot: "Root",
overridesResolver: (e, t) => {
const {
ownerState: o
} = e;
return [t.root, t[`size${L(o.size)}`]];
}
})(K(({
theme: e
}) => ({
...e.typography.button,
borderRadius: (e.vars || e).shape.borderRadius,
padding: 11,
border: `1px solid ${(e.vars || e).palette.divider}`,
color: (e.vars || e).palette.action.active,
[`&.${R.disabled}`]: {
color: (e.vars || e).palette.action.disabled,
border: `1px solid ${(e.vars || e).palette.action.disabledBackground}`
},
"&:hover": {
textDecoration: "none",
// Reset on mouse devices
backgroundColor: e.alpha((e.vars || e).palette.text.primary, (e.vars || e).palette.action.hoverOpacity),
"@media (hover: none)": {
backgroundColor: "transparent"
}
},
variants: [{
props: {
color: "standard"
},
style: {
[`&.${R.selected}`]: {
color: (e.vars || e).palette.text.primary,
backgroundColor: e.alpha((e.vars || e).palette.text.primary, (e.vars || e).palette.action.selectedOpacity),
"&:hover": {
backgroundColor: e.alpha((e.vars || e).palette.text.primary, `${(e.vars || e).palette.action.selectedOpacity} + ${(e.vars || e).palette.action.hoverOpacity}`),
// Reset on touch devices, it doesn't add specificity
"@media (hover: none)": {
backgroundColor: e.alpha((e.vars || e).palette.text.primary, (e.vars || e).palette.action.selectedOpacity)
}
}
}
}
}, ...Object.entries(e.palette).filter(de()).map(([t]) => ({
props: {
color: t
},
style: {
[`&.${R.selected}`]: {
color: (e.vars || e).palette[t].main,
backgroundColor: e.alpha((e.vars || e).palette[t].main, (e.vars || e).palette.action.selectedOpacity),
"&:hover": {
backgroundColor: e.alpha((e.vars || e).palette[t].main, `${(e.vars || e).palette.action.selectedOpacity} + ${(e.vars || e).palette.action.hoverOpacity}`),
// Reset on touch devices, it doesn't add specificity
"@media (hover: none)": {
backgroundColor: e.alpha((e.vars || e).palette[t].main, (e.vars || e).palette.action.selectedOpacity)
}
}
}
}
})), {
props: {
fullWidth: !0
},
style: {
width: "100%"
}
}, {
props: {
size: "small"
},
style: {
padding: 7,
fontSize: e.typography.pxToRem(13)
}
}, {
props: {
size: "large"
},
style: {
padding: 15,
fontSize: e.typography.pxToRem(15)
}
}]
}))), A = /* @__PURE__ */ C.forwardRef(function(t, o) {
const {
value: n,
...d
} = C.useContext(j), s = C.useContext(M), c = ie({
...d,
selected: Te(t.value, n)
}, t), l = U({
props: c,
name: "MuiToggleButton"
}), {
children: i,
className: f,
color: p = "standard",
disabled: g = !1,
disableFocusRipple: b = !1,
fullWidth: m = !1,
onChange: w,
onClick: x,
selected: T,
size: O = "medium",
value: N,
...G
} = l, v = {
...l,
color: p,
disabled: g,
disableFocusRipple: b,
fullWidth: m,
size: O
}, B = Be(v), F = (h) => {
x && (x(h, N), h.defaultPrevented) || w && w(h, N);
}, y = s || "";
return /* @__PURE__ */ a($e, {
className: ne(d.className, B.root, f, y),
disabled: g,
focusRipple: !b,
ref: o,
onClick: F,
onChange: w,
value: N,
ownerState: v,
"aria-pressed": T,
...G,
children: i
});
});
E.env.NODE_ENV !== "production" && (A.propTypes = {
// ┌────────────────────────────── Warning ──────────────────────────────┐
// │ These PropTypes are generated from the TypeScript type definitions. │
// │ To update them, edit the d.ts file and run `pnpm proptypes`. │
// └─────────────────────────────────────────────────────────────────────┘
/**
* The content of the component.
*/
children: r.node,
/**
* Override or extend the styles applied to the component.
*/
classes: r.object,
/**
* @ignore
*/
className: r.string,
/**
* The color of the button when it is in an active state.
* It supports both default and custom theme colors, which can be added as shown in the
* [palette customization guide](https://mui.com/material-ui/customization/palette/#custom-colors).
* @default 'standard'
*/
color: r.oneOfType([r.oneOf(["standard", "primary", "secondary", "error", "info", "success", "warning"]), r.string]),
/**
* If `true`, the component is disabled.
* @default false
*/
disabled: r.bool,
/**
* If `true`, the keyboard focus ripple is disabled.
* @default false
*/
disableFocusRipple: r.bool,
/**
* If `true`, the ripple effect is disabled.
*
* ⚠️ Without a ripple there is no styling for :focus-visible by default. Be sure
* to highlight the element by applying separate styles with the `.Mui-focusVisible` class.
* @default false
*/
disableRipple: r.bool,
/**
* If `true`, the button will take up the full width of its container.
* @default false
*/
fullWidth: r.bool,
/**
* Callback fired when the state changes.
*
* @param {React.MouseEvent<HTMLElement>} event The event source of the callback.
* @param {any} value of the selected button.
*/
onChange: r.func,
/**
* Callback fired when the button is clicked.
*
* @param {React.MouseEvent<HTMLElement>} event The event source of the callback.
* @param {any} value of the selected button.
*/
onClick: r.func,
/**
* If `true`, the button is rendered in an active state.
*/
selected: r.bool,
/**
* The size of the component.
* The prop defaults to the value inherited from the parent ToggleButtonGroup component.
* @default 'medium'
*/
size: r.oneOfType([r.oneOf(["small", "medium", "large"]), r.string]),
/**
* The system prop that allows defining system overrides as well as additional CSS styles.
*/
sx: r.oneOfType([r.arrayOf(r.oneOfType([r.func, r.object, r.bool])), r.func, r.object]),
/**
* The value to associate with the button when selected in a
* ToggleButtonGroup.
*/
value: r.any.isRequired
});
function Oe(e) {
return H("MuiToggleButtonGroup", e);
}
const u = I("MuiToggleButtonGroup", ["root", "selected", "horizontal", "vertical", "disabled", "grouped", "groupedHorizontal", "groupedVertical", "fullWidth", "firstButton", "lastButton", "middleButton"]), we = (e) => {
const {
classes: t,
orientation: o,
fullWidth: n,
disabled: d
} = e, s = {
root: ["root", o, n && "fullWidth"],
grouped: ["grouped", `grouped${L(o)}`, d && "disabled"],
firstButton: ["firstButton"],
lastButton: ["lastButton"],
middleButton: ["middleButton"]
};
return J(s, Oe, t);
}, xe = Q("div", {
name: "MuiToggleButtonGroup",
slot: "Root",
overridesResolver: (e, t) => {
const {
ownerState: o
} = e;
return [{
[`& .${u.grouped}`]: t.grouped
}, {
[`& .${u.grouped}`]: t[`grouped${L(o.orientation)}`]
}, {
[`& .${u.firstButton}`]: t.firstButton
}, {
[`& .${u.lastButton}`]: t.lastButton
}, {
[`& .${u.middleButton}`]: t.middleButton
}, t.root, o.orientation === "vertical" && t.vertical, o.fullWidth && t.fullWidth];
}
})(K(({
theme: e
}) => ({
display: "inline-flex",
borderRadius: (e.vars || e).shape.borderRadius,
variants: [{
props: {
orientation: "vertical"
},
style: {
flexDirection: "column",
[`& .${u.grouped}`]: {
[`&.${u.selected} + .${u.grouped}.${u.selected}`]: {
borderTop: 0,
marginTop: 0
}
},
[`& .${u.firstButton},& .${u.middleButton}`]: {
borderBottomLeftRadius: 0,
borderBottomRightRadius: 0
},
[`& .${u.lastButton},& .${u.middleButton}`]: {
marginTop: -1,
borderTop: "1px solid transparent",
borderTopLeftRadius: 0,
borderTopRightRadius: 0
},
[`& .${u.lastButton}.${R.disabled},& .${u.middleButton}.${R.disabled}`]: {
borderTop: "1px solid transparent"
}
}
}, {
props: {
fullWidth: !0
},
style: {
width: "100%"
}
}, {
props: {
orientation: "horizontal"
},
style: {
[`& .${u.grouped}`]: {
[`&.${u.selected} + .${u.grouped}.${u.selected}`]: {
borderLeft: 0,
marginLeft: 0
}
},
[`& .${u.firstButton},& .${u.middleButton}`]: {
borderTopRightRadius: 0,
borderBottomRightRadius: 0
},
[`& .${u.lastButton},& .${u.middleButton}`]: {
marginLeft: -1,
borderLeft: "1px solid transparent",
borderTopLeftRadius: 0,
borderBottomLeftRadius: 0
},
[`& .${u.lastButton}.${R.disabled},& .${u.middleButton}.${R.disabled}`]: {
borderLeft: "1px solid transparent"
}
}
}]
}))), re = /* @__PURE__ */ C.forwardRef(function(t, o) {
const n = U({
props: t,
name: "MuiToggleButtonGroup"
}), {
children: d,
className: s,
color: c = "standard",
disabled: l = !1,
exclusive: i = !1,
fullWidth: f = !1,
onChange: p,
orientation: g = "horizontal",
size: b = "medium",
value: m,
...w
} = n, x = {
...n,
disabled: l,
fullWidth: f,
orientation: g,
size: b
}, T = we(x), O = C.useCallback((y, h) => {
if (!p)
return;
const k = m && m.indexOf(h);
let D;
m && k >= 0 ? (D = m.slice(), D.splice(k, 1)) : D = m ? m.concat(h) : [h], p(y, D);
}, [p, m]), N = C.useCallback((y, h) => {
p && p(y, m === h ? null : h);
}, [p, m]), G = C.useMemo(() => ({
className: T.grouped,
onChange: i ? N : O,
value: m,
size: b,
fullWidth: f,
color: c,
disabled: l
}), [T.grouped, i, N, O, m, b, f, c, l]), v = ye(d), B = v.length, F = (y) => {
const h = y === 0, k = y === B - 1;
return h && k ? "" : h ? T.firstButton : k ? T.lastButton : T.middleButton;
};
return /* @__PURE__ */ a(xe, {
role: "group",
className: ne(T.root, s),
ref: o,
ownerState: x,
...w,
children: /* @__PURE__ */ a(j.Provider, {
value: G,
children: v.map((y, h) => (E.env.NODE_ENV !== "production" && ce.isFragment(y) && console.error(["MUI: The ToggleButtonGroup component doesn't accept a Fragment as a child.", "Consider providing an array instead."].join(`
`)), /* @__PURE__ */ a(M.Provider, {
value: F(h),
children: y
}, h)))
})
});
});
E.env.NODE_ENV !== "production" && (re.propTypes = {
// ┌────────────────────────────── Warning ──────────────────────────────┐
// │ These PropTypes are generated from the TypeScript type definitions. │
// │ To update them, edit the d.ts file and run `pnpm proptypes`. │
// └─────────────────────────────────────────────────────────────────────┘
/**
* The content of the component.
*/
children: r.node,
/**
* Override or extend the styles applied to the component.
*/
classes: r.object,
/**
* @ignore
*/
className: r.string,
/**
* The color of the button when it is selected.
* It supports both default and custom theme colors, which can be added as shown in the
* [palette customization guide](https://mui.com/material-ui/customization/palette/#custom-colors).
* @default 'standard'
*/
color: r.oneOfType([r.oneOf(["standard", "primary", "secondary", "error", "info", "success", "warning"]), r.string]),
/**
* If `true`, the component is disabled. This implies that all ToggleButton children will be disabled.
* @default false
*/
disabled: r.bool,
/**
* If `true`, only allow one of the child ToggleButton values to be selected.
* @default false
*/
exclusive: r.bool,
/**
* If `true`, the button group will take up the full width of its container.
* @default false
*/
fullWidth: r.bool,
/**
* Callback fired when the value changes.
*
* @param {React.MouseEvent<HTMLElement>} event The event source of the callback.
* @param {any} value of the selected buttons. When `exclusive` is true
* this is a single value; when false an array of selected values. If no value
* is selected and `exclusive` is true the value is null; when false an empty array.
*/
onChange: r.func,
/**
* The component orientation (layout flow direction).
* @default 'horizontal'
*/
orientation: r.oneOf(["horizontal", "vertical"]),
/**
* The size of the component.
* @default 'medium'
*/
size: r.oneOfType([r.oneOf(["small", "medium", "large"]), r.string]),
/**
* The system prop that allows defining system overrides as well as additional CSS styles.
*/
sx: r.oneOfType([r.arrayOf(r.oneOfType([r.func, r.object, r.bool])), r.func, r.object]),
/**
* The currently selected value within the group or an array of selected
* values when `exclusive` is false.
*
* The value must have reference equality with the option in order to be selected.
*/
value: r.any
});
function Ne({ value: e, ref: t }) {
const [o, n] = S(!1);
return W(t, e) !== e ? $("div", { children: [a("button", { onClick: () => {
n(!o);
}, children: o ? "Show simplified ALT" : "Show raw ALT" }), " ", o ? e : W(t, e)] }) : e;
}
function Fe({ value: e }) {
const [t, o] = S(!1), [n, d] = S(!1), s = String(e);
return s.length > 100 ? $(P, { children: [a("button", { type: "button", onClick: () => {
ue(s), d(!0), setTimeout(() => {
d(!1);
}, 700);
}, children: n ? "Copied to clipboard" : "Copy" }), a("button", { type: "button", onClick: () => {
o((c) => !c);
}, children: t ? "Show less" : "Show more" }), a("div", { children: t ? s : `${s.slice(0, 100)}...` })] }) : a("div", { children: s });
}
function Re({ checked: e, disabled: t, label: o, onChange: n }) {
return a(ee, { disabled: t, control: a(te, { checked: e, onChange: n }), label: a(_, { variant: "body2", children: o }) });
}
function Se(e) {
return e.toPrecision(3);
}
function Ge({ rows: e }) {
const [t, o] = S(!1), n = {};
if (t)
for (const l of e) {
const i = {}, f = l.GT.split(/[/|]/);
for (const g of f)
i[g] = (i[g] || 0) + 1;
const p = Object.entries(i).map(([g, b]) => `${g}:${b}`).join(";");
n[p] || (n[p] = {
count: 0,
GT: p,
genotype: l.genotype
}), n[p].count++;
}
else
for (const l of e) {
const i = l.GT;
n[i] || (n[i] = {
count: 0,
GT: l.GT,
genotype: l.genotype
}), n[i].count++;
}
const d = Object.entries(n).map(([l, i]) => ({
id: l,
...i,
count: `${i.count} / ${e.length}`,
frequency: `${Se(i.count / e.length * 100)}%`
})), c = (d[0] ? Object.keys(d[0]) : []).map((l) => X.measureGridWidth(d.map((i) => `${i[l]}`)));
return $("div", { children: [a(ee, { control: a(te, { checked: t }), label: a(_, { variant: "body2", children: "Use allele counts instead of exact GT" }), onChange: (l, i) => {
o(i);
} }), a(Z, { children: a(oe, { rows: d, hideFooter: !0, rowHeight: 25, columnHeaderHeight: 35, columns: [
{
field: "GT",
width: c[0]
},
{
field: "count",
width: c[1]
},
{
field: "frequency",
width: c[2]
},
{
field: "genotype",
width: c[3]
}
] }) })] });
}
function ke({ columns: e, filter: t, setFilter: o }) {
return $(P, { children: [a(_, { children: "These filters can use a plain text search or regex style query, e.g. in the genotype field, entering 1 will query for all genotypes that include the first alternate allele e.g. 0|1 or 1|1, entering [1-9]\\d* will find any non-zero allele e.g. 0|2 or 2/33" }), e.map(({ field: n }) => a(pe, { placeholder: `Filter ${n}`, value: t[n] || "", onChange: (d) => {
o({ ...t, [n]: d.target.value });
} }, `filter-${n}`))] });
}
function Ee(e, t, o, n) {
const d = Object.entries(e).map(([i, f]) => {
var p;
const g = (p = f.GT) === null || p === void 0 ? void 0 : p[0];
return [
i,
{
...f,
...g ? {
GT: `${g}`,
genotype: fe(`${g}`, t, o)
} : {}
}
];
});
let s, c = [];
const l = Object.keys(n);
try {
c = d.map(([i, f]) => ({
...Object.fromEntries(Object.entries(f).map(([p, g]) => [
p,
g
])),
sample: i,
id: i
})).filter((i) => l.length ? l.every((f) => {
const p = n[f];
return p ? new RegExp(p, "i").exec(i[f]) : !0;
}) : !0);
} catch (i) {
console.error(i), s = i;
}
return { rows: c, error: s };
}
function De(e) {
const { feature: t, descriptions: o = {} } = e, [n, d] = S({}), [s, c] = S("all"), [l, i] = S(!1), f = t.samples || {}, p = t.ALT, g = t.REF, { rows: b, error: m } = Ee(f, g, p, n), w = /* @__PURE__ */ new Set(["sample", ...Object.keys(b[0] || {})]);
w.delete("id");
const x = [...w], T = x.map((v) => X.measureGridWidth(b.map((B) => B[v]))), O = x.map((v, B) => {
var F, y;
return {
field: v,
description: (y = (F = o == null ? void 0 : o.FORMAT) === null || F === void 0 ? void 0 : F[v]) === null || y === void 0 ? void 0 : y.Description,
width: T[B]
};
}), N = /* @__PURE__ */ new Set(["sample", "GT"]), G = /* @__PURE__ */ new Set(["sample", "GT", "genotype"]);
return b.length ? $(P, { children: [a(q, { ...e, title: "Genotype frequencies", children: a(ge.ErrorBoundary, { FallbackComponent: ve.ErrorMessage, children: a(Ge, { rows: b }) }) }), $(q, { ...e, title: "Samples", children: [m ? a(_, { color: "error", children: `${m}` }) : null, $("div", { children: [a(Re, { label: "Show filters", checked: l, onChange: (v) => {
i(v.target.checked);
} }), $(re, { value: s, exclusive: !0, size: "small", onChange: (v, B) => {
B !== null && c(B);
}, children: [a(A, { value: "all", children: "All" }), a(A, { value: "gtOnly", children: "GT only" }), a(A, { value: "genotypeOnly", children: "GT+resolved genotype" })] })] }), l ? a(ke, { setFilter: d, columns: O, filter: n }) : null, a(Z, { children: a(oe, { rows: b, hideFooter: b.length < 100, columns: s === "gtOnly" ? O.filter((v) => N.has(v.field)) : s === "genotypeOnly" ? O.filter((v) => G.has(v.field)) : O, rowHeight: 25, columnHeaderHeight: 35, showToolbar: !0 }) })] })] }) : null;
}
const ze = {
CHROM: "chromosome: An identifier from the reference genome",
POS: "position: The reference position, with the 1st base having position 1",
ID: "identifier: Semi-colon separated list of unique identifiers where available",
REF: "reference base(s): Each base must be one of A,C,G,T,N (case insensitive).",
ALT: "alternate base(s): Comma-separated list of alternate non-reference alleles",
QUAL: "quality: Phred-scaled quality score for the assertion made in ALT",
FILTER: "filter status: PASS if this position has passed all filters, otherwise a semicolon-separated list of codes for filters that fail"
}, z = V(() => import("./LaunchBreakendPanel-DlICa3xR.js")), ae = V(() => import("./VariantConsequenceDataGrid-Cbj_NF6D.js"));
function Ae({ descriptions: e, feature: t }) {
var o, n, d, s, c;
const l = (n = (o = e == null ? void 0 : e.INFO) === null || o === void 0 ? void 0 : o.ANN) === null || n === void 0 ? void 0 : n.Description, i = ((s = (d = l == null ? void 0 : l.match(/.*Functional annotations:'(.*)'$/)) === null || d === void 0 ? void 0 : d[1]) === null || s === void 0 ? void 0 : s.split("|")) || [], f = ((c = t.INFO) === null || c === void 0 ? void 0 : c.ANN) || [];
return a(ae, { fields: i, data: f, title: "Variant ANN field" });
}
function Le({ descriptions: e, feature: t }) {
var o, n, d, s, c;
const l = (n = (o = e == null ? void 0 : e.INFO) === null || o === void 0 ? void 0 : o.CSQ) === null || n === void 0 ? void 0 : n.Description, i = ((s = (d = l == null ? void 0 : l.match(/.*Format: (.*)/)) === null || d === void 0 ? void 0 : d[1]) === null || s === void 0 ? void 0 : s.split("|")) || [], f = ((c = t.INFO) === null || c === void 0 ? void 0 : c.CSQ) || [];
return a(ae, { fields: i, data: f, title: "Variant CSQ field" });
}
function _e({ model: e }) {
const { featureData: t } = e, o = JSON.parse(JSON.stringify(t)), { type: n = "" } = o;
return n === "breakend" ? a(z, { feature: o, locStrings: o.ALT.map((d) => {
var s;
return ((s = he(d)) === null || s === void 0 ? void 0 : s.MatePosition) || "";
}), model: e }) : n === "translocation" ? a(z, { feature: o, model: e, locStrings: [`${o.INFO.CHR2[0]}:${o.INFO.END}`] }) : n === "paired_feature" ? a(z, { feature: o, model: e, locStrings: [`${o.mate.refName}:${o.mate.start}`] }) : n.includes("inversion") || n.includes("deletion") || n.includes("duplication") || n.includes("cnv") || n.includes("sv") ? a(z, { feature: {
uniqueId: "random",
refName: o.refName,
start: o.start,
end: o.start + 1,
mate: {
refName: o.refName,
start: o.end,
end: o.end + 1
}
}, model: e, locStrings: [`${o.refName}:${o.end}`] }) : null;
}
const Pe = Y(function(e) {
const { feat: t, model: o } = e, { descriptions: n } = o, { samples: d, ...s } = t, { REF: c } = s;
return $(me, { "data-testid": "variant-side-drawer", children: [a(be, { feature: s, descriptions: {
...ze,
...n
}, formatter: (l, i) => i === "ALT" ? a(Ne, { value: `${l}`, ref: c }) : a(Fe, { value: l }), ...e }), $(se, { fallback: null, children: [a(Le, { feature: s, descriptions: n }), a(Ae, { feature: s, descriptions: n }), a(_e, { model: o })] }), a(De, { feature: t, ...e, descriptions: n })] });
}), Xe = Y(function(e) {
const { model: t } = e, { featureData: o } = t, n = structuredClone(o);
return n ? a(Pe, { feat: n, ...e }) : a("div", { children: "No feature loaded, may not be available after page refresh because it was too large for localStorage" });
});
export {
Xe as default
};
//# sourceMappingURL=VariantFeatureWidget-C_HTn85S.js.map