tailwindcss-anchors
Version:
Anchors for Tailwind CSS provides a simple API for working with CSS anchor positioning, enabling flexible, declarative positioning relative to custom anchors.
135 lines (134 loc) • 3.98 kB
JavaScript
//#region index.ts
const getStyleVarName = (modifier) => modifier.startsWith("--") || modifier.startsWith("var(--") ? modifier : modifier.startsWith("[var(--") ? modifier.slice(1, -1) : `--tw-anchor_${modifier}`;
const generateViewTransitionId = (str) => `--tw-anchor-view-transition-${encodeString(str)}`;
const EMPTY_VALUES = { values: { DEFAULT: "" } };
var anchors_default = ({ matchUtilities, theme }) => {
matchUtilities({ anchor: (_, { modifier }) => {
const styles = {};
if (modifier) {
const anchorName = getStyleVarName(modifier);
if (anchorName) styles["anchor-name"] = anchorName;
}
return styles;
} }, {
...EMPTY_VALUES,
modifiers: "any"
});
matchUtilities({ anchored: (value, { modifier }) => {
if (!value && !modifier) return {};
const baseStyles = {};
if (value) baseStyles["position-area"] = value;
if (modifier) {
const viewTransitionName = generateViewTransitionId(modifier);
baseStyles["position-anchor"] = getStyleVarName(modifier);
baseStyles[":where(&)"] = {
position: "absolute",
...viewTransitionName && { "view-transition-name": viewTransitionName }
};
}
return baseStyles;
} }, {
values: {
DEFAULT: "",
"top-center": "top center",
"top-span-left": "top span-left",
"top-span-right": "top span-right",
top: "top",
"left-center": "left center",
"left-span-top": "left span-top",
"left-span-bottom": "left span-bottom",
left: "left",
"right-center": "right center",
"right-span-top": "right span-top",
"right-span-bottom": "right span-bottom",
right: "right",
"bottom-center": "bottom center",
"bottom-span-left": "bottom span-left",
"bottom-span-right": "bottom span-right",
bottom: "bottom",
"top-left": "top left",
"top-right": "top right",
"bottom-left": "bottom left",
"bottom-right": "bottom right"
},
modifiers: "any"
});
[
["top", theme("top")],
["right", theme("right")],
["bottom", theme("bottom")],
["left", theme("left")],
["inset", theme("inset")]
].forEach(([property, themeValues]) => {
[
"top",
"right",
"bottom",
"left",
"start",
"end",
"self-start",
"self-end",
"center"
].forEach((anchorSide) => {
matchUtilities({ [`${property}-anchor-${anchorSide}`]: (offset, { modifier }) => {
const anchorRef = modifier ? `${getStyleVarName(modifier)} ` : "";
const anchorFnExpr = `anchor-size(${anchorRef}${anchorSide})`;
const value = offset ? `calc(${anchorFnExpr} + ${offset})` : anchorFnExpr;
return { [property]: value };
} }, {
values: themeValues,
modifiers: "any"
});
});
});
[[
"w",
"width",
theme("width")
], [
"h",
"height",
theme("height")
]].forEach(([propertyAbbr, property, themeValues]) => {
[
"",
"width",
"height",
"block",
"inline",
"self-block",
"self-inline"
].forEach((anchorSize) => {
const anchorSizeUtilitySuffix = anchorSize ? `-${anchorSize}` : anchorSize;
matchUtilities({ [`${propertyAbbr}-anchor${anchorSizeUtilitySuffix}`]: (offset, { modifier }) => {
const anchorRef = modifier ? `${getStyleVarName(modifier)} ` : "";
const anchorFnExpr = `anchor-size(${anchorRef}${anchorSize})`;
const value = offset ? `calc(${anchorFnExpr} + ${offset})` : anchorFnExpr;
return { [property]: value };
} }, {
values: themeValues,
modifiers: "any"
});
});
});
};
function encodeString(str) {
let encoded = "";
for (let i = 0; i < str.length; i++) encoded += str.charCodeAt(i).toString(36);
return encoded;
}
function decodeString(encodedStr) {
const decodedChars = [];
let charCode = "";
for (let i = 0; i < encodedStr.length; i++) {
charCode += encodedStr[i];
if (parseInt(charCode, 36) >= 32 && parseInt(charCode, 36) <= 126) {
decodedChars.push(String.fromCharCode(parseInt(charCode, 36)));
charCode = "";
}
}
return decodedChars.join("");
}
//#endregion
export { decodeString, anchors_default as default, encodeString };