mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-11-04 11:52:25 +00:00
Refactor floating panel styling hooks
This commit is contained in:
1 parent
ae932cb968
commit
e614acdee2
10 files changed
+268
-57
No files matched your search
@@ -0,0 +1,140 @@
|
||||
const DEFAULT_STATE = {
|
||||
placement: "bottom",
|
||||
alignment: "start",
|
||||
strategy: "fixed",
|
||||
direction: "ltr",
|
||||
mode: "fallback",
|
||||
fallbackTop: null,
|
||||
fallbackLeft: null,
|
||||
};
|
||||
|
||||
const FALLBACK_TOP_VAR = "--floating-fallback-top";
|
||||
const FALLBACK_LEFT_VAR = "--floating-fallback-left";
|
||||
|
||||
function toCssPixel(value) {
|
||||
if (Number.isFinite(value)) {
|
||||
return `${value}px`;
|
||||
}
|
||||
if (typeof value === "string" && value.trim() !== "") {
|
||||
return value;
|
||||
}
|
||||
return "auto";
|
||||
}
|
||||
|
||||
function normalizeDirection(value) {
|
||||
return value === "rtl" ? "rtl" : "ltr";
|
||||
}
|
||||
|
||||
function ensureDatasetValue(element, key, value) {
|
||||
if (!element) {
|
||||
return;
|
||||
}
|
||||
if (value === undefined || value === null || value === "") {
|
||||
delete element.dataset[key];
|
||||
return;
|
||||
}
|
||||
element.dataset[key] = value;
|
||||
}
|
||||
|
||||
export function createFloatingPanelStyles(panel) {
|
||||
const safePanel = panel || null;
|
||||
const state = { ...DEFAULT_STATE };
|
||||
|
||||
if (safePanel) {
|
||||
safePanel.dataset.floatingPanel = "true";
|
||||
safePanel.style.setProperty(FALLBACK_TOP_VAR, "auto");
|
||||
safePanel.style.setProperty(FALLBACK_LEFT_VAR, "auto");
|
||||
}
|
||||
|
||||
const api = {
|
||||
element: safePanel,
|
||||
setPlacement(value) {
|
||||
state.placement = typeof value === "string" && value ? value : DEFAULT_STATE.placement;
|
||||
ensureDatasetValue(safePanel, "floatingPlacement", state.placement);
|
||||
return state.placement;
|
||||
},
|
||||
getPlacement() {
|
||||
return state.placement;
|
||||
},
|
||||
setAlignment(value) {
|
||||
state.alignment = typeof value === "string" && value ? value : DEFAULT_STATE.alignment;
|
||||
ensureDatasetValue(safePanel, "floatingAlignment", state.alignment);
|
||||
return state.alignment;
|
||||
},
|
||||
getAlignment() {
|
||||
return state.alignment;
|
||||
},
|
||||
setStrategy(value) {
|
||||
state.strategy = value === "absolute" ? "absolute" : DEFAULT_STATE.strategy;
|
||||
ensureDatasetValue(safePanel, "floatingStrategy", state.strategy);
|
||||
return state.strategy;
|
||||
},
|
||||
getStrategy() {
|
||||
return state.strategy;
|
||||
},
|
||||
setDirection(value) {
|
||||
state.direction = normalizeDirection(value);
|
||||
ensureDatasetValue(safePanel, "floatingDir", state.direction);
|
||||
return state.direction;
|
||||
},
|
||||
getDirection() {
|
||||
return state.direction;
|
||||
},
|
||||
setMode(value) {
|
||||
state.mode = value === "anchor" ? "anchor" : DEFAULT_STATE.mode;
|
||||
ensureDatasetValue(safePanel, "floatingMode", state.mode);
|
||||
return state.mode;
|
||||
},
|
||||
getMode() {
|
||||
return state.mode;
|
||||
},
|
||||
setFallbackPosition({ top, left }) {
|
||||
state.fallbackTop = Number.isFinite(top) ? Number(top) : null;
|
||||
state.fallbackLeft = Number.isFinite(left) ? Number(left) : null;
|
||||
if (safePanel) {
|
||||
safePanel.style.setProperty(FALLBACK_TOP_VAR, toCssPixel(state.fallbackTop));
|
||||
safePanel.style.setProperty(FALLBACK_LEFT_VAR, toCssPixel(state.fallbackLeft));
|
||||
}
|
||||
return { ...api.getFallbackPosition() };
|
||||
},
|
||||
getFallbackPosition() {
|
||||
return {
|
||||
top: state.fallbackTop,
|
||||
left: state.fallbackLeft,
|
||||
};
|
||||
},
|
||||
teardown() {
|
||||
if (!safePanel) {
|
||||
return;
|
||||
}
|
||||
safePanel.style.removeProperty(FALLBACK_TOP_VAR);
|
||||
safePanel.style.removeProperty(FALLBACK_LEFT_VAR);
|
||||
safePanel.style.removeProperty("right");
|
||||
safePanel.style.removeProperty("bottom");
|
||||
safePanel.style.removeProperty("position");
|
||||
delete safePanel.dataset.floatingPanel;
|
||||
delete safePanel.dataset.floatingPlacement;
|
||||
delete safePanel.dataset.floatingAlignment;
|
||||
delete safePanel.dataset.floatingStrategy;
|
||||
delete safePanel.dataset.floatingDir;
|
||||
delete safePanel.dataset.floatingMode;
|
||||
state.placement = DEFAULT_STATE.placement;
|
||||
state.alignment = DEFAULT_STATE.alignment;
|
||||
state.strategy = DEFAULT_STATE.strategy;
|
||||
state.direction = DEFAULT_STATE.direction;
|
||||
state.mode = DEFAULT_STATE.mode;
|
||||
state.fallbackTop = DEFAULT_STATE.fallbackTop;
|
||||
state.fallbackLeft = DEFAULT_STATE.fallbackLeft;
|
||||
},
|
||||
};
|
||||
|
||||
api.setPlacement(state.placement);
|
||||
api.setAlignment(state.alignment);
|
||||
api.setStrategy(state.strategy);
|
||||
api.setDirection(state.direction);
|
||||
api.setMode(state.mode);
|
||||
|
||||
return api;
|
||||
}
|
||||
|
||||
export default createFloatingPanelStyles;
|
||||
@@ -1,3 +1,5 @@
|
||||
import { createFloatingPanelStyles } from "./floatingPanelStyles.js";
|
||||
|
||||
const DEFAULT_OPTIONS = {
|
||||
placement: "bottom",
|
||||
alignment: "start",
|
||||
@@ -9,20 +11,6 @@ const DEFAULT_OPTIONS = {
|
||||
onUpdate: null,
|
||||
};
|
||||
|
||||
const PANEL_DATA_KEYS = [
|
||||
"floatingPanel",
|
||||
"floatingPlacement",
|
||||
"floatingAlignment",
|
||||
"floatingStrategy",
|
||||
"floatingDir",
|
||||
"floatingMode",
|
||||
];
|
||||
|
||||
const PANEL_STYLE_PROPS = [
|
||||
"--floating-fallback-top",
|
||||
"--floating-fallback-left",
|
||||
];
|
||||
|
||||
const OPPOSITE_PLACEMENT = {
|
||||
top: "bottom",
|
||||
bottom: "top",
|
||||
@@ -213,9 +201,10 @@ export function positionFloatingPanel(anchor, panel, options = {}) {
|
||||
const documentRef = safeAnchor.ownerDocument || safePanel.ownerDocument || globalThis.document;
|
||||
const windowRef = documentRef?.defaultView || globalThis;
|
||||
|
||||
const { styles: providedStyles, ...optionOverrides } = options || {};
|
||||
const config = {
|
||||
...DEFAULT_OPTIONS,
|
||||
...options,
|
||||
...optionOverrides,
|
||||
};
|
||||
config.placement = normalizePlacement(config.placement);
|
||||
config.alignment = normalizeAlignment(config.alignment);
|
||||
@@ -235,20 +224,21 @@ export function positionFloatingPanel(anchor, panel, options = {}) {
|
||||
cleanup: [],
|
||||
};
|
||||
|
||||
const styles =
|
||||
providedStyles && providedStyles.element === safePanel
|
||||
? providedStyles
|
||||
: createFloatingPanelStyles(safePanel);
|
||||
|
||||
safeAnchor.dataset.floatingAnchor = "true";
|
||||
safePanel.dataset.floatingPanel = "true";
|
||||
safePanel.dataset.floatingAlignment = config.alignment;
|
||||
safePanel.dataset.floatingStrategy = config.strategy;
|
||||
safePanel.dataset.floatingDir = rtl ? "rtl" : "ltr";
|
||||
safePanel.dataset.floatingMode = anchorSupported ? "anchor" : "fallback";
|
||||
styles.setAlignment(config.alignment);
|
||||
styles.setStrategy(config.strategy);
|
||||
styles.setDirection(rtl ? "rtl" : "ltr");
|
||||
styles.setMode(anchorSupported ? "anchor" : "fallback");
|
||||
styles.setPlacement(config.placement);
|
||||
|
||||
const applyPosition = ({ top, left, placement }) => {
|
||||
safePanel.dataset.floatingPlacement = placement;
|
||||
safePanel.style.position = config.strategy;
|
||||
safePanel.style.removeProperty("right");
|
||||
safePanel.style.removeProperty("bottom");
|
||||
safePanel.style.setProperty("--floating-fallback-top", `${top}px`);
|
||||
safePanel.style.setProperty("--floating-fallback-left", `${left}px`);
|
||||
styles.setPlacement(placement);
|
||||
styles.setFallbackPosition({ top, left });
|
||||
if (typeof config.onUpdate === "function") {
|
||||
config.onUpdate({ top, left, placement, alignment: config.alignment, rtl });
|
||||
}
|
||||
@@ -395,18 +385,10 @@ export function positionFloatingPanel(anchor, panel, options = {}) {
|
||||
// Ignore cleanup errors to avoid breaking consumer teardown flows.
|
||||
}
|
||||
}
|
||||
PANEL_STYLE_PROPS.forEach((prop) => {
|
||||
safePanel.style.removeProperty(prop);
|
||||
});
|
||||
safePanel.style.removeProperty("right");
|
||||
safePanel.style.removeProperty("bottom");
|
||||
safePanel.style.removeProperty("position");
|
||||
safePanel.style.position = "";
|
||||
PANEL_DATA_KEYS.forEach((key) => {
|
||||
delete safePanel.dataset[key];
|
||||
});
|
||||
styles.teardown();
|
||||
delete safeAnchor.dataset.floatingAnchor;
|
||||
},
|
||||
styles,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user