@ng-native/fabric 0.1.3 → 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/dist/css.d.ts +6 -1
- package/dist/css.js +104 -35
- package/dist/css.js.map +1 -1
- package/dist/inline-derived-token.d.ts +15 -0
- package/dist/inline-derived-token.js +252 -0
- package/dist/inline-derived-token.js.map +1 -0
- package/dist/inline-token.d.ts +4 -3
- package/dist/inline-token.js +20 -4
- package/dist/inline-token.js.map +1 -1
- package/package.json +1 -1
package/dist/css.d.ts
CHANGED
|
@@ -184,6 +184,11 @@ export interface DeferredDeclaration {
|
|
|
184
184
|
*/
|
|
185
185
|
readonly alternatives?: readonly string[];
|
|
186
186
|
readonly fallback?: unknown;
|
|
187
|
+
/**
|
|
188
|
+
* A fallback made of other tokens, `var(--missing, calc(var(--gap) * 2))`, worked out from the
|
|
189
|
+
* tokens in scope where it is used, as a browser substitutes it there.
|
|
190
|
+
*/
|
|
191
|
+
readonly fallbackToken?: TokenValue;
|
|
187
192
|
/**
|
|
188
193
|
* What to write when the reference resolves, whatever it resolves to: `flex: var(--grow)` sets a
|
|
189
194
|
* shrink of 1 and a basis of 0%, but only when there is a grow for them to go with.
|
|
@@ -646,7 +651,7 @@ type ChannelSpace = 'rgb' | 'hsl';
|
|
|
646
651
|
*/
|
|
647
652
|
type CalcExpression = number | {
|
|
648
653
|
readonly reference: string;
|
|
649
|
-
readonly fallback?:
|
|
654
|
+
readonly fallback?: CalcExpression;
|
|
650
655
|
} | readonly ['+' | '-' | '*' | '/' | 'max' | 'min', CalcExpression, CalcExpression];
|
|
651
656
|
interface CalcMarker {
|
|
652
657
|
readonly expression: CalcExpression;
|
package/dist/css.js
CHANGED
|
@@ -896,7 +896,9 @@ export class StyleResolver {
|
|
|
896
896
|
/** A reference with nothing defined for it and nothing to fall back to. */
|
|
897
897
|
reportUndefined(declaration, tokens) {
|
|
898
898
|
const name = declaration.reference;
|
|
899
|
-
if (name === undefined ||
|
|
899
|
+
if (name === undefined || name in tokens)
|
|
900
|
+
return;
|
|
901
|
+
if (declaration.fallback !== undefined || declaration.fallbackToken)
|
|
900
902
|
return;
|
|
901
903
|
if (declaration.alternatives?.some((alternative) => alternative in tokens))
|
|
902
904
|
return;
|
|
@@ -1017,32 +1019,79 @@ function resolveAliases(own, merged) {
|
|
|
1017
1019
|
const names = Object.keys(own);
|
|
1018
1020
|
const aliases = names.filter((name) => own[name].alias);
|
|
1019
1021
|
followAliases(aliases, merged);
|
|
1020
|
-
//
|
|
1021
|
-
//
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1022
|
+
// Left to work out: each token made of others and each alias that came to one, by a link or a
|
|
1023
|
+
// fallback, `var(--missing, calc(var(--gap) * 2))`, which is worked out here as well.
|
|
1024
|
+
const pending = new Set(names.filter((name) => isDerived(merged[name])));
|
|
1025
|
+
if (pending.size)
|
|
1026
|
+
settleDerived(own, merged, pending);
|
|
1027
|
+
return merged;
|
|
1028
|
+
}
|
|
1029
|
+
/** What a token not yet worked out reads as while another is: set, with no form of any kind. */
|
|
1030
|
+
const PENDING = Object.freeze({});
|
|
1031
|
+
/**
|
|
1032
|
+
* The tokens left to work out, each settled once none it reads is still to be, whatever order they
|
|
1033
|
+
* are defined in. One that reads another still to be waits, rather than taking a fallback: a
|
|
1034
|
+
* fallback is for a token that is unset or invalid. When every one left waits for another, those
|
|
1035
|
+
* in a cycle, counting only the references read, are invalid, and the rest go on without them,
|
|
1036
|
+
* taking their fallbacks, as CSS has it.
|
|
1037
|
+
*/
|
|
1038
|
+
function settleDerived(own, merged, pending) {
|
|
1039
|
+
const waitingOn = new Map();
|
|
1040
|
+
let read = new Set();
|
|
1041
|
+
const view = new Proxy(merged, {
|
|
1042
|
+
get: (tokens, name) => {
|
|
1043
|
+
if (!pending.has(name))
|
|
1044
|
+
return tokens[name];
|
|
1045
|
+
read.add(name);
|
|
1046
|
+
return PENDING;
|
|
1047
|
+
},
|
|
1048
|
+
});
|
|
1049
|
+
while (pending.size) {
|
|
1050
|
+
let settled = false;
|
|
1051
|
+
for (const name of pending) {
|
|
1052
|
+
read = new Set();
|
|
1053
|
+
const token = own[name];
|
|
1054
|
+
const value = token.alias ? substitutedIn(token, view) : derived(token, view);
|
|
1055
|
+
if (read.size) {
|
|
1056
|
+
waitingOn.set(name, read);
|
|
1057
|
+
continue;
|
|
1058
|
+
}
|
|
1059
|
+
pending.delete(name);
|
|
1060
|
+
settle(merged, name, value);
|
|
1032
1061
|
settled = true;
|
|
1033
|
-
|
|
1034
|
-
|
|
1062
|
+
}
|
|
1063
|
+
if (settled)
|
|
1064
|
+
continue;
|
|
1065
|
+
for (const name of inCycles(pending, waitingOn)) {
|
|
1066
|
+
pending.delete(name);
|
|
1067
|
+
delete merged[name];
|
|
1068
|
+
}
|
|
1035
1069
|
}
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1070
|
+
}
|
|
1071
|
+
/** An alias's target, or the first of its fallbacks that is set, with one made of others worked out. */
|
|
1072
|
+
function substitutedIn(token, tokens) {
|
|
1073
|
+
let link = token;
|
|
1074
|
+
while (link?.alias) {
|
|
1075
|
+
const target = tokens[link.alias];
|
|
1076
|
+
if (target !== undefined)
|
|
1077
|
+
return target;
|
|
1078
|
+
link = link.fallback;
|
|
1044
1079
|
}
|
|
1045
|
-
return
|
|
1080
|
+
return link && isDerived(link) ? derived(link, tokens) : link;
|
|
1081
|
+
}
|
|
1082
|
+
/** The names among `names` that reach themselves by what each waits on. */
|
|
1083
|
+
function inCycles(names, waitingOn) {
|
|
1084
|
+
const reaches = (from, to, seen) => {
|
|
1085
|
+
for (const next of waitingOn.get(from) ?? []) {
|
|
1086
|
+
if (next === to)
|
|
1087
|
+
return true;
|
|
1088
|
+
if (names.has(next) && !seen.has(next) && seen.add(next) && reaches(next, to, seen)) {
|
|
1089
|
+
return true;
|
|
1090
|
+
}
|
|
1091
|
+
}
|
|
1092
|
+
return false;
|
|
1093
|
+
};
|
|
1094
|
+
return [...names].filter((name) => reaches(name, name, new Set()));
|
|
1046
1095
|
}
|
|
1047
1096
|
/** Whether a token is made of others, and so worked out where it is defined. */
|
|
1048
1097
|
function isDerived(token) {
|
|
@@ -1090,7 +1139,7 @@ function calcToken(markers, tokens) {
|
|
|
1090
1139
|
}
|
|
1091
1140
|
/** An `hsl()` token's channels, read from the tokens in scope, as the colour they make. */
|
|
1092
1141
|
function resolveHsl(hsl, tokens) {
|
|
1093
|
-
const h = hslChannel(hsl.h, tokens);
|
|
1142
|
+
const h = hslChannel(hsl.h, tokens, true);
|
|
1094
1143
|
const s = hslChannel(hsl.s, tokens);
|
|
1095
1144
|
const l = hslChannel(hsl.l, tokens);
|
|
1096
1145
|
const alpha = hsl.alpha === undefined ? 1 : hslChannel(hsl.alpha, tokens);
|
|
@@ -1099,10 +1148,22 @@ function resolveHsl(hsl, tokens) {
|
|
|
1099
1148
|
}
|
|
1100
1149
|
return hslToRgb(h, s, l, alpha);
|
|
1101
1150
|
}
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1151
|
+
/**
|
|
1152
|
+
* A channel's number, or undefined when its token is the wrong kind for the slot: a hue is a
|
|
1153
|
+
* number or an angle, read in degrees, as `0.5turn` is 180 and not 0.5, and never a percentage; a
|
|
1154
|
+
* saturation, a lightness or an alpha is never an angle. The fallback is only for a token that is
|
|
1155
|
+
* not set, as a set one is substituted, whatever it holds.
|
|
1156
|
+
*/
|
|
1157
|
+
function hslChannel(channel, tokens, hue = false) {
|
|
1158
|
+
if (typeof channel === 'number')
|
|
1159
|
+
return channel;
|
|
1160
|
+
const token = tokens[channel.reference];
|
|
1161
|
+
if (!token)
|
|
1162
|
+
return channel.fallback;
|
|
1163
|
+
if (!hue)
|
|
1164
|
+
return token.angle === undefined ? token.number : undefined;
|
|
1165
|
+
const percentage = typeof token.length === 'string' && token.length.endsWith('%');
|
|
1166
|
+
return percentage ? undefined : (token.angle ?? token.number);
|
|
1106
1167
|
}
|
|
1107
1168
|
/**
|
|
1108
1169
|
* `hsl(h, s, l)` converted to sRGB, printed the same way `fromChannels` prints an rgba() built
|
|
@@ -1111,7 +1172,11 @@ function hslChannel(channel, tokens) {
|
|
|
1111
1172
|
* `h` is degrees; `s` and `l` are fractions, which is what a percentage token already reads as
|
|
1112
1173
|
* (see `formOf`), so nothing here rescales them.
|
|
1113
1174
|
*/
|
|
1114
|
-
function hslToRgb(h,
|
|
1175
|
+
function hslToRgb(h, saturation, l, opacity) {
|
|
1176
|
+
// Out of range as CSS Color 4 takes it: a saturation below 0 is 0, an alpha is clamped, and
|
|
1177
|
+
// anything else is converted as it is, each channel it makes then clamped into sRGB.
|
|
1178
|
+
const s = Math.max(0, saturation);
|
|
1179
|
+
const alpha = Math.min(1, Math.max(0, opacity));
|
|
1115
1180
|
const hue = ((h % 360) + 360) % 360;
|
|
1116
1181
|
const chroma = (1 - Math.abs(2 * l - 1)) * s;
|
|
1117
1182
|
const x = chroma * (1 - Math.abs(((hue / 60) % 2) - 1));
|
|
@@ -1127,9 +1192,7 @@ function hslToRgb(h, s, l, alpha) {
|
|
|
1127
1192
|
: hue < 300
|
|
1128
1193
|
? [x, 0, chroma]
|
|
1129
1194
|
: [chroma, 0, x];
|
|
1130
|
-
const r = Math.round((
|
|
1131
|
-
const g = Math.round((g1 + m) * 255);
|
|
1132
|
-
const b = Math.round((b1 + m) * 255);
|
|
1195
|
+
const [r, g, b] = [r1, g1, b1].map((c) => Math.round(Math.min(1, Math.max(0, c + m)) * 255));
|
|
1133
1196
|
return alpha >= 1
|
|
1134
1197
|
? `rgb(${r}, ${g}, ${b})`
|
|
1135
1198
|
: `rgba(${r}, ${g}, ${b}, ${Math.round(alpha * 1000) / 1000})`;
|
|
@@ -1180,12 +1243,17 @@ function referenced(declaration, tokens) {
|
|
|
1180
1243
|
break;
|
|
1181
1244
|
value = formOf(tokens[alternative], declaration.kind);
|
|
1182
1245
|
}
|
|
1183
|
-
value ??= declaration
|
|
1246
|
+
value ??= fallbackOf(declaration, tokens);
|
|
1184
1247
|
const base = CHANNEL_KINDS.has(declaration.kind)
|
|
1185
1248
|
? fromChannels(value, declaration.alpha, tokens, declaration.space)
|
|
1186
1249
|
: value;
|
|
1187
1250
|
return declaration.adjust ? adjusted(base, declaration.adjust) : base;
|
|
1188
1251
|
}
|
|
1252
|
+
/** The fallback written, or one made of other tokens, worked out from the tokens where it is used. */
|
|
1253
|
+
function fallbackOf(declaration, tokens) {
|
|
1254
|
+
const token = declaration.fallbackToken;
|
|
1255
|
+
return declaration.fallback ?? (token && formOf(derived(token, tokens), declaration.kind));
|
|
1256
|
+
}
|
|
1189
1257
|
const CHANNEL_KINDS = new Set(['channels', 'hslChannels']);
|
|
1190
1258
|
/**
|
|
1191
1259
|
* `13, 110, 253` as the colour it is, at the alpha the token beside it says, if one does: the
|
|
@@ -1356,7 +1424,8 @@ function calculated(expression, kind, tokens) {
|
|
|
1356
1424
|
return expression;
|
|
1357
1425
|
if (!Array.isArray(expression)) {
|
|
1358
1426
|
const leaf = expression;
|
|
1359
|
-
|
|
1427
|
+
const own = tokenNumber(tokens[leaf.reference], kind);
|
|
1428
|
+
return (own ?? (leaf.fallback === undefined ? undefined : calculated(leaf.fallback, kind, tokens)));
|
|
1360
1429
|
}
|
|
1361
1430
|
const [op, a, b] = expression;
|
|
1362
1431
|
const left = calculated(a, kind, tokens);
|