@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 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.2",
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
+ }
@@ -0,0 +1,15 @@
1
+ @layer knighted.stable;
2
+
3
+ :root {
4
+ --knighted-stable-namespace: 'knighted';
5
+ }
6
+
7
+ /*
8
+ Usage:
9
+ @import '@knighted/css/stable/stable.css';
10
+ @layer knighted.stable {
11
+ .knighted-button {
12
+ declarations go here;
13
+ }
14
+ }
15
+ */