@knighted/css 1.0.0-rc.2 → 1.0.0-rc.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/css.cjs +18 -0
- package/dist/cjs/stableSelectors.cjs +44 -0
- package/dist/cjs/stableSelectors.d.cts +13 -0
- package/dist/css.js +19 -1
- package/dist/stableSelectors.d.ts +13 -0
- package/dist/stableSelectors.js +36 -0
- package/package.json +20 -2
- package/stable/_index.scss +57 -0
- package/stable/stable.css +15 -0
package/dist/cjs/css.cjs
CHANGED
|
@@ -125,9 +125,27 @@ async function compileSass(filePath, indented, peerResolver) {
|
|
|
125
125
|
const sass = sassModule;
|
|
126
126
|
const result = sass.compile(filePath, {
|
|
127
127
|
style: 'expanded',
|
|
128
|
+
loadPaths: buildSassLoadPaths(filePath),
|
|
128
129
|
});
|
|
129
130
|
return result.css;
|
|
130
131
|
}
|
|
132
|
+
// Ensure Sass can resolve bare module specifiers by walking node_modules folders.
|
|
133
|
+
function buildSassLoadPaths(filePath) {
|
|
134
|
+
const loadPaths = new Set();
|
|
135
|
+
let cursor = node_path_1.default.dirname(filePath);
|
|
136
|
+
const root = node_path_1.default.parse(cursor).root;
|
|
137
|
+
while (true) {
|
|
138
|
+
loadPaths.add(cursor);
|
|
139
|
+
loadPaths.add(node_path_1.default.join(cursor, 'node_modules'));
|
|
140
|
+
if (cursor === root)
|
|
141
|
+
break;
|
|
142
|
+
cursor = node_path_1.default.dirname(cursor);
|
|
143
|
+
}
|
|
144
|
+
const cwd = process.cwd();
|
|
145
|
+
loadPaths.add(cwd);
|
|
146
|
+
loadPaths.add(node_path_1.default.join(cwd, 'node_modules'));
|
|
147
|
+
return Array.from(loadPaths).filter(dir => dir && (0, node_fs_1.existsSync)(dir));
|
|
148
|
+
}
|
|
131
149
|
async function compileLess(filePath, peerResolver) {
|
|
132
150
|
const mod = await optionalPeer('less', 'Less', peerResolver);
|
|
133
151
|
const less = unwrapModuleNamespace(mod);
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.stableClassFromModule = void 0;
|
|
4
|
+
exports.stableToken = stableToken;
|
|
5
|
+
exports.stableClass = stableClass;
|
|
6
|
+
exports.stableSelector = stableSelector;
|
|
7
|
+
exports.createStableClassFactory = createStableClassFactory;
|
|
8
|
+
exports.stableClassName = stableClassName;
|
|
9
|
+
const DEFAULT_NAMESPACE = 'knighted';
|
|
10
|
+
const defaultJoin = (values) => values.filter(Boolean).join(' ');
|
|
11
|
+
const normalizeToken = (token) => {
|
|
12
|
+
const sanitized = token
|
|
13
|
+
.trim()
|
|
14
|
+
.replace(/\s+/g, '-')
|
|
15
|
+
.replace(/[^A-Za-z0-9_-]/g, '-')
|
|
16
|
+
.replace(/-+/g, '-')
|
|
17
|
+
.replace(/^-|-$/g, '');
|
|
18
|
+
return sanitized.length ? sanitized : 'stable';
|
|
19
|
+
};
|
|
20
|
+
function stableToken(token, options) {
|
|
21
|
+
const normalized = normalizeToken(token);
|
|
22
|
+
const namespace = options?.namespace?.trim() ?? DEFAULT_NAMESPACE;
|
|
23
|
+
if (!namespace) {
|
|
24
|
+
return normalized;
|
|
25
|
+
}
|
|
26
|
+
return `${namespace}-${normalized}`;
|
|
27
|
+
}
|
|
28
|
+
function stableClass(token, options) {
|
|
29
|
+
return stableToken(token, options);
|
|
30
|
+
}
|
|
31
|
+
function stableSelector(token, options) {
|
|
32
|
+
return `.${stableToken(token, options)}`;
|
|
33
|
+
}
|
|
34
|
+
function createStableClassFactory(options) {
|
|
35
|
+
return (token) => stableClass(token, options);
|
|
36
|
+
}
|
|
37
|
+
function stableClassName(styles, key, options) {
|
|
38
|
+
const hashed = styles[key] ?? '';
|
|
39
|
+
const token = options?.token ?? String(key);
|
|
40
|
+
const stable = stableClass(token, options);
|
|
41
|
+
const join = options?.join ?? defaultJoin;
|
|
42
|
+
return join([hashed, stable]);
|
|
43
|
+
}
|
|
44
|
+
exports.stableClassFromModule = stableClassName;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export interface StableSelectorOptions {
|
|
2
|
+
namespace?: string;
|
|
3
|
+
}
|
|
4
|
+
export interface StableClassNameOptions extends StableSelectorOptions {
|
|
5
|
+
token?: string;
|
|
6
|
+
join?: (values: string[]) => string;
|
|
7
|
+
}
|
|
8
|
+
export declare function stableToken(token: string, options?: StableSelectorOptions): string;
|
|
9
|
+
export declare function stableClass(token: string, options?: StableSelectorOptions): string;
|
|
10
|
+
export declare function stableSelector(token: string, options?: StableSelectorOptions): string;
|
|
11
|
+
export declare function createStableClassFactory(options?: StableSelectorOptions): (token: string) => string;
|
|
12
|
+
export declare function stableClassName<T extends Record<string, string>>(styles: T, key: keyof T | string, options?: StableClassNameOptions): string;
|
|
13
|
+
export declare const stableClassFromModule: typeof stableClassName;
|
package/dist/css.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
|
-
import { promises as fs } from 'node:fs';
|
|
2
|
+
import { existsSync, promises as fs } from 'node:fs';
|
|
3
3
|
import dependencyTree from 'dependency-tree';
|
|
4
4
|
import { composeVisitors, transform as lightningTransform, } from 'lightningcss';
|
|
5
5
|
import { applyStringSpecificityBoost, buildSpecificityVisitor, } from './helpers.js';
|
|
@@ -116,9 +116,27 @@ async function compileSass(filePath, indented, peerResolver) {
|
|
|
116
116
|
const sass = sassModule;
|
|
117
117
|
const result = sass.compile(filePath, {
|
|
118
118
|
style: 'expanded',
|
|
119
|
+
loadPaths: buildSassLoadPaths(filePath),
|
|
119
120
|
});
|
|
120
121
|
return result.css;
|
|
121
122
|
}
|
|
123
|
+
// Ensure Sass can resolve bare module specifiers by walking node_modules folders.
|
|
124
|
+
function buildSassLoadPaths(filePath) {
|
|
125
|
+
const loadPaths = new Set();
|
|
126
|
+
let cursor = path.dirname(filePath);
|
|
127
|
+
const root = path.parse(cursor).root;
|
|
128
|
+
while (true) {
|
|
129
|
+
loadPaths.add(cursor);
|
|
130
|
+
loadPaths.add(path.join(cursor, 'node_modules'));
|
|
131
|
+
if (cursor === root)
|
|
132
|
+
break;
|
|
133
|
+
cursor = path.dirname(cursor);
|
|
134
|
+
}
|
|
135
|
+
const cwd = process.cwd();
|
|
136
|
+
loadPaths.add(cwd);
|
|
137
|
+
loadPaths.add(path.join(cwd, 'node_modules'));
|
|
138
|
+
return Array.from(loadPaths).filter(dir => dir && existsSync(dir));
|
|
139
|
+
}
|
|
122
140
|
async function compileLess(filePath, peerResolver) {
|
|
123
141
|
const mod = await optionalPeer('less', 'Less', peerResolver);
|
|
124
142
|
const less = unwrapModuleNamespace(mod);
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export interface StableSelectorOptions {
|
|
2
|
+
namespace?: string;
|
|
3
|
+
}
|
|
4
|
+
export interface StableClassNameOptions extends StableSelectorOptions {
|
|
5
|
+
token?: string;
|
|
6
|
+
join?: (values: string[]) => string;
|
|
7
|
+
}
|
|
8
|
+
export declare function stableToken(token: string, options?: StableSelectorOptions): string;
|
|
9
|
+
export declare function stableClass(token: string, options?: StableSelectorOptions): string;
|
|
10
|
+
export declare function stableSelector(token: string, options?: StableSelectorOptions): string;
|
|
11
|
+
export declare function createStableClassFactory(options?: StableSelectorOptions): (token: string) => string;
|
|
12
|
+
export declare function stableClassName<T extends Record<string, string>>(styles: T, key: keyof T | string, options?: StableClassNameOptions): string;
|
|
13
|
+
export declare const stableClassFromModule: typeof stableClassName;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
const DEFAULT_NAMESPACE = 'knighted';
|
|
2
|
+
const defaultJoin = (values) => values.filter(Boolean).join(' ');
|
|
3
|
+
const normalizeToken = (token) => {
|
|
4
|
+
const sanitized = token
|
|
5
|
+
.trim()
|
|
6
|
+
.replace(/\s+/g, '-')
|
|
7
|
+
.replace(/[^A-Za-z0-9_-]/g, '-')
|
|
8
|
+
.replace(/-+/g, '-')
|
|
9
|
+
.replace(/^-|-$/g, '');
|
|
10
|
+
return sanitized.length ? sanitized : 'stable';
|
|
11
|
+
};
|
|
12
|
+
export function stableToken(token, options) {
|
|
13
|
+
const normalized = normalizeToken(token);
|
|
14
|
+
const namespace = options?.namespace?.trim() ?? DEFAULT_NAMESPACE;
|
|
15
|
+
if (!namespace) {
|
|
16
|
+
return normalized;
|
|
17
|
+
}
|
|
18
|
+
return `${namespace}-${normalized}`;
|
|
19
|
+
}
|
|
20
|
+
export function stableClass(token, options) {
|
|
21
|
+
return stableToken(token, options);
|
|
22
|
+
}
|
|
23
|
+
export function stableSelector(token, options) {
|
|
24
|
+
return `.${stableToken(token, options)}`;
|
|
25
|
+
}
|
|
26
|
+
export function createStableClassFactory(options) {
|
|
27
|
+
return (token) => stableClass(token, options);
|
|
28
|
+
}
|
|
29
|
+
export function stableClassName(styles, key, options) {
|
|
30
|
+
const hashed = styles[key] ?? '';
|
|
31
|
+
const token = options?.token ?? String(key);
|
|
32
|
+
const stable = stableClass(token, options);
|
|
33
|
+
const join = options?.join ?? defaultJoin;
|
|
34
|
+
return join([hashed, stable]);
|
|
35
|
+
}
|
|
36
|
+
export const stableClassFromModule = stableClassName;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@knighted/css",
|
|
3
|
-
"version": "1.0.0-rc.
|
|
3
|
+
"version": "1.0.0-rc.4",
|
|
4
4
|
"description": "A build-time utility that traverses JavaScript/TypeScript module dependency graphs to extract, compile, and optimize all imported CSS into a single, in-memory string.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/css.js",
|
|
@@ -32,6 +32,18 @@
|
|
|
32
32
|
"./loader-queries": {
|
|
33
33
|
"types": "./loader-queries.d.ts",
|
|
34
34
|
"default": "./loader-queries.d.ts"
|
|
35
|
+
},
|
|
36
|
+
"./stableSelectors": {
|
|
37
|
+
"types": "./dist/stableSelectors.d.ts",
|
|
38
|
+
"import": "./dist/stableSelectors.js",
|
|
39
|
+
"require": "./dist/cjs/stableSelectors.cjs"
|
|
40
|
+
},
|
|
41
|
+
"./stable": {
|
|
42
|
+
"sass": "./stable/_index.scss",
|
|
43
|
+
"default": "./stable/_index.scss"
|
|
44
|
+
},
|
|
45
|
+
"./stable/stable.css": {
|
|
46
|
+
"default": "./stable/stable.css"
|
|
35
47
|
}
|
|
36
48
|
},
|
|
37
49
|
"keywords": [
|
|
@@ -56,6 +68,11 @@
|
|
|
56
68
|
"dependency-tree": "^11.2.0",
|
|
57
69
|
"lightningcss": "^1.30.2"
|
|
58
70
|
},
|
|
71
|
+
"overrides": {
|
|
72
|
+
"module-lookup-amd": {
|
|
73
|
+
"glob": "^9.0.0"
|
|
74
|
+
}
|
|
75
|
+
},
|
|
59
76
|
"peerDependencies": {
|
|
60
77
|
"@vanilla-extract/integration": "^8.0.0",
|
|
61
78
|
"less": "^4.2.0",
|
|
@@ -75,7 +92,8 @@
|
|
|
75
92
|
"files": [
|
|
76
93
|
"dist",
|
|
77
94
|
"loader-queries.d.ts",
|
|
78
|
-
"types.d.ts"
|
|
95
|
+
"types.d.ts",
|
|
96
|
+
"stable"
|
|
79
97
|
],
|
|
80
98
|
"author": "KCM <knightedcodemonkey@gmail.com>",
|
|
81
99
|
"license": "MIT",
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
// Knighted stable selector mixins
|
|
2
|
+
// Usage: @use '@knighted/css/stable' as knighted;
|
|
3
|
+
// .button { @include knighted.stable('button') { ... } }
|
|
4
|
+
|
|
5
|
+
@use 'sass:meta';
|
|
6
|
+
|
|
7
|
+
$knighted-stable-namespace: 'knighted' !default;
|
|
8
|
+
|
|
9
|
+
@function _knighted-normalize-token($token) {
|
|
10
|
+
@if meta.type-of($token) == 'number' {
|
|
11
|
+
@return $token;
|
|
12
|
+
}
|
|
13
|
+
@return $token;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
@function stable-token($token, $namespace: $knighted-stable-namespace) {
|
|
17
|
+
$normalized-token: _knighted-normalize-token($token);
|
|
18
|
+
@if $namespace == '' {
|
|
19
|
+
@return $normalized-token;
|
|
20
|
+
}
|
|
21
|
+
@return '#{$namespace}-#{$normalized-token}';
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
@function stable-class($token, $namespace: $knighted-stable-namespace) {
|
|
25
|
+
$token-value: stable-token($token, $namespace);
|
|
26
|
+
@return '.#{$token-value}';
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
@mixin stable($token, $namespace: $knighted-stable-namespace) {
|
|
30
|
+
@if not & {
|
|
31
|
+
@error 'The knighted.stable mixin must be used within a selector context so that "&" is defined.';
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
$stable-selector: stable-class($token, $namespace);
|
|
35
|
+
@at-root #{&},
|
|
36
|
+
#{$stable-selector} {
|
|
37
|
+
@content;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
@mixin stable-at-root($selector, $token, $namespace: $knighted-stable-namespace) {
|
|
42
|
+
$stable-selector: stable-class($token, $namespace);
|
|
43
|
+
@at-root #{$selector},
|
|
44
|
+
#{$stable-selector} {
|
|
45
|
+
@content;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
@function stable-class-name($token, $namespace: $knighted-stable-namespace) {
|
|
50
|
+
@return stable-token($token, $namespace);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
@mixin stable-only($token, $namespace: $knighted-stable-namespace) {
|
|
54
|
+
@at-root #{stable-class($token, $namespace)} {
|
|
55
|
+
@content;
|
|
56
|
+
}
|
|
57
|
+
}
|