@css-hooks/core 1.8.2 → 2.0.1

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/cjs/index.js CHANGED
@@ -1,273 +1,308 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.recommended = exports.buildHooksSystem = exports.genericStringify = void 0;
4
- function isHookSpec(x) {
5
- if (!x) {
6
- return false;
7
- }
8
- if (typeof x === "string") {
9
- return (x.startsWith(":") ||
10
- x.startsWith("@media ") ||
11
- x.startsWith("@container ") ||
12
- x.startsWith("@supports ") ||
13
- x.includes("&"));
14
- }
15
- if (typeof x === "object") {
16
- if ("or" in x && x.or instanceof Array) {
17
- return !x.or.some(xx => !isHookSpec(xx));
18
- }
19
- if ("and" in x && x.and instanceof Array) {
20
- return !x.and.some(xx => !isHookSpec(xx));
21
- }
22
- }
23
- return false;
24
- }
25
- /** @internal */
1
+ 'use strict';
2
+ // @ts-nocheck
3
+
4
+ const helpers = {
5
+ and: (...and) => ({ and }),
6
+ or: (...or) => ({ or }),
7
+ not: not => ({ not }),
8
+ };
9
+
26
10
  function genericStringify(_, value) {
27
- if (typeof value === "string") {
28
- return value;
29
- }
30
- if (typeof value === "number") {
31
- return `${value}`;
32
- }
33
- return null;
11
+ if (typeof value === "string") {
12
+ return value;
13
+ }
14
+
15
+ if (typeof value === "number") {
16
+ return `${value}`;
17
+ }
18
+
19
+ return null;
34
20
  }
