@css-hooks/core 1.2.1 → 1.4.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 CHANGED
@@ -23,22 +23,26 @@ styles to a link:
23
23
  ```jsx
24
24
  <a
25
25
  href="https://css-hooks.com/"
26
- style={hooks({
26
+ style={css({
27
27
  color: "#03f",
28
- hover: {
28
+ fontSize: "1rem",
29
+ "&:hover": {
29
30
  color: "#09f",
30
31
  },
31
- active: {
32
+ "&:active": {
32
33
  color: "#e33",
33
34
  },
35
+ "@media (1000px <= width)": {
36
+ fontSize: "1.25rem",
37
+ },
34
38
  })}
35
39
  >
36
40
  Hooks
37
41
  </a>
38
42
  ```
39
43
 
40
- Notably, the `hooks` function is pure. It simply returns a flat style object
41
- that is compatible with the `style` prop, creating dynamic property values that
44
+ Notably, the `css` function is pure. It simply returns a flat style object that
45
+ is compatible with the `style` prop, creating dynamic property values that
42
46
  change under various conditions through CSS variables.
43
47
 
44
48
  ## Documentation
package/cjs/index.js CHANGED
@@ -32,52 +32,38 @@ function genericStringify(_, value) {
32
32
  return null;
33
33
  }
34
34
  exports.genericStringify = genericStringify;
