@css-hooks/core 0.3.1 → 0.7.0

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/README.md ADDED
@@ -0,0 +1,66 @@
1
+ <p align="center">
2
+ <a href="https://css-hooks.com/#gh-dark-mode-only" target="_blank">
3
+ <img alt="CSS Hooks" src="https://raw.githubusercontent.com/css-hooks/css-hooks/HEAD/.github/logo-dark.svg" width="310" height="64" style="max-width: 100%;">
4
+ </a>
5
+ <a href="https://css-hooks.com/#gh-light-mode-only" target="_blank">
6
+ <img alt="CSS Hooks" src="https://raw.githubusercontent.com/css-hooks/css-hooks/HEAD/.github/logo-light.svg" width="310" height="64" style="max-width: 100%;">
7
+ </a>
8
+ </p>
9
+
10
+ <p align="center">
11
+ <a href="https://github.com/css-hooks/css-hooks/actions/workflows/ci.yml"><img src="https://img.shields.io/github/actions/workflow/status/css-hooks/css-hooks/ci.yml?branch=master" alt="Build Status"></a>
12
+ <a href="https://github.com/css-hooks/css-hooks/releases"><img src="https://img.shields.io/npm/v/hooks.css.svg" alt="Latest Release"></a>
13
+ <a href="https://github.com/css-hooks/css-hooks/blob/master/LICENSE"><img src="https://img.shields.io/npm/l/css-hooks.svg" alt="License"></a>
14
+ </p>
15
+
16
+ ---
17
+
18
+ ## Overview
19
+
20
+ Hooks bring CSS features to native inline styles, enabling you to target various
21
+ states such as hover, focus, and active, all without leaving the `style` prop.
22
+ For example, hooks can easily solve the common use case of applying state-driven
23
+ styles to a link:
24
+
25
+ ```jsx
26
+ <a
27
+ href="https://css-hooks.com/"
28
+ style={hooks({
29
+ color: "#03f",
30
+ hover: {
31
+ color: "#09f",
32
+ },
33
+ active: {
34
+ color: "#e33",
35
+ },
36
+ })}
37
+ >
38
+ Hooks
39
+ </a>
40
+ ```
41
+
42
+ Notably, the `hooks` function is pure. It simply returns a flat style object
43
+ that is compatible with the `style` prop, creating dynamic property values that
44
+ change under various conditions through CSS variables.
45
+
46
+ ## Documentation
47
+
48
+ Please visit [css-hooks.com](https://css-hooks.com) to get started.
49
+
50
+ ## Packages
51
+
52
+ - [hooks.css](packages/hooks.css): The style sheet that enables CSS Hooks
53
+ - [@css-hooks/react](packages/react): React framework integration
54
+ - [@css-hooks/solid](packages/solid): Solid framework integration
55
+ - [@css-hooks/preact](packages/preact): Preact framework integration
56
+ - [@css-hooks/core](packages/core): Core CSS Hooks package (internal use only)
57
+
58
+ ## Contributing
59
+
60
+ Contributions are welcome. Please see the
61
+ [contributing guidelines](CONTRIBUTING.md) for more information.
62
+
63
+ ## License
64
+
65
+ CSS Hooks is offered under the [MIT license](LICENSE) by
66
+ [Nick Saunders](https://github.com/nsaunders).
package/cjs/index.js CHANGED
@@ -1,17 +1,117 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.hookTypes = void 0;
4
- /** @internal */
5
- exports.hookTypes = {
3
+ exports.recommended = exports.buildHooksSystem = void 0;
4
+ function buildHooksSystem(stringify) {
5
+ return function createHooks(config) {
6
+ const stringifyImpl = (propertyName, value) => {
7
+ return typeof value === "string" && value.startsWith("var(")
8
+ ? value
9
+ : stringify(propertyName, value);
10
+ };
11
+ function forEachHook(obj, callback) {
12
+ return Object.entries(obj)
13
+ .filter(([key]) => key in config)
14
+ .forEach(([key, value]) => {
15
+ callback(key,
16
+ /* eslint-disable-next-line @typescript-eslint/no-explicit-any,@typescript-eslint/no-unsafe-argument */
17
+ value);
18
+ });
19
+ }
20
+ function hooksImpl(properties, fallback = propertyName => stringifyImpl(propertyName, properties[propertyName])) {
21
+ forEachHook(properties, (key, hook) => {
22
+ hooksImpl(hook, propertyName => {
23
+ let v = stringifyImpl(propertyName, hook[propertyName]);
24
+ if (v === null) {
25
+ v = fallback(propertyName);
26
+ }
27
+ if (v === null) {
28
+ v = "unset";
29
+ }
30
+ return v;
31
+ });
32
+ for (const propertyName in hook) {
33
+ const v1 = stringifyImpl(propertyName, hook[propertyName]);
34
+ if (v1 !== null) {
35
+ let v0 = fallback(propertyName);
36
+ if (v0 === null) {
37
+ v0 = "unset";
38
+ }
39
+ /* eslint-disable @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-explicit-any */
40
+ properties[propertyName] =
41
+ `var(--${String(key)}-1, ${v1}) var(--${String(key)}-0, ${v0})`;
42
+ /* eslint-enable @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-explicit-any */
43
+ }
44
+ }
45
+ delete properties[key];
46
+ });
47
+ return properties;
48
+ }
49
+ function off(name) {
50
+ return `--${name}-0:initial;--${name}-1: ;`;
51
+ }
52
+ function on(name) {
53
+ return `--${name}-0: ;--${name}-1:initial;`;
54
+ }
55
+ return [
56
+ [
57
+ "*{",
58
+ ...Object.keys(config).map(off),
59
+ "}",
60
+ ...Object.entries(config).map(([name, spec]) => {
61
+ if (typeof spec !== "string") {
62
+ return "";
63
+ }
64
+ if (spec.includes("&")) {
65
+ return `${spec.replace(/&/g, "*")}{${on(name)}}`;
66
+ }
67
+ if (spec.startsWith(":")) {
68
+ return `${spec}{${on(name)}}`;
69
+ }
70
+ if (spec.startsWith("@")) {
71
+ return `${spec}{*{${on(name)}}}`;
72
+ }
73
+ return "";
74
+ }),
75
+ ].join(""),
76
+ function hooks(properties) {
77
+ return hooksImpl(properties);
78
+ },
79
+ ];
80
+ };
81
+ }
82
+ exports.buildHooksSystem = buildHooksSystem;
83
+ /**
84
+ * A list of hooks offered as a "sensible default" to solve the most common use cases.
85
+ */
86
+ exports.recommended = {
6
87
  active: ":active",
88
+ autofill: ":autofill",
7
89
  checked: ":checked",
90
+ default: ":default",
8
91
  disabled: ":disabled",
9
- "even-child": ":nth-child(even)",
10
- "first-child": ":first-child",
92
+ empty: ":empty",
93
+ enabled: ":enabled",
94
+ evenChild: ":nth-child(even)",
95
+ firstChild: ":first-child",
96
+ firstOfType: ":first-of-type",
11
97
  focus: ":focus",
12
- "focus-visible": ":focus-visible",
13
- "focus-within": ":focus-within",
98
+ focusVisible: ":focus-visible",
99
+ focusWithin: ":focus-within",
14
100
  hover: ":hover",
15
- "last-child": ":last-child",
16
- "odd-child": ":nth-child(odd)",
101
+ inRange: ":in-range",
102
+ indeterminate: ":indeterminate",
103
+ invalid: ":invalid",
104
+ lastChild: ":last-child",
105
+ lastOfType: ":last-of-type",
106
+ oddChild: ":nth-child(odd)",
107
+ onlyChild: ":only-child",
108
+ onlyOfType: ":only-of-type",
109
+ outOfRange: ":out-of-range",
110
+ placeholderShown: ":placeholder-shown",
111
+ readOnly: ":read-only",
112
+ readWrite: ":read-write",
113
+ required: ":required",
114
+ target: ":target",
115
+ valid: ":valid",
116
+ visited: ":visited",
17
117
  };
package/esm/index.js CHANGED
@@ -1,14 +1,113 @@
1
- /** @internal */
2
- export const hookTypes = {
1
+ export function buildHooksSystem(stringify) {
2
+ return function createHooks(config) {
3
+ const stringifyImpl = (propertyName, value) => {
4
+ return typeof value === "string" && value.startsWith("var(")
5
+ ? value
6
+ : stringify(propertyName, value);
7
+ };
8
+ function forEachHook(obj, callback) {
9
+ return Object.entries(obj)
10
+ .filter(([key]) => key in config)
11
+ .forEach(([key, value]) => {
12
+ callback(key,
13
+ /* eslint-disable-next-line @typescript-eslint/no-explicit-any,@typescript-eslint/no-unsafe-argument */
14
+ value);
15
+ });
16
+ }
17
+ function hooksImpl(properties, fallback = propertyName => stringifyImpl(propertyName, properties[propertyName])) {
18
+ forEachHook(properties, (key, hook) => {
19
+ hooksImpl(hook, propertyName => {
20
+ let v = stringifyImpl(propertyName, hook[propertyName]);
21
+ if (v === null) {
22
+ v = fallback(propertyName);
23
+ }
24
+ if (v === null) {
25
+ v = "unset";
26
+ }
27
+ return v;
28
+ });
29
+ for (const propertyName in hook) {
30
+ const v1 = stringifyImpl(propertyName, hook[propertyName]);
31
+ if (v1 !== null) {
32
+ let v0 = fallback(propertyName);
33
+ if (v0 === null) {
34
+ v0 = "unset";
35
+ }
36
+ /* eslint-disable @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-explicit-any */
37
+ properties[propertyName] =
38
+ `var(--${String(key)}-1, ${v1}) var(--${String(key)}-0, ${v0})`;
39
+ /* eslint-enable @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-explicit-any */
40
+ }
41
+ }
42
+ delete properties[key];
43
+ });
44
+ return properties;
45
+ }
46
+ function off(name) {
47
+ return `--${name}-0:initial;--${name}-1: ;`;
48
+ }
49
+ function on(name) {
50
+ return `--${name}-0: ;--${name}-1:initial;`;
51
+ }
52
+ return [
53
+ [
54
+ "*{",
55
+ ...Object.keys(config).map(off),
56
+ "}",
57
+ ...Object.entries(config).map(([name, spec]) => {
58
+ if (typeof spec !== "string") {
59
+ return "";
60
+ }
61
+ if (spec.includes("&")) {
62
+ return `${spec.replace(/&/g, "*")}{${on(name)}}`;
63
+ }
64
+ if (spec.startsWith(":")) {
65
+ return `${spec}{${on(name)}}`;
66
+ }
67
+ if (spec.startsWith("@")) {
68
+ return `${spec}{*{${on(name)}}}`;
69
+ }
70
+ return "";
71
+ }),
72
+ ].join(""),
73
+ function hooks(properties) {
74
+ return hooksImpl(properties);
75
+ },
76
+ ];
77
+ };
78
+ }
79
+ /**
80
+ * A list of hooks offered as a "sensible default" to solve the most common use cases.
81
+ */
82
+ export const recommended = {
3
83
  active: ":active",
84
+ autofill: ":autofill",
4
85
  checked: ":checked",
86
+ default: ":default",
5
87
  disabled: ":disabled",
6
- "even-child": ":nth-child(even)",
7
- "first-child": ":first-child",
88
+ empty: ":empty",
89
+ enabled: ":enabled",
90
+ evenChild: ":nth-child(even)",
91
+ firstChild: ":first-child",
92
+ firstOfType: ":first-of-type",
8
93
  focus: ":focus",
9
- "focus-visible": ":focus-visible",
10
- "focus-within": ":focus-within",
94
+ focusVisible: ":focus-visible",
95
+ focusWithin: ":focus-within",
11
96
  hover: ":hover",
12
- "last-child": ":last-child",
13
- "odd-child": ":nth-child(odd)",
97
+ inRange: ":in-range",
98
+ indeterminate: ":indeterminate",
99
+ invalid: ":invalid",
100
+ lastChild: ":last-child",
101
+ lastOfType: ":last-of-type",
102
+ oddChild: ":nth-child(odd)",
103
+ onlyChild: ":only-child",
104
+ onlyOfType: ":only-of-type",
105
+ outOfRange: ":out-of-range",
106
+ placeholderShown: ":placeholder-shown",
107
+ readOnly: ":read-only",
108
+ readWrite: ":read-write",
109
+ required: ":required",
110
+ target: ":target",
111
+ valid: ":valid",
112
+ visited: ":visited",
14
113
  };
package/package.json CHANGED
@@ -1,32 +1,41 @@
1
1
  {
2
2
  "name": "@css-hooks/core",
3
3
  "description": "CSS Hooks core library",
4
- "version": "0.3.1",
4
+ "version": "0.7.0",
5
5
  "author": "Nick Saunders",
6
6
  "devDependencies": {
7
7
  "@tsconfig/node-lts": "^18.12.3",
8
8
  "@tsconfig/strictest": "^2.0.1",
9
- "lightningcss": "^1.21.5",
9
+ "@types/css-tree": "^2.3.2",
10
+ "@types/jest": "^29.5.3",
11
+ "@typescript-eslint/eslint-plugin": "^6.3.0",
12
+ "@typescript-eslint/parser": "^6.3.0",
13
+ "css-tree": "^2.3.1",
14
+ "eslint": "^8.47.0",
15
+ "jest": "^29.6.2",
10
16
  "rimraf": "^5.0.1",
11
- "ts-node": "^10.9.1",
17
+ "ts-jest": "^29.1.1",
12
18
  "typescript": "^5.1.6"
13
19
  },
14
20
  "files": [
15
21
  "cjs",
16
- "css",
17
22
  "esm",
18
23
  "types"
19
24
  ],
20
25
  "license": "MIT",
21
- "main": "cjs/index.js",
22
- "module": "esm/index.js",
26
+ "main": "cjs",
27
+ "module": "esm",
23
28
  "private": false,
24
- "repository": "css-hooks/css-hooks",
29
+ "repository": {
30
+ "type": "git",
31
+ "url": "https://github.com/css-hooks/css-hooks.git",
32
+ "directory": "packages/core"
33
+ },
25
34
  "scripts": {
26
- "clean": "rimraf cjs css esm types",
27
- "prepublishOnly": "ts-node ./__fixtures__/generate-css.ts && tsc -p tsconfig.dist.json --outDir esm --module es6 && tsc -p tsconfig.dist.json --outDir cjs --module commonjs && tsc -p tsconfig.dist.json --outDir types --declaration --emitDeclarationOnly",
28
- "test": "echo \"You should add tests.\""
35
+ "clean": "rimraf cjs esm types",
36
+ "lint": "eslint __tests__ src .*.*js *.*js",
37
+ "prepublishOnly": "tsc -p tsconfig.dist.json --outDir esm --module es6 && tsc -p tsconfig.dist.json --outDir cjs --module commonjs && tsc -p tsconfig.dist.json --outDir types --declaration --emitDeclarationOnly",
38
+ "test": "jest"
29
39
  },
30
- "style": "css/index.css",
31
- "types": "types/index.d.ts"
40
+ "types": "types"
32
41
  }
package/types/index.d.ts CHANGED
@@ -1,15 +1,43 @@
1
- /** @internal */
2
- export declare const hookTypes: {
1
+ type UnionToIntersection<T> = (T extends any ? (t: T) => any : never) extends (t: infer U) => any ? U : never;
2
+ type HookSpec = `@${"media" | "container"} ${string}` | `:${string}` | `${string}&${string}`;
3
+ export type WithHooks<HookProperties, Properties> = WithHooksImpl<Properties, HookProperties>;
4
+ type WithHooksImpl<Properties, HookProperties, HookPropertiesSub extends HookProperties = HookProperties> = Properties & Partial<UnionToIntersection<HookPropertiesSub extends string ? {
5
+ [K in HookPropertiesSub]: WithHooksImpl<Properties, Exclude<HookProperties, HookPropertiesSub>>;
6
+ } : never>>;
7
+ export declare function buildHooksSystem<Properties>(stringify: (propertyName: keyof Properties, value: unknown) => string | null): <HookProperties extends string | number | symbol>(config: Record<HookProperties, HookSpec>) => readonly [string, (properties: WithHooks<HookProperties, Properties>) => Properties];
8
+ /**
9
+ * A list of hooks offered as a "sensible default" to solve the most common use cases.
10
+ */
11
+ export declare const recommended: {
3
12
  readonly active: ":active";
13
+ readonly autofill: ":autofill";
4
14
  readonly checked: ":checked";
15
+ readonly default: ":default";
5
16
  readonly disabled: ":disabled";
6
- readonly "even-child": ":nth-child(even)";
7
- readonly "first-child": ":first-child";
17
+ readonly empty: ":empty";
18
+ readonly enabled: ":enabled";
19
+ readonly evenChild: ":nth-child(even)";
20
+ readonly firstChild: ":first-child";
21
+ readonly firstOfType: ":first-of-type";
8
22
  readonly focus: ":focus";
9
- readonly "focus-visible": ":focus-visible";
10
- readonly "focus-within": ":focus-within";
23
+ readonly focusVisible: ":focus-visible";
24
+ readonly focusWithin: ":focus-within";
11
25
  readonly hover: ":hover";
12
- readonly "last-child": ":last-child";
13
- readonly "odd-child": ":nth-child(odd)";
26
+ readonly inRange: ":in-range";
27
+ readonly indeterminate: ":indeterminate";
28
+ readonly invalid: ":invalid";
29
+ readonly lastChild: ":last-child";
30
+ readonly lastOfType: ":last-of-type";
31
+ readonly oddChild: ":nth-child(odd)";
32
+ readonly onlyChild: ":only-child";
33
+ readonly onlyOfType: ":only-of-type";
34
+ readonly outOfRange: ":out-of-range";
35
+ readonly placeholderShown: ":placeholder-shown";
36
+ readonly readOnly: ":read-only";
37
+ readonly readWrite: ":read-write";
38
+ readonly required: ":required";
39
+ readonly target: ":target";
40
+ readonly valid: ":valid";
41
+ readonly visited: ":visited";
14
42
  };
15
- export type HookType = keyof typeof hookTypes;
43
+ export {};
package/css/index.css DELETED
@@ -1,80 +0,0 @@
1
-
2
- .hooks {
3
- --active-0: initial;
4
- --active-1: ;
5
- --checked-0: initial;
6
- --checked-1: ;
7
- --disabled-0: initial;
8
- --disabled-1: ;
9
- --even-child-0: initial;
10
- --even-child-1: ;
11
- --first-child-0: initial;
12
- --first-child-1: ;
13
- --focus-0: initial;
14
- --focus-1: ;
15
- --focus-visible-0: initial;
16
- --focus-visible-1: ;
17
- --focus-within-0: initial;
18
- --focus-within-1: ;
19
- --hover-0: initial;
20
- --hover-1: ;
21
- --last-child-0: initial;
22
- --last-child-1: ;
23
- --odd-child-0: initial;
24
- --odd-child-1: ;
25
- }
26
-
27
- .hooks:active {
28
- --active-0: ;
29
- --active-1: initial;
30
- }
31
-
32
- .hooks:checked {
33
- --checked-0: ;
34
- --checked-1: initial;
35
- }
36
-
37
- .hooks:disabled {
38
- --disabled-0: ;
39
- --disabled-1: initial;
40
- }
41
-
42
- .hooks:nth-child(even) {
43
- --even-child-0: ;
44
- --even-child-1: initial;
45
- }
46
-
47
- .hooks:first-child {
48
- --first-child-0: ;
49
- --first-child-1: initial;
50
- }
51
-
52
- .hooks:focus {
53
- --focus-0: ;
54
- --focus-1: initial;
55
- }
56
-
57
- .hooks:focus-visible {
58
- --focus-visible-0: ;
59
- --focus-visible-1: initial;
60
- }
61
-
62
- .hooks:focus-within {
63
- --focus-within-0: ;
64
- --focus-within-1: initial;
65
- }
66
-
67
- .hooks:hover {
68
- --hover-0: ;
69
- --hover-1: initial;
70
- }
71
-
72
- .hooks:last-child {
73
- --last-child-0: ;
74
- --last-child-1: initial;
75
- }
76
-
77
- .hooks:nth-child(odd) {
78
- --odd-child-0: ;
79
- --odd-child-1: initial;
80
- }
package/css/index.min.css DELETED
@@ -1 +0,0 @@
1
- .hooks{--active-0:initial;--active-1: ;--checked-0:initial;--checked-1: ;--disabled-0:initial;--disabled-1: ;--even-child-0:initial;--even-child-1: ;--first-child-0:initial;--first-child-1: ;--focus-0:initial;--focus-1: ;--focus-visible-0:initial;--focus-visible-1: ;--focus-within-0:initial;--focus-within-1: ;--hover-0:initial;--hover-1: ;--last-child-0:initial;--last-child-1: ;--odd-child-0:initial;--odd-child-1: }.hooks:active{--active-0: ;--active-1:initial}.hooks:checked{--checked-0: ;--checked-1:initial}.hooks:disabled{--disabled-0: ;--disabled-1:initial}.hooks:nth-child(2n){--even-child-0: ;--even-child-1:initial}.hooks:first-child{--first-child-0: ;--first-child-1:initial}.hooks:focus{--focus-0: ;--focus-1:initial}.hooks:focus-visible{--focus-visible-0: ;--focus-visible-1:initial}.hooks:focus-within{--focus-within-0: ;--focus-within-1:initial}.hooks:hover{--hover-0: ;--hover-1:initial}.hooks:last-child{--last-child-0: ;--last-child-1:initial}.hooks:nth-child(odd){--odd-child-0: ;--odd-child-1:initial}
@@ -1 +0,0 @@
1
- {"version":3,"sourceRoot":null,"mappings":"AACA,maAyBA,8CAKA,iDAKA,oDAKA,6DAKA,6DAKA,2CAKA,mEAKA,gEAKA,2CAKA,0DAKA","sources":["index.css"],"sourcesContent":["\n.hooks {\n --active-0: initial;\n --active-1: ;\n --checked-0: initial;\n --checked-1: ;\n --disabled-0: initial;\n --disabled-1: ;\n --even-child-0: initial;\n --even-child-1: ;\n --first-child-0: initial;\n --first-child-1: ;\n --focus-0: initial;\n --focus-1: ;\n --focus-visible-0: initial;\n --focus-visible-1: ;\n --focus-within-0: initial;\n --focus-within-1: ;\n --hover-0: initial;\n --hover-1: ;\n --last-child-0: initial;\n --last-child-1: ;\n --odd-child-0: initial;\n --odd-child-1: ;\n}\n\n.hooks:active {\n --active-0: ;\n --active-1: initial;\n}\n\n.hooks:checked {\n --checked-0: ;\n --checked-1: initial;\n}\n\n.hooks:disabled {\n --disabled-0: ;\n --disabled-1: initial;\n}\n\n.hooks:nth-child(even) {\n --even-child-0: ;\n --even-child-1: initial;\n}\n\n.hooks:first-child {\n --first-child-0: ;\n --first-child-1: initial;\n}\n\n.hooks:focus {\n --focus-0: ;\n --focus-1: initial;\n}\n\n.hooks:focus-visible {\n --focus-visible-0: ;\n --focus-visible-1: initial;\n}\n\n.hooks:focus-within {\n --focus-within-0: ;\n --focus-within-1: initial;\n}\n\n.hooks:hover {\n --hover-0: ;\n --hover-1: initial;\n}\n\n.hooks:last-child {\n --last-child-0: ;\n --last-child-1: initial;\n}\n\n.hooks:nth-child(odd) {\n --odd-child-0: ;\n --odd-child-1: initial;\n}\n"],"names":[]}