proto-1
This commit is contained in:
@@ -0,0 +1,4 @@
|
|||||||
|
node_modules
|
||||||
|
dist
|
||||||
|
pnpm-lock.yaml
|
||||||
|
.direnv
|
||||||
Generated
+60
@@ -0,0 +1,60 @@
|
|||||||
|
{
|
||||||
|
"nodes": {
|
||||||
|
"flake-utils": {
|
||||||
|
"inputs": {
|
||||||
|
"systems": "systems"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1731533236,
|
||||||
|
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "flake-utils",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1776105745,
|
||||||
|
"narHash": "sha256-3TdZByz6NafPdfpFS+pevgO75kSS9qFOR2pI9cZp7XE=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "d17aeaf88dea0fe37c73d33629d71cb51deafdb0",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-utils": "flake-utils",
|
||||||
|
"nixpkgs": "nixpkgs"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"systems": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1681028828,
|
||||||
|
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"root": "root",
|
||||||
|
"version": 7
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
{
|
||||||
|
"name": "tailwind-dashed-border",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"description": "Configurable dashed border utility for Tailwind CSS v4",
|
||||||
|
"type": "module",
|
||||||
|
"main": "./dist/index.js",
|
||||||
|
"types": "./dist/index.d.ts",
|
||||||
|
"exports": {
|
||||||
|
".": {
|
||||||
|
"types": "./dist/index.d.ts",
|
||||||
|
"import": "./dist/index.js"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"dist",
|
||||||
|
"README.md"
|
||||||
|
],
|
||||||
|
"scripts": {
|
||||||
|
"build": "tsc -p tsconfig.json",
|
||||||
|
"check": "tsc -p tsconfig.json --noEmit"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"tailwindcss",
|
||||||
|
"tailwind",
|
||||||
|
"plugin",
|
||||||
|
"dashed-border",
|
||||||
|
"border"
|
||||||
|
],
|
||||||
|
"peerDependencies": {
|
||||||
|
"tailwindcss": "^4.0.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"tailwindcss": "^4.2.1",
|
||||||
|
"typescript": "^5.9.3"
|
||||||
|
},
|
||||||
|
"publishConfig": {
|
||||||
|
"access": "public"
|
||||||
|
},
|
||||||
|
"license": "MIT"
|
||||||
|
}
|
||||||
+199
@@ -0,0 +1,199 @@
|
|||||||
|
import plugin from "tailwindcss/plugin";
|
||||||
|
|
||||||
|
interface ThemeValueMap {
|
||||||
|
[key: string]: string | ThemeValueMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
const DEFAULT_SPACING_VALUE = "0.25rem";
|
||||||
|
const DEFAULT_GAP = `calc(var(--spacing, ${DEFAULT_SPACING_VALUE}) * 2)`;
|
||||||
|
const DEFAULT_LENGTH = `calc(var(--spacing, ${DEFAULT_SPACING_VALUE}) * 3)`;
|
||||||
|
const DEFAULT_BORDER_WIDTH = "1px";
|
||||||
|
const DEFAULT_OFFSET = "0px";
|
||||||
|
const DEFAULT_COLOR = "currentColor";
|
||||||
|
const DEFAULT_RADIUS = "0px";
|
||||||
|
const svgRadius = "max(0px, calc(var(--tw-dashed-border-radius) - (var(--tw-dashed-border-width) / 2)))";
|
||||||
|
const dashedBorderTransitionProperties =
|
||||||
|
"stroke-dasharray, stroke-dashoffset, stroke-width, stroke, rx";
|
||||||
|
|
||||||
|
const flattenThemeMap = (
|
||||||
|
input: ThemeValueMap,
|
||||||
|
path: string[] = [],
|
||||||
|
): Record<string, string> => {
|
||||||
|
const output: Record<string, string> = {};
|
||||||
|
|
||||||
|
for (const [key, value] of Object.entries(input)) {
|
||||||
|
const nextPath = key === "DEFAULT" ? path : [...path, key];
|
||||||
|
|
||||||
|
if (typeof value === "string") {
|
||||||
|
output[nextPath.join("-")] = value;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Object.assign(output, flattenThemeMap(value, nextPath));
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
};
|
||||||
|
|
||||||
|
const roundedSelector = (name: string): string =>
|
||||||
|
name === "DEFAULT" ? ".rounded" : `.rounded-${name}`;
|
||||||
|
|
||||||
|
const dashedBorderPlugin: ReturnType<typeof plugin> = plugin(
|
||||||
|
({ addBase, addUtilities, matchUtilities, theme }) => {
|
||||||
|
addBase({
|
||||||
|
"@property --tw-dashed-border-gap": {
|
||||||
|
syntax: "<length-percentage>",
|
||||||
|
inherits: "true",
|
||||||
|
"initial-value": "0.5rem",
|
||||||
|
},
|
||||||
|
"@property --tw-dashed-border-length": {
|
||||||
|
syntax: "<length-percentage>",
|
||||||
|
inherits: "true",
|
||||||
|
"initial-value": "0.75rem",
|
||||||
|
},
|
||||||
|
"@property --tw-dashed-border-offset": {
|
||||||
|
syntax: "<length-percentage>",
|
||||||
|
inherits: "true",
|
||||||
|
"initial-value": DEFAULT_OFFSET,
|
||||||
|
},
|
||||||
|
"@property --tw-dashed-border-width": {
|
||||||
|
syntax: "<length>",
|
||||||
|
inherits: "true",
|
||||||
|
"initial-value": DEFAULT_BORDER_WIDTH,
|
||||||
|
},
|
||||||
|
"@property --tw-dashed-border-radius": {
|
||||||
|
syntax: "<length-percentage>",
|
||||||
|
inherits: "true",
|
||||||
|
"initial-value": DEFAULT_RADIUS,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
addUtilities({
|
||||||
|
".dashed-border": {
|
||||||
|
"--tw-dashed-border-gap": DEFAULT_GAP,
|
||||||
|
"--tw-dashed-border-length": DEFAULT_LENGTH,
|
||||||
|
"--tw-dashed-border-offset": DEFAULT_OFFSET,
|
||||||
|
"--tw-dashed-border-width": DEFAULT_BORDER_WIDTH,
|
||||||
|
"--tw-dashed-border-color": DEFAULT_COLOR,
|
||||||
|
"--tw-dashed-border-radius": DEFAULT_RADIUS,
|
||||||
|
position: "relative",
|
||||||
|
},
|
||||||
|
".dashed-border-svg": {
|
||||||
|
display: "block",
|
||||||
|
position: "absolute",
|
||||||
|
inset: "0",
|
||||||
|
width: "100%",
|
||||||
|
height: "100%",
|
||||||
|
overflow: "hidden",
|
||||||
|
pointerEvents: "none",
|
||||||
|
},
|
||||||
|
".dashed-border-rect": {
|
||||||
|
fill: "none",
|
||||||
|
stroke: "var(--tw-dashed-border-color)",
|
||||||
|
strokeWidth: "var(--tw-dashed-border-width)",
|
||||||
|
strokeDasharray:
|
||||||
|
"var(--tw-dashed-border-length) var(--tw-dashed-border-gap)",
|
||||||
|
strokeDashoffset: "var(--tw-dashed-border-offset)",
|
||||||
|
shapeRendering: "geometricPrecision",
|
||||||
|
vectorEffect: "non-scaling-stroke",
|
||||||
|
x: "calc(var(--tw-dashed-border-width) / 2)",
|
||||||
|
y: "calc(var(--tw-dashed-border-width) / 2)",
|
||||||
|
width: "calc(100% - var(--tw-dashed-border-width))",
|
||||||
|
height: "calc(100% - var(--tw-dashed-border-width))",
|
||||||
|
rx: svgRadius,
|
||||||
|
},
|
||||||
|
".dashed-border-transition, .dashed-border.transition, .dashed-border.transition-all":
|
||||||
|
{
|
||||||
|
transitionTimingFunction:
|
||||||
|
"var(--default-transition-timing-function, cubic-bezier(0.4, 0, 0.2, 1))",
|
||||||
|
transitionDuration: "var(--default-transition-duration, 150ms)",
|
||||||
|
},
|
||||||
|
".dashed-border.transition-colors": {
|
||||||
|
transitionTimingFunction:
|
||||||
|
"var(--default-transition-timing-function, cubic-bezier(0.4, 0, 0.2, 1))",
|
||||||
|
transitionDuration: "var(--default-transition-duration, 150ms)",
|
||||||
|
},
|
||||||
|
".dashed-border-transition .dashed-border-rect, .dashed-border.transition .dashed-border-rect, .dashed-border.transition-all .dashed-border-rect":
|
||||||
|
{
|
||||||
|
transitionProperty: dashedBorderTransitionProperties,
|
||||||
|
transitionTimingFunction: "inherit",
|
||||||
|
transitionDuration: "inherit",
|
||||||
|
},
|
||||||
|
".dashed-border.transition-colors .dashed-border-rect": {
|
||||||
|
transitionProperty: "stroke",
|
||||||
|
transitionTimingFunction:
|
||||||
|
"inherit",
|
||||||
|
transitionDuration: "inherit",
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const spacing = theme("spacing", {}) as Record<string, string>;
|
||||||
|
const borderWidths = theme("borderWidth", {
|
||||||
|
DEFAULT: DEFAULT_BORDER_WIDTH,
|
||||||
|
}) as Record<string, string>;
|
||||||
|
const colors = flattenThemeMap(theme("colors", {}) as ThemeValueMap);
|
||||||
|
const radii = theme("borderRadius", {
|
||||||
|
DEFAULT: DEFAULT_RADIUS,
|
||||||
|
}) as Record<string, string>;
|
||||||
|
|
||||||
|
matchUtilities(
|
||||||
|
{
|
||||||
|
"dashed-border-gap": (value: string) => ({
|
||||||
|
"--tw-dashed-border-gap": value,
|
||||||
|
}),
|
||||||
|
"dashed-border-length": (value: string) => ({
|
||||||
|
"--tw-dashed-border-length": value,
|
||||||
|
}),
|
||||||
|
"dashed-border-offset": (value: string) => ({
|
||||||
|
"--tw-dashed-border-offset": value,
|
||||||
|
}),
|
||||||
|
"dashed-border-radius": (value: string) => ({
|
||||||
|
"--tw-dashed-border-radius": value,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
values: spacing,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
matchUtilities(
|
||||||
|
{
|
||||||
|
"dashed-border-width": (value: string) => ({
|
||||||
|
"--tw-dashed-border-width": value,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
values: borderWidths,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
matchUtilities(
|
||||||
|
{
|
||||||
|
"dashed-border-color": (value: string) => ({
|
||||||
|
"--tw-dashed-border-color": value,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
values: {
|
||||||
|
...colors,
|
||||||
|
current: "currentColor",
|
||||||
|
inherit: "inherit",
|
||||||
|
transparent: "transparent",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
addUtilities(
|
||||||
|
Object.fromEntries(
|
||||||
|
Object.entries(radii).map(([name, value]) => [
|
||||||
|
`.dashed-border${roundedSelector(name)}`,
|
||||||
|
{
|
||||||
|
"--tw-dashed-border-radius": value,
|
||||||
|
},
|
||||||
|
]),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
export default dashedBorderPlugin;
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "ES2022",
|
||||||
|
"module": "NodeNext",
|
||||||
|
"moduleResolution": "NodeNext",
|
||||||
|
"declaration": true,
|
||||||
|
"outDir": "./dist",
|
||||||
|
"rootDir": "./src",
|
||||||
|
"strict": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"skipLibCheck": true
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"src"
|
||||||
|
]
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user