attempt from scratch
This commit is contained in:
+217
@@ -0,0 +1,217 @@
|
|||||||
|
import plugin from "tailwindcss/plugin";
|
||||||
|
import flattenColorPalette from "tailwindcss/lib/util/flattenColorPalette";
|
||||||
|
|
||||||
|
const DEFAULT_GAP = "calc(var(--spacing, 0.25rem) * 2)";
|
||||||
|
const DEFAULT_LENGTH = "calc(var(--spacing, 0.25rem) * 3)";
|
||||||
|
const DEFAULT_OFFSET = "0px";
|
||||||
|
const DEFAULT_WIDTH = "1px";
|
||||||
|
const DEFAULT_COLOR = "currentColor";
|
||||||
|
const DEFAULT_RADIUS = "0px";
|
||||||
|
|
||||||
|
const DASH_ARRAY = "var(--tw-dashed-border-length) var(--tw-dashed-border-gap)";
|
||||||
|
const INSET = "calc(var(--tw-dashed-border-width) / 2)";
|
||||||
|
const INNER_SIZE = "calc(100% - var(--tw-dashed-border-width))";
|
||||||
|
const ADJUSTED_RADIUS =
|
||||||
|
"max(0px, calc(var(--tw-dashed-border-radius) - (var(--tw-dashed-border-width) / 2)))";
|
||||||
|
|
||||||
|
const ALL_TRANSITION_PROPERTIES =
|
||||||
|
"stroke-dasharray, stroke-dashoffset, stroke-width, stroke, rx";
|
||||||
|
const COLOR_TRANSITION_PROPERTIES = "stroke";
|
||||||
|
const TRANSITION_DURATION =
|
||||||
|
"var(--tw-duration, var(--default-transition-duration))";
|
||||||
|
const TRANSITION_TIMING_FUNCTION =
|
||||||
|
"var(--tw-ease, var(--default-transition-timing-function))";
|
||||||
|
|
||||||
|
type ThemeLeafMap = Record<string, string>;
|
||||||
|
|
||||||
|
function isRecord(value: unknown): value is Record<string, unknown> {
|
||||||
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
function flattenThemeLeaves(
|
||||||
|
value: unknown,
|
||||||
|
path: string[] = [],
|
||||||
|
): ThemeLeafMap {
|
||||||
|
if (!isRecord(value)) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const flattened: ThemeLeafMap = {};
|
||||||
|
|
||||||
|
for (const [key, entry] of Object.entries(value)) {
|
||||||
|
if (key === "__CSS_VALUES__") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const nextPath = key === "DEFAULT" ? path : [...path, key];
|
||||||
|
|
||||||
|
if (isRecord(entry)) {
|
||||||
|
Object.assign(flattened, flattenThemeLeaves(entry, nextPath));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof entry === "string" || typeof entry === "number") {
|
||||||
|
const flattenedKey = nextPath.join("-");
|
||||||
|
flattened[flattenedKey === "" ? "DEFAULT" : flattenedKey] = String(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return flattened;
|
||||||
|
}
|
||||||
|
|
||||||
|
function omitDefaultKey(values: ThemeLeafMap): ThemeLeafMap {
|
||||||
|
const { DEFAULT: _default, ...rest } = values;
|
||||||
|
return rest;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createTransitionStyles(properties: string) {
|
||||||
|
return {
|
||||||
|
"transition-property": properties,
|
||||||
|
"transition-duration": TRANSITION_DURATION,
|
||||||
|
"transition-timing-function": TRANSITION_TIMING_FUNCTION,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const dashedBorderPlugin: ReturnType<typeof plugin> = plugin(
|
||||||
|
({ addBase, addUtilities, matchUtilities, theme }) => {
|
||||||
|
const spacingValues = flattenThemeLeaves(theme("spacing"));
|
||||||
|
const borderWidthValues = omitDefaultKey(
|
||||||
|
flattenThemeLeaves(theme("borderWidth")),
|
||||||
|
);
|
||||||
|
const borderRadiusValues = flattenThemeLeaves(theme("borderRadius"));
|
||||||
|
const colorValues = {
|
||||||
|
...flattenColorPalette(theme("colors") ?? {}),
|
||||||
|
current: "currentColor",
|
||||||
|
inherit: "inherit",
|
||||||
|
transparent: "transparent",
|
||||||
|
};
|
||||||
|
|
||||||
|
addBase({
|
||||||
|
"@property --tw-dashed-border-gap": {
|
||||||
|
syntax: "<length>",
|
||||||
|
inherits: "true",
|
||||||
|
"initial-value": DEFAULT_GAP,
|
||||||
|
},
|
||||||
|
"@property --tw-dashed-border-length": {
|
||||||
|
syntax: "<length>",
|
||||||
|
inherits: "true",
|
||||||
|
"initial-value": DEFAULT_LENGTH,
|
||||||
|
},
|
||||||
|
"@property --tw-dashed-border-offset": {
|
||||||
|
syntax: "<length>",
|
||||||
|
inherits: "true",
|
||||||
|
"initial-value": DEFAULT_OFFSET,
|
||||||
|
},
|
||||||
|
"@property --tw-dashed-border-width": {
|
||||||
|
syntax: "<length>",
|
||||||
|
inherits: "true",
|
||||||
|
"initial-value": DEFAULT_WIDTH,
|
||||||
|
},
|
||||||
|
"@property --tw-dashed-border-radius": {
|
||||||
|
syntax: "<length>",
|
||||||
|
inherits: "true",
|
||||||
|
"initial-value": DEFAULT_RADIUS,
|
||||||
|
},
|
||||||
|
".dashed-border": {
|
||||||
|
position: "relative",
|
||||||
|
"--tw-dashed-border-gap": DEFAULT_GAP,
|
||||||
|
"--tw-dashed-border-length": DEFAULT_LENGTH,
|
||||||
|
"--tw-dashed-border-offset": DEFAULT_OFFSET,
|
||||||
|
"--tw-dashed-border-width": DEFAULT_WIDTH,
|
||||||
|
"--tw-dashed-border-color": DEFAULT_COLOR,
|
||||||
|
"--tw-dashed-border-radius": DEFAULT_RADIUS,
|
||||||
|
},
|
||||||
|
".dashed-border-svg": {
|
||||||
|
position: "absolute",
|
||||||
|
inset: "0",
|
||||||
|
width: "100%",
|
||||||
|
height: "100%",
|
||||||
|
overflow: "hidden",
|
||||||
|
"pointer-events": "none",
|
||||||
|
},
|
||||||
|
".dashed-border-rect": {
|
||||||
|
fill: "none",
|
||||||
|
stroke: "var(--tw-dashed-border-color)",
|
||||||
|
"stroke-width": "var(--tw-dashed-border-width)",
|
||||||
|
"stroke-dasharray": DASH_ARRAY,
|
||||||
|
"stroke-dashoffset": "var(--tw-dashed-border-offset)",
|
||||||
|
"vector-effect": "non-scaling-stroke",
|
||||||
|
x: INSET,
|
||||||
|
y: INSET,
|
||||||
|
width: INNER_SIZE,
|
||||||
|
height: INNER_SIZE,
|
||||||
|
rx: ADJUSTED_RADIUS,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
matchUtilities(
|
||||||
|
{
|
||||||
|
"dashed-border-gap": (value) => ({
|
||||||
|
"--tw-dashed-border-gap": value,
|
||||||
|
}),
|
||||||
|
"dashed-border-length": (value) => ({
|
||||||
|
"--tw-dashed-border-length": value,
|
||||||
|
}),
|
||||||
|
"dashed-border-offset": (value) => ({
|
||||||
|
"--tw-dashed-border-offset": value,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "length",
|
||||||
|
values: spacingValues,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
matchUtilities(
|
||||||
|
{
|
||||||
|
"dashed-border-width": (value) => ({
|
||||||
|
"--tw-dashed-border-width": value,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "length",
|
||||||
|
values: borderWidthValues,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
matchUtilities(
|
||||||
|
{
|
||||||
|
"dashed-border-color": (value) => ({
|
||||||
|
"--tw-dashed-border-color": value,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: "color",
|
||||||
|
values: colorValues,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const radiusUtilities = Object.fromEntries(
|
||||||
|
Object.entries(borderRadiusValues).map(([key, value]) => {
|
||||||
|
const roundedClass = key === "DEFAULT" ? "rounded" : `rounded-${key}`;
|
||||||
|
return [
|
||||||
|
`.dashed-border.${roundedClass}`,
|
||||||
|
{
|
||||||
|
"--tw-dashed-border-radius": value,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
addUtilities({
|
||||||
|
...radiusUtilities,
|
||||||
|
".dashed-border-transition .dashed-border-rect": createTransitionStyles(
|
||||||
|
ALL_TRANSITION_PROPERTIES,
|
||||||
|
),
|
||||||
|
".dashed-border.transition .dashed-border-rect": createTransitionStyles(
|
||||||
|
ALL_TRANSITION_PROPERTIES,
|
||||||
|
),
|
||||||
|
".dashed-border.transition-all .dashed-border-rect":
|
||||||
|
createTransitionStyles(ALL_TRANSITION_PROPERTIES),
|
||||||
|
".dashed-border.transition-colors .dashed-border-rect":
|
||||||
|
createTransitionStyles(COLOR_TRANSITION_PROPERTIES),
|
||||||
|
});
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
export default dashedBorderPlugin;
|
||||||
Reference in New Issue
Block a user