fashionable 0.0.0 → 0.2.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/LICENSE.md +21 -0
- package/README.md +276 -0
- package/dist/calc/index.d.mts +2 -0
- package/dist/calc/index.mjs +2 -0
- package/dist/data/index.d.mts +208 -0
- package/dist/data/index.mjs +696 -0
- package/dist/data/index.mjs.map +1 -0
- package/dist/declaration/index.d.mts +2 -0
- package/dist/declaration/index.mjs +74 -0
- package/dist/declaration/index.mjs.map +1 -0
- package/dist/fontFace/index.d.mts +2 -0
- package/dist/fontFace/index.mjs +102 -0
- package/dist/fontFace/index.mjs.map +1 -0
- package/dist/property/index.d.mts +2 -0
- package/dist/property/index.mjs +293 -0
- package/dist/property/index.mjs.map +1 -0
- package/dist/query/index.d.mts +2 -0
- package/dist/query/index.mjs +62 -0
- package/dist/query/index.mjs.map +1 -0
- package/dist/rule/index.d.mts +2 -0
- package/dist/rule/index.mjs +234 -0
- package/dist/rule/index.mjs.map +1 -0
- package/dist/selector/index.d.mts +2 -0
- package/dist/selector/index.mjs +178 -0
- package/dist/selector/index.mjs.map +1 -0
- package/dist/shared/calc-Cih4o2r7.mjs +1145 -0
- package/dist/shared/calc-Cih4o2r7.mjs.map +1 -0
- package/dist/shared/color-BvNJ2YqL.d.mts +590 -0
- package/dist/shared/color.internal-Dts5ycTm.mjs +450 -0
- package/dist/shared/color.internal-Dts5ycTm.mjs.map +1 -0
- package/dist/shared/declaration-1DlO_ltT.d.mts +166 -0
- package/dist/shared/declaration.internal-wLB4ssxC.mjs +73 -0
- package/dist/shared/declaration.internal-wLB4ssxC.mjs.map +1 -0
- package/dist/shared/equal-U9G5LhtL.mjs +71 -0
- package/dist/shared/equal-U9G5LhtL.mjs.map +1 -0
- package/dist/shared/fontFaceRule-C7nYgH6X.d.mts +294 -0
- package/dist/shared/fontFaceRule.internal-D5u48TUO.mjs +214 -0
- package/dist/shared/fontFaceRule.internal-D5u48TUO.mjs.map +1 -0
- package/dist/shared/format-B9jsmCER.mjs +53 -0
- package/dist/shared/format-B9jsmCER.mjs.map +1 -0
- package/dist/shared/index-BvtwY4FQ.d.mts +841 -0
- package/dist/shared/mediaQuery-BYR1z-iD.d.mts +145 -0
- package/dist/shared/mediaQuery.internal-B6iuMd75.mjs +100 -0
- package/dist/shared/mediaQuery.internal-B6iuMd75.mjs.map +1 -0
- package/dist/shared/mediaRule-BDB4WCYy.d.mts +558 -0
- package/dist/shared/precision.internal-0lv1nEpF.mjs +40 -0
- package/dist/shared/precision.internal-0lv1nEpF.mjs.map +1 -0
- package/dist/shared/propertyRule-BbkFh9b9.d.mts +466 -0
- package/dist/shared/propertyRule.internal-Bc_HrfcL.mjs +246 -0
- package/dist/shared/propertyRule.internal-Bc_HrfcL.mjs.map +1 -0
- package/dist/shared/render-BqcFH9Vr.mjs +9 -0
- package/dist/shared/render-BqcFH9Vr.mjs.map +1 -0
- package/dist/shared/rolldown-runtime-D7D4PA-g.mjs +13 -0
- package/dist/shared/ruleSet.internal-DodzVMUU.mjs +218 -0
- package/dist/shared/ruleSet.internal-DodzVMUU.mjs.map +1 -0
- package/dist/shared/selector-HZY-W6l6.d.mts +346 -0
- package/dist/shared/selector.internal-ESe9s0IH.mjs +290 -0
- package/dist/shared/selector.internal-ESe9s0IH.mjs.map +1 -0
- package/dist/shared/utils-BKm298I-.d.mts +179 -0
- package/dist/stylesheet/index.d.mts +316 -0
- package/dist/stylesheet/index.mjs +296 -0
- package/dist/stylesheet/index.mjs.map +1 -0
- package/dist/utils.d.mts +2 -0
- package/dist/utils.mjs +131 -0
- package/dist/utils.mjs.map +1 -0
- package/package.json +96 -8
- package/index.js +0 -1
|
@@ -0,0 +1,1145 @@
|
|
|
1
|
+
import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
|
|
2
|
+
import { Pipeable, dual, invariant } from "../utils.mjs";
|
|
3
|
+
import { i as equals$2, n as HashTypeId, o as hashNumber, r as combine, s as hashString, t as EqualTypeId } from "./equal-U9G5LhtL.mjs";
|
|
4
|
+
import { a as specFidelity, i as specEquals, r as formatWith, t as DEFAULT_FORMAT } from "./format-B9jsmCER.mjs";
|
|
5
|
+
import { i as toSpec, n as isPrecision$1, r as significant$1, t as decimals$1 } from "./precision.internal-0lv1nEpF.mjs";
|
|
6
|
+
//#region src/internal/refs.ts
|
|
7
|
+
/**
|
|
8
|
+
* Runtime helpers for the unbound-reference sets carried by expression
|
|
9
|
+
* values. The matching type-level machinery (the phantom `Refs` parameter
|
|
10
|
+
* and `ApplyBindings`) lives with the public types in calc/calc.ts;
|
|
11
|
+
* container modules extract refs from heterogeneous members with
|
|
12
|
+
* conditionals over their member unions (`RuleSet.MemberRefs`).
|
|
13
|
+
*/
|
|
14
|
+
/** @internal */
|
|
15
|
+
const unionRefs = (...sets) => {
|
|
16
|
+
const merged = /* @__PURE__ */ new Set();
|
|
17
|
+
for (const set of sets) for (const ref of set) merged.add(ref);
|
|
18
|
+
return merged;
|
|
19
|
+
};
|
|
20
|
+
/** @internal */
|
|
21
|
+
const EMPTY_REFS = /* @__PURE__ */ new Set();
|
|
22
|
+
//#endregion
|
|
23
|
+
//#region src/calc/calc.internal.ts
|
|
24
|
+
const CalcTypeId = Symbol.for("fashionable/calc");
|
|
25
|
+
const isConstant = (node) => node._tag === "Constant";
|
|
26
|
+
const constantNode = (value, precision, unit = void 0, kind = "number") => {
|
|
27
|
+
invariant(Number.isFinite(value), `Constant value must be a finite number, got ${value}`);
|
|
28
|
+
return {
|
|
29
|
+
_tag: "Constant",
|
|
30
|
+
value,
|
|
31
|
+
precision,
|
|
32
|
+
unit,
|
|
33
|
+
kind
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* The shared (unit, kind) of a run of constants, or `undefined` when they mix
|
|
38
|
+
* units and so cannot fold to a single constant (`10px + 5vw` stays symbolic).
|
|
39
|
+
*/
|
|
40
|
+
const commonDimension = (nodes) => {
|
|
41
|
+
const first = nodes[0];
|
|
42
|
+
if (first === void 0) return {
|
|
43
|
+
unit: void 0,
|
|
44
|
+
kind: "number"
|
|
45
|
+
};
|
|
46
|
+
for (const node of nodes) if (node.unit !== first.unit) return;
|
|
47
|
+
return {
|
|
48
|
+
unit: first.unit,
|
|
49
|
+
kind: first.kind
|
|
50
|
+
};
|
|
51
|
+
};
|
|
52
|
+
const bestPrecision = (nodes) => {
|
|
53
|
+
let best;
|
|
54
|
+
for (const node of nodes) if (specFidelity(node.precision) > specFidelity(best)) best = node.precision;
|
|
55
|
+
return best;
|
|
56
|
+
};
|
|
57
|
+
const addNode = (terms) => {
|
|
58
|
+
if (terms.every(isConstant)) {
|
|
59
|
+
const dim = commonDimension(terms);
|
|
60
|
+
if (dim !== void 0) return constantNode(terms.reduce((total, term) => total + term.value, 0), bestPrecision(terms), dim.unit, dim.kind);
|
|
61
|
+
}
|
|
62
|
+
return {
|
|
63
|
+
_tag: "Add",
|
|
64
|
+
terms
|
|
65
|
+
};
|
|
66
|
+
};
|
|
67
|
+
const subtractNode = (left, right) => {
|
|
68
|
+
if (isConstant(left) && isConstant(right) && left.unit === right.unit) return constantNode(left.value - right.value, bestPrecision([left, right]), left.unit, left.kind);
|
|
69
|
+
return {
|
|
70
|
+
_tag: "Subtract",
|
|
71
|
+
left,
|
|
72
|
+
right
|
|
73
|
+
};
|
|
74
|
+
};
|
|
75
|
+
const multiplyNode = (left, right) => {
|
|
76
|
+
if (isConstant(left) && isConstant(right)) {
|
|
77
|
+
if (left.unit === void 0) return constantNode(left.value * right.value, bestPrecision([left, right]), right.unit, right.kind);
|
|
78
|
+
if (right.unit === void 0) return constantNode(left.value * right.value, bestPrecision([left, right]), left.unit, left.kind);
|
|
79
|
+
}
|
|
80
|
+
return {
|
|
81
|
+
_tag: "Multiply",
|
|
82
|
+
left,
|
|
83
|
+
right
|
|
84
|
+
};
|
|
85
|
+
};
|
|
86
|
+
const divideNode = (left, right) => {
|
|
87
|
+
if (isConstant(left) && isConstant(right)) {
|
|
88
|
+
if (left.unit === right.unit) return constantNode(left.value / right.value, bestPrecision([left, right]));
|
|
89
|
+
if (right.unit === void 0) return constantNode(left.value / right.value, bestPrecision([left, right]), left.unit, left.kind);
|
|
90
|
+
}
|
|
91
|
+
return {
|
|
92
|
+
_tag: "Divide",
|
|
93
|
+
left,
|
|
94
|
+
right
|
|
95
|
+
};
|
|
96
|
+
};
|
|
97
|
+
const modNode = (left, right) => {
|
|
98
|
+
if (isConstant(left) && isConstant(right) && left.unit === right.unit) return constantNode(left.value - right.value * Math.floor(left.value / right.value), bestPrecision([left, right]), left.unit, left.kind);
|
|
99
|
+
return {
|
|
100
|
+
_tag: "Mod",
|
|
101
|
+
left,
|
|
102
|
+
right
|
|
103
|
+
};
|
|
104
|
+
};
|
|
105
|
+
const powNode = (base, exponent) => {
|
|
106
|
+
if (isConstant(base) && isConstant(exponent)) return constantNode(base.value ** exponent.value, bestPrecision([base, exponent]));
|
|
107
|
+
return {
|
|
108
|
+
_tag: "Pow",
|
|
109
|
+
base,
|
|
110
|
+
exponent
|
|
111
|
+
};
|
|
112
|
+
};
|
|
113
|
+
const signedPowNode = (base, exponent) => {
|
|
114
|
+
if (isConstant(base) && isConstant(exponent)) return constantNode(Math.abs(base.value) ** exponent.value * Math.sign(base.value), bestPrecision([base, exponent]));
|
|
115
|
+
return {
|
|
116
|
+
_tag: "SignedPow",
|
|
117
|
+
base,
|
|
118
|
+
exponent
|
|
119
|
+
};
|
|
120
|
+
};
|
|
121
|
+
const naryNode = (tag, compute) => (args) => {
|
|
122
|
+
if (args.every(isConstant)) {
|
|
123
|
+
const dim = commonDimension(args);
|
|
124
|
+
if (dim !== void 0) return constantNode(compute(args.map((arg) => arg.value)), bestPrecision(args), dim.unit, dim.kind);
|
|
125
|
+
}
|
|
126
|
+
return {
|
|
127
|
+
_tag: tag,
|
|
128
|
+
args
|
|
129
|
+
};
|
|
130
|
+
};
|
|
131
|
+
const minNode = naryNode("Min", (values) => Math.min(...values));
|
|
132
|
+
const maxNode = naryNode("Max", (values) => Math.max(...values));
|
|
133
|
+
const clampNode = (minimum, value, maximum) => {
|
|
134
|
+
if (isConstant(minimum) && isConstant(value) && isConstant(maximum)) {
|
|
135
|
+
const dim = commonDimension([
|
|
136
|
+
minimum,
|
|
137
|
+
value,
|
|
138
|
+
maximum
|
|
139
|
+
]);
|
|
140
|
+
if (dim !== void 0) return constantNode(Math.max(minimum.value, Math.min(value.value, maximum.value)), bestPrecision([
|
|
141
|
+
minimum,
|
|
142
|
+
value,
|
|
143
|
+
maximum
|
|
144
|
+
]), dim.unit, dim.kind);
|
|
145
|
+
}
|
|
146
|
+
return {
|
|
147
|
+
_tag: "Clamp",
|
|
148
|
+
minimum,
|
|
149
|
+
value,
|
|
150
|
+
maximum
|
|
151
|
+
};
|
|
152
|
+
};
|
|
153
|
+
/**
|
|
154
|
+
* Per-function data for the unary math nodes — the single source of truth the
|
|
155
|
+
* fold constructor, the evaluator, and the serializer all read:
|
|
156
|
+
*
|
|
157
|
+
* - `fn` both folds a constant operand and lowers the node under `solve`, so the
|
|
158
|
+
* construction-time and solve-time numerics can never drift.
|
|
159
|
+
* - `css` is the math-function name serialization emits.
|
|
160
|
+
* - `result` is the folded constant's dimension: `sign`/`sin`/`cos`/`tan`
|
|
161
|
+
* produce a plain `number`; `abs` preserves the operand's; `acos` returns
|
|
162
|
+
* radians, so its constant composes with `Angle.rad` terms and stays valid CSS
|
|
163
|
+
* with no plain-number-beside-angle hack.
|
|
164
|
+
*/
|
|
165
|
+
const UNARY = {
|
|
166
|
+
Abs: {
|
|
167
|
+
fn: Math.abs,
|
|
168
|
+
css: "abs",
|
|
169
|
+
result: "preserve"
|
|
170
|
+
},
|
|
171
|
+
Sign: {
|
|
172
|
+
fn: Math.sign,
|
|
173
|
+
css: "sign",
|
|
174
|
+
result: "number"
|
|
175
|
+
},
|
|
176
|
+
Sin: {
|
|
177
|
+
fn: Math.sin,
|
|
178
|
+
css: "sin",
|
|
179
|
+
result: "number"
|
|
180
|
+
},
|
|
181
|
+
Cos: {
|
|
182
|
+
fn: Math.cos,
|
|
183
|
+
css: "cos",
|
|
184
|
+
result: "number"
|
|
185
|
+
},
|
|
186
|
+
Tan: {
|
|
187
|
+
fn: Math.tan,
|
|
188
|
+
css: "tan",
|
|
189
|
+
result: "number"
|
|
190
|
+
},
|
|
191
|
+
Acos: {
|
|
192
|
+
fn: Math.acos,
|
|
193
|
+
css: "acos",
|
|
194
|
+
result: "rad"
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
const foldUnary = (tag, argument) => {
|
|
198
|
+
if (!isConstant(argument)) return {
|
|
199
|
+
_tag: tag,
|
|
200
|
+
argument
|
|
201
|
+
};
|
|
202
|
+
const { fn, result } = UNARY[tag];
|
|
203
|
+
const value = fn(argument.value);
|
|
204
|
+
switch (result) {
|
|
205
|
+
case "number": return constantNode(value, argument.precision);
|
|
206
|
+
case "preserve": return constantNode(value, argument.precision, argument.unit, argument.kind);
|
|
207
|
+
case "rad": return constantNode(value, argument.precision, "rad", "angle");
|
|
208
|
+
}
|
|
209
|
+
};
|
|
210
|
+
const atan2Node = (y, x) => {
|
|
211
|
+
if (isConstant(y) && isConstant(x) && y.unit === x.unit) return constantNode(Math.atan2(y.value, x.value), bestPrecision([y, x]), "rad", "angle");
|
|
212
|
+
return {
|
|
213
|
+
_tag: "Atan2",
|
|
214
|
+
y,
|
|
215
|
+
x
|
|
216
|
+
};
|
|
217
|
+
};
|
|
218
|
+
/** @internal */
|
|
219
|
+
const substituteNode = (node, bindings) => {
|
|
220
|
+
switch (node._tag) {
|
|
221
|
+
case "Constant": return node;
|
|
222
|
+
case "Ref": return bindings[node.name] ?? node;
|
|
223
|
+
case "Ident": return node;
|
|
224
|
+
case "Add": return addNode(node.terms.map((term) => substituteNode(term, bindings)));
|
|
225
|
+
case "Subtract": return subtractNode(substituteNode(node.left, bindings), substituteNode(node.right, bindings));
|
|
226
|
+
case "Multiply": return multiplyNode(substituteNode(node.left, bindings), substituteNode(node.right, bindings));
|
|
227
|
+
case "Divide": return divideNode(substituteNode(node.left, bindings), substituteNode(node.right, bindings));
|
|
228
|
+
case "Mod": return modNode(substituteNode(node.left, bindings), substituteNode(node.right, bindings));
|
|
229
|
+
case "Pow": return powNode(substituteNode(node.base, bindings), substituteNode(node.exponent, bindings));
|
|
230
|
+
case "SignedPow": return signedPowNode(substituteNode(node.base, bindings), substituteNode(node.exponent, bindings));
|
|
231
|
+
case "Min": return minNode(node.args.map((arg) => substituteNode(arg, bindings)));
|
|
232
|
+
case "Max": return maxNode(node.args.map((arg) => substituteNode(arg, bindings)));
|
|
233
|
+
case "Clamp": return clampNode(substituteNode(node.minimum, bindings), substituteNode(node.value, bindings), substituteNode(node.maximum, bindings));
|
|
234
|
+
case "Abs":
|
|
235
|
+
case "Sign":
|
|
236
|
+
case "Sin":
|
|
237
|
+
case "Cos":
|
|
238
|
+
case "Tan":
|
|
239
|
+
case "Acos": return foldUnary(node._tag, substituteNode(node.argument, bindings));
|
|
240
|
+
case "Atan2": return atan2Node(substituteNode(node.y, bindings), substituteNode(node.x, bindings));
|
|
241
|
+
}
|
|
242
|
+
};
|
|
243
|
+
/**
|
|
244
|
+
* The units that lower with no caller-supplied ratio: `px` is the pixel base
|
|
245
|
+
* (`1`), a radian is already the numeric measure of its angle (`1`), and a
|
|
246
|
+
* degree is a fixed `pi / 180` of one. Every other unit is context-dependent
|
|
247
|
+
* and must appear in the solve context.
|
|
248
|
+
*
|
|
249
|
+
* @internal
|
|
250
|
+
*/
|
|
251
|
+
const DEFAULT_RATIOS = {
|
|
252
|
+
px: 1,
|
|
253
|
+
rad: 1,
|
|
254
|
+
deg: Math.PI / 180
|
|
255
|
+
};
|
|
256
|
+
/** @internal */
|
|
257
|
+
const evaluateNode = (node, context) => {
|
|
258
|
+
switch (node._tag) {
|
|
259
|
+
case "Constant": {
|
|
260
|
+
if (node.unit === void 0) return node.value;
|
|
261
|
+
const ratio = context[node.unit] ?? DEFAULT_RATIOS[node.unit];
|
|
262
|
+
invariant(ratio !== void 0, `Cannot evaluate ${node.value}${node.unit}: no ratio for '${node.unit}' in the unit context`);
|
|
263
|
+
return node.value * ratio;
|
|
264
|
+
}
|
|
265
|
+
case "Ref": throw new Error(`Cannot evaluate non-constant reference: ${node.name}`);
|
|
266
|
+
case "Ident": {
|
|
267
|
+
const value = context[node.name];
|
|
268
|
+
invariant(value !== void 0, `Cannot evaluate '${node.name}': no value for it in the solve context`);
|
|
269
|
+
return value;
|
|
270
|
+
}
|
|
271
|
+
case "Add": return node.terms.reduce((total, term) => total + evaluateNode(term, context), 0);
|
|
272
|
+
case "Subtract": return evaluateNode(node.left, context) - evaluateNode(node.right, context);
|
|
273
|
+
case "Multiply": return evaluateNode(node.left, context) * evaluateNode(node.right, context);
|
|
274
|
+
case "Divide": return evaluateNode(node.left, context) / evaluateNode(node.right, context);
|
|
275
|
+
case "Mod": {
|
|
276
|
+
const dividend = evaluateNode(node.left, context);
|
|
277
|
+
const divisor = evaluateNode(node.right, context);
|
|
278
|
+
return dividend - divisor * Math.floor(dividend / divisor);
|
|
279
|
+
}
|
|
280
|
+
case "Pow": return evaluateNode(node.base, context) ** evaluateNode(node.exponent, context);
|
|
281
|
+
case "SignedPow": {
|
|
282
|
+
const base = evaluateNode(node.base, context);
|
|
283
|
+
return Math.abs(base) ** evaluateNode(node.exponent, context) * Math.sign(base);
|
|
284
|
+
}
|
|
285
|
+
case "Min": return Math.min(...node.args.map((arg) => evaluateNode(arg, context)));
|
|
286
|
+
case "Max": return Math.max(...node.args.map((arg) => evaluateNode(arg, context)));
|
|
287
|
+
case "Clamp": return Math.max(evaluateNode(node.minimum, context), Math.min(evaluateNode(node.value, context), evaluateNode(node.maximum, context)));
|
|
288
|
+
case "Abs":
|
|
289
|
+
case "Sign":
|
|
290
|
+
case "Sin":
|
|
291
|
+
case "Cos":
|
|
292
|
+
case "Tan":
|
|
293
|
+
case "Acos": return UNARY[node._tag].fn(evaluateNode(node.argument, context));
|
|
294
|
+
case "Atan2": return Math.atan2(evaluateNode(node.y, context), evaluateNode(node.x, context));
|
|
295
|
+
}
|
|
296
|
+
};
|
|
297
|
+
/**
|
|
298
|
+
* True for the arithmetic forms that need a `calc()` wrapper when they
|
|
299
|
+
* stand alone; function forms and leaves never do.
|
|
300
|
+
*
|
|
301
|
+
* @internal
|
|
302
|
+
*/
|
|
303
|
+
const needsCalcWrap = (node) => node._tag === "Add" || node._tag === "Subtract" || node._tag === "Multiply" || node._tag === "Divide" || node._tag === "SignedPow";
|
|
304
|
+
const PI_TOLERANCE = 1e-10;
|
|
305
|
+
const formatConstant = (node, insideMath, context) => {
|
|
306
|
+
if (node.unit === void 0 && insideMath && Math.abs(node.value - Math.PI) < PI_TOLERANCE) return "pi";
|
|
307
|
+
const text = formatWith(node.value, node.precision ?? context.precision);
|
|
308
|
+
return node.unit !== void 0 ? `${text}${node.unit}` : text;
|
|
309
|
+
};
|
|
310
|
+
const wrapOperand = (node, serialized) => node._tag === "Add" || node._tag === "Subtract" ? `(${serialized})` : serialized;
|
|
311
|
+
const hasNegativeCoefficient = (node) => {
|
|
312
|
+
if (isConstant(node)) return node.value < 0;
|
|
313
|
+
if (node._tag === "Multiply" || node._tag === "Divide") return isConstant(node.left) && node.left.value < 0;
|
|
314
|
+
return false;
|
|
315
|
+
};
|
|
316
|
+
/**
|
|
317
|
+
* Serializes the negation of a term whose leading coefficient is a
|
|
318
|
+
* negative constant, so `a + (-k * x)` renders as `a - k * x`.
|
|
319
|
+
*/
|
|
320
|
+
const serializeNegated = (node, insideMath, context) => {
|
|
321
|
+
if (isConstant(node)) return formatConstant(constantNode(-node.value, node.precision, node.unit, node.kind), insideMath, context);
|
|
322
|
+
const binary = node;
|
|
323
|
+
const left = binary.left;
|
|
324
|
+
const negated = {
|
|
325
|
+
_tag: binary._tag,
|
|
326
|
+
left: constantNode(-left.value, left.precision, left.unit, left.kind),
|
|
327
|
+
right: binary.right
|
|
328
|
+
};
|
|
329
|
+
return serializeNode(negated, insideMath, context);
|
|
330
|
+
};
|
|
331
|
+
/** @internal */
|
|
332
|
+
const serializeNode = (node, insideMath, context) => {
|
|
333
|
+
switch (node._tag) {
|
|
334
|
+
case "Constant": return formatConstant(node, insideMath, context);
|
|
335
|
+
case "Ref": return `var(--${node.name})`;
|
|
336
|
+
case "Ident": return node.name;
|
|
337
|
+
case "Add": {
|
|
338
|
+
let out = "";
|
|
339
|
+
for (const [index, term] of node.terms.entries()) if (index === 0) out = serializeNode(term, insideMath, context);
|
|
340
|
+
else if (hasNegativeCoefficient(term)) out += ` - ${serializeNegated(term, insideMath, context)}`;
|
|
341
|
+
else out += ` + ${serializeNode(term, insideMath, context)}`;
|
|
342
|
+
return out;
|
|
343
|
+
}
|
|
344
|
+
case "Subtract": {
|
|
345
|
+
const left = serializeNode(node.left, insideMath, context);
|
|
346
|
+
if (hasNegativeCoefficient(node.right)) return `${left} + ${serializeNegated(node.right, insideMath, context)}`;
|
|
347
|
+
return `${left} - ${serializeNode(node.right, insideMath, context)}`;
|
|
348
|
+
}
|
|
349
|
+
case "Multiply": return `${wrapOperand(node.left, serializeNode(node.left, insideMath, context))} * ${wrapOperand(node.right, serializeNode(node.right, insideMath, context))}`;
|
|
350
|
+
case "Divide": return `${wrapOperand(node.left, serializeNode(node.left, insideMath, context))} / ${wrapOperand(node.right, serializeNode(node.right, insideMath, context))}`;
|
|
351
|
+
case "Mod": return `mod(${serializeNode(node.left, true, context)}, ${serializeNode(node.right, true, context)})`;
|
|
352
|
+
case "Pow": return `pow(${serializeNode(node.base, true, context)}, ${serializeNode(node.exponent, true, context)})`;
|
|
353
|
+
case "SignedPow": {
|
|
354
|
+
const base = serializeNode(node.base, true, context);
|
|
355
|
+
return `pow(abs(${base}), ${serializeNode(node.exponent, true, context)}) * sign(${base})`;
|
|
356
|
+
}
|
|
357
|
+
case "Min": return `min(${node.args.map((arg) => serializeNode(arg, true, context)).join(", ")})`;
|
|
358
|
+
case "Max": return `max(${node.args.map((arg) => serializeNode(arg, true, context)).join(", ")})`;
|
|
359
|
+
case "Clamp": return `clamp(${serializeNode(node.minimum, true, context)}, ${serializeNode(node.value, true, context)}, ${serializeNode(node.maximum, true, context)})`;
|
|
360
|
+
case "Abs":
|
|
361
|
+
case "Sign":
|
|
362
|
+
case "Sin":
|
|
363
|
+
case "Cos":
|
|
364
|
+
case "Tan":
|
|
365
|
+
case "Acos": return `${UNARY[node._tag].css}(${serializeNode(node.argument, true, context)})`;
|
|
366
|
+
case "Atan2": return `atan2(${serializeNode(node.y, true, context)}, ${serializeNode(node.x, true, context)})`;
|
|
367
|
+
}
|
|
368
|
+
};
|
|
369
|
+
/** @internal */
|
|
370
|
+
const serializeTop = (node, precision) => {
|
|
371
|
+
const wrap = needsCalcWrap(node);
|
|
372
|
+
const body = serializeNode(node, wrap, { precision });
|
|
373
|
+
return wrap ? `calc(${body})` : body;
|
|
374
|
+
};
|
|
375
|
+
const nodeArrayEquals = (a, b) => a.length === b.length && a.every((node, index) => nodeEquals(node, b[index]));
|
|
376
|
+
/** @internal */
|
|
377
|
+
const nodeEquals = (a, b) => {
|
|
378
|
+
if (a === b) return true;
|
|
379
|
+
if (a._tag !== b._tag) return false;
|
|
380
|
+
switch (a._tag) {
|
|
381
|
+
case "Constant": {
|
|
382
|
+
const other = b;
|
|
383
|
+
return a.value === other.value && a.unit === other.unit && specEquals(a.precision, other.precision);
|
|
384
|
+
}
|
|
385
|
+
case "Ref": return a.name === b.name;
|
|
386
|
+
case "Ident": return a.name === b.name;
|
|
387
|
+
case "Add": return nodeArrayEquals(a.terms, b.terms);
|
|
388
|
+
case "Subtract":
|
|
389
|
+
case "Multiply":
|
|
390
|
+
case "Divide":
|
|
391
|
+
case "Mod": {
|
|
392
|
+
const other = b;
|
|
393
|
+
return nodeEquals(a.left, other.left) && nodeEquals(a.right, other.right);
|
|
394
|
+
}
|
|
395
|
+
case "Pow":
|
|
396
|
+
case "SignedPow": {
|
|
397
|
+
const other = b;
|
|
398
|
+
return nodeEquals(a.base, other.base) && nodeEquals(a.exponent, other.exponent);
|
|
399
|
+
}
|
|
400
|
+
case "Min":
|
|
401
|
+
case "Max": return nodeArrayEquals(a.args, b.args);
|
|
402
|
+
case "Clamp": {
|
|
403
|
+
const other = b;
|
|
404
|
+
return nodeEquals(a.minimum, other.minimum) && nodeEquals(a.value, other.value) && nodeEquals(a.maximum, other.maximum);
|
|
405
|
+
}
|
|
406
|
+
case "Abs":
|
|
407
|
+
case "Sign":
|
|
408
|
+
case "Sin":
|
|
409
|
+
case "Cos":
|
|
410
|
+
case "Tan":
|
|
411
|
+
case "Acos": return nodeEquals(a.argument, b.argument);
|
|
412
|
+
case "Atan2": {
|
|
413
|
+
const other = b;
|
|
414
|
+
return nodeEquals(a.y, other.y) && nodeEquals(a.x, other.x);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
};
|
|
418
|
+
const hashNodeArray = (tag, nodes) => {
|
|
419
|
+
let h = hashString(tag);
|
|
420
|
+
for (const node of nodes) h = combine(h, nodeHash(node));
|
|
421
|
+
return h;
|
|
422
|
+
};
|
|
423
|
+
/** @internal */
|
|
424
|
+
const nodeHash = (node) => {
|
|
425
|
+
switch (node._tag) {
|
|
426
|
+
case "Constant": {
|
|
427
|
+
const precision = node.precision === void 0 ? 0 : combine(hashString(node.precision.mode), node.precision.digits | 0);
|
|
428
|
+
const unit = node.unit === void 0 ? 0 : hashString(node.unit);
|
|
429
|
+
return combine(hashString("Constant"), combine(combine(hashNumber(node.value), precision), unit));
|
|
430
|
+
}
|
|
431
|
+
case "Ref": return combine(hashString("Ref"), hashString(node.name));
|
|
432
|
+
case "Ident": return combine(hashString("Ident"), hashString(node.name));
|
|
433
|
+
case "Add": return hashNodeArray("Add", node.terms);
|
|
434
|
+
case "Subtract":
|
|
435
|
+
case "Multiply":
|
|
436
|
+
case "Divide":
|
|
437
|
+
case "Mod": return hashNodeArray(node._tag, [node.left, node.right]);
|
|
438
|
+
case "Pow":
|
|
439
|
+
case "SignedPow": return hashNodeArray(node._tag, [node.base, node.exponent]);
|
|
440
|
+
case "Min":
|
|
441
|
+
case "Max": return hashNodeArray(node._tag, node.args);
|
|
442
|
+
case "Clamp": return hashNodeArray("Clamp", [
|
|
443
|
+
node.minimum,
|
|
444
|
+
node.value,
|
|
445
|
+
node.maximum
|
|
446
|
+
]);
|
|
447
|
+
case "Abs":
|
|
448
|
+
case "Sign":
|
|
449
|
+
case "Sin":
|
|
450
|
+
case "Cos":
|
|
451
|
+
case "Tan":
|
|
452
|
+
case "Acos": return hashNodeArray(node._tag, [node.argument]);
|
|
453
|
+
case "Atan2": return hashNodeArray("Atan2", [node.y, node.x]);
|
|
454
|
+
}
|
|
455
|
+
};
|
|
456
|
+
var CalcImpl = class extends Pipeable {
|
|
457
|
+
[CalcTypeId] = CalcTypeId;
|
|
458
|
+
node;
|
|
459
|
+
refSet;
|
|
460
|
+
#hash;
|
|
461
|
+
constructor(node, refSet) {
|
|
462
|
+
super();
|
|
463
|
+
this.node = node;
|
|
464
|
+
this.refSet = refSet;
|
|
465
|
+
}
|
|
466
|
+
[EqualTypeId](that) {
|
|
467
|
+
return isCalc$1(that) && nodeEquals(this.node, nodeOf(that));
|
|
468
|
+
}
|
|
469
|
+
[HashTypeId]() {
|
|
470
|
+
this.#hash ??= combine(hashString("fashionable/calc"), nodeHash(this.node));
|
|
471
|
+
return this.#hash;
|
|
472
|
+
}
|
|
473
|
+
get [Symbol.toStringTag]() {
|
|
474
|
+
return `Calc(${serializeTop(this.node, DEFAULT_FORMAT)})`;
|
|
475
|
+
}
|
|
476
|
+
get [Symbol.for("nodejs.util.inspect.custom")]() {
|
|
477
|
+
return this[Symbol.toStringTag];
|
|
478
|
+
}
|
|
479
|
+
};
|
|
480
|
+
/** @internal */
|
|
481
|
+
const isCalc$1 = (u) => typeof u === "object" && u !== null && CalcTypeId in u;
|
|
482
|
+
/** @internal */
|
|
483
|
+
const nodeOf = (expr) => expr.node;
|
|
484
|
+
/** @internal */
|
|
485
|
+
const refsOf = (expr) => expr.refSet;
|
|
486
|
+
const collectIdents = (node, into) => {
|
|
487
|
+
switch (node._tag) {
|
|
488
|
+
case "Ident":
|
|
489
|
+
into.add(node.name);
|
|
490
|
+
return;
|
|
491
|
+
case "Constant":
|
|
492
|
+
case "Ref": return;
|
|
493
|
+
case "Add":
|
|
494
|
+
for (const term of node.terms) collectIdents(term, into);
|
|
495
|
+
return;
|
|
496
|
+
case "Min":
|
|
497
|
+
case "Max":
|
|
498
|
+
for (const arg of node.args) collectIdents(arg, into);
|
|
499
|
+
return;
|
|
500
|
+
case "Subtract":
|
|
501
|
+
case "Multiply":
|
|
502
|
+
case "Divide":
|
|
503
|
+
case "Mod":
|
|
504
|
+
collectIdents(node.left, into);
|
|
505
|
+
collectIdents(node.right, into);
|
|
506
|
+
return;
|
|
507
|
+
case "Pow":
|
|
508
|
+
case "SignedPow":
|
|
509
|
+
collectIdents(node.base, into);
|
|
510
|
+
collectIdents(node.exponent, into);
|
|
511
|
+
return;
|
|
512
|
+
case "Clamp":
|
|
513
|
+
collectIdents(node.minimum, into);
|
|
514
|
+
collectIdents(node.value, into);
|
|
515
|
+
collectIdents(node.maximum, into);
|
|
516
|
+
return;
|
|
517
|
+
case "Abs":
|
|
518
|
+
case "Sign":
|
|
519
|
+
case "Sin":
|
|
520
|
+
case "Cos":
|
|
521
|
+
case "Tan":
|
|
522
|
+
case "Acos":
|
|
523
|
+
collectIdents(node.argument, into);
|
|
524
|
+
return;
|
|
525
|
+
case "Atan2":
|
|
526
|
+
collectIdents(node.y, into);
|
|
527
|
+
collectIdents(node.x, into);
|
|
528
|
+
return;
|
|
529
|
+
}
|
|
530
|
+
};
|
|
531
|
+
/** @internal */
|
|
532
|
+
const identsOf = (node) => {
|
|
533
|
+
const set = /* @__PURE__ */ new Set();
|
|
534
|
+
collectIdents(node, set);
|
|
535
|
+
return set;
|
|
536
|
+
};
|
|
537
|
+
const makeCalc = (node, refSet) => new CalcImpl(node, refSet);
|
|
538
|
+
/** @internal */
|
|
539
|
+
const toCalc = (input) => typeof input === "number" ? of$1(input) : input;
|
|
540
|
+
const mergeRefs = (exprs) => {
|
|
541
|
+
const merged = /* @__PURE__ */ new Set();
|
|
542
|
+
for (const expr of exprs) for (const name of refsOf(expr)) merged.add(name);
|
|
543
|
+
return merged;
|
|
544
|
+
};
|
|
545
|
+
/** @internal */
|
|
546
|
+
function of$1(value, precision) {
|
|
547
|
+
return makeCalc(constantNode(value, precision === void 0 ? void 0 : toSpec(precision)), EMPTY_REFS);
|
|
548
|
+
}
|
|
549
|
+
/**
|
|
550
|
+
* Builds a dimensioned constant. The `data` module's `Length`/`Angle`
|
|
551
|
+
* constructors call this and cast the result to the precise leaf-branded type;
|
|
552
|
+
* the calc core stays unit-agnostic, carrying `unit` and `kind` as given.
|
|
553
|
+
*
|
|
554
|
+
* @internal
|
|
555
|
+
*/
|
|
556
|
+
function dimension(value, unit, kind, precision) {
|
|
557
|
+
return makeCalc(constantNode(value, precision === void 0 ? void 0 : toSpec(precision), unit, kind), EMPTY_REFS);
|
|
558
|
+
}
|
|
559
|
+
const refCache = /* @__PURE__ */ new Map();
|
|
560
|
+
/** @internal */
|
|
561
|
+
function ref$1(name) {
|
|
562
|
+
const cached = refCache.get(name);
|
|
563
|
+
if (cached) return cached;
|
|
564
|
+
invariant(name.length > 0, "Reference name must be a non-empty string");
|
|
565
|
+
const expr = makeCalc({
|
|
566
|
+
_tag: "Ref",
|
|
567
|
+
name
|
|
568
|
+
}, /* @__PURE__ */ new Set([name]));
|
|
569
|
+
refCache.set(name, expr);
|
|
570
|
+
return expr;
|
|
571
|
+
}
|
|
572
|
+
/**
|
|
573
|
+
* Builds a bare-identifier constant — a leaf serializing as `name`, carrying no
|
|
574
|
+
* references. The `data` module's `Channel` keywords call this; the identifier
|
|
575
|
+
* text is opaque to the calc core, resolved by whatever CSS context surrounds
|
|
576
|
+
* it (a relative-color function today).
|
|
577
|
+
*
|
|
578
|
+
* @internal
|
|
579
|
+
*/
|
|
580
|
+
function ident(name) {
|
|
581
|
+
invariant(name.length > 0, "Identifier name must be a non-empty string");
|
|
582
|
+
return makeCalc({
|
|
583
|
+
_tag: "Ident",
|
|
584
|
+
name
|
|
585
|
+
}, EMPTY_REFS);
|
|
586
|
+
}
|
|
587
|
+
const liftNary = (construct) => (args) => {
|
|
588
|
+
const exprs = args.map(toCalc);
|
|
589
|
+
return makeCalc(construct(exprs.map(nodeOf)), mergeRefs(exprs));
|
|
590
|
+
};
|
|
591
|
+
const addImpl = liftNary(addNode);
|
|
592
|
+
const minImpl = liftNary(minNode);
|
|
593
|
+
const maxImpl = liftNary(maxNode);
|
|
594
|
+
const naryCombinator = (impl) => ((...args) => impl(args));
|
|
595
|
+
/** @internal */
|
|
596
|
+
const add$1 = naryCombinator(addImpl);
|
|
597
|
+
/** @internal */
|
|
598
|
+
const min$1 = naryCombinator(minImpl);
|
|
599
|
+
/** @internal */
|
|
600
|
+
const max$1 = naryCombinator(maxImpl);
|
|
601
|
+
const liftBinary = (construct) => (left, right) => {
|
|
602
|
+
const l = toCalc(left);
|
|
603
|
+
const r = toCalc(right);
|
|
604
|
+
return makeCalc(construct(nodeOf(l), nodeOf(r)), mergeRefs([l, r]));
|
|
605
|
+
};
|
|
606
|
+
const subtractImpl = liftBinary(subtractNode);
|
|
607
|
+
const multiplyImpl = liftBinary(multiplyNode);
|
|
608
|
+
const divideImpl = liftBinary(divideNode);
|
|
609
|
+
const modImpl = liftBinary(modNode);
|
|
610
|
+
const powImpl = liftBinary(powNode);
|
|
611
|
+
const signedPowImpl = liftBinary(signedPowNode);
|
|
612
|
+
const atan2Impl = liftBinary(atan2Node);
|
|
613
|
+
/** @internal */
|
|
614
|
+
function subtract$1(left, right) {
|
|
615
|
+
return subtractImpl(left, right);
|
|
616
|
+
}
|
|
617
|
+
/** @internal */
|
|
618
|
+
function multiply$1(left, right) {
|
|
619
|
+
return multiplyImpl(left, right);
|
|
620
|
+
}
|
|
621
|
+
/** @internal */
|
|
622
|
+
function mod$1(left, right) {
|
|
623
|
+
return modImpl(left, right);
|
|
624
|
+
}
|
|
625
|
+
/** @internal */
|
|
626
|
+
function divide$1(left, right) {
|
|
627
|
+
return divideImpl(left, right);
|
|
628
|
+
}
|
|
629
|
+
/** @internal */
|
|
630
|
+
function pow$1(base, exponent) {
|
|
631
|
+
return powImpl(base, exponent);
|
|
632
|
+
}
|
|
633
|
+
/** @internal */
|
|
634
|
+
function signedPow$1(base, exponent) {
|
|
635
|
+
return signedPowImpl(base, exponent);
|
|
636
|
+
}
|
|
637
|
+
const liftUnary = (construct) => (argument) => {
|
|
638
|
+
const arg = toCalc(argument);
|
|
639
|
+
return makeCalc(construct(nodeOf(arg)), refsOf(arg));
|
|
640
|
+
};
|
|
641
|
+
const absImpl = liftUnary((argument) => foldUnary("Abs", argument));
|
|
642
|
+
const signImpl = liftUnary((argument) => foldUnary("Sign", argument));
|
|
643
|
+
const sinImpl = liftUnary((argument) => foldUnary("Sin", argument));
|
|
644
|
+
const cosImpl = liftUnary((argument) => foldUnary("Cos", argument));
|
|
645
|
+
const tanImpl = liftUnary((argument) => foldUnary("Tan", argument));
|
|
646
|
+
const acosImpl = liftUnary((argument) => foldUnary("Acos", argument));
|
|
647
|
+
/** @internal */
|
|
648
|
+
function abs$1(argument) {
|
|
649
|
+
return absImpl(argument);
|
|
650
|
+
}
|
|
651
|
+
/** @internal */
|
|
652
|
+
function sign$1(argument) {
|
|
653
|
+
return signImpl(argument);
|
|
654
|
+
}
|
|
655
|
+
/** @internal */
|
|
656
|
+
function sin$1(argument) {
|
|
657
|
+
return sinImpl(argument);
|
|
658
|
+
}
|
|
659
|
+
/** @internal */
|
|
660
|
+
function cos$1(argument) {
|
|
661
|
+
return cosImpl(argument);
|
|
662
|
+
}
|
|
663
|
+
/** @internal */
|
|
664
|
+
function tan$1(argument) {
|
|
665
|
+
return tanImpl(argument);
|
|
666
|
+
}
|
|
667
|
+
/** @internal */
|
|
668
|
+
function acos$1(argument) {
|
|
669
|
+
return acosImpl(argument);
|
|
670
|
+
}
|
|
671
|
+
/** @internal */
|
|
672
|
+
function atan2$1(y, x) {
|
|
673
|
+
return atan2Impl(y, x);
|
|
674
|
+
}
|
|
675
|
+
/** @internal */
|
|
676
|
+
function clamp$1(minimum, value, maximum) {
|
|
677
|
+
const lo = toCalc(minimum);
|
|
678
|
+
const mid = toCalc(value);
|
|
679
|
+
const hi = toCalc(maximum);
|
|
680
|
+
return makeCalc(clampNode(nodeOf(lo), nodeOf(mid), nodeOf(hi)), mergeRefs([
|
|
681
|
+
lo,
|
|
682
|
+
mid,
|
|
683
|
+
hi
|
|
684
|
+
]));
|
|
685
|
+
}
|
|
686
|
+
/** @internal */
|
|
687
|
+
function lerp$1(a, b, t) {
|
|
688
|
+
return add$1(multiply$1(subtract$1(1, t), a), multiply$1(t, b));
|
|
689
|
+
}
|
|
690
|
+
/** @internal */
|
|
691
|
+
const collectBindings = (refSet, bindings) => {
|
|
692
|
+
const nodeBindings = {};
|
|
693
|
+
const newRefs = new Set(refSet);
|
|
694
|
+
for (const [key, value] of Object.entries(bindings)) {
|
|
695
|
+
if (value === void 0 || !refSet.has(key)) continue;
|
|
696
|
+
const expr = toCalc(value);
|
|
697
|
+
nodeBindings[key] = nodeOf(expr);
|
|
698
|
+
newRefs.delete(key);
|
|
699
|
+
for (const name of refsOf(expr)) newRefs.add(name);
|
|
700
|
+
}
|
|
701
|
+
return {
|
|
702
|
+
nodeBindings,
|
|
703
|
+
refSet: newRefs
|
|
704
|
+
};
|
|
705
|
+
};
|
|
706
|
+
/** @internal */
|
|
707
|
+
const bind$1 = dual(2, (expr, bindings) => {
|
|
708
|
+
const collected = collectBindings(refsOf(expr), bindings);
|
|
709
|
+
return makeCalc(substituteNode(nodeOf(expr), collected.nodeBindings), collected.refSet);
|
|
710
|
+
});
|
|
711
|
+
/** @internal */
|
|
712
|
+
function solve$1(expr, bindings, context) {
|
|
713
|
+
let node = nodeOf(expr);
|
|
714
|
+
let remaining = refsOf(expr);
|
|
715
|
+
if (bindings !== void 0) {
|
|
716
|
+
const collected = collectBindings(remaining, bindings);
|
|
717
|
+
node = substituteNode(node, collected.nodeBindings);
|
|
718
|
+
remaining = collected.refSet;
|
|
719
|
+
}
|
|
720
|
+
invariant(remaining.size === 0, "Cannot convert expression to number: unbound references remain");
|
|
721
|
+
return evaluateNode(node, context ?? {});
|
|
722
|
+
}
|
|
723
|
+
/** @internal */
|
|
724
|
+
function serialize$1(expr, options) {
|
|
725
|
+
let node = nodeOf(expr);
|
|
726
|
+
if (options?.bindings !== void 0) {
|
|
727
|
+
const collected = collectBindings(refsOf(expr), options.bindings);
|
|
728
|
+
node = substituteNode(node, collected.nodeBindings);
|
|
729
|
+
}
|
|
730
|
+
const precision = options?.precision === void 0 ? DEFAULT_FORMAT : toSpec(options.precision);
|
|
731
|
+
return serializeTop(node, precision);
|
|
732
|
+
}
|
|
733
|
+
/** @internal */
|
|
734
|
+
function refs$1(expr) {
|
|
735
|
+
return refsOf(expr);
|
|
736
|
+
}
|
|
737
|
+
/** @internal */
|
|
738
|
+
function channels$1(expr) {
|
|
739
|
+
return identsOf(nodeOf(expr));
|
|
740
|
+
}
|
|
741
|
+
/** @internal */
|
|
742
|
+
const equals$1 = dual(2, (self, that) => equals$2(self, that));
|
|
743
|
+
//#endregion
|
|
744
|
+
//#region src/calc/calc.ts
|
|
745
|
+
var calc_exports = /* @__PURE__ */ __exportAll({
|
|
746
|
+
abs: () => abs,
|
|
747
|
+
acos: () => acos,
|
|
748
|
+
add: () => add,
|
|
749
|
+
atan2: () => atan2,
|
|
750
|
+
bind: () => bind,
|
|
751
|
+
channels: () => channels,
|
|
752
|
+
clamp: () => clamp,
|
|
753
|
+
cos: () => cos,
|
|
754
|
+
divide: () => divide,
|
|
755
|
+
equals: () => equals,
|
|
756
|
+
isCalc: () => isCalc,
|
|
757
|
+
lerp: () => lerp,
|
|
758
|
+
max: () => max,
|
|
759
|
+
min: () => min,
|
|
760
|
+
mod: () => mod,
|
|
761
|
+
multiply: () => multiply,
|
|
762
|
+
of: () => of,
|
|
763
|
+
pow: () => pow,
|
|
764
|
+
ref: () => ref,
|
|
765
|
+
refs: () => refs,
|
|
766
|
+
serialize: () => serialize,
|
|
767
|
+
sign: () => sign,
|
|
768
|
+
signedPow: () => signedPow,
|
|
769
|
+
sin: () => sin,
|
|
770
|
+
solve: () => solve,
|
|
771
|
+
subtract: () => subtract,
|
|
772
|
+
tan: () => tan
|
|
773
|
+
});
|
|
774
|
+
/**
|
|
775
|
+
* Checks if a value is a `Calc`.
|
|
776
|
+
*
|
|
777
|
+
* True only for values built by this module's constructors, which carry
|
|
778
|
+
* the brand.
|
|
779
|
+
*
|
|
780
|
+
* @param u - The value to check.
|
|
781
|
+
* @returns `true` if the value is a `Calc`, `false` otherwise.
|
|
782
|
+
* @since 0.1.0
|
|
783
|
+
*/
|
|
784
|
+
const isCalc = isCalc$1;
|
|
785
|
+
/**
|
|
786
|
+
* Creates a constant expression, optionally annotated with a serialization
|
|
787
|
+
* precision that overrides the context default wherever the constant lands
|
|
788
|
+
* — including in constants produced by folding it with others (the
|
|
789
|
+
* highest-fidelity operand annotation wins).
|
|
790
|
+
*
|
|
791
|
+
* Bare numbers passed to combinators become unannotated constants; `of`
|
|
792
|
+
* exists to name a value or pin its precision.
|
|
793
|
+
*
|
|
794
|
+
* @param value - The constant value. Must be finite.
|
|
795
|
+
* @param precision - Optional precision annotation.
|
|
796
|
+
* @returns A constant `Calc<never>`.
|
|
797
|
+
* @throws `Error` when `value` is not finite.
|
|
798
|
+
* @example
|
|
799
|
+
* ```ts
|
|
800
|
+
* const k = Calc.of(0.8377580409572781, Precision.significant(10))
|
|
801
|
+
* Calc.serialize(Calc.multiply(k, Calc.ref('t'))) // 'calc(0.837758041 * var(--t))'
|
|
802
|
+
* ```
|
|
803
|
+
* @since 0.1.0
|
|
804
|
+
*/
|
|
805
|
+
const of = of$1;
|
|
806
|
+
/**
|
|
807
|
+
* Creates a reference to an unbound name. References serialize as
|
|
808
|
+
* `var(--name)` and are the channel through which expressions read CSS
|
|
809
|
+
* custom properties; `bind` replaces them with values or other
|
|
810
|
+
* expressions.
|
|
811
|
+
*
|
|
812
|
+
* Repeated calls with the same name return the same instance.
|
|
813
|
+
*
|
|
814
|
+
* @param name - The reference name, without the `--` prefix. Must be non-empty.
|
|
815
|
+
* @returns A `Calc` with `name` as its one unbound reference.
|
|
816
|
+
* @throws `Error` when `name` is empty.
|
|
817
|
+
* @example
|
|
818
|
+
* ```ts
|
|
819
|
+
* Calc.serialize(Calc.ref('width')) // 'var(--width)'
|
|
820
|
+
* ```
|
|
821
|
+
* @since 0.1.0
|
|
822
|
+
*/
|
|
823
|
+
const ref = ref$1;
|
|
824
|
+
/**
|
|
825
|
+
* Adds expressions. Constant operands fold at construction.
|
|
826
|
+
*
|
|
827
|
+
* Serializes as `a + b + ...` inside a `calc()` wrapper; negative constant
|
|
828
|
+
* terms (and products led by a negative constant) render subtractively:
|
|
829
|
+
* `a + (-2)` serializes as `a - 2`.
|
|
830
|
+
*
|
|
831
|
+
* @param a - The first operand.
|
|
832
|
+
* @param b - The second operand.
|
|
833
|
+
* @returns The sum, with the operands' references unioned.
|
|
834
|
+
* @example
|
|
835
|
+
* ```ts
|
|
836
|
+
* Calc.serialize(Calc.add(Calc.ref('x'), 10)) // 'calc(var(--x) + 10)'
|
|
837
|
+
* ```
|
|
838
|
+
* @since 0.1.0
|
|
839
|
+
*/
|
|
840
|
+
const add = add$1;
|
|
841
|
+
/**
|
|
842
|
+
* Subtracts `right` from `left`. Constant operands fold at construction.
|
|
843
|
+
*
|
|
844
|
+
* @param left - The minuend.
|
|
845
|
+
* @param right - The subtrahend.
|
|
846
|
+
* @returns The difference, with the operands' references unioned.
|
|
847
|
+
* @since 0.1.0
|
|
848
|
+
*/
|
|
849
|
+
const subtract = subtract$1;
|
|
850
|
+
/**
|
|
851
|
+
* The CSS `mod()` of `dividend` and `divisor` — the remainder that takes the
|
|
852
|
+
* sign of the divisor (the floored modulo), so `mod(x, 360)` lands in
|
|
853
|
+
* `[0, 360)` for a positive divisor. Same-kind operands, as `subtract`;
|
|
854
|
+
* constant operands fold at construction.
|
|
855
|
+
*
|
|
856
|
+
* @param dividend - The value to reduce.
|
|
857
|
+
* @param divisor - The modulus, sharing `dividend`'s kind.
|
|
858
|
+
* @returns The modulo, with the operands' references unioned.
|
|
859
|
+
* @example
|
|
860
|
+
* ```ts
|
|
861
|
+
* Calc.serialize(Calc.mod(Calc.ref('h'), 360)) // 'mod(var(--h), 360)'
|
|
862
|
+
* ```
|
|
863
|
+
* @since 0.2.0
|
|
864
|
+
*/
|
|
865
|
+
const mod = mod$1;
|
|
866
|
+
/**
|
|
867
|
+
* Multiplies expressions. Constant operands fold at construction.
|
|
868
|
+
*
|
|
869
|
+
* Addition and subtraction operands are parenthesized when serialized
|
|
870
|
+
* under a product: `(a + b) * c`.
|
|
871
|
+
*
|
|
872
|
+
* @param left - The first factor.
|
|
873
|
+
* @param right - The second factor.
|
|
874
|
+
* @returns The product, with the operands' references unioned.
|
|
875
|
+
* @since 0.1.0
|
|
876
|
+
*/
|
|
877
|
+
const multiply = multiply$1;
|
|
878
|
+
/**
|
|
879
|
+
* Divides `left` by `right`. Constant operands fold at construction.
|
|
880
|
+
*
|
|
881
|
+
* @param left - The dividend.
|
|
882
|
+
* @param right - The divisor.
|
|
883
|
+
* @returns The quotient, with the operands' references unioned.
|
|
884
|
+
* @since 0.1.0
|
|
885
|
+
*/
|
|
886
|
+
const divide = divide$1;
|
|
887
|
+
/**
|
|
888
|
+
* Raises `base` to `exponent`. Serializes as the CSS `pow()` function.
|
|
889
|
+
*
|
|
890
|
+
* @param base - The base.
|
|
891
|
+
* @param exponent - The exponent.
|
|
892
|
+
* @returns The power, with the operands' references unioned.
|
|
893
|
+
* @since 0.1.0
|
|
894
|
+
*/
|
|
895
|
+
const pow = pow$1;
|
|
896
|
+
/**
|
|
897
|
+
* Sign-preserving power: `abs(base) ^ exponent * sign(base)`. Unlike
|
|
898
|
+
* `pow`, well-defined for negative bases with fractional exponents.
|
|
899
|
+
* Serializes as `pow(abs(base), exponent) * sign(base)`.
|
|
900
|
+
*
|
|
901
|
+
* @param base - The base.
|
|
902
|
+
* @param exponent - The exponent.
|
|
903
|
+
* @returns The signed power, with the operands' references unioned.
|
|
904
|
+
* @since 0.1.0
|
|
905
|
+
*/
|
|
906
|
+
const signedPow = signedPow$1;
|
|
907
|
+
/**
|
|
908
|
+
* The minimum of the operands. Serializes as the CSS `min()` function.
|
|
909
|
+
*
|
|
910
|
+
* @param a - The first operand.
|
|
911
|
+
* @param b - The second operand.
|
|
912
|
+
* @returns The minimum, with the operands' references unioned.
|
|
913
|
+
* @since 0.1.0
|
|
914
|
+
*/
|
|
915
|
+
const min = min$1;
|
|
916
|
+
/**
|
|
917
|
+
* The maximum of the operands. Serializes as the CSS `max()` function.
|
|
918
|
+
*
|
|
919
|
+
* @param a - The first operand.
|
|
920
|
+
* @param b - The second operand.
|
|
921
|
+
* @returns The maximum, with the operands' references unioned.
|
|
922
|
+
* @since 0.1.0
|
|
923
|
+
*/
|
|
924
|
+
const max = max$1;
|
|
925
|
+
/**
|
|
926
|
+
* Clamps `value` between `minimum` and `maximum`. Serializes as the CSS
|
|
927
|
+
* `clamp()` function, with the CSS argument order `(min, value, max)`.
|
|
928
|
+
*
|
|
929
|
+
* @param minimum - The lower bound.
|
|
930
|
+
* @param value - The value to clamp.
|
|
931
|
+
* @param maximum - The upper bound.
|
|
932
|
+
* @returns The clamped expression, with the operands' references unioned.
|
|
933
|
+
* @example
|
|
934
|
+
* ```ts
|
|
935
|
+
* Calc.serialize(Calc.clamp(-1, Calc.ref('u'), 1)) // 'clamp(-1, var(--u), 1)'
|
|
936
|
+
* ```
|
|
937
|
+
* @since 0.1.0
|
|
938
|
+
*/
|
|
939
|
+
const clamp = clamp$1;
|
|
940
|
+
/**
|
|
941
|
+
* Linear interpolation from `a` to `b` by `t`. This is sugar, not a node:
|
|
942
|
+
* it desugars to `(1 - t) * a + t * b`, and serializes as that expanded
|
|
943
|
+
* form.
|
|
944
|
+
*
|
|
945
|
+
* @param a - The value at `t = 0`.
|
|
946
|
+
* @param b - The value at `t = 1`.
|
|
947
|
+
* @param t - The interpolation parameter.
|
|
948
|
+
* @returns The interpolated expression, with the operands' references unioned.
|
|
949
|
+
* @since 0.1.0
|
|
950
|
+
*/
|
|
951
|
+
const lerp = lerp$1;
|
|
952
|
+
/**
|
|
953
|
+
* The absolute value. Serializes as the CSS `abs()` function.
|
|
954
|
+
*
|
|
955
|
+
* @param argument - The operand.
|
|
956
|
+
* @returns The absolute value expression.
|
|
957
|
+
* @since 0.1.0
|
|
958
|
+
*/
|
|
959
|
+
const abs = abs$1;
|
|
960
|
+
/**
|
|
961
|
+
* The sign (`-1`, `0`, or `1`). Serializes as the CSS `sign()` function.
|
|
962
|
+
*
|
|
963
|
+
* @param argument - The operand.
|
|
964
|
+
* @returns The sign expression.
|
|
965
|
+
* @since 0.1.0
|
|
966
|
+
*/
|
|
967
|
+
const sign = sign$1;
|
|
968
|
+
/**
|
|
969
|
+
* The sine of its argument. Serializes as the CSS `sin()` function, which
|
|
970
|
+
* accepts an `<angle>` or a plain number treated as radians — so this takes
|
|
971
|
+
* either an angle-kind expression or a number, and returns a number.
|
|
972
|
+
*
|
|
973
|
+
* @param argument - An angle, or a plain number in radians.
|
|
974
|
+
* @returns The sine, a `<number>`, carrying the argument's units.
|
|
975
|
+
* @since 0.1.0
|
|
976
|
+
*/
|
|
977
|
+
const sin = sin$1;
|
|
978
|
+
/**
|
|
979
|
+
* The cosine of its argument. Serializes as the CSS `cos()` function, which
|
|
980
|
+
* accepts an `<angle>` or a plain number treated as radians — so this takes
|
|
981
|
+
* either an angle-kind expression or a number, and returns a number.
|
|
982
|
+
*
|
|
983
|
+
* @param argument - An angle, or a plain number in radians.
|
|
984
|
+
* @returns The cosine, a `<number>`, carrying the argument's units.
|
|
985
|
+
* @since 0.1.0
|
|
986
|
+
*/
|
|
987
|
+
const cos = cos$1;
|
|
988
|
+
/**
|
|
989
|
+
* The tangent of its argument. Serializes as the CSS `tan()` function, which
|
|
990
|
+
* accepts an `<angle>` or a plain number treated as radians. Paired with
|
|
991
|
+
* `atan2`, `tan(atan2(a, b))` divides two same-kind dimensions to a `<number>` —
|
|
992
|
+
* the length ratio that works where `a / b` does not, since Firefox does not
|
|
993
|
+
* yet support `<length> / <length>` in `calc()`.
|
|
994
|
+
*
|
|
995
|
+
* @param argument - An angle, or a plain number in radians.
|
|
996
|
+
* @returns The tangent, a `<number>`, carrying the argument's units.
|
|
997
|
+
* @since 0.2.0
|
|
998
|
+
*/
|
|
999
|
+
const tan = tan$1;
|
|
1000
|
+
/**
|
|
1001
|
+
* The arccosine of a value in `[-1, 1]`, an `<angle>` in radians (CSS's
|
|
1002
|
+
* `acos()` returns an `<angle>`). Solving evaluates `Math.acos`, in radians.
|
|
1003
|
+
*
|
|
1004
|
+
* Because the result is angle-kind, it composes only with other angles: divide
|
|
1005
|
+
* or scale it by a number, and add or subtract an `Angle.rad(...)` phase. A
|
|
1006
|
+
* plain number added to it is a type error — supply the phase as an angle.
|
|
1007
|
+
*
|
|
1008
|
+
* @param argument - The cosine value, in `[-1, 1]`.
|
|
1009
|
+
* @returns The arccosine, an `<angle>`, carrying the argument's units.
|
|
1010
|
+
* @example
|
|
1011
|
+
* ```ts
|
|
1012
|
+
* const phase = Angle.rad(2.0943951)
|
|
1013
|
+
* Calc.serialize(Calc.cos(Calc.subtract(Calc.divide(Calc.acos(Calc.ref('u')), 3), phase)))
|
|
1014
|
+
* // 'cos(acos(var(--u)) / 3 - 2.0944rad)'
|
|
1015
|
+
* ```
|
|
1016
|
+
* @since 0.1.0
|
|
1017
|
+
*/
|
|
1018
|
+
const acos = acos$1;
|
|
1019
|
+
/**
|
|
1020
|
+
* The angle, in radians, of the vector from the origin to `(x, y)` — CSS's
|
|
1021
|
+
* `atan2()`, which returns an `<angle>`. The operands must share a kind (two
|
|
1022
|
+
* numbers, two lengths, two angles); their units cancel in the ratio, so
|
|
1023
|
+
* `tan(atan2(a, b))` recovers `a / b` as a `<number>` and is the portable way to
|
|
1024
|
+
* divide two `<length>`s.
|
|
1025
|
+
*
|
|
1026
|
+
* @param y - The vertical component.
|
|
1027
|
+
* @param x - The horizontal component, sharing `y`'s kind.
|
|
1028
|
+
* @returns The angle, an `<angle>`, with the operands' units unioned.
|
|
1029
|
+
* @example
|
|
1030
|
+
* ```ts
|
|
1031
|
+
* const ratio = Calc.tan(Calc.atan2(Calc.subtract(Length.vw(100), Length.px(320)), Length.px(160)))
|
|
1032
|
+
* Calc.serialize(ratio) // 'tan(atan2(100vw - 320px, 160px))'
|
|
1033
|
+
* ```
|
|
1034
|
+
* @since 0.2.0
|
|
1035
|
+
*/
|
|
1036
|
+
const atan2 = atan2$1;
|
|
1037
|
+
const bind = bind$1;
|
|
1038
|
+
const solve = solve$1;
|
|
1039
|
+
/**
|
|
1040
|
+
* Renders an expression as CSS text. Arithmetic gets a `calc()` wrapper;
|
|
1041
|
+
* function forms (`min`, `clamp`, `sin`, ...) and leaves stand alone.
|
|
1042
|
+
* References render as `var(--name)`.
|
|
1043
|
+
*
|
|
1044
|
+
* Bindings in `options` are applied first and may be partial — this is
|
|
1045
|
+
* the serialize half of the solve/serialize duality, and unbound
|
|
1046
|
+
* references are the values left for the browser. Constants render with
|
|
1047
|
+
* their annotated precision, or the context `precision` option (default
|
|
1048
|
+
* `Precision.decimals(5)`). Constants equal to pi render as the CSS
|
|
1049
|
+
* constant `pi` where a math function surrounds them.
|
|
1050
|
+
*
|
|
1051
|
+
* @param expr - The expression to render.
|
|
1052
|
+
* @param options - Optional bindings and precision context.
|
|
1053
|
+
* @returns Deterministic CSS text.
|
|
1054
|
+
* @example
|
|
1055
|
+
* ```ts
|
|
1056
|
+
* const fluid = Calc.add(10, Calc.ref('runtime'))
|
|
1057
|
+
* Calc.serialize(fluid) // 'calc(10 + var(--runtime))'
|
|
1058
|
+
* Calc.serialize(fluid, { bindings: { runtime: 4 } }) // '14'
|
|
1059
|
+
* ```
|
|
1060
|
+
* @since 0.1.0
|
|
1061
|
+
*/
|
|
1062
|
+
const serialize = serialize$1;
|
|
1063
|
+
/**
|
|
1064
|
+
* The expression's unbound reference names.
|
|
1065
|
+
*
|
|
1066
|
+
* @param expr - The expression to inspect.
|
|
1067
|
+
* @returns The set of unbound reference names.
|
|
1068
|
+
* @since 0.1.0
|
|
1069
|
+
*/
|
|
1070
|
+
const refs = refs$1;
|
|
1071
|
+
/**
|
|
1072
|
+
* The channel-keyword tokens the expression reads — the `Channel` keywords a
|
|
1073
|
+
* relative color introduces (`l`, `c`, `h`, ...). Empty for an expression with
|
|
1074
|
+
* no channel keywords.
|
|
1075
|
+
*
|
|
1076
|
+
* This is the runtime companion to the `Leaves`-level scoping that `solve`'s
|
|
1077
|
+
* context requires: `channels` reports which values a context must supply,
|
|
1078
|
+
* exactly as `refs` reports the custom properties a binding must, and — unlike
|
|
1079
|
+
* a `Calc`'s `Kind`/`Leaves` type — survives on a `Calc<Refs, Kind, unknown>`
|
|
1080
|
+
* whose leaves have been erased. Channel keywords are not references, so `refs`
|
|
1081
|
+
* never lists them and they never reach a `Stylesheet`'s dependency report.
|
|
1082
|
+
*
|
|
1083
|
+
* @param expr - The expression to inspect.
|
|
1084
|
+
* @returns The set of channel-keyword tokens the expression reads.
|
|
1085
|
+
* @example
|
|
1086
|
+
* ```ts
|
|
1087
|
+
* Calc.channels(Calc.multiply(Channel.L, 0.8)) // Set { 'l' }
|
|
1088
|
+
* Calc.channels(Calc.ref('x')) // Set {}
|
|
1089
|
+
* ```
|
|
1090
|
+
* @since 0.2.0
|
|
1091
|
+
*/
|
|
1092
|
+
const channels = channels$1;
|
|
1093
|
+
const equals = equals$1;
|
|
1094
|
+
//#endregion
|
|
1095
|
+
//#region src/calc/precision.ts
|
|
1096
|
+
var precision_exports = /* @__PURE__ */ __exportAll({
|
|
1097
|
+
decimals: () => decimals,
|
|
1098
|
+
isPrecision: () => isPrecision,
|
|
1099
|
+
significant: () => significant
|
|
1100
|
+
});
|
|
1101
|
+
/**
|
|
1102
|
+
* Checks if a value is a `Precision`.
|
|
1103
|
+
*
|
|
1104
|
+
* True only for values built by `decimals` or `significant`, which carry
|
|
1105
|
+
* the brand.
|
|
1106
|
+
*
|
|
1107
|
+
* @param u - The value to check.
|
|
1108
|
+
* @returns `true` if the value is a `Precision`, `false` otherwise.
|
|
1109
|
+
* @since 0.1.0
|
|
1110
|
+
*/
|
|
1111
|
+
const isPrecision = isPrecision$1;
|
|
1112
|
+
/**
|
|
1113
|
+
* Creates a `Precision` fixing the count of digits after the decimal
|
|
1114
|
+
* point. The library default for unannotated constants is `decimals(5)`.
|
|
1115
|
+
*
|
|
1116
|
+
* @param digits - Digits after the decimal point. Must be an integer in `[0, 100]`.
|
|
1117
|
+
* @returns A `Precision` in `decimals` mode.
|
|
1118
|
+
* @throws `Error` when `digits` is not an integer in `[0, 100]`.
|
|
1119
|
+
* @example
|
|
1120
|
+
* ```ts
|
|
1121
|
+
* Calc.serialize(Calc.of(1 / 3), { precision: Precision.decimals(2) }) // '0.33'
|
|
1122
|
+
* ```
|
|
1123
|
+
* @since 0.1.0
|
|
1124
|
+
*/
|
|
1125
|
+
const decimals = decimals$1;
|
|
1126
|
+
/**
|
|
1127
|
+
* Creates a `Precision` fixing the count of significant digits. Use it for
|
|
1128
|
+
* unit-free constants whose error is amplified downstream — solved curve
|
|
1129
|
+
* coefficients, for example — where fixed decimal places would truncate.
|
|
1130
|
+
*
|
|
1131
|
+
* @param digits - Significant digits. Must be an integer in `[1, 100]`.
|
|
1132
|
+
* @returns A `Precision` in `significant` mode.
|
|
1133
|
+
* @throws `Error` when `digits` is not an integer in `[1, 100]`.
|
|
1134
|
+
* @example
|
|
1135
|
+
* ```ts
|
|
1136
|
+
* const k = Calc.of(0.8377580409572781, Precision.significant(10))
|
|
1137
|
+
* Calc.serialize(k) // '0.837758041'
|
|
1138
|
+
* ```
|
|
1139
|
+
* @since 0.1.0
|
|
1140
|
+
*/
|
|
1141
|
+
const significant = significant$1;
|
|
1142
|
+
//#endregion
|
|
1143
|
+
export { EMPTY_REFS as C, toCalc as S, nodeOf as _, multiply as a, serializeNode as b, bind$1 as c, ident as d, identsOf as f, nodeHash as g, nodeEquals as h, mod as i, collectBindings as l, needsCalcWrap as m, add as n, sign as o, isCalc$1 as p, calc_exports as r, subtract as s, precision_exports as t, dimension as u, refsOf as v, unionRefs as w, substituteNode as x, serialize$1 as y };
|
|
1144
|
+
|
|
1145
|
+
//# sourceMappingURL=calc-Cih4o2r7.mjs.map
|