35
+ function hash(obj) {
36
+ const jsonString = JSON.stringify(obj);
37
+ let hashValue = 0;
38
+ for (let i = 0; i < jsonString.length; i++) {
39
+ const charCode = jsonString.charCodeAt(i);
40
+ hashValue = (hashValue << 5) - hashValue + charCode;
41
+ hashValue &= 0x7fffffff;
42
+ }
43
+ return hashValue.toString(36);
44
+ }
35
45
  function buildHooksSystem(stringify = genericStringify) {
36
- return function createHooks(config) {
46
+ return function createHooks(config, options) {
37
47
  const stringifyImpl = (propertyName, value) => {
38
48
  return typeof value === "string" && value.startsWith("var(")
39
49
  ? value
40
50
  : stringify(propertyName, value);
41
51
  };
42
- function forEachHook(obj, callback) {
43
- return Object.entries(obj)
44
- .filter(([key]) => key in config)
45
- .forEach(([key, value]) => {
46
- callback(key,
47
- /* eslint-disable-next-line @typescript-eslint/no-explicit-any,@typescript-eslint/no-unsafe-argument */
48
- value);
52
+ const hookId = (options === null || options === void 0 ? void 0 : options.hookNameToId) ||
53
+ ((hookName) => {
54
+ const specHash = hash(config[hookName]);
55
+ return (options === null || options === void 0 ? void 0 : options.debug)
56
+ ? `${hookName.replace(/[^A-Za-z0-9-]/g, "_")}-${specHash}`
57
+ : specHash;
49
58
  });
50
- }
51
- function hooksImpl(properties, fallback = propertyName => stringifyImpl(propertyName, properties[propertyName])) {
52
- forEachHook(properties, (key, hook) => {
53
- hooksImpl(hook, propertyName => {
54
- let v = stringifyImpl(propertyName, hook[propertyName]);
55
- if (v === null) {
56
- v = fallback(propertyName);
57
- }
58
- if (v === null) {
59
- v = "unset";
60
- }
61
- return v;
62
- });
63
- for (const propertyName in hook) {
64
- const v1 = stringifyImpl(propertyName, hook[propertyName]);
65
- if (v1 !== null) {
66
- let v0 = fallback(propertyName);
67
- if (v0 === null) {
68
- v0 = "unset";
69
- }
70
- /* eslint-disable @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-explicit-any */
71
- properties[propertyName] =
72
- `var(--${String(key)}-1, ${v1}) var(--${String(key)}-0, ${v0})`;
73
- /* eslint-enable @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-explicit-any */
74
- }
75
- }
76
- delete properties[key];
59
+ function forEachHook(properties, callback) {
60
+ return Object.entries(properties)
61
+ .filter(([key]) => key in config)
62
+ .forEach(([hookName, value]) => {
63
+ callback(hookName, value);
77
64
  });
78
- return properties;
79
65
  }
80
- const css = Object.entries(config)
66
+ const hooks = Object.entries(config)
81
67
  .map(([name, definition]) => {
82
68
  function nest(input) {
83
69
  if (typeof input === "object") {
@@ -107,12 +93,12 @@ function buildHooksSystem(stringify = genericStringify) {
107
93
  }
108
94
  return [name, nest(definition)];
109
95
  })
110
- .flatMap(function css([name, definition]) {
96
+ .flatMap(([name, definition]) => (function hooksCSS(name, definition) {
111
97
  if (!isHookSpec(definition)) {
112
98
  return [];
113
99
  }
114
100
  if (typeof definition === "object") {
115
- let a, operator, b, extraCSS = [];
101
+ let a, operator, b, extraHooksCSS = [];
116
102
  if ("or" in definition) {
117
103
  operator = "or";
118
104
  [a, b] = definition.or;
@@ -120,9 +106,9 @@ function buildHooksSystem(stringify = genericStringify) {
120
106
  return [];
121
107
  }
122
108
  if (!b) {
123
- return css.bind(this)([name, a]);
109
+ return hooksCSS(name, a);
124
110
  }
125
- extraCSS = [
111
+ extraHooksCSS = [
126
112
  {
127
113
  init: (function aorb(x) {
128
114
  const a = `${x}A`;
@@ -142,9 +128,9 @@ function buildHooksSystem(stringify = genericStringify) {
142
128
  return [];
143
129
  }
144
130
  if (!b) {
145
- return css.bind(this)([name, a]);
131
+ return hooksCSS(name, a);
146
132
  }
147
- extraCSS = [
133
+ extraHooksCSS = [
148
134
  {
149
135
  init: (function aandb(x) {
150
136
  const a = `${x}A`;
@@ -159,9 +145,9 @@ function buildHooksSystem(stringify = genericStringify) {
159
145
  }
160
146
  if (operator) {
161
147
  return [
162
- ...css.bind(this)([`${name}A`, a]),
163
- ...css.bind(this)([`${name}B`, b]),
164
- ...extraCSS,
148
+ ...hooksCSS(`${name}A`, a),
149
+ ...hooksCSS(`${name}B`, b),
150
+ ...extraHooksCSS,
165
151
  ];
166
152
  }
167
153
  }
@@ -179,7 +165,7 @@ function buildHooksSystem(stringify = genericStringify) {
179
165
  }
180
166
  }
181
167
  return rule === undefined ? [] : [{ init, rule }];
182
- })
168
+ })(hookId(name), definition))
183
169
  .reduce((acc, { init = "", rule = "" }) => ({
184
170
  init: acc.init + init,
185
171
  rule: acc.rule + rule,
@@ -187,10 +173,39 @@ function buildHooksSystem(stringify = genericStringify) {
187
173
  init: "",
188
174
  rule: "",
189
175
  });
176
+ function cssImpl(properties, fallback = propertyName => stringifyImpl(propertyName, properties[propertyName])) {
177
+ forEachHook(properties, (hookName, innerProperties) => {
178
+ cssImpl(innerProperties, propertyName => {
179
+ let v = stringifyImpl(propertyName, innerProperties[propertyName]);
180
+ if (v === null) {
181
+ v = fallback(propertyName);
182
+ }
183
+ if (v === null) {
184
+ v = "unset";
185
+ }
186
+ return v;
187
+ });
188
+ for (const propertyName in innerProperties) {
189
+ const v1 = stringifyImpl(propertyName, innerProperties[propertyName]);
190
+ if (v1 !== null) {
191
+ let v0 = fallback(propertyName);
192
+ if (v0 === null) {
193
+ v0 = "unset";
194
+ }
195
+ /* eslint-disable @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-explicit-any */
196
+ properties[propertyName] =
197
+ `var(--${hookId(hookName)}-1, ${v1}) var(--${hookId(hookName)}-0, ${v0})`;
198
+ /* eslint-enable @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-explicit-any */
199
+ }
200
+ }
201
+ delete properties[hookName];
202
+ });
203
+ return properties;
204
+ }
190
205
  return [
191
- `*{${css.init}}${css.rule}`,
192
- function hooks(properties) {
193
- return hooksImpl(JSON.parse(JSON.stringify(properties)));
206
+ `*{${hooks.init}}${hooks.rule}`,
207
+ function css(properties) {
208
+ return cssImpl(JSON.parse(JSON.stringify(properties)));
194
209
  },
195
210
  ];
196
211
  };
@@ -198,6 +213,8 @@ function buildHooksSystem(stringify = genericStringify) {
198
213
  exports.buildHooksSystem = buildHooksSystem;
199
214
  /**
200
215
  * A list of hooks offered as a "sensible default" to solve the most common use cases.
216
+ *
217
+ * @deprecated Use the `@css-hooks/recommended` package instead.
201
218
  */
202
219
  exports.recommended = {
203
220
  active: ":active",
package/esm/index.js CHANGED
@@ -28,52 +28,38 @@ export function genericStringify(_, value) {
28
28
  }
29
29
  return null;
30
30
  }
31
+ function hash(obj) {
32
+ const jsonString = JSON.stringify(obj);
33
+ let hashValue = 0;
34
+ for (let i = 0; i < jsonString.length; i++) {
35
+ const charCode = jsonString.charCodeAt(i);
36
+ hashValue = (hashValue << 5) - hashValue + charCode;
37
+ hashValue &= 0x7fffffff;
38
+ }
39
+ return hashValue.toString(36);
40
+ }
31
41
  export function buildHooksSystem(stringify = genericStringify) {
32
- return function createHooks(config) {
42
+ return function createHooks(config, options) {
33
43
  const stringifyImpl = (propertyName, value) => {
34
44
  return typeof value === "string" && value.startsWith("var(")
35
45
  ? value
36
46
  : stringify(propertyName, value);
37
47
  };
38
- function forEachHook(obj, callback) {
39
- return Object.entries(obj)
40
- .filter(([key]) => key in config)
41
- .forEach(([key, value]) => {
42
- callback(key,
43
- /* eslint-disable-next-line @typescript-eslint/no-explicit-any,@typescript-eslint/no-unsafe-argument */
44
- value);
48
+ const hookId = (options === null || options === void 0 ? void 0 : options.hookNameToId) ||
49
+ ((hookName) => {
50
+ const specHash = hash(config[hookName]);
51
+ return (options === null || options === void 0 ? void 0 : options.debug)
52
+ ? `${hookName.replace(/[^A-Za-z0-9-]/g, "_")}-${specHash}`
53
+ : specHash;
45
54
  });
46
- }
47
- function hooksImpl(properties, fallback = propertyName => stringifyImpl(propertyName, properties[propertyName])) {
48
- forEachHook(properties, (key, hook) => {
49
- hooksImpl(hook, propertyName => {
50
- let v = stringifyImpl(propertyName, hook[propertyName]);
51
- if (v === null) {
52
- v = fallback(propertyName);
53
- }
54
- if (v === null) {
55
- v = "unset";
56
- }
57
- return v;
58
- });
59
- for (const propertyName in hook) {
60
- const v1 = stringifyImpl(propertyName, hook[propertyName]);
61
- if (v1 !== null) {
62
- let v0 = fallback(propertyName);
63
- if (v0 === null) {
64
- v0 = "unset";
65
- }
66
- /* eslint-disable @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-explicit-any */
67
- properties[propertyName] =
68
- `var(--${String(key)}-1, ${v1}) var(--${String(key)}-0, ${v0})`;
69
- /* eslint-enable @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-explicit-any */
70
- }
71
- }
72
- delete properties[key];
55
+ function forEachHook(properties, callback) {
56
+ return Object.entries(properties)
57
+ .filter(([key]) => key in config)
58
+ .forEach(([hookName, value]) => {
59
+ callback(hookName, value);
73
60
  });
74
- return properties;
75
61
  }
76
- const css = Object.entries(config)
62
+ const hooks = Object.entries(config)
77
63
  .map(([name, definition]) => {
78
64
  function nest(input) {
79
65
  if (typeof input === "object") {
@@ -103,12 +89,12 @@ export function buildHooksSystem(stringify = genericStringify) {
103
89
  }
104
90
  return [name, nest(definition)];
105
91
  })
106
- .flatMap(function css([name, definition]) {
92
+ .flatMap(([name, definition]) => (function hooksCSS(name, definition) {
107
93
  if (!isHookSpec(definition)) {
108
94
  return [];
109
95
  }
110
96
  if (typeof definition === "object") {
111
- let a, operator, b, extraCSS = [];
97
+ let a, operator, b, extraHooksCSS = [];
112
98
  if ("or" in definition) {
113
99
  operator = "or";
114
100
  [a, b] = definition.or;
@@ -116,9 +102,9 @@ export function buildHooksSystem(stringify = genericStringify) {
116
102
  return [];
117
103
  }
118
104
  if (!b) {
119
- return css.bind(this)([name, a]);
105
+ return hooksCSS(name, a);
120
106
  }
121
- extraCSS = [
107
+ extraHooksCSS = [
122
108
  {
123
109
  init: (function aorb(x) {
124
110
  const a = `${x}A`;
@@ -138,9 +124,9 @@ export function buildHooksSystem(stringify = genericStringify) {
138
124
  return [];
139
125
  }
140
126
  if (!b) {
141
- return css.bind(this)([name, a]);
127
+ return hooksCSS(name, a);
142
128
  }
143
- extraCSS = [
129
+ extraHooksCSS = [
144
130
  {
145
131
  init: (function aandb(x) {
146
132
  const a = `${x}A`;
@@ -155,9 +141,9 @@ export function buildHooksSystem(stringify = genericStringify) {
155
141
  }
156
142
  if (operator) {
157
143
  return [
158
- ...css.bind(this)([`${name}A`, a]),
159
- ...css.bind(this)([`${name}B`, b]),
160
- ...extraCSS,
144
+ ...hooksCSS(`${name}A`, a),
145
+ ...hooksCSS(`${name}B`, b),
146
+ ...extraHooksCSS,
161
147
  ];
162
148
  }
163
149
  }
@@ -175,7 +161,7 @@ export function buildHooksSystem(stringify = genericStringify) {
175
161
  }
176
162
  }
177
163
  return rule === undefined ? [] : [{ init, rule }];
178
- })
164
+ })(hookId(name), definition))
179
165
  .reduce((acc, { init = "", rule = "" }) => ({
180
166
  init: acc.init + init,
181
167
  rule: acc.rule + rule,
@@ -183,16 +169,47 @@ export function buildHooksSystem(stringify = genericStringify) {
183
169
  init: "",
184
170
  rule: "",
185
171
  });
172
+ function cssImpl(properties, fallback = propertyName => stringifyImpl(propertyName, properties[propertyName])) {
173
+ forEachHook(properties, (hookName, innerProperties) => {
174
+ cssImpl(innerProperties, propertyName => {
175
+ let v = stringifyImpl(propertyName, innerProperties[propertyName]);
176
+ if (v === null) {
177
+ v = fallback(propertyName);
178
+ }
179
+ if (v === null) {
180
+ v = "unset";
181
+ }
182
+ return v;
183
+ });
184
+ for (const propertyName in innerProperties) {
185
+ const v1 = stringifyImpl(propertyName, innerProperties[propertyName]);
186
+ if (v1 !== null) {
187
+ let v0 = fallback(propertyName);
188
+ if (v0 === null) {
189
+ v0 = "unset";
190
+ }
191
+ /* eslint-disable @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-explicit-any */
192
+ properties[propertyName] =
193
+ `var(--${hookId(hookName)}-1, ${v1}) var(--${hookId(hookName)}-0, ${v0})`;
194
+ /* eslint-enable @typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-explicit-any */
195
+ }
196
+ }
197
+ delete properties[hookName];
198
+ });
199
+ return properties;
200
+ }
186
201
  return [
187
- `*{${css.init}}${css.rule}`,
188
- function hooks(properties) {
189
- return hooksImpl(JSON.parse(JSON.stringify(properties)));
202
+ `*{${hooks.init}}${hooks.rule}`,
203
+ function css(properties) {
204
+ return cssImpl(JSON.parse(JSON.stringify(properties)));
190
205
  },
191
206
  ];
192
207
  };
193
208
  }
194
209
  /**
195
210
  * A list of hooks offered as a "sensible default" to solve the most common use cases.
211
+ *
212
+ * @deprecated Use the `@css-hooks/recommended` package instead.
196
213
  */
197
214
  export const recommended = {
198
215
  active: ":active",
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@css-hooks/core",
3
3
  "description": "CSS Hooks core library",
4
- "version": "1.2.1",
4
+ "version": "1.4.0",
5
5
  "author": "Nick Saunders",
6
6
  "devDependencies": {
7
7
  "@tsconfig/strictest": "^2.0.1",
package/types/index.d.ts CHANGED
@@ -10,9 +10,17 @@ type WithHooksImpl<Properties, HookProperties, HookPropertiesSub extends HookPro
10
10
  } : never>>;
11
11
  /** @internal */
12
12
  export declare function genericStringify(_: unknown, value: unknown): string | null;
13
- export declare function buildHooksSystem<Properties = Record<string, unknown>>(stringify?: (propertyName: keyof Properties, value: unknown) => string | null): <HookProperties extends string>(config: Record<HookProperties, HookSpec>) => readonly [`*{${string}}undefined` | `*{${string}}${string}`, (properties: WithHooks<HookProperties, Properties>) => Properties];
13
+ export declare function buildHooksSystem<Properties = Record<string, unknown>>(stringify?: (propertyName: keyof Properties, value: unknown) => string | null): <HookProperties extends string>(config: Record<HookProperties, HookSpec>, options?: {
14
+ debug?: boolean; /** @internal */
15
+ hookNameToId?: undefined;
16
+ } | {
17
+ debug?: undefined;
18
+ /** @internal */ hookNameToId?: (hookName: string) => string;
19
+ } | undefined) => readonly [`*{${string}}undefined` | `*{${string}}${string}`, (properties: WithHooks<HookProperties, Properties>) => Properties];
14
20
  /**
15
21
  * A list of hooks offered as a "sensible default" to solve the most common use cases.
22
+ *
23
+ * @deprecated Use the `@css-hooks/recommended` package instead.
16
24
  */
17
25
  export declare const recommended: {
18
26
  readonly active: ":active";