35
- exports.genericStringify = genericStringify;
21
+
36
22
  function hash(obj) {
37
- const jsonString = JSON.stringify(obj);
38
- let hashValue = 0;
39
- for (let i = 0; i < jsonString.length; i++) {
40
- const charCode = jsonString.charCodeAt(i);
41
- hashValue = (hashValue << 5) - hashValue + charCode;
42
- hashValue &= 0x7fffffff;
23
+ const jsonString = JSON.stringify(obj);
24
+
25
+ let hashValue = 0;
26
+
27
+ for (let i = 0; i < jsonString.length; i++) {
28
+ const charCode = jsonString.charCodeAt(i);
29
+ hashValue = (hashValue << 5) - hashValue + charCode;
30
+ hashValue &= 0x7fffffff;
31
+ }
32
+
33
+ return hashValue.toString(36);
34
+ }
35
+
36
+ function normalizeCondition(cond) {
37
+ if (!cond) {
38
+ return undefined;
39
+ }
40
+ if (typeof cond === "string") {
41
+ return cond;
42
+ }
43
+ if (typeof cond !== "object") {
44
+ return undefined;
45
+ }
46
+ if ("not" in cond) {
47
+ if (!cond.not) {
48
+ return undefined;
43
49
  }
44
- return hashValue.toString(36);
50
+ if (cond.not.not) {
51
+ return normalizeCondition(cond.not.not);
52
+ }
53
+ const inner = normalizeCondition(cond.not);
54
+ return inner ? { not: inner } : undefined;
55
+ }
56
+ const [operator] = Object.keys(cond);
57
+ const [head, ...tail] = cond[operator].map(normalizeCondition).filter(x => x);
58
+ if (!head) {
59
+ return undefined;
60
+ }
61
+ if (tail.length === 0) {
62
+ return head;
63
+ }
64
+ if (tail.length === 1) {
65
+ return { [operator]: [head, tail[0]] };
66
+ }
67
+ return { [operator]: [head, normalizeCondition({ [operator]: tail })] };
45
68
  }
69
+
46
70
  function buildHooksSystem(stringify = genericStringify) {
47
- return function createHooks(config, options) {
48
- const fallbackKeyword = (options === null || options === void 0 ? void 0 : options.fallback) || "unset";
49
- const stringifyImpl = (propertyName, value) => {
50
- return typeof value === "string" && value.startsWith("var(")
51
- ? value
52
- : stringify(propertyName, value);
53
- };
54
- const hookId = (options === null || options === void 0 ? void 0 : options.hookNameToId) ||
55
- ((hookName) => {
56
- const specHash = hash(config[hookName]);
57
- return (options === null || options === void 0 ? void 0 : options.debug)
58
- ? `${hookName.replace(/[^A-Za-z0-9-]/g, "_")}-${specHash}`
59
- : specHash;
60
- });
61
- const hooks = Object.entries(config)
62
- .map(([name, definition]) => {
63
- function nest(input) {
64
- if (typeof input === "object") {
65
- if ("and" in input) {
66
- if (input.and.length > 2) {
67
- const [left, ...rest] = input.and;
68
- return { and: [left, nest({ and: rest })] };
69
- }
70
- return {
71
- and: input.and.map(item => typeof item === "string" ? item : nest(item)),
72
- };
73
- }
74
- if ("or" in input) {
75
- if (input.or.length > 2) {
76
- const [left, ...rest] = input.or;
77
- return { or: [left, nest({ or: rest })] };
78
- }
79
- return {
80
- or: input.or.map(item => typeof item === "string" ? item : nest(item)),
81
- };
82
- }
83
- }
84
- return input;
71
+ return function createHooks({
72
+ hooks: hooksConfigUnresolved,
73
+ fallback = "revert-layer",
74
+ debug,
75
+ sort: {
76
+ properties: sortProperties = true,
77
+ conditionalStyles: sortConditionalStyles = true,
78
+ } = {},
79
+ hookNameToId: customHookNameToId,
80
+ }) {
81
+ const hooksConfig =
82
+ typeof hooksConfigUnresolved === "function"
83
+ ? hooksConfigUnresolved(helpers)
84
+ : hooksConfigUnresolved;
85
+
86
+ const [space, newline] = debug ? [" ", "\n"] : ["", ""];
87
+ const indent = `${space}${space}`;
88
+
89
+ const hookNameToId =
90
+ customHookNameToId ||
91
+ (hookName => {
92
+ const specHash = hash(hooksConfig[hookName]);
93
+ return debug
94
+ ? `${hookName.replace(/[^A-Za-z0-9-]/g, "_")}-${specHash}`
95
+ : specHash;
96
+ });
97
+
98
+ function conditionToId(condition) {
99
+ if (condition) {
100
+ if (typeof condition === "string") {
101
+ return hookNameToId(condition);
102
+ }
103
+ if (typeof condition === "object") {
104
+ if (condition.and) {
105
+ return `_${condition.and.map(conditionToId).join("-and-")}_`;
106
+ }
107
+ if (condition.or) {
108
+ return `_${condition.or.map(conditionToId).join("-or-")}_`;
109
+ }
110
+ if (condition.not) {
111
+ return `_-not-${conditionToId(condition.not)}_`;
112
+ }
113
+ }
114
+ }
115
+ return `${condition}`;
116
+ }
117
+
118
+ function styleSheet() {
119
+ function variablePair({ id, initial, indents }) {
120
+ return [0, 1]
121
+ .map(
122
+ i =>
123
+ `${Array(indents).fill(indent).join("")}--${id}-${i}:${space}${
124
+ initial === i ? "initial" : space ? "" : " "
125
+ };${newline}`,
126
+ )
127
+ .join("");
128
+ }
129
+
130
+ let sheet = `*${space}{${newline}`;
131
+
132
+ const hooks = Object.entries(hooksConfig)
133
+ .map(([hookName, hookCondition]) => [
134
+ hookName,
135
+ normalizeCondition(hookCondition),
136
+ ])
137
+ .filter(([, hookCondition]) => hookCondition);
138
+
139
+ for (const [hookName, hookCondition] of hooks) {
140
+ (function it(id, hookCondition) {
141
+ if (hookCondition && typeof hookCondition === "object") {
142
+ if (hookCondition.not) {
143
+ it(`${id}X`, hookCondition.not);
144
+ sheet += `${indent}--${id}-0:${space}var(--${id}X-1);${newline}`;
145
+ sheet += `${indent}--${id}-1:${space}var(--${id}X-0);${newline}`;
146
+ return;
85
147
  }
86
- if (!isHookSpec(definition) || typeof definition !== "object") {
87
- return [name, definition];
148
+
149
+ if ("and" in hookCondition || "or" in hookCondition) {
150
+ const operator = hookCondition.and ? "and" : "or";
151
+ it(`${id}A`, hookCondition[operator][0]);
152
+ it(`${id}B`, hookCondition[operator][1]);
153
+ if (operator === "and") {
154
+ sheet += `${indent}--${id}-0:${space}var(--${id}A-0)${space}var(--${id}B-0);${newline}`;
155
+ sheet += `${indent}--${id}-1:${space}var(--${id}A-1,${space}var(--${id}B-1));${newline}`;
156
+ } else {
157
+ sheet += `${indent}--${id}-0:${space}var(--${id}A-0,${space}var(--${id}B-0));${newline}`;
158
+ sheet += `${indent}--${id}-1:${space}var(--${id}A-1)${space}var(--${id}B-1);${newline}`;
159
+ }
160
+ return;
88
161
  }
89
- return [name, nest(definition)];
90
- })
91
- .flatMap(([name, definition]) => (function hooksCSS(name, definition) {
92
- if (!isHookSpec(definition)) {
93
- return [];
162
+ }
163
+ sheet += variablePair({ id, initial: 0, indents: 1 });
164
+ })(hookNameToId(hookName), hookCondition);
165
+ }
166
+
167
+ sheet += `}${newline}`;
168
+
169
+ for (const [hookName, hookCondition] of hooks) {
170
+ (function it(id, hookCondition) {
171
+ if (hookCondition && typeof hookCondition === "object") {
172
+ if (hookCondition.not) {
173
+ return it(`${id}X`, hookCondition.not);
94
174
  }
95
- if (typeof definition === "object") {
96
- let a, operator, b, extraHooksCSS = [];
97
- if ("or" in definition) {
98
- operator = "or";
99
- [a, b] = definition.or;
100
- if (!a) {
101
- return [];
102
- }
103
- if (!b) {
104
- return hooksCSS(name, a);
105
- }
106
- extraHooksCSS = [
107
- {
108
- init: (function aorb(x) {
109
- const a = `${x}A`;
110
- const b = `${x}B`;
111
- return [
112
- `--${x}-0:var(--${a}-0,var(--${b}-0));`,
113
- `--${x}-1:var(--${a}-1) var(--${b}-1);`,
114
- ].join("");
115
- })(name),
116
- },
117
- ];
118
- }
119
- else if ("and" in definition) {
120
- operator = "and";
121
- [a, b] = definition.and;
122
- if (!a) {
123
- return [];
124
- }
125
- if (!b) {
126
- return hooksCSS(name, a);
127
- }
128
- extraHooksCSS = [
129
- {
130
- init: (function aandb(x) {
131
- const a = `${x}A`;
132
- const b = `${x}B`;
133
- return [
134
- `--${x}-0:var(--${a}-0) var(--${b}-0);`,
135
- `--${x}-1:var(--${a}-1,var(--${b}-1));`,
136
- ].join("");
137
- })(name),
138
- },
139
- ];
140
- }
141
- if (operator) {
142
- return [
143
- ...hooksCSS(`${name}A`, a),
144
- ...hooksCSS(`${name}B`, b),
145
- ...extraHooksCSS,
146
- ];
147
- }
175
+
176
+ if ("and" in hookCondition || "or" in hookCondition) {
177
+ const operator = hookCondition.and ? "and" : "or";
178
+ it(`${id}A`, hookCondition[operator][0]);
179
+ it(`${id}B`, hookCondition[operator][1]);
180
+ return;
148
181
  }
149
- const init = `--${name}-0:initial;--${name}-1: ;`;
150
- let rule;
151
- if (typeof definition === "string") {
152
- if (definition.includes("&")) {
153
- rule = `${definition.replace(/&/g, "*")}{--${name}-0: ;--${name}-1:initial;}`;
154
- }
155
- else if (definition.startsWith(":")) {
156
- rule = `${definition}{--${name}-0: ;--${name}-1:initial;}`;
157
- }
158
- else if (definition.startsWith("@")) {
159
- rule = `${definition}{*{--${name}-0: ;--${name}-1:initial;}}`;
160
- }
182
+ }
183
+
184
+ if (typeof hookCondition === "string") {
185
+ if (hookCondition[0] === "@") {
186
+ sheet += [
187
+ `${hookCondition}${space}{${newline}`,
188
+ `${indent}*${space}{${newline}`,
189
+ variablePair({
190
+ id,
191
+ initial: 1,
192
+ indents: 2,
193
+ }),
194
+ `${indent}}${newline}`,
195
+ `}${newline}`,
196
+ ].join("");
197
+ } else {
198
+ sheet += [
199
+ `${hookCondition.replace(/&/g, "*")}${space}{${newline}`,
200
+ variablePair({
201
+ id,
202
+ initial: 1,
203
+ indents: 1,
204
+ }),
205
+ `}${newline}`,
206
+ ].join("");
161
207
  }
162
- return rule === undefined ? [] : [{ init, rule }];
163
- })(hookId(name), definition))
164
- .reduce((acc, { init = "", rule = "" }) => ({
165
- init: acc.init + init,
166
- rule: acc.rule + rule,
167
- }), {
168
- init: "",
169
- rule: "",
170
- });
171
- function cssImpl(properties, fallback = propertyName => stringifyImpl(propertyName, properties[propertyName])) {
172
- const sort = options === null || options === void 0 ? void 0 : options.sort;
173
- const keys = sort ? Object.keys(properties) : [];
174
- for (const k in properties) {
175
- const key = k;
176
- const value = properties[key];
177
- if (key in config) {
178
- const hookName = key;
179
- const innerProperties = value;
180
- cssImpl(innerProperties, propertyName => {
181
- let v = stringifyImpl(propertyName, innerProperties[propertyName]);
182
- if (v === null) {
183
- v = fallback(propertyName);
184
- }
185
- if (v === null) {
186
- v = fallbackKeyword;
187
- }
188
- return v;
189
- });
190
- for (const propertyNameStr in innerProperties) {
191
- if (keys.indexOf(propertyNameStr) > keys.indexOf(hookName)) {
192
- continue;
193
- }
194
- const propertyName = propertyNameStr;
195
- const v1 = stringifyImpl(propertyName, innerProperties[propertyName]);
196
- if (v1 !== null) {
197
- let v0 = fallback(propertyName);
198
- if (v0 === null) {
199
- v0 = fallbackKeyword;
200
- }
201
- if (sort) {
202
- delete properties[propertyName];
203
- }
204
- properties[propertyName] = `var(--${hookId(hookName)}-1, ${v1}) var(--${hookId(hookName)}-0, ${v0})`;
205
- }
206
- }
207
- delete properties[hookName];
208
- }
209
- else if (sort) {
210
- delete properties[key];
211
- Object.assign(properties, { [key]: value });
212
- }
208
+ }
209
+ })(hookNameToId(hookName), hookCondition);
210
+ }
211
+
212
+ return sheet;
213
+ }
214
+
215
+ function css(...args) {
216
+ const style = {};
217
+ const rules = args
218
+ .filter(rule => rule)
219
+ .reduce(
220
+ ([baseStyles, conditionalStyles], rule) => {
221
+ if (rule.on) {
222
+ baseStyles.push(rule);
223
+ (sortConditionalStyles ? conditionalStyles : baseStyles).push(
224
+ ...(typeof rule.on === "function"
225
+ ? rule.on((condition, styles) => [condition, styles], helpers)
226
+ : rule.on),
227
+ );
228
+ } else {
229
+ baseStyles.push(rule);
213
230
  }
214
- return properties;
231
+ delete rule.on;
232
+ return [baseStyles, conditionalStyles];
233
+ },
234
+ [[], []],
235
+ )
236
+ .reduce((a, b) => {
237
+ return a.concat(b);
238
+ }, []);
239
+ for (const rule of rules) {
240
+ if (!rule || typeof rule !== "object") {
241
+ continue;
215
242
  }
216
- function css(...properties) {
217
- const styles = [{}].concat(JSON.parse(JSON.stringify(properties)));
218
- do {
219
- const current = styles[0];
220
- const next = styles[1] || {};
221
- if (options === null || options === void 0 ? void 0 : options.sort) {
222
- for (const k in next) {
223
- if (k in current) {
224
- delete current[k];
225
- }
226
- }
243
+ if (rule instanceof Array && rule.length === 2) {
244
+ let conditionId = normalizeCondition(rule[0]);
245
+ if (!conditionId) {
246
+ continue;
247
+ }
248
+ if (typeof conditionId === "string") {
249
+ conditionId = hookNameToId(conditionId);
250
+ } else if (typeof conditionId === "object") {
251
+ conditionId = (function it(name, cond) {
252
+ if (typeof cond === "string") {
253
+ return hookNameToId(cond);
254
+ }
255
+ if (cond.not) {
256
+ const inner = it(`${name}X`, cond.not);
257
+ style[`--${name}-0`] = `var(--${inner}-1)`;
258
+ style[`--${name}-1`] = `var(--${inner}-0)`;
259
+ }
260
+ if (cond.and || cond.or) {
261
+ const operator = cond.and ? "and" : "or";
262
+ const a = it(`${name}A`, cond[operator][0]);
263
+ const b = it(`${name}B`, cond[operator][1]);
264
+ if (operator === "and") {
265
+ style[`--${name}-0`] = `var(--${a}-0)${space}var(--${b}-0)`;
266
+ style[`--${name}-1`] = `var(--${a}-1,${space}var(--${b}-1))`;
267
+ } else {
268
+ style[`--${name}-0`] = `var(--${a}-0,${space}var(--${b}-0))`;
269
+ style[`--${name}-1`] = `var(--${a}-1)${space}var(--${b}-1)`;
227
270
  }
228
- styles[0] = cssImpl(Object.assign(current, next));
229
- styles.splice(1, 1);
230
- } while (styles[1]);
231
- return styles[0];
271
+ }
272
+ return name;
273
+ })(`cond-${hash(conditionToId(conditionId))}`, conditionId);
274
+ }
275
+ for (const [property, value] of Object.entries(rule[1])) {
276
+ const stringifiedValue = stringify(property, value);
277
+ if (stringifiedValue === null) {
278
+ continue;
279
+ }
280
+ const fallbackValue = (() => {
281
+ if (!(property in style)) {
282
+ return fallback;
283
+ }
284
+ const stringifiedValue = stringify(property, style[property]);
285
+ return stringifiedValue === null ? fallback : stringifiedValue;
286
+ })();
287
+ if (sortProperties) {
288
+ delete style[property];
289
+ }
290
+ style[property] =
291
+ `var(--${conditionId}-1,${space}${stringifiedValue})${space}var(--${conditionId}-0,${space}${fallbackValue})`;
292
+ }
293
+ continue;
232
294
  }
233
- return [`*{${hooks.init}}${hooks.rule}`, css];
234
- };
295
+ for (const [property, value] of Object.entries(rule)) {
296
+ if (sortProperties) {
297
+ delete style[property];
298
+ }
299
+ style[property] = value;
300
+ }
301
+ }
302
+ return style;
303
+ }
304
+
305
+ return { styleSheet, css };
306
+ };
235
307
  }
236
- exports.buildHooksSystem = buildHooksSystem;
237
- /**
238
- * A list of hooks offered as a "sensible default" to solve the most common use cases.
239
- *
240
- * @deprecated Use the `@css-hooks/recommended` package instead.
241
- */
242
- exports.recommended = {
243
- active: ":active",
244
- autofill: { or: [":autofill", ":-webkit-autofill"] },
245
- checked: ":checked",
246
- default: ":default",
247
- disabled: ":disabled",
248
- empty: ":empty",
249
- enabled: ":enabled",
250
- evenChild: ":nth-child(even)",
251
- firstChild: ":first-child",
252
- firstOfType: ":first-of-type",
253
- focus: ":focus",
254
- focusVisible: ":focus-visible",
255
- focusWithin: ":focus-within",
256
- hover: ":hover",
257
- inRange: ":in-range",
258
- indeterminate: ":indeterminate",
259
- invalid: ":invalid",
260
- lastChild: ":last-child",
261
- lastOfType: ":last-of-type",
262
- oddChild: ":nth-child(odd)",
263
- onlyChild: ":only-child",
264
- onlyOfType: ":only-of-type",
265
- outOfRange: ":out-of-range",
266
- placeholderShown: { or: [":placeholder-shown", ":-moz-placeholder-shown"] },
267
- readOnly: { or: [":read-only", ":-moz-read-only"] },
268
- readWrite: { or: [":read-write", ":-moz-read-write"] },
269
- required: ":required",
270
- target: ":target",
271
- valid: ":valid",
272
- visited: ":visited",
273
- };
308
+ exports.buildHooksSystem = buildHooksSystem