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