stickyflow 0.9.3 → 0.11.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/CHANGELOG.md +20 -0
- package/README.md +1 -1
- package/dist/binding/index.cjs +9 -9
- package/dist/binding/index.d.cts +4 -4
- package/dist/binding/index.d.ts +4 -4
- package/dist/binding/index.js +3 -3
- package/dist/{chunk-EURX7QT3.cjs → chunk-5G3BEXQU.cjs} +1300 -891
- package/dist/chunk-5G3BEXQU.cjs.map +1 -0
- package/dist/{chunk-AAP24GBG.js → chunk-BFQWCOEC.js} +3 -3
- package/dist/chunk-BFQWCOEC.js.map +1 -0
- package/dist/{chunk-3EOG34QN.cjs → chunk-F24JURN2.cjs} +561 -258
- package/dist/chunk-F24JURN2.cjs.map +1 -0
- package/dist/{chunk-2GKXPZRL.cjs → chunk-FXGXUWSI.cjs} +23 -23
- package/dist/chunk-FXGXUWSI.cjs.map +1 -0
- package/dist/{chunk-Q6FBISNP.js → chunk-G6IW2IX3.js} +601 -350
- package/dist/chunk-G6IW2IX3.js.map +1 -0
- package/dist/{chunk-G2N3KJYJ.js → chunk-Q6QLU6YQ.js} +662 -253
- package/dist/chunk-Q6QLU6YQ.js.map +1 -0
- package/dist/{chunk-C3LVKPWQ.js → chunk-RQYZNW2I.js} +532 -229
- package/dist/chunk-RQYZNW2I.js.map +1 -0
- package/dist/{chunk-XNNNIOJU.js → chunk-UB2ANTWF.js} +5 -5
- package/dist/{chunk-XNNNIOJU.js.map → chunk-UB2ANTWF.js.map} +1 -1
- package/dist/{chunk-C25NWWIH.cjs → chunk-UHKFJBY5.cjs} +605 -350
- package/dist/chunk-UHKFJBY5.cjs.map +1 -0
- package/dist/{chunk-MR32IJQO.cjs → chunk-WZA3DJJH.cjs} +15 -15
- package/dist/chunk-WZA3DJJH.cjs.map +1 -0
- package/dist/index.cjs +36 -36
- package/dist/index.d.cts +35 -30
- package/dist/index.d.ts +35 -30
- package/dist/index.js +5 -5
- package/dist/interaction/index.cjs +319 -352
- package/dist/interaction/index.cjs.map +1 -1
- package/dist/interaction/index.d.cts +3 -3
- package/dist/interaction/index.d.ts +3 -3
- package/dist/interaction/index.js +94 -127
- package/dist/interaction/index.js.map +1 -1
- package/dist/{render-DU4lYbRl.d.ts → render-BDO4S5uF.d.cts} +16 -0
- package/dist/{render-DU4lYbRl.d.cts → render-BDO4S5uF.d.ts} +16 -0
- package/dist/{runtime-DG8X3Fwf.d.cts → runtime-C-C5v9po.d.cts} +2 -2
- package/dist/{runtime-kqD1RS17.d.ts → runtime-lCAfU-1Q.d.ts} +2 -2
- package/dist/{runtimeTypes-vRaHOIHi.d.ts → runtimeTypes-B7p6b1Bi.d.cts} +2 -2
- package/dist/{runtimeTypes-CvjlBZds.d.cts → runtimeTypes-BDA_CfWh.d.ts} +2 -2
- package/dist/stickyflow-diagram.global.js +197 -44
- package/dist/stickyflow-diagram.global.js.map +1 -1
- package/dist/{types-B5jrEEcF.d.cts → types-CZJzycKw.d.cts} +1 -1
- package/dist/{types-B7IkZ0w4.d.ts → types-Dp8JVZLB.d.ts} +1 -1
- package/dist/viewer/index.cjs +9 -9
- package/dist/viewer/index.d.cts +4 -4
- package/dist/viewer/index.d.ts +4 -4
- package/dist/viewer/index.js +4 -4
- package/dist/web-component/index.cjs +6 -6
- package/dist/web-component/index.cjs.map +1 -1
- package/dist/web-component/index.d.cts +2 -2
- package/dist/web-component/index.d.ts +2 -2
- package/dist/web-component/index.js +4 -4
- package/dist/web-component/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-2GKXPZRL.cjs.map +0 -1
- package/dist/chunk-3EOG34QN.cjs.map +0 -1
- package/dist/chunk-AAP24GBG.js.map +0 -1
- package/dist/chunk-C25NWWIH.cjs.map +0 -1
- package/dist/chunk-C3LVKPWQ.js.map +0 -1
- package/dist/chunk-EURX7QT3.cjs.map +0 -1
- package/dist/chunk-G2N3KJYJ.js.map +0 -1
- package/dist/chunk-MR32IJQO.cjs.map +0 -1
- package/dist/chunk-Q6FBISNP.js.map +0 -1
|
@@ -191,23 +191,135 @@ function extrudeFootprint(frame, footprint, cornerRadius = 0) {
|
|
|
191
191
|
return { top, sides };
|
|
192
192
|
}
|
|
193
193
|
|
|
194
|
-
// src/model/
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
194
|
+
// src/model/color/conversion.ts
|
|
195
|
+
var hexToRgb = (hex) => {
|
|
196
|
+
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})?$/i.exec(hex);
|
|
197
|
+
if (!result) {
|
|
198
|
+
return { r: 255, g: 255, b: 255, a: 1 };
|
|
199
|
+
}
|
|
200
|
+
return {
|
|
201
|
+
r: parseInt(result[1], 16),
|
|
202
|
+
g: parseInt(result[2], 16),
|
|
203
|
+
b: parseInt(result[3], 16),
|
|
204
|
+
a: result[4] === void 0 ? 1 : parseInt(result[4], 16) / 255
|
|
205
|
+
};
|
|
206
|
+
};
|
|
207
|
+
var parseHexRgb = (value) => {
|
|
208
|
+
const match = /^#?([0-9a-f]{3}|[0-9a-f]{6})$/i.exec(value.trim());
|
|
200
209
|
if (!match) {
|
|
201
210
|
return null;
|
|
202
211
|
}
|
|
203
|
-
const
|
|
212
|
+
const digits = match[1].length === 3 ? [...match[1]].map((digit) => digit + digit).join("") : match[1];
|
|
213
|
+
const n = Number.parseInt(digits, 16);
|
|
204
214
|
return [n >> 16 & 255, n >> 8 & 255, n & 255];
|
|
215
|
+
};
|
|
216
|
+
var rgbToHex = (r, g, b, a) => {
|
|
217
|
+
const channel = (x) => {
|
|
218
|
+
const hex = Math.max(0, Math.min(255, Math.round(x))).toString(16);
|
|
219
|
+
return hex.length === 1 ? `0${hex}` : hex;
|
|
220
|
+
};
|
|
221
|
+
const alphaChannel = a === void 0 || a >= 1 ? "" : channel(a * 255);
|
|
222
|
+
return `#${channel(r)}${channel(g)}${channel(b)}${alphaChannel}`;
|
|
223
|
+
};
|
|
224
|
+
var hsvToRgb = (h, s, v) => {
|
|
225
|
+
const c = v * s;
|
|
226
|
+
const x = c * (1 - Math.abs(h / 60 % 2 - 1));
|
|
227
|
+
const m = v - c;
|
|
228
|
+
let r = 0, g = 0, b = 0;
|
|
229
|
+
if (h >= 0 && h < 60) {
|
|
230
|
+
r = c;
|
|
231
|
+
g = x;
|
|
232
|
+
b = 0;
|
|
233
|
+
} else if (h >= 60 && h < 120) {
|
|
234
|
+
r = x;
|
|
235
|
+
g = c;
|
|
236
|
+
b = 0;
|
|
237
|
+
} else if (h >= 120 && h < 180) {
|
|
238
|
+
r = 0;
|
|
239
|
+
g = c;
|
|
240
|
+
b = x;
|
|
241
|
+
} else if (h >= 180 && h < 240) {
|
|
242
|
+
r = 0;
|
|
243
|
+
g = x;
|
|
244
|
+
b = c;
|
|
245
|
+
} else if (h >= 240 && h < 300) {
|
|
246
|
+
r = x;
|
|
247
|
+
g = 0;
|
|
248
|
+
b = c;
|
|
249
|
+
} else if (h >= 300 && h < 360) {
|
|
250
|
+
r = c;
|
|
251
|
+
g = 0;
|
|
252
|
+
b = x;
|
|
253
|
+
}
|
|
254
|
+
return {
|
|
255
|
+
r: Math.round((r + m) * 255),
|
|
256
|
+
g: Math.round((g + m) * 255),
|
|
257
|
+
b: Math.round((b + m) * 255)
|
|
258
|
+
};
|
|
259
|
+
};
|
|
260
|
+
var rgbToHsv = (r, g, b) => {
|
|
261
|
+
r /= 255;
|
|
262
|
+
g /= 255;
|
|
263
|
+
b /= 255;
|
|
264
|
+
const max = Math.max(r, g, b);
|
|
265
|
+
const min = Math.min(r, g, b);
|
|
266
|
+
const delta = max - min;
|
|
267
|
+
let h = 0;
|
|
268
|
+
if (delta !== 0) {
|
|
269
|
+
if (max === r) {
|
|
270
|
+
h = 60 * ((g - b) / delta % 6);
|
|
271
|
+
} else if (max === g) {
|
|
272
|
+
h = 60 * ((b - r) / delta + 2);
|
|
273
|
+
} else if (max === b) {
|
|
274
|
+
h = 60 * ((r - g) / delta + 4);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
if (h < 0) {
|
|
278
|
+
h += 360;
|
|
279
|
+
}
|
|
280
|
+
const s = max === 0 ? 0 : delta / max;
|
|
281
|
+
const v = max;
|
|
282
|
+
return { h, s, v };
|
|
283
|
+
};
|
|
284
|
+
|
|
285
|
+
// src/model/color/interpolation.ts
|
|
286
|
+
function mixHexColors(start, end, ratio) {
|
|
287
|
+
const startRgb = hexToRgb(start);
|
|
288
|
+
const endRgb = hexToRgb(end);
|
|
289
|
+
const startAlpha = startRgb.a ?? 1;
|
|
290
|
+
const endAlpha = endRgb.a ?? 1;
|
|
291
|
+
return rgbToHex(
|
|
292
|
+
Math.round(startRgb.r + (endRgb.r - startRgb.r) * ratio),
|
|
293
|
+
Math.round(startRgb.g + (endRgb.g - startRgb.g) * ratio),
|
|
294
|
+
Math.round(startRgb.b + (endRgb.b - startRgb.b) * ratio),
|
|
295
|
+
startAlpha + (endAlpha - startAlpha) * ratio
|
|
296
|
+
);
|
|
205
297
|
}
|
|
206
|
-
function
|
|
207
|
-
|
|
298
|
+
function interpolateHexColorStops(stops, position) {
|
|
299
|
+
const sortedStops = [...stops].sort((first2, second) => first2.position - second.position);
|
|
300
|
+
const first = sortedStops[0];
|
|
301
|
+
const last = sortedStops[sortedStops.length - 1];
|
|
302
|
+
if (position <= first.position) {
|
|
303
|
+
return first.color;
|
|
304
|
+
}
|
|
305
|
+
if (position >= last.position) {
|
|
306
|
+
return last.color;
|
|
307
|
+
}
|
|
308
|
+
for (let index = 0; index < sortedStops.length - 1; index++) {
|
|
309
|
+
const start = sortedStops[index];
|
|
310
|
+
const end = sortedStops[index + 1];
|
|
311
|
+
if (position >= start.position && position <= end.position) {
|
|
312
|
+
const range = end.position - start.position;
|
|
313
|
+
const ratio = range === 0 ? 0 : (position - start.position) / range;
|
|
314
|
+
return mixHexColors(start.color, end.color, ratio);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
return last.color;
|
|
208
318
|
}
|
|
319
|
+
|
|
320
|
+
// src/model/isometricObject/shading.ts
|
|
209
321
|
function multiply(hex, factor) {
|
|
210
|
-
const rgb =
|
|
322
|
+
const rgb = parseHexRgb(hex);
|
|
211
323
|
if (!rgb) {
|
|
212
324
|
return hex;
|
|
213
325
|
}
|
|
@@ -366,6 +478,36 @@ var BUILT_IN_DESCRIPTORS = [
|
|
|
366
478
|
pointerScale: true,
|
|
367
479
|
size: { width: 200, height: 200 }
|
|
368
480
|
},
|
|
481
|
+
{
|
|
482
|
+
type: "hand",
|
|
483
|
+
group: "readout",
|
|
484
|
+
category: "instrument",
|
|
485
|
+
value: { type: "number", writable: false, default: 0 },
|
|
486
|
+
properties: {
|
|
487
|
+
max: { type: "number", default: 60, min: 1, max: 7200 },
|
|
488
|
+
start: { type: "number", default: 0, min: -360, max: 360 },
|
|
489
|
+
length: { type: "number", default: 0.8, min: 0.05, max: 1, step: 0.01 },
|
|
490
|
+
tail: { type: "number", default: 0, min: 0, max: 1, step: 0.01 },
|
|
491
|
+
gap: { type: "number", default: 0, min: 0, max: 1, step: 0.01 },
|
|
492
|
+
width: { type: "number", default: 6, min: 0.5, max: 80 },
|
|
493
|
+
taper: { type: "number", default: 0.4, min: 0, max: 1, step: 0.05 },
|
|
494
|
+
color: { type: "color", default: "#ffffff" },
|
|
495
|
+
root: { type: "color", default: "", optional: true },
|
|
496
|
+
fade: { type: "number", default: 0, min: 0, max: 1, step: 0.05 },
|
|
497
|
+
tipFade: { type: "number", default: 0, min: 0, max: 1, step: 0.05 },
|
|
498
|
+
soft: { type: "number", default: 0, min: 0, max: 40 },
|
|
499
|
+
bloom: { type: "number", default: 0, min: 0, max: 60 },
|
|
500
|
+
glow: { type: "number", default: 0, min: 0, max: 80 },
|
|
501
|
+
glowColor: { type: "color", default: "", optional: true },
|
|
502
|
+
hub: { type: "number", default: 0, min: 0, max: 80 },
|
|
503
|
+
hubFill: { type: "color", default: "#000000", optional: true },
|
|
504
|
+
hubRing: { type: "number", default: 2, min: 0, max: 40 },
|
|
505
|
+
animate: { type: "number", default: 0, min: 0, max: 2e3, step: 10 }
|
|
506
|
+
},
|
|
507
|
+
interaction: "none",
|
|
508
|
+
pointerScale: false,
|
|
509
|
+
size: { width: 200, height: 200, minWidth: 20, minHeight: 20, aspect: 1 }
|
|
510
|
+
},
|
|
369
511
|
{
|
|
370
512
|
type: "ruler",
|
|
371
513
|
group: "input",
|
|
@@ -1056,6 +1198,7 @@ var NAMED_BLOCK_KINDS = [
|
|
|
1056
1198
|
"Component",
|
|
1057
1199
|
"Shape",
|
|
1058
1200
|
"Text",
|
|
1201
|
+
"Image",
|
|
1059
1202
|
"Isometric",
|
|
1060
1203
|
"Dimension",
|
|
1061
1204
|
"Link",
|
|
@@ -1070,14 +1213,16 @@ var NAMED_BLOCK_KINDS = [
|
|
|
1070
1213
|
"Symbol",
|
|
1071
1214
|
"Port",
|
|
1072
1215
|
"DataSource",
|
|
1073
|
-
"Repeat"
|
|
1216
|
+
"Repeat",
|
|
1217
|
+
"Template",
|
|
1218
|
+
"Use"
|
|
1074
1219
|
];
|
|
1075
1220
|
var SIDES = ["top", "bottom", "left", "right"];
|
|
1076
1221
|
var isSide = (s) => SIDES.includes(s);
|
|
1077
1222
|
var isComponentBlockKind = (kind) => kind === "Component" || kind === "Widget";
|
|
1078
1223
|
var isNamedBlockKind = (s) => NAMED_BLOCK_KINDS.includes(s);
|
|
1079
1224
|
|
|
1080
|
-
// src/sflLanguage/parsing/
|
|
1225
|
+
// src/sflLanguage/parsing/pathSegments.ts
|
|
1081
1226
|
function parsePathSegments(cursor) {
|
|
1082
1227
|
const segments = [cursor.expect("ident", "path identifier").value];
|
|
1083
1228
|
while (cursor.at("dot")) {
|
|
@@ -1086,111 +1231,6 @@ function parsePathSegments(cursor) {
|
|
|
1086
1231
|
}
|
|
1087
1232
|
return segments;
|
|
1088
1233
|
}
|
|
1089
|
-
function parseEndpoint(cursor) {
|
|
1090
|
-
const segments = parsePathSegments(cursor);
|
|
1091
|
-
let side;
|
|
1092
|
-
let fraction;
|
|
1093
|
-
if (cursor.at("comma")) {
|
|
1094
|
-
cursor.next();
|
|
1095
|
-
const sideToken = cursor.expect("ident", 'side after ","');
|
|
1096
|
-
if (!isSide(sideToken.value)) {
|
|
1097
|
-
throw new SflParseError(
|
|
1098
|
-
`expected a side (top/right/bottom/left), got '${sideToken.value}'`,
|
|
1099
|
-
sideToken.line,
|
|
1100
|
-
sideToken.col
|
|
1101
|
-
);
|
|
1102
|
-
}
|
|
1103
|
-
side = sideToken.value;
|
|
1104
|
-
if (cursor.at("lparen")) {
|
|
1105
|
-
cursor.next();
|
|
1106
|
-
fraction = cursor.expectNumber('fraction inside "("');
|
|
1107
|
-
cursor.expect("rparen", "')'");
|
|
1108
|
-
}
|
|
1109
|
-
}
|
|
1110
|
-
return { type: "endpoint", segments, side, fraction };
|
|
1111
|
-
}
|
|
1112
|
-
function parseList(cursor) {
|
|
1113
|
-
cursor.expect("lbracket", "'['");
|
|
1114
|
-
const values = [];
|
|
1115
|
-
cursor.skipNewlines();
|
|
1116
|
-
if (!cursor.at("rbracket")) {
|
|
1117
|
-
values.push(parseValue(cursor, false));
|
|
1118
|
-
cursor.skipNewlines();
|
|
1119
|
-
while (cursor.at("comma")) {
|
|
1120
|
-
cursor.next();
|
|
1121
|
-
cursor.skipNewlines();
|
|
1122
|
-
if (cursor.at("rbracket")) {
|
|
1123
|
-
break;
|
|
1124
|
-
}
|
|
1125
|
-
values.push(parseValue(cursor, false));
|
|
1126
|
-
cursor.skipNewlines();
|
|
1127
|
-
}
|
|
1128
|
-
}
|
|
1129
|
-
cursor.expect("rbracket", "']'");
|
|
1130
|
-
return { type: "list", values };
|
|
1131
|
-
}
|
|
1132
|
-
var ARITHMETIC = /* @__PURE__ */ new Set(["+", "-", "*", "/", ">", "<", ">=", "<=", "==", "!=", "&&", "||"]);
|
|
1133
|
-
function startsComputed(cursor) {
|
|
1134
|
-
const first = cursor.peek();
|
|
1135
|
-
if (first.type === "op" && first.value === "-") {
|
|
1136
|
-
return true;
|
|
1137
|
-
}
|
|
1138
|
-
if (first.type !== "number" && first.type !== "ident" && first.type !== "lparen") {
|
|
1139
|
-
return false;
|
|
1140
|
-
}
|
|
1141
|
-
for (let offset = 0; ; offset++) {
|
|
1142
|
-
const token = cursor.peek(offset);
|
|
1143
|
-
if (token.type === "newline" || token.type === "semi" || token.type === "rbrace" || token.type === "eof") {
|
|
1144
|
-
return false;
|
|
1145
|
-
}
|
|
1146
|
-
if (token.type === "lparen" || token.type === "op" && ARITHMETIC.has(token.value)) {
|
|
1147
|
-
return true;
|
|
1148
|
-
}
|
|
1149
|
-
if (token.type === "ident" && cursor.peek(offset - 1).type === "comma") {
|
|
1150
|
-
return true;
|
|
1151
|
-
}
|
|
1152
|
-
if (offset === 0 && token.type === "ident" && cursor.peek(1).type === "comma") {
|
|
1153
|
-
return true;
|
|
1154
|
-
}
|
|
1155
|
-
}
|
|
1156
|
-
}
|
|
1157
|
-
function parseComputed(cursor) {
|
|
1158
|
-
const items = [parseExpression(cursor)];
|
|
1159
|
-
while (cursor.at("comma")) {
|
|
1160
|
-
cursor.next();
|
|
1161
|
-
items.push(parseExpression(cursor));
|
|
1162
|
-
}
|
|
1163
|
-
return { type: "expr", items };
|
|
1164
|
-
}
|
|
1165
|
-
function parseValue(cursor, allowTuple = true) {
|
|
1166
|
-
if (allowTuple && startsComputed(cursor)) {
|
|
1167
|
-
return parseComputed(cursor);
|
|
1168
|
-
}
|
|
1169
|
-
const token = cursor.peek();
|
|
1170
|
-
switch (token.type) {
|
|
1171
|
-
case "string":
|
|
1172
|
-
cursor.next();
|
|
1173
|
-
return { type: "string", value: token.value };
|
|
1174
|
-
case "lbracket":
|
|
1175
|
-
return parseList(cursor);
|
|
1176
|
-
case "number": {
|
|
1177
|
-
const firstValue = cursor.expectNumber("number");
|
|
1178
|
-
if (!allowTuple || !cursor.at("comma")) {
|
|
1179
|
-
return { type: "number", value: firstValue };
|
|
1180
|
-
}
|
|
1181
|
-
const values = [firstValue];
|
|
1182
|
-
while (cursor.at("comma")) {
|
|
1183
|
-
cursor.next();
|
|
1184
|
-
values.push(cursor.expectNumber("number in tuple"));
|
|
1185
|
-
}
|
|
1186
|
-
return { type: "tuple", values };
|
|
1187
|
-
}
|
|
1188
|
-
case "ident":
|
|
1189
|
-
return { type: "ident", segments: parsePathSegments(cursor) };
|
|
1190
|
-
default:
|
|
1191
|
-
throw new SflParseError(`expected a value, got '${token.value || token.type}'`, token.line, token.col);
|
|
1192
|
-
}
|
|
1193
|
-
}
|
|
1194
1234
|
|
|
1195
1235
|
// src/sflLanguage/parsing/expressions.ts
|
|
1196
1236
|
var COMPARISONS = /* @__PURE__ */ new Set([">", "<", ">=", "<=", "==", "!="]);
|
|
@@ -1316,21 +1356,128 @@ function parseHandler(cursor) {
|
|
|
1316
1356
|
if (cursor.at("eof")) {
|
|
1317
1357
|
throw new SflParseError(`unterminated handler '${event.value}'`, event.line, event.col);
|
|
1318
1358
|
}
|
|
1319
|
-
assignments.push(parseAssignment(cursor));
|
|
1320
|
-
expectEnd(cursor, "assignment");
|
|
1321
|
-
cursor.skipNewlines();
|
|
1359
|
+
assignments.push(parseAssignment(cursor));
|
|
1360
|
+
expectEnd(cursor, "assignment");
|
|
1361
|
+
cursor.skipNewlines();
|
|
1362
|
+
}
|
|
1363
|
+
cursor.expect("rbrace", "'}'");
|
|
1364
|
+
}
|
|
1365
|
+
return { event: event.value, assignments, line: event.line, col: event.col };
|
|
1366
|
+
}
|
|
1367
|
+
function expectEnd(cursor, what) {
|
|
1368
|
+
const next = cursor.peek();
|
|
1369
|
+
if (!["newline", "semi", "rbrace", "eof"].includes(next.type)) {
|
|
1370
|
+
throw new SflParseError(`unexpected '${next.value || next.type}' after ${what}`, next.line, next.col);
|
|
1371
|
+
}
|
|
1372
|
+
if (next.type === "semi") {
|
|
1373
|
+
cursor.next();
|
|
1374
|
+
}
|
|
1375
|
+
}
|
|
1376
|
+
|
|
1377
|
+
// src/sflLanguage/parsing/values.ts
|
|
1378
|
+
function parseEndpoint(cursor) {
|
|
1379
|
+
const segments = parsePathSegments(cursor);
|
|
1380
|
+
let side;
|
|
1381
|
+
let fraction;
|
|
1382
|
+
if (cursor.at("comma")) {
|
|
1383
|
+
cursor.next();
|
|
1384
|
+
const sideToken = cursor.expect("ident", 'side after ","');
|
|
1385
|
+
if (!isSide(sideToken.value)) {
|
|
1386
|
+
throw new SflParseError(
|
|
1387
|
+
`expected a side (top/right/bottom/left), got '${sideToken.value}'`,
|
|
1388
|
+
sideToken.line,
|
|
1389
|
+
sideToken.col
|
|
1390
|
+
);
|
|
1391
|
+
}
|
|
1392
|
+
side = sideToken.value;
|
|
1393
|
+
if (cursor.at("lparen")) {
|
|
1394
|
+
cursor.next();
|
|
1395
|
+
fraction = cursor.expectNumber('fraction inside "("');
|
|
1396
|
+
cursor.expect("rparen", "')'");
|
|
1397
|
+
}
|
|
1398
|
+
}
|
|
1399
|
+
return { type: "endpoint", segments, side, fraction };
|
|
1400
|
+
}
|
|
1401
|
+
function parseList(cursor) {
|
|
1402
|
+
cursor.expect("lbracket", "'['");
|
|
1403
|
+
const values = [];
|
|
1404
|
+
cursor.skipNewlines();
|
|
1405
|
+
if (!cursor.at("rbracket")) {
|
|
1406
|
+
values.push(parseValue(cursor, false));
|
|
1407
|
+
cursor.skipNewlines();
|
|
1408
|
+
while (cursor.at("comma")) {
|
|
1409
|
+
cursor.next();
|
|
1410
|
+
cursor.skipNewlines();
|
|
1411
|
+
if (cursor.at("rbracket")) {
|
|
1412
|
+
break;
|
|
1413
|
+
}
|
|
1414
|
+
values.push(parseValue(cursor, false));
|
|
1415
|
+
cursor.skipNewlines();
|
|
1416
|
+
}
|
|
1417
|
+
}
|
|
1418
|
+
cursor.expect("rbracket", "']'");
|
|
1419
|
+
return { type: "list", values };
|
|
1420
|
+
}
|
|
1421
|
+
var ARITHMETIC = /* @__PURE__ */ new Set(["+", "-", "*", "/", ">", "<", ">=", "<=", "==", "!=", "&&", "||"]);
|
|
1422
|
+
function startsComputed(cursor) {
|
|
1423
|
+
const first = cursor.peek();
|
|
1424
|
+
if (first.type === "op" && first.value === "-") {
|
|
1425
|
+
return true;
|
|
1426
|
+
}
|
|
1427
|
+
if (first.type !== "number" && first.type !== "ident" && first.type !== "lparen") {
|
|
1428
|
+
return false;
|
|
1429
|
+
}
|
|
1430
|
+
for (let offset = 0; ; offset++) {
|
|
1431
|
+
const token = cursor.peek(offset);
|
|
1432
|
+
if (token.type === "newline" || token.type === "semi" || token.type === "rbrace" || token.type === "eof") {
|
|
1433
|
+
return false;
|
|
1434
|
+
}
|
|
1435
|
+
if (token.type === "lparen" || token.type === "op" && ARITHMETIC.has(token.value)) {
|
|
1436
|
+
return true;
|
|
1437
|
+
}
|
|
1438
|
+
if (token.type === "ident" && cursor.peek(offset - 1).type === "comma") {
|
|
1439
|
+
return true;
|
|
1440
|
+
}
|
|
1441
|
+
if (offset === 0 && token.type === "ident" && cursor.peek(1).type === "comma") {
|
|
1442
|
+
return true;
|
|
1443
|
+
}
|
|
1444
|
+
}
|
|
1445
|
+
}
|
|
1446
|
+
function parseComputed(cursor) {
|
|
1447
|
+
const items = [parseExpression(cursor)];
|
|
1448
|
+
while (cursor.at("comma")) {
|
|
1449
|
+
cursor.next();
|
|
1450
|
+
items.push(parseExpression(cursor));
|
|
1451
|
+
}
|
|
1452
|
+
return { type: "expr", items };
|
|
1453
|
+
}
|
|
1454
|
+
function parseValue(cursor, allowTuple = true) {
|
|
1455
|
+
if (allowTuple && startsComputed(cursor)) {
|
|
1456
|
+
return parseComputed(cursor);
|
|
1457
|
+
}
|
|
1458
|
+
const token = cursor.peek();
|
|
1459
|
+
switch (token.type) {
|
|
1460
|
+
case "string":
|
|
1461
|
+
cursor.next();
|
|
1462
|
+
return { type: "string", value: token.value };
|
|
1463
|
+
case "lbracket":
|
|
1464
|
+
return parseList(cursor);
|
|
1465
|
+
case "number": {
|
|
1466
|
+
const firstValue = cursor.expectNumber("number");
|
|
1467
|
+
if (!allowTuple || !cursor.at("comma")) {
|
|
1468
|
+
return { type: "number", value: firstValue };
|
|
1469
|
+
}
|
|
1470
|
+
const values = [firstValue];
|
|
1471
|
+
while (cursor.at("comma")) {
|
|
1472
|
+
cursor.next();
|
|
1473
|
+
values.push(cursor.expectNumber("number in tuple"));
|
|
1474
|
+
}
|
|
1475
|
+
return { type: "tuple", values };
|
|
1322
1476
|
}
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
}
|
|
1327
|
-
function expectEnd(cursor, what) {
|
|
1328
|
-
const next = cursor.peek();
|
|
1329
|
-
if (!["newline", "semi", "rbrace", "eof"].includes(next.type)) {
|
|
1330
|
-
throw new SflParseError(`unexpected '${next.value || next.type}' after ${what}`, next.line, next.col);
|
|
1331
|
-
}
|
|
1332
|
-
if (next.type === "semi") {
|
|
1333
|
-
cursor.next();
|
|
1477
|
+
case "ident":
|
|
1478
|
+
return { type: "ident", segments: parsePathSegments(cursor) };
|
|
1479
|
+
default:
|
|
1480
|
+
throw new SflParseError(`expected a value, got '${token.value || token.type}'`, token.line, token.col);
|
|
1334
1481
|
}
|
|
1335
1482
|
}
|
|
1336
1483
|
|
|
@@ -1608,7 +1755,7 @@ function emitComposition(composition) {
|
|
|
1608
1755
|
return ` : ${composition.join(" & ")}`;
|
|
1609
1756
|
}
|
|
1610
1757
|
|
|
1611
|
-
// src/sflLanguage/emitting/
|
|
1758
|
+
// src/sflLanguage/emitting/literals.ts
|
|
1612
1759
|
function formatNumber(value) {
|
|
1613
1760
|
if (Object.is(value, -0)) {
|
|
1614
1761
|
return "0";
|
|
@@ -1619,33 +1766,6 @@ function emitString(value) {
|
|
|
1619
1766
|
const escaped = value.replace(/\r\n?/g, "\n").replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n").replace(/\t/g, "\\t");
|
|
1620
1767
|
return `"${escaped}"`;
|
|
1621
1768
|
}
|
|
1622
|
-
function emitValue(value) {
|
|
1623
|
-
switch (value.type) {
|
|
1624
|
-
case "string":
|
|
1625
|
-
return emitString(value.value);
|
|
1626
|
-
case "number":
|
|
1627
|
-
return formatNumber(value.value);
|
|
1628
|
-
case "tuple":
|
|
1629
|
-
return value.values.map(formatNumber).join(", ");
|
|
1630
|
-
case "list":
|
|
1631
|
-
return `[${value.values.map(emitValue).join(", ")}]`;
|
|
1632
|
-
case "ident":
|
|
1633
|
-
return value.segments.join(".");
|
|
1634
|
-
case "expr":
|
|
1635
|
-
return value.items.map((item) => emitExpression(item)).join(", ");
|
|
1636
|
-
case "endpoint": {
|
|
1637
|
-
let output = value.segments.join(".");
|
|
1638
|
-
if (value.side) {
|
|
1639
|
-
output += `, ${value.side}`;
|
|
1640
|
-
if (value.fraction !== void 0) {
|
|
1641
|
-
output += ` (${formatNumber(value.fraction)})`;
|
|
1642
|
-
}
|
|
1643
|
-
}
|
|
1644
|
-
return output;
|
|
1645
|
-
}
|
|
1646
|
-
}
|
|
1647
|
-
}
|
|
1648
|
-
var emitProperty = (property) => `${property.key}: ${emitValue(property.value)}`;
|
|
1649
1769
|
|
|
1650
1770
|
// src/sflLanguage/emitting/expressions.ts
|
|
1651
1771
|
var PRECEDENCE = {
|
|
@@ -1667,7 +1787,7 @@ function emitExpression(expr, parentPrecedence = 0) {
|
|
|
1667
1787
|
case "number":
|
|
1668
1788
|
return String(expr.value);
|
|
1669
1789
|
case "string":
|
|
1670
|
-
return
|
|
1790
|
+
return emitString(expr.value);
|
|
1671
1791
|
case "boolean":
|
|
1672
1792
|
return String(expr.value);
|
|
1673
1793
|
case "ref":
|
|
@@ -1736,6 +1856,35 @@ function compareByOrder(order, a, b) {
|
|
|
1736
1856
|
var compareLayoutProps = (a, b) => compareByOrder(LAYOUT_ORDER, a, b);
|
|
1737
1857
|
var compareStyleProps = (a, b) => compareByOrder(STYLE_ORDER, a, b);
|
|
1738
1858
|
|
|
1859
|
+
// src/sflLanguage/emitting/values.ts
|
|
1860
|
+
function emitValue(value) {
|
|
1861
|
+
switch (value.type) {
|
|
1862
|
+
case "string":
|
|
1863
|
+
return emitString(value.value);
|
|
1864
|
+
case "number":
|
|
1865
|
+
return formatNumber(value.value);
|
|
1866
|
+
case "tuple":
|
|
1867
|
+
return value.values.map(formatNumber).join(", ");
|
|
1868
|
+
case "list":
|
|
1869
|
+
return `[${value.values.map(emitValue).join(", ")}]`;
|
|
1870
|
+
case "ident":
|
|
1871
|
+
return value.segments.join(".");
|
|
1872
|
+
case "expr":
|
|
1873
|
+
return value.items.map((item) => emitExpression(item)).join(", ");
|
|
1874
|
+
case "endpoint": {
|
|
1875
|
+
let output = value.segments.join(".");
|
|
1876
|
+
if (value.side) {
|
|
1877
|
+
output += `, ${value.side}`;
|
|
1878
|
+
if (value.fraction !== void 0) {
|
|
1879
|
+
output += ` (${formatNumber(value.fraction)})`;
|
|
1880
|
+
}
|
|
1881
|
+
}
|
|
1882
|
+
return output;
|
|
1883
|
+
}
|
|
1884
|
+
}
|
|
1885
|
+
}
|
|
1886
|
+
var emitProperty = (property) => `${property.key}: ${emitValue(property.value)}`;
|
|
1887
|
+
|
|
1739
1888
|
// src/sflLanguage/emitting/propertyBlock.ts
|
|
1740
1889
|
var INDENT = " ";
|
|
1741
1890
|
function emitPropertyBlock(name, properties, depth, bindings = []) {
|
|
@@ -1867,51 +2016,34 @@ function canonicalizeSource(sflText) {
|
|
|
1867
2016
|
return emitDocument(parseSource(sflText));
|
|
1868
2017
|
}
|
|
1869
2018
|
|
|
1870
|
-
// src/sflSemantic/canvasObjects/artifacts/chart/
|
|
2019
|
+
// src/sflSemantic/canvasObjects/artifacts/chart/object.ts
|
|
1871
2020
|
function isChartObject(canvasObject) {
|
|
1872
2021
|
return canvasObject.objectType === "chart" && canvasObject.chart !== void 0;
|
|
1873
2022
|
}
|
|
1874
2023
|
|
|
1875
|
-
// src/sflSemantic/canvasObjects/artifacts/dimension/
|
|
2024
|
+
// src/sflSemantic/canvasObjects/artifacts/dimension/object.ts
|
|
1876
2025
|
function isDimensionObject(canvasObject) {
|
|
1877
2026
|
return canvasObject.objectType === "dimension" && canvasObject.dimension !== void 0;
|
|
1878
2027
|
}
|
|
1879
2028
|
|
|
1880
|
-
// src/sflSemantic/canvasObjects/artifacts/isometric/
|
|
2029
|
+
// src/sflSemantic/canvasObjects/artifacts/isometric/object.ts
|
|
1881
2030
|
function isIsometricObject(canvasObject) {
|
|
1882
2031
|
return canvasObject.objectType === "isometric" && canvasObject.isometric !== void 0;
|
|
1883
2032
|
}
|
|
1884
2033
|
|
|
1885
|
-
// src/sflSemantic/canvasObjects/artifacts/path/
|
|
2034
|
+
// src/sflSemantic/canvasObjects/artifacts/path/object.ts
|
|
1886
2035
|
function isPathObject(canvasObject) {
|
|
1887
2036
|
return canvasObject.objectType === "path" && canvasObject.path !== void 0;
|
|
1888
2037
|
}
|
|
1889
2038
|
|
|
1890
|
-
// src/sflSemantic/canvasObjects/artifacts/swimlane/
|
|
2039
|
+
// src/sflSemantic/canvasObjects/artifacts/swimlane/object.ts
|
|
1891
2040
|
function isSwimlaneObject(canvasObject) {
|
|
1892
2041
|
return canvasObject.objectType === "swimlane" && canvasObject.swimlane !== void 0;
|
|
1893
2042
|
}
|
|
1894
2043
|
|
|
1895
|
-
// src/sflLanguage/expansion/
|
|
1896
|
-
var RESERVED = /* @__PURE__ */ new Set(["columns", "rows", "count", "step", "origin", "seed", "jitter", "chance", "order", "where"]);
|
|
1897
|
-
var MAX_CELLS = 2e4;
|
|
1898
|
-
var MAX_VALUES = 1e6;
|
|
1899
|
-
var Random = class {
|
|
1900
|
-
state;
|
|
1901
|
-
constructor(seed) {
|
|
1902
|
-
this.state = seed >>> 0;
|
|
1903
|
-
}
|
|
1904
|
-
// mulberry32: a small generator that gives the same numbers for the same seed, on every machine.
|
|
1905
|
-
next() {
|
|
1906
|
-
this.state = this.state + 1831565813 >>> 0;
|
|
1907
|
-
let t = this.state;
|
|
1908
|
-
t = Math.imul(t ^ t >>> 15, t | 1);
|
|
1909
|
-
t ^= t + Math.imul(t ^ t >>> 7, t | 61);
|
|
1910
|
-
return ((t ^ t >>> 14) >>> 0) / 4294967296;
|
|
1911
|
-
}
|
|
1912
|
-
};
|
|
2044
|
+
// src/sflLanguage/expansion/scope.ts
|
|
1913
2045
|
function fail(scope, message) {
|
|
1914
|
-
throw new Error(
|
|
2046
|
+
throw new Error(`${scope.label}: ${message}`);
|
|
1915
2047
|
}
|
|
1916
2048
|
function numberOf(scope, value, what) {
|
|
1917
2049
|
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
@@ -1919,6 +2051,8 @@ function numberOf(scope, value, what) {
|
|
|
1919
2051
|
}
|
|
1920
2052
|
return value;
|
|
1921
2053
|
}
|
|
2054
|
+
|
|
2055
|
+
// src/sflLanguage/expansion/functions.ts
|
|
1922
2056
|
function rgbOf(scope, value) {
|
|
1923
2057
|
const match = typeof value === "string" ? /^#([0-9a-f]{6})$/i.exec(value) : null;
|
|
1924
2058
|
if (!match) {
|
|
@@ -1987,6 +2121,8 @@ function callFunction(scope, name, args) {
|
|
|
1987
2121
|
return fail(scope, `unknown function ${name}()`);
|
|
1988
2122
|
}
|
|
1989
2123
|
}
|
|
2124
|
+
|
|
2125
|
+
// src/sflLanguage/expansion/evaluation.ts
|
|
1990
2126
|
function evaluate(scope, expr) {
|
|
1991
2127
|
switch (expr.kind) {
|
|
1992
2128
|
case "number":
|
|
@@ -2044,27 +2180,37 @@ function evaluate(scope, expr) {
|
|
|
2044
2180
|
}
|
|
2045
2181
|
}
|
|
2046
2182
|
var round2 = (value) => Math.round(value * 1e3) / 1e3;
|
|
2183
|
+
function scalarValue(scope, only) {
|
|
2184
|
+
if (typeof only === "number") {
|
|
2185
|
+
return { type: "number", value: round2(numberOf(scope, only, "a value")) };
|
|
2186
|
+
}
|
|
2187
|
+
if (typeof only === "string") {
|
|
2188
|
+
return { type: "string", value: only };
|
|
2189
|
+
}
|
|
2190
|
+
return { type: "ident", segments: [String(only)] };
|
|
2191
|
+
}
|
|
2047
2192
|
function resolveValue(scope, value) {
|
|
2193
|
+
if (scope.substitute && value.type === "ident" && value.segments.length === 1) {
|
|
2194
|
+
const known = scope.vars.get(value.segments[0]);
|
|
2195
|
+
if (known !== void 0) {
|
|
2196
|
+
return scalarValue(scope, known);
|
|
2197
|
+
}
|
|
2198
|
+
}
|
|
2048
2199
|
if (value.type !== "expr") {
|
|
2049
2200
|
return value;
|
|
2050
2201
|
}
|
|
2051
2202
|
const results = value.items.map((item) => evaluate(scope, item));
|
|
2052
2203
|
if (results.length === 1) {
|
|
2053
|
-
|
|
2054
|
-
if (typeof only === "number") {
|
|
2055
|
-
return { type: "number", value: round2(numberOf(scope, only, "a value")) };
|
|
2056
|
-
}
|
|
2057
|
-
if (typeof only === "string") {
|
|
2058
|
-
return { type: "string", value: only };
|
|
2059
|
-
}
|
|
2060
|
-
return { type: "ident", segments: [String(only)] };
|
|
2204
|
+
return scalarValue(scope, results[0]);
|
|
2061
2205
|
}
|
|
2062
2206
|
return { type: "tuple", values: results.map((result) => round2(numberOf(scope, result, "a tuple"))) };
|
|
2063
2207
|
}
|
|
2208
|
+
|
|
2209
|
+
// src/sflLanguage/expansion/instance.ts
|
|
2064
2210
|
function propertiesOf(scope, properties) {
|
|
2065
2211
|
return properties.map((property) => ({ key: property.key, value: resolveValue(scope, property.value) }));
|
|
2066
2212
|
}
|
|
2067
|
-
function entryOf(scope, entry,
|
|
2213
|
+
function entryOf(scope, entry, rename) {
|
|
2068
2214
|
switch (entry.type) {
|
|
2069
2215
|
case "property":
|
|
2070
2216
|
return {
|
|
@@ -2076,18 +2222,20 @@ function entryOf(scope, entry, suffix) {
|
|
|
2076
2222
|
case "style":
|
|
2077
2223
|
return { type: "style", style: { ...entry.style, properties: propertiesOf(scope, entry.style.properties) } };
|
|
2078
2224
|
case "block":
|
|
2079
|
-
return { type: "block", block: instance(scope, entry.block,
|
|
2225
|
+
return { type: "block", block: instance(scope, entry.block, rename) };
|
|
2080
2226
|
default:
|
|
2081
2227
|
return entry;
|
|
2082
2228
|
}
|
|
2083
2229
|
}
|
|
2084
|
-
function instance(scope, block2,
|
|
2230
|
+
function instance(scope, block2, rename) {
|
|
2085
2231
|
return {
|
|
2086
2232
|
...block2,
|
|
2087
|
-
name:
|
|
2088
|
-
entries: block2.entries.map((entry) => entryOf(scope, entry,
|
|
2233
|
+
name: rename(block2.name),
|
|
2234
|
+
entries: block2.entries.map((entry) => entryOf(scope, entry, rename))
|
|
2089
2235
|
};
|
|
2090
2236
|
}
|
|
2237
|
+
|
|
2238
|
+
// src/sflLanguage/expansion/properties.ts
|
|
2091
2239
|
function propertyOf(block2, key) {
|
|
2092
2240
|
for (const entry of block2.entries) {
|
|
2093
2241
|
if (entry.type === "property" && entry.property.key === key) {
|
|
@@ -2110,88 +2258,244 @@ function numbersOf(block2, key) {
|
|
|
2110
2258
|
}
|
|
2111
2259
|
return void 0;
|
|
2112
2260
|
}
|
|
2113
|
-
|
|
2114
|
-
|
|
2261
|
+
|
|
2262
|
+
// src/sflLanguage/expansion/random.ts
|
|
2263
|
+
var Random = class {
|
|
2264
|
+
state;
|
|
2265
|
+
constructor(seed) {
|
|
2266
|
+
this.state = seed >>> 0;
|
|
2267
|
+
}
|
|
2268
|
+
// mulberry32: a small generator that gives the same numbers for the same seed, on every machine.
|
|
2269
|
+
next() {
|
|
2270
|
+
this.state = this.state + 1831565813 >>> 0;
|
|
2271
|
+
let t = this.state;
|
|
2272
|
+
t = Math.imul(t ^ t >>> 15, t | 1);
|
|
2273
|
+
t ^= t + Math.imul(t ^ t >>> 7, t | 61);
|
|
2274
|
+
return ((t ^ t >>> 14) >>> 0) / 4294967296;
|
|
2275
|
+
}
|
|
2276
|
+
};
|
|
2277
|
+
|
|
2278
|
+
// src/sflLanguage/expansion/repeat.ts
|
|
2279
|
+
var RESERVED = /* @__PURE__ */ new Set(["columns", "rows", "count", "step", "origin", "seed", "jitter", "chance", "order", "where"]);
|
|
2280
|
+
var MAX_CELLS = 2e4;
|
|
2281
|
+
var MAX_VALUES = 1e6;
|
|
2282
|
+
function readGrid(block2, scope) {
|
|
2115
2283
|
const count = numbersOf(block2, "count")?.[0];
|
|
2116
2284
|
const columns = Math.max(1, Math.floor(count ?? numbersOf(block2, "columns")?.[0] ?? 1));
|
|
2117
2285
|
const rows = count === void 0 ? Math.max(1, Math.floor(numbersOf(block2, "rows")?.[0] ?? 1)) : 1;
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
fail(scope, `${total} cells are too many, the limit is ${MAX_CELLS}`);
|
|
2286
|
+
if (columns * rows > MAX_CELLS) {
|
|
2287
|
+
fail(scope, `${columns * rows} cells are too many, the limit is ${MAX_CELLS}`);
|
|
2121
2288
|
}
|
|
2122
2289
|
const [stepX = 0, stepY = stepX] = numbersOf(block2, "step") ?? [];
|
|
2123
2290
|
const [originX = 0, originY = 0] = numbersOf(block2, "origin") ?? [];
|
|
2124
|
-
const
|
|
2125
|
-
const jitter = numbersOf(block2, "jitter")?.[0] ?? 0;
|
|
2126
|
-
const chance = numbersOf(block2, "chance")?.[0] ?? 1;
|
|
2127
|
-
const diagonal = propertyOf(block2, "order")?.type === "ident" && propertyOf(block2, "order").segments[0] === "diagonal";
|
|
2128
|
-
const condition = propertyOf(block2, "where");
|
|
2129
|
-
const helpers = block2.entries.flatMap(
|
|
2130
|
-
(entry) => entry.type === "property" && entry.property.value.type === "expr" && !RESERVED.has(entry.property.key) ? [entry.property] : []
|
|
2131
|
-
);
|
|
2291
|
+
const order = propertyOf(block2, "order");
|
|
2132
2292
|
const templates = block2.entries.flatMap((entry) => entry.type === "block" ? [entry.block] : []);
|
|
2133
2293
|
if (templates.some((template) => template.kind === "Repeat")) {
|
|
2134
2294
|
fail(scope, "a Repeat cannot hold another Repeat");
|
|
2135
2295
|
}
|
|
2136
|
-
if (
|
|
2296
|
+
if (columns * rows * Math.max(1, templates.length) > MAX_VALUES) {
|
|
2137
2297
|
fail(scope, "too many blocks");
|
|
2138
2298
|
}
|
|
2299
|
+
return {
|
|
2300
|
+
columns,
|
|
2301
|
+
rows,
|
|
2302
|
+
step: [stepX, stepY],
|
|
2303
|
+
origin: [originX, originY],
|
|
2304
|
+
seed: numbersOf(block2, "seed")?.[0] ?? 0,
|
|
2305
|
+
jitter: numbersOf(block2, "jitter")?.[0] ?? 0,
|
|
2306
|
+
chance: numbersOf(block2, "chance")?.[0] ?? 1,
|
|
2307
|
+
diagonal: order?.type === "ident" && order.segments[0] === "diagonal",
|
|
2308
|
+
condition: propertyOf(block2, "where"),
|
|
2309
|
+
helpers: block2.entries.flatMap(
|
|
2310
|
+
(entry) => entry.type === "property" && entry.property.value.type === "expr" && !RESERVED.has(entry.property.key) ? [entry.property] : []
|
|
2311
|
+
),
|
|
2312
|
+
templates
|
|
2313
|
+
};
|
|
2314
|
+
}
|
|
2315
|
+
function cellsOf(grid) {
|
|
2139
2316
|
const cells = [];
|
|
2140
|
-
for (let row = 0; row < rows; row++) {
|
|
2141
|
-
for (let col = 0; col < columns; col++) {
|
|
2317
|
+
for (let row = 0; row < grid.rows; row++) {
|
|
2318
|
+
for (let col = 0; col < grid.columns; col++) {
|
|
2142
2319
|
cells.push([col, row]);
|
|
2143
2320
|
}
|
|
2144
2321
|
}
|
|
2145
|
-
|
|
2146
|
-
|
|
2322
|
+
return grid.diagonal ? cells.sort((a, b) => a[0] + a[1] - (b[0] + b[1]) || a[0] - b[0]) : cells;
|
|
2323
|
+
}
|
|
2324
|
+
function enterCell(scope, grid, col, row) {
|
|
2325
|
+
const index = row * grid.columns + col;
|
|
2326
|
+
scope.random = new Random(Math.imul(grid.seed + 1, 2654435761) ^ Math.imul(index + 1, 2246822507));
|
|
2327
|
+
if (grid.chance < 1 && scope.random.next() >= grid.chance) {
|
|
2328
|
+
return false;
|
|
2147
2329
|
}
|
|
2148
|
-
const
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2330
|
+
const spread = () => grid.jitter > 0 ? (scope.random.next() * 2 - 1) * grid.jitter : 0;
|
|
2331
|
+
scope.vars = /* @__PURE__ */ new Map([
|
|
2332
|
+
["col", col],
|
|
2333
|
+
["row", row],
|
|
2334
|
+
["index", index],
|
|
2335
|
+
["count", grid.columns * grid.rows],
|
|
2336
|
+
["columns", grid.columns],
|
|
2337
|
+
["rows", grid.rows],
|
|
2338
|
+
["x", round2(grid.origin[0] + col * grid.step[0] + spread())],
|
|
2339
|
+
["y", round2(grid.origin[1] + row * grid.step[1] + spread())]
|
|
2340
|
+
]);
|
|
2341
|
+
return true;
|
|
2342
|
+
}
|
|
2343
|
+
function nameHelpers(scope, helpers) {
|
|
2344
|
+
for (const helper of helpers) {
|
|
2345
|
+
const value = resolveValue(scope, helper.value);
|
|
2346
|
+
if (value.type === "number" || value.type === "string") {
|
|
2347
|
+
scope.vars.set(helper.key, value.value);
|
|
2348
|
+
} else if (value.type === "ident") {
|
|
2349
|
+
scope.vars.set(helper.key, value.segments[0] === "true" ? 1 : 0);
|
|
2350
|
+
} else {
|
|
2351
|
+
fail(scope, `${helper.key} needs a number`);
|
|
2352
|
+
}
|
|
2353
|
+
}
|
|
2354
|
+
}
|
|
2355
|
+
function keepsCell(scope, condition) {
|
|
2356
|
+
return condition?.type !== "expr" || Boolean(condition.items.map((item) => evaluate(scope, item))[0]);
|
|
2357
|
+
}
|
|
2358
|
+
function expandRepeat(block2) {
|
|
2359
|
+
const scope = { vars: /* @__PURE__ */ new Map(), random: new Random(0), label: `Repeat ${block2.name}` };
|
|
2360
|
+
const grid = readGrid(block2, scope);
|
|
2361
|
+
const made = [];
|
|
2362
|
+
for (const [col, row] of cellsOf(grid)) {
|
|
2363
|
+
if (!enterCell(scope, grid, col, row)) {
|
|
2364
|
+
continue;
|
|
2365
|
+
}
|
|
2366
|
+
nameHelpers(scope, grid.helpers);
|
|
2367
|
+
if (!keepsCell(scope, grid.condition)) {
|
|
2368
|
+
continue;
|
|
2369
|
+
}
|
|
2370
|
+
const suffix = grid.rows === 1 ? `_${col}` : `_${col}_${row}`;
|
|
2371
|
+
for (const template of grid.templates) {
|
|
2372
|
+
made.push(instance(scope, template, (name) => `${name}${suffix}`));
|
|
2373
|
+
}
|
|
2374
|
+
}
|
|
2375
|
+
return made;
|
|
2376
|
+
}
|
|
2377
|
+
function expandRepeatBlocks(blocks) {
|
|
2378
|
+
return blocks.flatMap((block2) => {
|
|
2379
|
+
if (block2.kind === "Repeat") {
|
|
2380
|
+
return expandRepeat(block2);
|
|
2381
|
+
}
|
|
2382
|
+
if (block2.kind === "Template" || !block2.entries.some((entry) => entry.type === "block")) {
|
|
2383
|
+
return [block2];
|
|
2384
|
+
}
|
|
2385
|
+
return [
|
|
2386
|
+
{
|
|
2387
|
+
...block2,
|
|
2388
|
+
entries: block2.entries.flatMap(
|
|
2389
|
+
(entry) => entry.type === "block" ? expandRepeatBlocks([entry.block]).map((child) => ({ type: "block", block: child })) : [entry]
|
|
2390
|
+
)
|
|
2176
2391
|
}
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2392
|
+
];
|
|
2393
|
+
});
|
|
2394
|
+
}
|
|
2395
|
+
function hasRepeats(blocks) {
|
|
2396
|
+
return blocks.some(
|
|
2397
|
+
(block2) => block2.kind === "Repeat" || block2.entries.some((entry) => entry.type === "block" && hasRepeats([entry.block]))
|
|
2398
|
+
);
|
|
2399
|
+
}
|
|
2400
|
+
|
|
2401
|
+
// src/sflLanguage/expansion/template.ts
|
|
2402
|
+
var MAX_DEPTH = 4;
|
|
2403
|
+
var MAX_BLOCKS = 1e5;
|
|
2404
|
+
var OWN = /* @__PURE__ */ new Set(["at", "seed"]);
|
|
2405
|
+
var PLACE = /* @__PURE__ */ new Set(["x", "y"]);
|
|
2406
|
+
function hashOf(text) {
|
|
2407
|
+
let hash = 2166136261;
|
|
2408
|
+
for (let index = 0; index < text.length; index++) {
|
|
2409
|
+
hash = Math.imul(hash ^ text.charCodeAt(index), 16777619);
|
|
2410
|
+
}
|
|
2411
|
+
return hash >>> 0;
|
|
2412
|
+
}
|
|
2413
|
+
function collect(blocks, into) {
|
|
2414
|
+
for (const block2 of blocks) {
|
|
2415
|
+
if (block2.kind === "Template") {
|
|
2416
|
+
if (into.has(block2.name)) {
|
|
2417
|
+
throw new Error(`Template ${block2.name}: there is another Template of this name`);
|
|
2182
2418
|
}
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
out.push(instance(scope, template, suffix));
|
|
2419
|
+
if (block2.entries.some((entry) => entry.type === "block" && entry.block.kind === "Repeat")) {
|
|
2420
|
+
throw new Error(`Template ${block2.name}: a Template cannot hold a Repeat, a Repeat can hold a Use`);
|
|
2186
2421
|
}
|
|
2422
|
+
into.set(block2.name, block2);
|
|
2423
|
+
}
|
|
2424
|
+
collect(
|
|
2425
|
+
block2.entries.flatMap((entry) => entry.type === "block" ? [entry.block] : []),
|
|
2426
|
+
into
|
|
2427
|
+
);
|
|
2428
|
+
}
|
|
2429
|
+
}
|
|
2430
|
+
var BlockBudget = class {
|
|
2431
|
+
made = 0;
|
|
2432
|
+
take(count, scope) {
|
|
2433
|
+
this.made += count;
|
|
2434
|
+
if (this.made > MAX_BLOCKS) {
|
|
2435
|
+
fail(scope, "too many blocks");
|
|
2436
|
+
}
|
|
2437
|
+
}
|
|
2438
|
+
};
|
|
2439
|
+
function expandUse(use, templates, depth, budget) {
|
|
2440
|
+
const scope = { vars: /* @__PURE__ */ new Map(), random: new Random(0), label: `Use ${use.name}`, substitute: true };
|
|
2441
|
+
if (depth > MAX_DEPTH) {
|
|
2442
|
+
fail(scope, `Templates are nested more than ${MAX_DEPTH} deep, which may be a Template that uses itself`);
|
|
2443
|
+
}
|
|
2444
|
+
if (use.composition.length !== 1) {
|
|
2445
|
+
fail(scope, "a Use names one Template, as in Use oak : tree");
|
|
2446
|
+
}
|
|
2447
|
+
const template = templates.get(use.composition[0]);
|
|
2448
|
+
if (!template) {
|
|
2449
|
+
fail(scope, `there is no Template ${use.composition[0]}`);
|
|
2450
|
+
}
|
|
2451
|
+
const seed = numbersOf(use, "seed")?.[0] ?? 0;
|
|
2452
|
+
scope.random = new Random(Math.imul(seed + 1, 2654435761) ^ hashOf(use.name));
|
|
2453
|
+
const [x = 0, y = 0] = numbersOf(use, "at") ?? [];
|
|
2454
|
+
scope.vars.set("x", x);
|
|
2455
|
+
scope.vars.set("y", y);
|
|
2456
|
+
const given = new Map(
|
|
2457
|
+
use.entries.flatMap(
|
|
2458
|
+
(entry) => entry.type === "property" && !OWN.has(entry.property.key) ? [[entry.property.key, entry.property.value]] : []
|
|
2459
|
+
)
|
|
2460
|
+
);
|
|
2461
|
+
for (const entry of template.entries) {
|
|
2462
|
+
if (entry.type !== "property") {
|
|
2463
|
+
continue;
|
|
2464
|
+
}
|
|
2465
|
+
const { key, value } = entry.property;
|
|
2466
|
+
if (PLACE.has(key) || OWN.has(key)) {
|
|
2467
|
+
fail(scope, `${key} is the name of something a Use sets, so it cannot be a parameter`);
|
|
2468
|
+
}
|
|
2469
|
+
const chosen = resolveValue(scope, given.get(key) ?? value);
|
|
2470
|
+
given.delete(key);
|
|
2471
|
+
if (chosen.type === "number" || chosen.type === "string") {
|
|
2472
|
+
scope.vars.set(key, chosen.value);
|
|
2473
|
+
} else if (chosen.type === "ident") {
|
|
2474
|
+
scope.vars.set(
|
|
2475
|
+
key,
|
|
2476
|
+
chosen.segments[0] === "true" ? 1 : chosen.segments[0] === "false" ? 0 : chosen.segments.join(".")
|
|
2477
|
+
);
|
|
2478
|
+
} else {
|
|
2479
|
+
fail(scope, `${key} needs a number, a text or a name`);
|
|
2187
2480
|
}
|
|
2188
2481
|
}
|
|
2189
|
-
|
|
2482
|
+
const unknown = [...given.keys()][0];
|
|
2483
|
+
if (unknown !== void 0) {
|
|
2484
|
+
fail(scope, `Template ${template.name} has no parameter ${unknown}`);
|
|
2485
|
+
}
|
|
2486
|
+
const made = template.entries.flatMap(
|
|
2487
|
+
(entry) => entry.type === "block" ? [instance(scope, entry.block, (name) => `${use.name}_${name}`)] : []
|
|
2488
|
+
);
|
|
2489
|
+
budget.take(made.length, scope);
|
|
2490
|
+
return expandIn(made, templates, depth + 1, budget);
|
|
2190
2491
|
}
|
|
2191
|
-
function
|
|
2492
|
+
function expandIn(blocks, templates, depth, budget) {
|
|
2192
2493
|
return blocks.flatMap((block2) => {
|
|
2193
|
-
if (block2.kind === "
|
|
2194
|
-
return
|
|
2494
|
+
if (block2.kind === "Template") {
|
|
2495
|
+
return [];
|
|
2496
|
+
}
|
|
2497
|
+
if (block2.kind === "Use") {
|
|
2498
|
+
return expandUse(block2, templates, depth, budget);
|
|
2195
2499
|
}
|
|
2196
2500
|
if (!block2.entries.some((entry) => entry.type === "block")) {
|
|
2197
2501
|
return [block2];
|
|
@@ -2200,15 +2504,24 @@ function expandBlocks(blocks) {
|
|
|
2200
2504
|
{
|
|
2201
2505
|
...block2,
|
|
2202
2506
|
entries: block2.entries.flatMap(
|
|
2203
|
-
(entry) => entry.type === "block" ? (entry.block
|
|
2204
|
-
type: "block",
|
|
2205
|
-
block: child
|
|
2206
|
-
})) : [entry]
|
|
2507
|
+
(entry) => entry.type === "block" ? expandIn([entry.block], templates, depth, budget).map((child) => ({ type: "block", block: child })) : [entry]
|
|
2207
2508
|
)
|
|
2208
2509
|
}
|
|
2209
2510
|
];
|
|
2210
2511
|
});
|
|
2211
2512
|
}
|
|
2513
|
+
function hasTemplates(blocks) {
|
|
2514
|
+
return blocks.some(
|
|
2515
|
+
(block2) => block2.kind === "Template" || block2.kind === "Use" || block2.entries.some((entry) => entry.type === "block" && hasTemplates([entry.block]))
|
|
2516
|
+
);
|
|
2517
|
+
}
|
|
2518
|
+
function expandUses(blocks) {
|
|
2519
|
+
const templates = /* @__PURE__ */ new Map();
|
|
2520
|
+
collect(blocks, templates);
|
|
2521
|
+
return expandIn(blocks, templates, 0, new BlockBudget());
|
|
2522
|
+
}
|
|
2523
|
+
|
|
2524
|
+
// src/sflLanguage/expansion/expandDocument.ts
|
|
2212
2525
|
function checkNoComputed(blocks) {
|
|
2213
2526
|
for (const block2 of blocks) {
|
|
2214
2527
|
for (const entry of block2.entries) {
|
|
@@ -2226,15 +2539,13 @@ function checkNoComputed(blocks) {
|
|
|
2226
2539
|
}
|
|
2227
2540
|
}
|
|
2228
2541
|
}
|
|
2229
|
-
function
|
|
2230
|
-
const
|
|
2231
|
-
|
|
2232
|
-
);
|
|
2233
|
-
if (!has(doc.blocks)) {
|
|
2542
|
+
function expandDocument(doc) {
|
|
2543
|
+
const repeats = hasRepeats(doc.blocks);
|
|
2544
|
+
if (!repeats && !hasTemplates(doc.blocks)) {
|
|
2234
2545
|
checkNoComputed(doc.blocks);
|
|
2235
2546
|
return doc;
|
|
2236
2547
|
}
|
|
2237
|
-
const expanded = { ...doc, blocks:
|
|
2548
|
+
const expanded = { ...doc, blocks: expandUses(repeats ? expandRepeatBlocks(doc.blocks) : doc.blocks) };
|
|
2238
2549
|
checkNoComputed(expanded.blocks);
|
|
2239
2550
|
return expanded;
|
|
2240
2551
|
}
|
|
@@ -2356,6 +2667,7 @@ var CANVAS_OBJECT_BLOCK_KINDS = [
|
|
|
2356
2667
|
"Entity",
|
|
2357
2668
|
"Shape",
|
|
2358
2669
|
"Text",
|
|
2670
|
+
"Image",
|
|
2359
2671
|
"Container",
|
|
2360
2672
|
"Path",
|
|
2361
2673
|
"Chart",
|
|
@@ -2920,6 +3232,9 @@ function declaredCanvasObjectKind(block2, properties) {
|
|
|
2920
3232
|
if (block2.kind === "Text") {
|
|
2921
3233
|
return "text";
|
|
2922
3234
|
}
|
|
3235
|
+
if (block2.kind === "Image") {
|
|
3236
|
+
return "image";
|
|
3237
|
+
}
|
|
2923
3238
|
if (block2.kind === "Isometric") {
|
|
2924
3239
|
return "isometric";
|
|
2925
3240
|
}
|
|
@@ -2980,13 +3295,14 @@ function readCanvasObjectGeometry(block2, origin, layoutProperty, positionOverri
|
|
|
2980
3295
|
|
|
2981
3296
|
// src/sflSemantic/canvasObjects/processing/presentation.ts
|
|
2982
3297
|
var STRUCTURAL_PROPERTIES = /* @__PURE__ */ new Set(["id", "kind", "text", "shape", "parent", "order", "orientation", "lanes"]);
|
|
3298
|
+
var TUPLE_PROPERTIES = /* @__PURE__ */ new Set(["crop", "imageSize"]);
|
|
2983
3299
|
function readCanvasObjectPresentation(properties) {
|
|
2984
3300
|
const presentation = {};
|
|
2985
3301
|
for (const [key, value] of properties) {
|
|
2986
3302
|
if (STRUCTURAL_PROPERTIES.has(key)) {
|
|
2987
3303
|
continue;
|
|
2988
3304
|
}
|
|
2989
|
-
const text = asString(value);
|
|
3305
|
+
const text = TUPLE_PROPERTIES.has(key) ? tupleValues(value)?.join(",") : asString(value);
|
|
2990
3306
|
if (text !== void 0) {
|
|
2991
3307
|
presentation[key] = text;
|
|
2992
3308
|
}
|
|
@@ -3313,7 +3629,7 @@ function collectBlockDiagnostics(block2, styleBlocks, layoutBlocks, diagnostics)
|
|
|
3313
3629
|
severity: "warning",
|
|
3314
3630
|
code: "unresolved-style-or-layout",
|
|
3315
3631
|
ownerId: block2.name,
|
|
3316
|
-
message: `"${reference}" is not a Style or Layout defined at the top level of the document \
|
|
3632
|
+
message: `"${reference}" is not a Style or Layout defined at the top level of the document \u2014 "${block2.name}" gets no shape, fill, or stroke from it.`
|
|
3317
3633
|
});
|
|
3318
3634
|
}
|
|
3319
3635
|
}
|
|
@@ -3409,7 +3725,7 @@ function collectUnsupportedChartTypes(doc) {
|
|
|
3409
3725
|
severity: "warning",
|
|
3410
3726
|
code: "unsupported-chart-type",
|
|
3411
3727
|
ownerId: block2.name,
|
|
3412
|
-
message: `Unsupported chart type '${declared}' \
|
|
3728
|
+
message: `Unsupported chart type '${declared}' \u2014 drawn as a plain series plot. Supported: ${CHART_TYPES.join(", ")}.`
|
|
3413
3729
|
});
|
|
3414
3730
|
}
|
|
3415
3731
|
}
|
|
@@ -3432,7 +3748,7 @@ function collectEmptySeries(doc) {
|
|
|
3432
3748
|
severity: "warning",
|
|
3433
3749
|
code: "series-without-values",
|
|
3434
3750
|
ownerId: series.name,
|
|
3435
|
-
message: `Series '${series.name}' has no values. If this was meant to be an Axis or Rule, it needs that keyword in front of the name \
|
|
3751
|
+
message: `Series '${series.name}' has no values. If this was meant to be an Axis or Rule, it needs that keyword in front of the name \u2014 inside data{}, a bare name is read as a Series.`
|
|
3436
3752
|
});
|
|
3437
3753
|
}
|
|
3438
3754
|
}
|
|
@@ -3458,7 +3774,7 @@ function collectUnsupportedGridShapes(doc) {
|
|
|
3458
3774
|
severity: "warning",
|
|
3459
3775
|
code: "unsupported-grid-shape",
|
|
3460
3776
|
ownerId: block2.name,
|
|
3461
|
-
message: `gridShape: circle isn't supported on '${chartType}' \
|
|
3777
|
+
message: `gridShape: circle isn't supported on '${chartType}' \u2014 drawn with the standard rectangular grid instead. Supported: ${[...OPTIONAL_CIRCULAR_GRID_CHART_TYPES].join(", ")}.`
|
|
3462
3778
|
});
|
|
3463
3779
|
}
|
|
3464
3780
|
}
|
|
@@ -3501,6 +3817,7 @@ function collectUnsupportedComponentTypes(sflDocument) {
|
|
|
3501
3817
|
var OBJECTS = /* @__PURE__ */ new Set([
|
|
3502
3818
|
"Shape",
|
|
3503
3819
|
"Text",
|
|
3820
|
+
"Image",
|
|
3504
3821
|
"Container",
|
|
3505
3822
|
"Chart",
|
|
3506
3823
|
"Path",
|
|
@@ -3588,7 +3905,7 @@ function resolveCanvasState(document) {
|
|
|
3588
3905
|
|
|
3589
3906
|
// src/sflSemantic/sflToCanvasState.ts
|
|
3590
3907
|
function sflToCanvasState(source) {
|
|
3591
|
-
return resolveCanvasState(
|
|
3908
|
+
return resolveCanvasState(expandDocument(parseSource(source)));
|
|
3592
3909
|
}
|
|
3593
3910
|
|
|
3594
3911
|
// src/svg/domContract/version.ts
|
|
@@ -4733,63 +5050,6 @@ function createPieSlicePath(geometry, angles, cornerRadius = 0, gapPx = 0) {
|
|
|
4733
5050
|
return cornerRadius > 0 ? roundedDonutSlicePath(geometry, geometry.innerRadius, outerAngles, innerAngles, cornerRadius) : donutSlicePath(geometry, geometry.innerRadius, outerAngles, innerAngles);
|
|
4734
5051
|
}
|
|
4735
5052
|
|
|
4736
|
-
// src/model/color/conversion.ts
|
|
4737
|
-
var hexToRgb2 = (hex) => {
|
|
4738
|
-
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})?$/i.exec(hex);
|
|
4739
|
-
if (!result) {
|
|
4740
|
-
return { r: 255, g: 255, b: 255, a: 1 };
|
|
4741
|
-
}
|
|
4742
|
-
return {
|
|
4743
|
-
r: parseInt(result[1], 16),
|
|
4744
|
-
g: parseInt(result[2], 16),
|
|
4745
|
-
b: parseInt(result[3], 16),
|
|
4746
|
-
a: result[4] === void 0 ? 1 : parseInt(result[4], 16) / 255
|
|
4747
|
-
};
|
|
4748
|
-
};
|
|
4749
|
-
var rgbToHex2 = (r, g, b, a) => {
|
|
4750
|
-
const channel = (x) => {
|
|
4751
|
-
const hex = Math.max(0, Math.min(255, Math.round(x))).toString(16);
|
|
4752
|
-
return hex.length === 1 ? `0${hex}` : hex;
|
|
4753
|
-
};
|
|
4754
|
-
const alphaChannel = a === void 0 || a >= 1 ? "" : channel(a * 255);
|
|
4755
|
-
return `#${channel(r)}${channel(g)}${channel(b)}${alphaChannel}`;
|
|
4756
|
-
};
|
|
4757
|
-
|
|
4758
|
-
// src/model/color/interpolation.ts
|
|
4759
|
-
function mixHexColors(start, end, ratio) {
|
|
4760
|
-
const startRgb = hexToRgb2(start);
|
|
4761
|
-
const endRgb = hexToRgb2(end);
|
|
4762
|
-
const startAlpha = startRgb.a ?? 1;
|
|
4763
|
-
const endAlpha = endRgb.a ?? 1;
|
|
4764
|
-
return rgbToHex2(
|
|
4765
|
-
Math.round(startRgb.r + (endRgb.r - startRgb.r) * ratio),
|
|
4766
|
-
Math.round(startRgb.g + (endRgb.g - startRgb.g) * ratio),
|
|
4767
|
-
Math.round(startRgb.b + (endRgb.b - startRgb.b) * ratio),
|
|
4768
|
-
startAlpha + (endAlpha - startAlpha) * ratio
|
|
4769
|
-
);
|
|
4770
|
-
}
|
|
4771
|
-
function interpolateHexColorStops(stops, position) {
|
|
4772
|
-
const sortedStops = [...stops].sort((first2, second) => first2.position - second.position);
|
|
4773
|
-
const first = sortedStops[0];
|
|
4774
|
-
const last = sortedStops[sortedStops.length - 1];
|
|
4775
|
-
if (position <= first.position) {
|
|
4776
|
-
return first.color;
|
|
4777
|
-
}
|
|
4778
|
-
if (position >= last.position) {
|
|
4779
|
-
return last.color;
|
|
4780
|
-
}
|
|
4781
|
-
for (let index = 0; index < sortedStops.length - 1; index++) {
|
|
4782
|
-
const start = sortedStops[index];
|
|
4783
|
-
const end = sortedStops[index + 1];
|
|
4784
|
-
if (position >= start.position && position <= end.position) {
|
|
4785
|
-
const range = end.position - start.position;
|
|
4786
|
-
const ratio = range === 0 ? 0 : (position - start.position) / range;
|
|
4787
|
-
return mixHexColors(start.color, end.color, ratio);
|
|
4788
|
-
}
|
|
4789
|
-
}
|
|
4790
|
-
return last.color;
|
|
4791
|
-
}
|
|
4792
|
-
|
|
4793
5053
|
// src/renderScene/charts/primitives/defaults.ts
|
|
4794
5054
|
var CHART_COLORS = ["#7c3aed", "#0ea5e9", "#f97316", "#10b981", "#ec4899", "#eab308"];
|
|
4795
5055
|
var DEFAULT_ZONE_FILL = "#94a3b8";
|
|
@@ -4868,16 +5128,11 @@ function computeBoxplotStats(values) {
|
|
|
4868
5128
|
}
|
|
4869
5129
|
|
|
4870
5130
|
// src/renderScene/color.ts
|
|
4871
|
-
function
|
|
4872
|
-
|
|
4873
|
-
return void 0;
|
|
4874
|
-
}
|
|
4875
|
-
const channels = hex.length === 4 ? hex.slice(1).split("").map((channel) => parseInt(channel + channel, 16)) : [1, 3, 5].map((index) => parseInt(hex.slice(index, index + 2), 16));
|
|
4876
|
-
const [red, green, blue] = channels;
|
|
4877
|
-
return [red, green, blue].some((channel) => Number.isNaN(channel)) ? void 0 : [red, green, blue];
|
|
5131
|
+
function hexToRgb2(hex) {
|
|
5132
|
+
return hex?.startsWith("#") ? parseHexRgb(hex) ?? void 0 : void 0;
|
|
4878
5133
|
}
|
|
4879
5134
|
function colorWithAlpha(hex, alpha) {
|
|
4880
|
-
const rgb =
|
|
5135
|
+
const rgb = hexToRgb2(hex);
|
|
4881
5136
|
const clamped = Math.max(0, Math.min(1, alpha));
|
|
4882
5137
|
if (!rgb) {
|
|
4883
5138
|
return clamped <= 0 ? "transparent" : hex ?? "transparent";
|
|
@@ -4885,10 +5140,6 @@ function colorWithAlpha(hex, alpha) {
|
|
|
4885
5140
|
const [red, green, blue] = rgb;
|
|
4886
5141
|
return `rgba(${red}, ${green}, ${blue}, ${clamped})`;
|
|
4887
5142
|
}
|
|
4888
|
-
function rgbToHex3(red, green, blue) {
|
|
4889
|
-
const channel = (value) => Math.round(Math.max(0, Math.min(255, value))).toString(16).padStart(2, "0");
|
|
4890
|
-
return `#${channel(red)}${channel(green)}${channel(blue)}`;
|
|
4891
|
-
}
|
|
4892
5143
|
function rgbToHsl(red, green, blue) {
|
|
4893
5144
|
const r = red / 255;
|
|
4894
5145
|
const g = green / 255;
|
|
@@ -4954,7 +5205,7 @@ var SAME_HUE_LIGHT_MIN_LIGHTNESS = 0.78;
|
|
|
4954
5205
|
var SAME_HUE_LIGHT_MAX_LIGHTNESS = 0.92;
|
|
4955
5206
|
var SAME_HUE_MIN_CONTRAST = 3;
|
|
4956
5207
|
function contrastTextColor(hex) {
|
|
4957
|
-
const rgb =
|
|
5208
|
+
const rgb = hexToRgb2(hex);
|
|
4958
5209
|
if (!rgb) {
|
|
4959
5210
|
return "#0f172a";
|
|
4960
5211
|
}
|
|
@@ -4970,10 +5221,10 @@ function contrastTextColor(hex) {
|
|
|
4970
5221
|
);
|
|
4971
5222
|
const variant = hslToRgb(hue, saturation, targetLightness);
|
|
4972
5223
|
const ratio = contrastRatio(relativeLuminance(red, green, blue), relativeLuminance(...variant));
|
|
4973
|
-
return ratio >= SAME_HUE_MIN_CONTRAST ?
|
|
5224
|
+
return ratio >= SAME_HUE_MIN_CONTRAST ? rgbToHex(...variant) : fallback;
|
|
4974
5225
|
}
|
|
4975
5226
|
function sameHueContrastColor(hex, fallback) {
|
|
4976
|
-
const rgb =
|
|
5227
|
+
const rgb = hexToRgb2(hex);
|
|
4977
5228
|
if (!rgb) {
|
|
4978
5229
|
return fallback;
|
|
4979
5230
|
}
|
|
@@ -4986,14 +5237,14 @@ function sameHueContrastColor(hex, fallback) {
|
|
|
4986
5237
|
SAME_HUE_LIGHT_MAX_LIGHTNESS,
|
|
4987
5238
|
Math.max(lightness + SAME_HUE_LIGHTNESS_GAP, SAME_HUE_LIGHT_MIN_LIGHTNESS)
|
|
4988
5239
|
);
|
|
4989
|
-
return
|
|
5240
|
+
return rgbToHex(...hslToRgb(hue, saturation, targetLightness));
|
|
4990
5241
|
}
|
|
4991
5242
|
function isLightColor(hex) {
|
|
4992
|
-
const rgb =
|
|
5243
|
+
const rgb = hexToRgb2(hex);
|
|
4993
5244
|
return rgb ? rgbToHsl(...rgb)[2] > 0.5 : false;
|
|
4994
5245
|
}
|
|
4995
5246
|
function sameHueTint(hex, targetLightness) {
|
|
4996
|
-
const rgb =
|
|
5247
|
+
const rgb = hexToRgb2(hex);
|
|
4997
5248
|
if (!rgb) {
|
|
4998
5249
|
return void 0;
|
|
4999
5250
|
}
|
|
@@ -5001,7 +5252,7 @@ function sameHueTint(hex, targetLightness) {
|
|
|
5001
5252
|
if (saturation === 0) {
|
|
5002
5253
|
return void 0;
|
|
5003
5254
|
}
|
|
5004
|
-
return
|
|
5255
|
+
return rgbToHex(...hslToRgb(hue, saturation, targetLightness));
|
|
5005
5256
|
}
|
|
5006
5257
|
|
|
5007
5258
|
// src/renderScene/charts/primitives/colors.ts
|
|
@@ -5845,7 +6096,7 @@ exports.elementCenter = elementCenter;
|
|
|
5845
6096
|
exports.ellipsizeToWidth = ellipsizeToWidth;
|
|
5846
6097
|
exports.errorBarRange = errorBarRange;
|
|
5847
6098
|
exports.estimateTextWidth = estimateTextWidth;
|
|
5848
|
-
exports.
|
|
6099
|
+
exports.expandDocument = expandDocument;
|
|
5849
6100
|
exports.extrudeFootprint = extrudeFootprint;
|
|
5850
6101
|
exports.finite = finite;
|
|
5851
6102
|
exports.flattenPath = flattenPath;
|
|
@@ -5858,6 +6109,7 @@ exports.getComponentDescriptor = getComponentDescriptor;
|
|
|
5858
6109
|
exports.getLineMidpoint = getLineMidpoint;
|
|
5859
6110
|
exports.heuristicRichMeasure = heuristicRichMeasure;
|
|
5860
6111
|
exports.horizontalRows = horizontalRows;
|
|
6112
|
+
exports.hsvToRgb = hsvToRgb;
|
|
5861
6113
|
exports.interpolateHexColorStops = interpolateHexColorStops;
|
|
5862
6114
|
exports.isBuiltInComponentType = isBuiltInComponentType;
|
|
5863
6115
|
exports.isChartObject = isChartObject;
|
|
@@ -5883,6 +6135,7 @@ exports.mapChartValue = mapChartValue;
|
|
|
5883
6135
|
exports.maxApexCornerRadius = maxApexCornerRadius;
|
|
5884
6136
|
exports.maxPieCornerRadius = maxPieCornerRadius;
|
|
5885
6137
|
exports.paint = paint;
|
|
6138
|
+
exports.parseHexRgb = parseHexRgb;
|
|
5886
6139
|
exports.parseSource = parseSource;
|
|
5887
6140
|
exports.pathBounds = pathBounds;
|
|
5888
6141
|
exports.pathToSymbol = pathToSymbol;
|
|
@@ -5908,6 +6161,8 @@ exports.representativeColor = representativeColor;
|
|
|
5908
6161
|
exports.resolveChartShadow = resolveChartShadow;
|
|
5909
6162
|
exports.resolvePieRadii = resolvePieRadii;
|
|
5910
6163
|
exports.resolveRollingNumberStyle = resolveRollingNumberStyle;
|
|
6164
|
+
exports.rgbToHex = rgbToHex;
|
|
6165
|
+
exports.rgbToHsv = rgbToHsv;
|
|
5911
6166
|
exports.rightRoundedRectPath = rightRoundedRectPath;
|
|
5912
6167
|
exports.rotatedBounds = rotatedBounds;
|
|
5913
6168
|
exports.roundedBarPath = roundedBarPath;
|
|
@@ -5937,5 +6192,5 @@ exports.tokenizeSource = tokenizeSource;
|
|
|
5937
6192
|
exports.topRoundedRectPath = topRoundedRectPath;
|
|
5938
6193
|
exports.wrapText = wrapText;
|
|
5939
6194
|
exports.zoneColorAtValue = zoneColorAtValue;
|
|
5940
|
-
//# sourceMappingURL=chunk-
|
|
5941
|
-
//# sourceMappingURL=chunk-
|
|
6195
|
+
//# sourceMappingURL=chunk-UHKFJBY5.cjs.map
|
|
6196
|
+
//# sourceMappingURL=chunk-UHKFJBY5.cjs.map
|