@pre.style/core 3.1.0-alpha.2 → 3.1.0-alpha.3

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/index.js CHANGED
@@ -4,10 +4,10 @@
4
4
  function notTransformed() {
5
5
  throw new Error('pre.style transform not applied. css and scss blocks must be compiled by a pre.style bundler plugin, such as @pre.style/vite.');
6
6
  }
7
- export function css(_strings) {
7
+ export function css(_strings, ..._values) {
8
8
  return notTransformed();
9
9
  }
10
- export function scss(_strings) {
10
+ export function scss(_strings, ..._values) {
11
11
  return notTransformed();
12
12
  }
13
13
  import { createCn } from './cn.js';
@@ -0,0 +1,2 @@
1
+ export declare const dynamic: (classes: string, values: readonly unknown[], ...variables: import("./runtime.ts").RuntimeVariable[]) => string;
2
+ export declare const dynamicLowercase: (classes: string, values: readonly unknown[], ...variables: import("./runtime.ts").RuntimeVariable[]) => string;
@@ -0,0 +1,9 @@
1
+ import { CASE_INSENSITIVE, CASE_SENSITIVE, create } from './runtime.js';
2
+ // `./runtime.ts` with full error messages, which the bundler plugin uses
3
+ // outside production builds.
4
+ const invalidValue = (value, strings) => {
5
+ const got = typeof value === 'number' ? String(value) : typeof value;
6
+ throw new TypeError(`pre.style: \`\${…}\` values must be strings or numbers, or null or undefined to use the default. Got ${got} in \`${strings.join('${…}')}\`. For a condition, write \`\${open ? width : null}\` rather than \`\${open && width}\`.`);
7
+ };
8
+ export const dynamic = /* @__PURE__ */ create(CASE_SENSITIVE, invalidValue);
9
+ export const dynamicLowercase = /* @__PURE__ */ create(CASE_INSENSITIVE, invalidValue);
@@ -0,0 +1,16 @@
1
+ import type { CnLookup } from './cn.ts';
2
+ export type RuntimeVariable = [
3
+ name: string,
4
+ strings: readonly string[],
5
+ indexes: readonly number[],
6
+ property?: string | 0,
7
+ selector?: readonly string[]
8
+ ];
9
+ export declare const CASE_SENSITIVE: string;
10
+ export declare const CASE_INSENSITIVE: string;
11
+ export type InvalidValue = (value: unknown, strings: readonly string[]) => never;
12
+ export declare const create: (alphabet: string, invalid: InvalidValue) => (classes: string, values: readonly unknown[], ...variables: RuntimeVariable[]) => string;
13
+ export declare const dynamic: (classes: string, values: readonly unknown[], ...variables: RuntimeVariable[]) => string;
14
+ export declare const dynamicLowercase: (classes: string, values: readonly unknown[], ...variables: RuntimeVariable[]) => string;
15
+ export type CnVariables = Record<string, string>;
16
+ export declare const generatedClasses: (variables: CnVariables) => CnLookup;
@@ -0,0 +1,99 @@
1
+ const DIGITS = '0123456789';
2
+ const LOWERCASE = 'abcdefghijklmnopqrstuvwxyz';
3
+ export const CASE_SENSITIVE = DIGITS + LOWERCASE + LOWERCASE.toUpperCase();
4
+ export const CASE_INSENSITIVE = DIGITS + LOWERCASE;
5
+ const HASH_LENGTH = 4;
6
+ // A hash of a value that's the same on the server and in the browser, since
7
+ // the class names it's part of have to match for hydration. FNV-1a.
8
+ function hash(value, alphabet) {
9
+ let h = 0x811c9dc5;
10
+ for (let i = 0; i < value.length; i++) {
11
+ h ^= value.charCodeAt(i);
12
+ h = Math.imul(h, 0x01000193);
13
+ }
14
+ h >>>= 0;
15
+ let result = '';
16
+ for (let i = 0; i < HASH_LENGTH; i++) {
17
+ result += alphabet[h % alphabet.length];
18
+ h = Math.floor(h / alphabet.length);
19
+ }
20
+ return result;
21
+ }
22
+ // The variable's value, or null when any of its values is null or undefined,
23
+ // so its default applies. Anything else is almost always a bug, which falling
24
+ // back would hide.
25
+ function text(strings, indexes, values, invalid) {
26
+ let result = strings[0];
27
+ let missing = false;
28
+ for (let i = 0; i < indexes.length; i++) {
29
+ const value = values[indexes[i]];
30
+ if (value === null || value === undefined)
31
+ missing = true;
32
+ else if (typeof value === 'string' || (typeof value === 'number' && Number.isFinite(value)))
33
+ result += value + strings[i + 1];
34
+ else
35
+ invalid(value, strings);
36
+ }
37
+ return missing ? null : result;
38
+ }
39
+ let sheet;
40
+ const inserted = new Set();
41
+ // Inserts a generated class's rule once. `setProperty` parses the value alone,
42
+ // so a value can't add rules or declarations, even if it comes from a user.
43
+ function insert(selector, className, property, value) {
44
+ if (inserted.has(className))
45
+ return;
46
+ inserted.add(className);
47
+ // An unknown selector is ignored, as it is in the CSS file. Browsers without
48
+ // constructable stylesheets, or where the list can't be changed (Chrome before
49
+ // 99, Firefox before 101, Safari before 16.4), keep the defaults rather than
50
+ // failing the render.
51
+ try {
52
+ if (sheet === undefined) {
53
+ sheet = new CSSStyleSheet();
54
+ document.adoptedStyleSheets.push(sheet);
55
+ }
56
+ const index = sheet.insertRule(`${selector}{}`, sheet.cssRules.length);
57
+ sheet.cssRules[index].style.setProperty(property, value);
58
+ }
59
+ catch { }
60
+ }
61
+ export const create = (alphabet, invalid) => (classes, values, ...variables) => {
62
+ let result = classes;
63
+ for (const [name, strings, indexes, property, selector] of variables) {
64
+ const value = text(strings, indexes, values, invalid);
65
+ if (value === null)
66
+ continue;
67
+ const className = `_${name}${hash(value, alphabet)}`;
68
+ // The server returns the same class strings, without the rules, so
69
+ // hydration matches and the page uses its defaults until this runs.
70
+ if (typeof document !== 'undefined')
71
+ insert(selector ? selector.join(`.${className}`) : `.${className}`, className, property || `--${name}`, value);
72
+ result += result === '' ? className : ` ${className}`;
73
+ }
74
+ return result;
75
+ };
76
+ // Production errors are numbered, to keep the runtime small. The site's
77
+ // `/errors` pages explain them, and `./runtime-dev.ts` has the full messages.
78
+ const invalidValue = (value) => {
79
+ throw new TypeError(`pre.style error 1 (${typeof value}): https://pre.style/errors/1`);
80
+ };
81
+ // What a block with `${…}` compiles to. It takes the block's class string, its
82
+ // expressions' values, so each runs once and in order, and its variables, and
83
+ // returns the class string with a generated class for each value.
84
+ export const dynamic = /* @__PURE__ */ create(CASE_SENSITIVE, invalidValue);
85
+ // For the `quirksMode` setting, where class selectors ignore case.
86
+ export const dynamicLowercase = /* @__PURE__ */ create(CASE_INSENSITIVE, invalidValue);
87
+ // A `cn` lookup that also recognizes generated classes, which aren't in its
88
+ // table: `_`, a variable's name, and four characters. Each sets its variable on
89
+ // the element. It's here rather than in `cn`, so apps without `${…}` don't ship
90
+ // it.
91
+ export const generatedClasses = (variables) => new (class extends Map {
92
+ get(className) {
93
+ const name = className.slice(1, -4);
94
+ return (super.get(className) ??
95
+ (className[0] === '_' && Object.hasOwn(variables, name)
96
+ ? ['', variables[name] || `--${name}`]
97
+ : undefined));
98
+ }
99
+ })();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pre.style/core",
3
- "version": "3.1.0-alpha.2",
3
+ "version": "3.1.0-alpha.3",
4
4
  "description": "Zero-runtime CSS-in-JS that compiles css and scss blocks into atomic CSS classes.",
5
5
  "keywords": [
6
6
  "atomic-css",
@@ -37,6 +37,16 @@
37
37
  "types": "./dist/index.d.ts",
38
38
  "default": "./dist/index.js"
39
39
  },
40
+ "./runtime": {
41
+ "pre.style-source": "./src/runtime.ts",
42
+ "types": "./dist/runtime.d.ts",
43
+ "default": "./dist/runtime.js"
44
+ },
45
+ "./runtime/dev": {
46
+ "pre.style-source": "./src/runtime-dev.ts",
47
+ "types": "./dist/runtime-dev.d.ts",
48
+ "default": "./dist/runtime-dev.js"
49
+ },
40
50
  "./compiler": {
41
51
  "pre.style-source": "./src/compiler/index.ts",
42
52
  "types": "./dist/compiler/index.d.ts",
@@ -61,6 +61,10 @@
61
61
  "prependFiles": {
62
62
  "$ref": "#/definitions/prependFiles"
63
63
  },
64
+ "customPropertyLocalization": {
65
+ "description": "Give each custom property declared in the library's blocks and stylesheet files a generated name, used only in the block or file that declares it. Names it only reads, and names from prepended files, stay global. The app's setting doesn't apply to libraries.",
66
+ "type": "boolean"
67
+ },
64
68
  "keyframeLocalization": {
65
69
  "description": "Give each @keyframes in the library's blocks and stylesheet files a generated name, used only in the block or file that defines it, like styled-components' `keyframes`. The app's setting doesn't apply to libraries.",
66
70
  "type": "boolean"
@@ -88,6 +92,10 @@
88
92
  "prependFiles": {
89
93
  "$ref": "#/definitions/prependFiles"
90
94
  },
95
+ "customPropertyLocalization": {
96
+ "description": "Give each custom property declared in the app's blocks and stylesheet files a generated name, used only in the block or file that declares it. Names it only reads, and names from prepended files, stay global. Libraries use their own setting.",
97
+ "type": "boolean"
98
+ },
91
99
  "keyframeLocalization": {
92
100
  "description": "Give each @keyframes in the app's blocks and stylesheet files a generated name, used only in the block or file that defines it (including keyframes from prepended files), like styled-components' `keyframes`. Libraries use their own setting.",
93
101
  "type": "boolean"