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
|
@@ -189,23 +189,135 @@ function extrudeFootprint(frame, footprint, cornerRadius = 0) {
|
|
|
189
189
|
return { top, sides };
|
|
190
190
|
}
|
|
191
191
|
|
|
192
|
-
// src/model/
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
192
|
+
// src/model/color/conversion.ts
|
|
193
|
+
var hexToRgb = (hex) => {
|
|
194
|
+
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})?$/i.exec(hex);
|
|
195
|
+
if (!result) {
|
|
196
|
+
return { r: 255, g: 255, b: 255, a: 1 };
|
|
197
|
+
}
|
|
198
|
+
return {
|
|
199
|
+
r: parseInt(result[1], 16),
|
|
200
|
+
g: parseInt(result[2], 16),
|
|
201
|
+
b: parseInt(result[3], 16),
|
|
202
|
+
a: result[4] === void 0 ? 1 : parseInt(result[4], 16) / 255
|
|
203
|
+
};
|
|
204
|
+
};
|
|
205
|
+
var parseHexRgb = (value) => {
|
|
206
|
+
const match = /^#?([0-9a-f]{3}|[0-9a-f]{6})$/i.exec(value.trim());
|
|
198
207
|
if (!match) {
|
|
199
208
|
return null;
|
|
200
209
|
}
|
|
201
|
-
const
|
|
210
|
+
const digits = match[1].length === 3 ? [...match[1]].map((digit) => digit + digit).join("") : match[1];
|
|
211
|
+
const n = Number.parseInt(digits, 16);
|
|
202
212
|
return [n >> 16 & 255, n >> 8 & 255, n & 255];
|
|
213
|
+
};
|
|
214
|
+
var rgbToHex = (r, g, b, a) => {
|
|
215
|
+
const channel = (x) => {
|
|
216
|
+
const hex = Math.max(0, Math.min(255, Math.round(x))).toString(16);
|
|
217
|
+
return hex.length === 1 ? `0${hex}` : hex;
|
|
218
|
+
};
|
|
219
|
+
const alphaChannel = a === void 0 || a >= 1 ? "" : channel(a * 255);
|
|
220
|
+
return `#${channel(r)}${channel(g)}${channel(b)}${alphaChannel}`;
|
|
221
|
+
};
|
|
222
|
+
var hsvToRgb = (h, s, v) => {
|
|
223
|
+
const c = v * s;
|
|
224
|
+
const x = c * (1 - Math.abs(h / 60 % 2 - 1));
|
|
225
|
+
const m = v - c;
|
|
226
|
+
let r = 0, g = 0, b = 0;
|
|
227
|
+
if (h >= 0 && h < 60) {
|
|
228
|
+
r = c;
|
|
229
|
+
g = x;
|
|
230
|
+
b = 0;
|
|
231
|
+
} else if (h >= 60 && h < 120) {
|
|
232
|
+
r = x;
|
|
233
|
+
g = c;
|
|
234
|
+
b = 0;
|
|
235
|
+
} else if (h >= 120 && h < 180) {
|
|
236
|
+
r = 0;
|
|
237
|
+
g = c;
|
|
238
|
+
b = x;
|
|
239
|
+
} else if (h >= 180 && h < 240) {
|
|
240
|
+
r = 0;
|
|
241
|
+
g = x;
|
|
242
|
+
b = c;
|
|
243
|
+
} else if (h >= 240 && h < 300) {
|
|
244
|
+
r = x;
|
|
245
|
+
g = 0;
|
|
246
|
+
b = c;
|
|
247
|
+
} else if (h >= 300 && h < 360) {
|
|
248
|
+
r = c;
|
|
249
|
+
g = 0;
|
|
250
|
+
b = x;
|
|
251
|
+
}
|
|
252
|
+
return {
|
|
253
|
+
r: Math.round((r + m) * 255),
|
|
254
|
+
g: Math.round((g + m) * 255),
|
|
255
|
+
b: Math.round((b + m) * 255)
|
|
256
|
+
};
|
|
257
|
+
};
|
|
258
|
+
var rgbToHsv = (r, g, b) => {
|
|
259
|
+
r /= 255;
|
|
260
|
+
g /= 255;
|
|
261
|
+
b /= 255;
|
|
262
|
+
const max = Math.max(r, g, b);
|
|
263
|
+
const min = Math.min(r, g, b);
|
|
264
|
+
const delta = max - min;
|
|
265
|
+
let h = 0;
|
|
266
|
+
if (delta !== 0) {
|
|
267
|
+
if (max === r) {
|
|
268
|
+
h = 60 * ((g - b) / delta % 6);
|
|
269
|
+
} else if (max === g) {
|
|
270
|
+
h = 60 * ((b - r) / delta + 2);
|
|
271
|
+
} else if (max === b) {
|
|
272
|
+
h = 60 * ((r - g) / delta + 4);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
if (h < 0) {
|
|
276
|
+
h += 360;
|
|
277
|
+
}
|
|
278
|
+
const s = max === 0 ? 0 : delta / max;
|
|
279
|
+
const v = max;
|
|
280
|
+
return { h, s, v };
|
|
281
|
+
};
|
|
282
|
+
|
|
283
|
+
// src/model/color/interpolation.ts
|
|
284
|
+
function mixHexColors(start, end, ratio) {
|
|
285
|
+
const startRgb = hexToRgb(start);
|
|
286
|
+
const endRgb = hexToRgb(end);
|
|
287
|
+
const startAlpha = startRgb.a ?? 1;
|
|
288
|
+
const endAlpha = endRgb.a ?? 1;
|
|
289
|
+
return rgbToHex(
|
|
290
|
+
Math.round(startRgb.r + (endRgb.r - startRgb.r) * ratio),
|
|
291
|
+
Math.round(startRgb.g + (endRgb.g - startRgb.g) * ratio),
|
|
292
|
+
Math.round(startRgb.b + (endRgb.b - startRgb.b) * ratio),
|
|
293
|
+
startAlpha + (endAlpha - startAlpha) * ratio
|
|
294
|
+
);
|
|
203
295
|
}
|
|
204
|
-
function
|
|
205
|
-
|
|
296
|
+
function interpolateHexColorStops(stops, position) {
|
|
297
|
+
const sortedStops = [...stops].sort((first2, second) => first2.position - second.position);
|
|
298
|
+
const first = sortedStops[0];
|
|
299
|
+
const last = sortedStops[sortedStops.length - 1];
|
|
300
|
+
if (position <= first.position) {
|
|
301
|
+
return first.color;
|
|
302
|
+
}
|
|
303
|
+
if (position >= last.position) {
|
|
304
|
+
return last.color;
|
|
305
|
+
}
|
|
306
|
+
for (let index = 0; index < sortedStops.length - 1; index++) {
|
|
307
|
+
const start = sortedStops[index];
|
|
308
|
+
const end = sortedStops[index + 1];
|
|
309
|
+
if (position >= start.position && position <= end.position) {
|
|
310
|
+
const range = end.position - start.position;
|
|
311
|
+
const ratio = range === 0 ? 0 : (position - start.position) / range;
|
|
312
|
+
return mixHexColors(start.color, end.color, ratio);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
return last.color;
|
|
206
316
|
}
|
|
317
|
+
|
|
318
|
+
// src/model/isometricObject/shading.ts
|
|
207
319
|
function multiply(hex, factor) {
|
|
208
|
-
const rgb =
|
|
320
|
+
const rgb = parseHexRgb(hex);
|
|
209
321
|
if (!rgb) {
|
|
210
322
|
return hex;
|
|
211
323
|
}
|
|
@@ -364,6 +476,36 @@ var BUILT_IN_DESCRIPTORS = [
|
|
|
364
476
|
pointerScale: true,
|
|
365
477
|
size: { width: 200, height: 200 }
|
|
366
478
|
},
|
|
479
|
+
{
|
|
480
|
+
type: "hand",
|
|
481
|
+
group: "readout",
|
|
482
|
+
category: "instrument",
|
|
483
|
+
value: { type: "number", writable: false, default: 0 },
|
|
484
|
+
properties: {
|
|
485
|
+
max: { type: "number", default: 60, min: 1, max: 7200 },
|
|
486
|
+
start: { type: "number", default: 0, min: -360, max: 360 },
|
|
487
|
+
length: { type: "number", default: 0.8, min: 0.05, max: 1, step: 0.01 },
|
|
488
|
+
tail: { type: "number", default: 0, min: 0, max: 1, step: 0.01 },
|
|
489
|
+
gap: { type: "number", default: 0, min: 0, max: 1, step: 0.01 },
|
|
490
|
+
width: { type: "number", default: 6, min: 0.5, max: 80 },
|
|
491
|
+
taper: { type: "number", default: 0.4, min: 0, max: 1, step: 0.05 },
|
|
492
|
+
color: { type: "color", default: "#ffffff" },
|
|
493
|
+
root: { type: "color", default: "", optional: true },
|
|
494
|
+
fade: { type: "number", default: 0, min: 0, max: 1, step: 0.05 },
|
|
495
|
+
tipFade: { type: "number", default: 0, min: 0, max: 1, step: 0.05 },
|
|
496
|
+
soft: { type: "number", default: 0, min: 0, max: 40 },
|
|
497
|
+
bloom: { type: "number", default: 0, min: 0, max: 60 },
|
|
498
|
+
glow: { type: "number", default: 0, min: 0, max: 80 },
|
|
499
|
+
glowColor: { type: "color", default: "", optional: true },
|
|
500
|
+
hub: { type: "number", default: 0, min: 0, max: 80 },
|
|
501
|
+
hubFill: { type: "color", default: "#000000", optional: true },
|
|
502
|
+
hubRing: { type: "number", default: 2, min: 0, max: 40 },
|
|
503
|
+
animate: { type: "number", default: 0, min: 0, max: 2e3, step: 10 }
|
|
504
|
+
},
|
|
505
|
+
interaction: "none",
|
|
506
|
+
pointerScale: false,
|
|
507
|
+
size: { width: 200, height: 200, minWidth: 20, minHeight: 20, aspect: 1 }
|
|
508
|
+
},
|
|
367
509
|
{
|
|
368
510
|
type: "ruler",
|
|
369
511
|
group: "input",
|
|
@@ -1054,6 +1196,7 @@ var NAMED_BLOCK_KINDS = [
|
|
|
1054
1196
|
"Component",
|
|
1055
1197
|
"Shape",
|
|
1056
1198
|
"Text",
|
|
1199
|
+
"Image",
|
|
1057
1200
|
"Isometric",
|
|
1058
1201
|
"Dimension",
|
|
1059
1202
|
"Link",
|
|
@@ -1068,14 +1211,16 @@ var NAMED_BLOCK_KINDS = [
|
|
|
1068
1211
|
"Symbol",
|
|
1069
1212
|
"Port",
|
|
1070
1213
|
"DataSource",
|
|
1071
|
-
"Repeat"
|
|
1214
|
+
"Repeat",
|
|
1215
|
+
"Template",
|
|
1216
|
+
"Use"
|
|
1072
1217
|
];
|
|
1073
1218
|
var SIDES = ["top", "bottom", "left", "right"];
|
|
1074
1219
|
var isSide = (s) => SIDES.includes(s);
|
|
1075
1220
|
var isComponentBlockKind = (kind) => kind === "Component" || kind === "Widget";
|
|
1076
1221
|
var isNamedBlockKind = (s) => NAMED_BLOCK_KINDS.includes(s);
|
|
1077
1222
|
|
|
1078
|
-
// src/sflLanguage/parsing/
|
|
1223
|
+
// src/sflLanguage/parsing/pathSegments.ts
|
|
1079
1224
|
function parsePathSegments(cursor) {
|
|
1080
1225
|
const segments = [cursor.expect("ident", "path identifier").value];
|
|
1081
1226
|
while (cursor.at("dot")) {
|
|
@@ -1084,111 +1229,6 @@ function parsePathSegments(cursor) {
|
|
|
1084
1229
|
}
|
|
1085
1230
|
return segments;
|
|
1086
1231
|
}
|
|
1087
|
-
function parseEndpoint(cursor) {
|
|
1088
|
-
const segments = parsePathSegments(cursor);
|
|
1089
|
-
let side;
|
|
1090
|
-
let fraction;
|
|
1091
|
-
if (cursor.at("comma")) {
|
|
1092
|
-
cursor.next();
|
|
1093
|
-
const sideToken = cursor.expect("ident", 'side after ","');
|
|
1094
|
-
if (!isSide(sideToken.value)) {
|
|
1095
|
-
throw new SflParseError(
|
|
1096
|
-
`expected a side (top/right/bottom/left), got '${sideToken.value}'`,
|
|
1097
|
-
sideToken.line,
|
|
1098
|
-
sideToken.col
|
|
1099
|
-
);
|
|
1100
|
-
}
|
|
1101
|
-
side = sideToken.value;
|
|
1102
|
-
if (cursor.at("lparen")) {
|
|
1103
|
-
cursor.next();
|
|
1104
|
-
fraction = cursor.expectNumber('fraction inside "("');
|
|
1105
|
-
cursor.expect("rparen", "')'");
|
|
1106
|
-
}
|
|
1107
|
-
}
|
|
1108
|
-
return { type: "endpoint", segments, side, fraction };
|
|
1109
|
-
}
|
|
1110
|
-
function parseList(cursor) {
|
|
1111
|
-
cursor.expect("lbracket", "'['");
|
|
1112
|
-
const values = [];
|
|
1113
|
-
cursor.skipNewlines();
|
|
1114
|
-
if (!cursor.at("rbracket")) {
|
|
1115
|
-
values.push(parseValue(cursor, false));
|
|
1116
|
-
cursor.skipNewlines();
|
|
1117
|
-
while (cursor.at("comma")) {
|
|
1118
|
-
cursor.next();
|
|
1119
|
-
cursor.skipNewlines();
|
|
1120
|
-
if (cursor.at("rbracket")) {
|
|
1121
|
-
break;
|
|
1122
|
-
}
|
|
1123
|
-
values.push(parseValue(cursor, false));
|
|
1124
|
-
cursor.skipNewlines();
|
|
1125
|
-
}
|
|
1126
|
-
}
|
|
1127
|
-
cursor.expect("rbracket", "']'");
|
|
1128
|
-
return { type: "list", values };
|
|
1129
|
-
}
|
|
1130
|
-
var ARITHMETIC = /* @__PURE__ */ new Set(["+", "-", "*", "/", ">", "<", ">=", "<=", "==", "!=", "&&", "||"]);
|
|
1131
|
-
function startsComputed(cursor) {
|
|
1132
|
-
const first = cursor.peek();
|
|
1133
|
-
if (first.type === "op" && first.value === "-") {
|
|
1134
|
-
return true;
|
|
1135
|
-
}
|
|
1136
|
-
if (first.type !== "number" && first.type !== "ident" && first.type !== "lparen") {
|
|
1137
|
-
return false;
|
|
1138
|
-
}
|
|
1139
|
-
for (let offset = 0; ; offset++) {
|
|
1140
|
-
const token = cursor.peek(offset);
|
|
1141
|
-
if (token.type === "newline" || token.type === "semi" || token.type === "rbrace" || token.type === "eof") {
|
|
1142
|
-
return false;
|
|
1143
|
-
}
|
|
1144
|
-
if (token.type === "lparen" || token.type === "op" && ARITHMETIC.has(token.value)) {
|
|
1145
|
-
return true;
|
|
1146
|
-
}
|
|
1147
|
-
if (token.type === "ident" && cursor.peek(offset - 1).type === "comma") {
|
|
1148
|
-
return true;
|
|
1149
|
-
}
|
|
1150
|
-
if (offset === 0 && token.type === "ident" && cursor.peek(1).type === "comma") {
|
|
1151
|
-
return true;
|
|
1152
|
-
}
|
|
1153
|
-
}
|
|
1154
|
-
}
|
|
1155
|
-
function parseComputed(cursor) {
|
|
1156
|
-
const items = [parseExpression(cursor)];
|
|
1157
|
-
while (cursor.at("comma")) {
|
|
1158
|
-
cursor.next();
|
|
1159
|
-
items.push(parseExpression(cursor));
|
|
1160
|
-
}
|
|
1161
|
-
return { type: "expr", items };
|
|
1162
|
-
}
|
|
1163
|
-
function parseValue(cursor, allowTuple = true) {
|
|
1164
|
-
if (allowTuple && startsComputed(cursor)) {
|
|
1165
|
-
return parseComputed(cursor);
|
|
1166
|
-
}
|
|
1167
|
-
const token = cursor.peek();
|
|
1168
|
-
switch (token.type) {
|
|
1169
|
-
case "string":
|
|
1170
|
-
cursor.next();
|
|
1171
|
-
return { type: "string", value: token.value };
|
|
1172
|
-
case "lbracket":
|
|
1173
|
-
return parseList(cursor);
|
|
1174
|
-
case "number": {
|
|
1175
|
-
const firstValue = cursor.expectNumber("number");
|
|
1176
|
-
if (!allowTuple || !cursor.at("comma")) {
|
|
1177
|
-
return { type: "number", value: firstValue };
|
|
1178
|
-
}
|
|
1179
|
-
const values = [firstValue];
|
|
1180
|
-
while (cursor.at("comma")) {
|
|
1181
|
-
cursor.next();
|
|
1182
|
-
values.push(cursor.expectNumber("number in tuple"));
|
|
1183
|
-
}
|
|
1184
|
-
return { type: "tuple", values };
|
|
1185
|
-
}
|
|
1186
|
-
case "ident":
|
|
1187
|
-
return { type: "ident", segments: parsePathSegments(cursor) };
|
|
1188
|
-
default:
|
|
1189
|
-
throw new SflParseError(`expected a value, got '${token.value || token.type}'`, token.line, token.col);
|
|
1190
|
-
}
|
|
1191
|
-
}
|
|
1192
1232
|
|
|
1193
1233
|
// src/sflLanguage/parsing/expressions.ts
|
|
1194
1234
|
var COMPARISONS = /* @__PURE__ */ new Set([">", "<", ">=", "<=", "==", "!="]);
|
|
@@ -1314,21 +1354,128 @@ function parseHandler(cursor) {
|
|
|
1314
1354
|
if (cursor.at("eof")) {
|
|
1315
1355
|
throw new SflParseError(`unterminated handler '${event.value}'`, event.line, event.col);
|
|
1316
1356
|
}
|
|
1317
|
-
assignments.push(parseAssignment(cursor));
|
|
1318
|
-
expectEnd(cursor, "assignment");
|
|
1319
|
-
cursor.skipNewlines();
|
|
1357
|
+
assignments.push(parseAssignment(cursor));
|
|
1358
|
+
expectEnd(cursor, "assignment");
|
|
1359
|
+
cursor.skipNewlines();
|
|
1360
|
+
}
|
|
1361
|
+
cursor.expect("rbrace", "'}'");
|
|
1362
|
+
}
|
|
1363
|
+
return { event: event.value, assignments, line: event.line, col: event.col };
|
|
1364
|
+
}
|
|
1365
|
+
function expectEnd(cursor, what) {
|
|
1366
|
+
const next = cursor.peek();
|
|
1367
|
+
if (!["newline", "semi", "rbrace", "eof"].includes(next.type)) {
|
|
1368
|
+
throw new SflParseError(`unexpected '${next.value || next.type}' after ${what}`, next.line, next.col);
|
|
1369
|
+
}
|
|
1370
|
+
if (next.type === "semi") {
|
|
1371
|
+
cursor.next();
|
|
1372
|
+
}
|
|
1373
|
+
}
|
|
1374
|
+
|
|
1375
|
+
// src/sflLanguage/parsing/values.ts
|
|
1376
|
+
function parseEndpoint(cursor) {
|
|
1377
|
+
const segments = parsePathSegments(cursor);
|
|
1378
|
+
let side;
|
|
1379
|
+
let fraction;
|
|
1380
|
+
if (cursor.at("comma")) {
|
|
1381
|
+
cursor.next();
|
|
1382
|
+
const sideToken = cursor.expect("ident", 'side after ","');
|
|
1383
|
+
if (!isSide(sideToken.value)) {
|
|
1384
|
+
throw new SflParseError(
|
|
1385
|
+
`expected a side (top/right/bottom/left), got '${sideToken.value}'`,
|
|
1386
|
+
sideToken.line,
|
|
1387
|
+
sideToken.col
|
|
1388
|
+
);
|
|
1389
|
+
}
|
|
1390
|
+
side = sideToken.value;
|
|
1391
|
+
if (cursor.at("lparen")) {
|
|
1392
|
+
cursor.next();
|
|
1393
|
+
fraction = cursor.expectNumber('fraction inside "("');
|
|
1394
|
+
cursor.expect("rparen", "')'");
|
|
1395
|
+
}
|
|
1396
|
+
}
|
|
1397
|
+
return { type: "endpoint", segments, side, fraction };
|
|
1398
|
+
}
|
|
1399
|
+
function parseList(cursor) {
|
|
1400
|
+
cursor.expect("lbracket", "'['");
|
|
1401
|
+
const values = [];
|
|
1402
|
+
cursor.skipNewlines();
|
|
1403
|
+
if (!cursor.at("rbracket")) {
|
|
1404
|
+
values.push(parseValue(cursor, false));
|
|
1405
|
+
cursor.skipNewlines();
|
|
1406
|
+
while (cursor.at("comma")) {
|
|
1407
|
+
cursor.next();
|
|
1408
|
+
cursor.skipNewlines();
|
|
1409
|
+
if (cursor.at("rbracket")) {
|
|
1410
|
+
break;
|
|
1411
|
+
}
|
|
1412
|
+
values.push(parseValue(cursor, false));
|
|
1413
|
+
cursor.skipNewlines();
|
|
1414
|
+
}
|
|
1415
|
+
}
|
|
1416
|
+
cursor.expect("rbracket", "']'");
|
|
1417
|
+
return { type: "list", values };
|
|
1418
|
+
}
|
|
1419
|
+
var ARITHMETIC = /* @__PURE__ */ new Set(["+", "-", "*", "/", ">", "<", ">=", "<=", "==", "!=", "&&", "||"]);
|
|
1420
|
+
function startsComputed(cursor) {
|
|
1421
|
+
const first = cursor.peek();
|
|
1422
|
+
if (first.type === "op" && first.value === "-") {
|
|
1423
|
+
return true;
|
|
1424
|
+
}
|
|
1425
|
+
if (first.type !== "number" && first.type !== "ident" && first.type !== "lparen") {
|
|
1426
|
+
return false;
|
|
1427
|
+
}
|
|
1428
|
+
for (let offset = 0; ; offset++) {
|
|
1429
|
+
const token = cursor.peek(offset);
|
|
1430
|
+
if (token.type === "newline" || token.type === "semi" || token.type === "rbrace" || token.type === "eof") {
|
|
1431
|
+
return false;
|
|
1432
|
+
}
|
|
1433
|
+
if (token.type === "lparen" || token.type === "op" && ARITHMETIC.has(token.value)) {
|
|
1434
|
+
return true;
|
|
1435
|
+
}
|
|
1436
|
+
if (token.type === "ident" && cursor.peek(offset - 1).type === "comma") {
|
|
1437
|
+
return true;
|
|
1438
|
+
}
|
|
1439
|
+
if (offset === 0 && token.type === "ident" && cursor.peek(1).type === "comma") {
|
|
1440
|
+
return true;
|
|
1441
|
+
}
|
|
1442
|
+
}
|
|
1443
|
+
}
|
|
1444
|
+
function parseComputed(cursor) {
|
|
1445
|
+
const items = [parseExpression(cursor)];
|
|
1446
|
+
while (cursor.at("comma")) {
|
|
1447
|
+
cursor.next();
|
|
1448
|
+
items.push(parseExpression(cursor));
|
|
1449
|
+
}
|
|
1450
|
+
return { type: "expr", items };
|
|
1451
|
+
}
|
|
1452
|
+
function parseValue(cursor, allowTuple = true) {
|
|
1453
|
+
if (allowTuple && startsComputed(cursor)) {
|
|
1454
|
+
return parseComputed(cursor);
|
|
1455
|
+
}
|
|
1456
|
+
const token = cursor.peek();
|
|
1457
|
+
switch (token.type) {
|
|
1458
|
+
case "string":
|
|
1459
|
+
cursor.next();
|
|
1460
|
+
return { type: "string", value: token.value };
|
|
1461
|
+
case "lbracket":
|
|
1462
|
+
return parseList(cursor);
|
|
1463
|
+
case "number": {
|
|
1464
|
+
const firstValue = cursor.expectNumber("number");
|
|
1465
|
+
if (!allowTuple || !cursor.at("comma")) {
|
|
1466
|
+
return { type: "number", value: firstValue };
|
|
1467
|
+
}
|
|
1468
|
+
const values = [firstValue];
|
|
1469
|
+
while (cursor.at("comma")) {
|
|
1470
|
+
cursor.next();
|
|
1471
|
+
values.push(cursor.expectNumber("number in tuple"));
|
|
1472
|
+
}
|
|
1473
|
+
return { type: "tuple", values };
|
|
1320
1474
|
}
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
}
|
|
1325
|
-
function expectEnd(cursor, what) {
|
|
1326
|
-
const next = cursor.peek();
|
|
1327
|
-
if (!["newline", "semi", "rbrace", "eof"].includes(next.type)) {
|
|
1328
|
-
throw new SflParseError(`unexpected '${next.value || next.type}' after ${what}`, next.line, next.col);
|
|
1329
|
-
}
|
|
1330
|
-
if (next.type === "semi") {
|
|
1331
|
-
cursor.next();
|
|
1475
|
+
case "ident":
|
|
1476
|
+
return { type: "ident", segments: parsePathSegments(cursor) };
|
|
1477
|
+
default:
|
|
1478
|
+
throw new SflParseError(`expected a value, got '${token.value || token.type}'`, token.line, token.col);
|
|
1332
1479
|
}
|
|
1333
1480
|
}
|
|
1334
1481
|
|
|
@@ -1606,7 +1753,7 @@ function emitComposition(composition) {
|
|
|
1606
1753
|
return ` : ${composition.join(" & ")}`;
|
|
1607
1754
|
}
|
|
1608
1755
|
|
|
1609
|
-
// src/sflLanguage/emitting/
|
|
1756
|
+
// src/sflLanguage/emitting/literals.ts
|
|
1610
1757
|
function formatNumber(value) {
|
|
1611
1758
|
if (Object.is(value, -0)) {
|
|
1612
1759
|
return "0";
|
|
@@ -1617,33 +1764,6 @@ function emitString(value) {
|
|
|
1617
1764
|
const escaped = value.replace(/\r\n?/g, "\n").replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n").replace(/\t/g, "\\t");
|
|
1618
1765
|
return `"${escaped}"`;
|
|
1619
1766
|
}
|
|
1620
|
-
function emitValue(value) {
|
|
1621
|
-
switch (value.type) {
|
|
1622
|
-
case "string":
|
|
1623
|
-
return emitString(value.value);
|
|
1624
|
-
case "number":
|
|
1625
|
-
return formatNumber(value.value);
|
|
1626
|
-
case "tuple":
|
|
1627
|
-
return value.values.map(formatNumber).join(", ");
|
|
1628
|
-
case "list":
|
|
1629
|
-
return `[${value.values.map(emitValue).join(", ")}]`;
|
|
1630
|
-
case "ident":
|
|
1631
|
-
return value.segments.join(".");
|
|
1632
|
-
case "expr":
|
|
1633
|
-
return value.items.map((item) => emitExpression(item)).join(", ");
|
|
1634
|
-
case "endpoint": {
|
|
1635
|
-
let output = value.segments.join(".");
|
|
1636
|
-
if (value.side) {
|
|
1637
|
-
output += `, ${value.side}`;
|
|
1638
|
-
if (value.fraction !== void 0) {
|
|
1639
|
-
output += ` (${formatNumber(value.fraction)})`;
|
|
1640
|
-
}
|
|
1641
|
-
}
|
|
1642
|
-
return output;
|
|
1643
|
-
}
|
|
1644
|
-
}
|
|
1645
|
-
}
|
|
1646
|
-
var emitProperty = (property) => `${property.key}: ${emitValue(property.value)}`;
|
|
1647
1767
|
|
|
1648
1768
|
// src/sflLanguage/emitting/expressions.ts
|
|
1649
1769
|
var PRECEDENCE = {
|
|
@@ -1665,7 +1785,7 @@ function emitExpression(expr, parentPrecedence = 0) {
|
|
|
1665
1785
|
case "number":
|
|
1666
1786
|
return String(expr.value);
|
|
1667
1787
|
case "string":
|
|
1668
|
-
return
|
|
1788
|
+
return emitString(expr.value);
|
|
1669
1789
|
case "boolean":
|
|
1670
1790
|
return String(expr.value);
|
|
1671
1791
|
case "ref":
|
|
@@ -1734,6 +1854,35 @@ function compareByOrder(order, a, b) {
|
|
|
1734
1854
|
var compareLayoutProps = (a, b) => compareByOrder(LAYOUT_ORDER, a, b);
|
|
1735
1855
|
var compareStyleProps = (a, b) => compareByOrder(STYLE_ORDER, a, b);
|
|
1736
1856
|
|
|
1857
|
+
// src/sflLanguage/emitting/values.ts
|
|
1858
|
+
function emitValue(value) {
|
|
1859
|
+
switch (value.type) {
|
|
1860
|
+
case "string":
|
|
1861
|
+
return emitString(value.value);
|
|
1862
|
+
case "number":
|
|
1863
|
+
return formatNumber(value.value);
|
|
1864
|
+
case "tuple":
|
|
1865
|
+
return value.values.map(formatNumber).join(", ");
|
|
1866
|
+
case "list":
|
|
1867
|
+
return `[${value.values.map(emitValue).join(", ")}]`;
|
|
1868
|
+
case "ident":
|
|
1869
|
+
return value.segments.join(".");
|
|
1870
|
+
case "expr":
|
|
1871
|
+
return value.items.map((item) => emitExpression(item)).join(", ");
|
|
1872
|
+
case "endpoint": {
|
|
1873
|
+
let output = value.segments.join(".");
|
|
1874
|
+
if (value.side) {
|
|
1875
|
+
output += `, ${value.side}`;
|
|
1876
|
+
if (value.fraction !== void 0) {
|
|
1877
|
+
output += ` (${formatNumber(value.fraction)})`;
|
|
1878
|
+
}
|
|
1879
|
+
}
|
|
1880
|
+
return output;
|
|
1881
|
+
}
|
|
1882
|
+
}
|
|
1883
|
+
}
|
|
1884
|
+
var emitProperty = (property) => `${property.key}: ${emitValue(property.value)}`;
|
|
1885
|
+
|
|
1737
1886
|
// src/sflLanguage/emitting/propertyBlock.ts
|
|
1738
1887
|
var INDENT = " ";
|
|
1739
1888
|
function emitPropertyBlock(name, properties, depth, bindings = []) {
|
|
@@ -1865,51 +2014,34 @@ function canonicalizeSource(sflText) {
|
|
|
1865
2014
|
return emitDocument(parseSource(sflText));
|
|
1866
2015
|
}
|
|
1867
2016
|
|
|
1868
|
-
// src/sflSemantic/canvasObjects/artifacts/chart/
|
|
2017
|
+
// src/sflSemantic/canvasObjects/artifacts/chart/object.ts
|
|
1869
2018
|
function isChartObject(canvasObject) {
|
|
1870
2019
|
return canvasObject.objectType === "chart" && canvasObject.chart !== void 0;
|
|
1871
2020
|
}
|
|
1872
2021
|
|
|
1873
|
-
// src/sflSemantic/canvasObjects/artifacts/dimension/
|
|
2022
|
+
// src/sflSemantic/canvasObjects/artifacts/dimension/object.ts
|
|
1874
2023
|
function isDimensionObject(canvasObject) {
|
|
1875
2024
|
return canvasObject.objectType === "dimension" && canvasObject.dimension !== void 0;
|
|
1876
2025
|
}
|
|
1877
2026
|
|
|
1878
|
-
// src/sflSemantic/canvasObjects/artifacts/isometric/
|
|
2027
|
+
// src/sflSemantic/canvasObjects/artifacts/isometric/object.ts
|
|
1879
2028
|
function isIsometricObject(canvasObject) {
|
|
1880
2029
|
return canvasObject.objectType === "isometric" && canvasObject.isometric !== void 0;
|
|
1881
2030
|
}
|
|
1882
2031
|
|
|
1883
|
-
// src/sflSemantic/canvasObjects/artifacts/path/
|
|
2032
|
+
// src/sflSemantic/canvasObjects/artifacts/path/object.ts
|
|
1884
2033
|
function isPathObject(canvasObject) {
|
|
1885
2034
|
return canvasObject.objectType === "path" && canvasObject.path !== void 0;
|
|
1886
2035
|
}
|
|
1887
2036
|
|
|
1888
|
-
// src/sflSemantic/canvasObjects/artifacts/swimlane/
|
|
2037
|
+
// src/sflSemantic/canvasObjects/artifacts/swimlane/object.ts
|
|
1889
2038
|
function isSwimlaneObject(canvasObject) {
|
|
1890
2039
|
return canvasObject.objectType === "swimlane" && canvasObject.swimlane !== void 0;
|
|
1891
2040
|
}
|
|
1892
2041
|
|
|
1893
|
-
// src/sflLanguage/expansion/
|
|
1894
|
-
var RESERVED = /* @__PURE__ */ new Set(["columns", "rows", "count", "step", "origin", "seed", "jitter", "chance", "order", "where"]);
|
|
1895
|
-
var MAX_CELLS = 2e4;
|
|
1896
|
-
var MAX_VALUES = 1e6;
|
|
1897
|
-
var Random = class {
|
|
1898
|
-
state;
|
|
1899
|
-
constructor(seed) {
|
|
1900
|
-
this.state = seed >>> 0;
|
|
1901
|
-
}
|
|
1902
|
-
// mulberry32: a small generator that gives the same numbers for the same seed, on every machine.
|
|
1903
|
-
next() {
|
|
1904
|
-
this.state = this.state + 1831565813 >>> 0;
|
|
1905
|
-
let t = this.state;
|
|
1906
|
-
t = Math.imul(t ^ t >>> 15, t | 1);
|
|
1907
|
-
t ^= t + Math.imul(t ^ t >>> 7, t | 61);
|
|
1908
|
-
return ((t ^ t >>> 14) >>> 0) / 4294967296;
|
|
1909
|
-
}
|
|
1910
|
-
};
|
|
2042
|
+
// src/sflLanguage/expansion/scope.ts
|
|
1911
2043
|
function fail(scope, message) {
|
|
1912
|
-
throw new Error(
|
|
2044
|
+
throw new Error(`${scope.label}: ${message}`);
|
|
1913
2045
|
}
|
|
1914
2046
|
function numberOf(scope, value, what) {
|
|
1915
2047
|
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
@@ -1917,6 +2049,8 @@ function numberOf(scope, value, what) {
|
|
|
1917
2049
|
}
|
|
1918
2050
|
return value;
|
|
1919
2051
|
}
|
|
2052
|
+
|
|
2053
|
+
// src/sflLanguage/expansion/functions.ts
|
|
1920
2054
|
function rgbOf(scope, value) {
|
|
1921
2055
|
const match = typeof value === "string" ? /^#([0-9a-f]{6})$/i.exec(value) : null;
|
|
1922
2056
|
if (!match) {
|
|
@@ -1985,6 +2119,8 @@ function callFunction(scope, name, args) {
|
|
|
1985
2119
|
return fail(scope, `unknown function ${name}()`);
|
|
1986
2120
|
}
|
|
1987
2121
|
}
|
|
2122
|
+
|
|
2123
|
+
// src/sflLanguage/expansion/evaluation.ts
|
|
1988
2124
|
function evaluate(scope, expr) {
|
|
1989
2125
|
switch (expr.kind) {
|
|
1990
2126
|
case "number":
|
|
@@ -2042,27 +2178,37 @@ function evaluate(scope, expr) {
|
|
|
2042
2178
|
}
|
|
2043
2179
|
}
|
|
2044
2180
|
var round2 = (value) => Math.round(value * 1e3) / 1e3;
|
|
2181
|
+
function scalarValue(scope, only) {
|
|
2182
|
+
if (typeof only === "number") {
|
|
2183
|
+
return { type: "number", value: round2(numberOf(scope, only, "a value")) };
|
|
2184
|
+
}
|
|
2185
|
+
if (typeof only === "string") {
|
|
2186
|
+
return { type: "string", value: only };
|
|
2187
|
+
}
|
|
2188
|
+
return { type: "ident", segments: [String(only)] };
|
|
2189
|
+
}
|
|
2045
2190
|
function resolveValue(scope, value) {
|
|
2191
|
+
if (scope.substitute && value.type === "ident" && value.segments.length === 1) {
|
|
2192
|
+
const known = scope.vars.get(value.segments[0]);
|
|
2193
|
+
if (known !== void 0) {
|
|
2194
|
+
return scalarValue(scope, known);
|
|
2195
|
+
}
|
|
2196
|
+
}
|
|
2046
2197
|
if (value.type !== "expr") {
|
|
2047
2198
|
return value;
|
|
2048
2199
|
}
|
|
2049
2200
|
const results = value.items.map((item) => evaluate(scope, item));
|
|
2050
2201
|
if (results.length === 1) {
|
|
2051
|
-
|
|
2052
|
-
if (typeof only === "number") {
|
|
2053
|
-
return { type: "number", value: round2(numberOf(scope, only, "a value")) };
|
|
2054
|
-
}
|
|
2055
|
-
if (typeof only === "string") {
|
|
2056
|
-
return { type: "string", value: only };
|
|
2057
|
-
}
|
|
2058
|
-
return { type: "ident", segments: [String(only)] };
|
|
2202
|
+
return scalarValue(scope, results[0]);
|
|
2059
2203
|
}
|
|
2060
2204
|
return { type: "tuple", values: results.map((result) => round2(numberOf(scope, result, "a tuple"))) };
|
|
2061
2205
|
}
|
|
2206
|
+
|
|
2207
|
+
// src/sflLanguage/expansion/instance.ts
|
|
2062
2208
|
function propertiesOf(scope, properties) {
|
|
2063
2209
|
return properties.map((property) => ({ key: property.key, value: resolveValue(scope, property.value) }));
|
|
2064
2210
|
}
|
|
2065
|
-
function entryOf(scope, entry,
|
|
2211
|
+
function entryOf(scope, entry, rename) {
|
|
2066
2212
|
switch (entry.type) {
|
|
2067
2213
|
case "property":
|
|
2068
2214
|
return {
|
|
@@ -2074,18 +2220,20 @@ function entryOf(scope, entry, suffix) {
|
|
|
2074
2220
|
case "style":
|
|
2075
2221
|
return { type: "style", style: { ...entry.style, properties: propertiesOf(scope, entry.style.properties) } };
|
|
2076
2222
|
case "block":
|
|
2077
|
-
return { type: "block", block: instance(scope, entry.block,
|
|
2223
|
+
return { type: "block", block: instance(scope, entry.block, rename) };
|
|
2078
2224
|
default:
|
|
2079
2225
|
return entry;
|
|
2080
2226
|
}
|
|
2081
2227
|
}
|
|
2082
|
-
function instance(scope, block2,
|
|
2228
|
+
function instance(scope, block2, rename) {
|
|
2083
2229
|
return {
|
|
2084
2230
|
...block2,
|
|
2085
|
-
name:
|
|
2086
|
-
entries: block2.entries.map((entry) => entryOf(scope, entry,
|
|
2231
|
+
name: rename(block2.name),
|
|
2232
|
+
entries: block2.entries.map((entry) => entryOf(scope, entry, rename))
|
|
2087
2233
|
};
|
|
2088
2234
|
}
|
|
2235
|
+
|
|
2236
|
+
// src/sflLanguage/expansion/properties.ts
|
|
2089
2237
|
function propertyOf(block2, key) {
|
|
2090
2238
|
for (const entry of block2.entries) {
|
|
2091
2239
|
if (entry.type === "property" && entry.property.key === key) {
|
|
@@ -2108,88 +2256,244 @@ function numbersOf(block2, key) {
|
|
|
2108
2256
|
}
|
|
2109
2257
|
return void 0;
|
|
2110
2258
|
}
|
|
2111
|
-
|
|
2112
|
-
|
|
2259
|
+
|
|
2260
|
+
// src/sflLanguage/expansion/random.ts
|
|
2261
|
+
var Random = class {
|
|
2262
|
+
state;
|
|
2263
|
+
constructor(seed) {
|
|
2264
|
+
this.state = seed >>> 0;
|
|
2265
|
+
}
|
|
2266
|
+
// mulberry32: a small generator that gives the same numbers for the same seed, on every machine.
|
|
2267
|
+
next() {
|
|
2268
|
+
this.state = this.state + 1831565813 >>> 0;
|
|
2269
|
+
let t = this.state;
|
|
2270
|
+
t = Math.imul(t ^ t >>> 15, t | 1);
|
|
2271
|
+
t ^= t + Math.imul(t ^ t >>> 7, t | 61);
|
|
2272
|
+
return ((t ^ t >>> 14) >>> 0) / 4294967296;
|
|
2273
|
+
}
|
|
2274
|
+
};
|
|
2275
|
+
|
|
2276
|
+
// src/sflLanguage/expansion/repeat.ts
|
|
2277
|
+
var RESERVED = /* @__PURE__ */ new Set(["columns", "rows", "count", "step", "origin", "seed", "jitter", "chance", "order", "where"]);
|
|
2278
|
+
var MAX_CELLS = 2e4;
|
|
2279
|
+
var MAX_VALUES = 1e6;
|
|
2280
|
+
function readGrid(block2, scope) {
|
|
2113
2281
|
const count = numbersOf(block2, "count")?.[0];
|
|
2114
2282
|
const columns = Math.max(1, Math.floor(count ?? numbersOf(block2, "columns")?.[0] ?? 1));
|
|
2115
2283
|
const rows = count === void 0 ? Math.max(1, Math.floor(numbersOf(block2, "rows")?.[0] ?? 1)) : 1;
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
fail(scope, `${total} cells are too many, the limit is ${MAX_CELLS}`);
|
|
2284
|
+
if (columns * rows > MAX_CELLS) {
|
|
2285
|
+
fail(scope, `${columns * rows} cells are too many, the limit is ${MAX_CELLS}`);
|
|
2119
2286
|
}
|
|
2120
2287
|
const [stepX = 0, stepY = stepX] = numbersOf(block2, "step") ?? [];
|
|
2121
2288
|
const [originX = 0, originY = 0] = numbersOf(block2, "origin") ?? [];
|
|
2122
|
-
const
|
|
2123
|
-
const jitter = numbersOf(block2, "jitter")?.[0] ?? 0;
|
|
2124
|
-
const chance = numbersOf(block2, "chance")?.[0] ?? 1;
|
|
2125
|
-
const diagonal = propertyOf(block2, "order")?.type === "ident" && propertyOf(block2, "order").segments[0] === "diagonal";
|
|
2126
|
-
const condition = propertyOf(block2, "where");
|
|
2127
|
-
const helpers = block2.entries.flatMap(
|
|
2128
|
-
(entry) => entry.type === "property" && entry.property.value.type === "expr" && !RESERVED.has(entry.property.key) ? [entry.property] : []
|
|
2129
|
-
);
|
|
2289
|
+
const order = propertyOf(block2, "order");
|
|
2130
2290
|
const templates = block2.entries.flatMap((entry) => entry.type === "block" ? [entry.block] : []);
|
|
2131
2291
|
if (templates.some((template) => template.kind === "Repeat")) {
|
|
2132
2292
|
fail(scope, "a Repeat cannot hold another Repeat");
|
|
2133
2293
|
}
|
|
2134
|
-
if (
|
|
2294
|
+
if (columns * rows * Math.max(1, templates.length) > MAX_VALUES) {
|
|
2135
2295
|
fail(scope, "too many blocks");
|
|
2136
2296
|
}
|
|
2297
|
+
return {
|
|
2298
|
+
columns,
|
|
2299
|
+
rows,
|
|
2300
|
+
step: [stepX, stepY],
|
|
2301
|
+
origin: [originX, originY],
|
|
2302
|
+
seed: numbersOf(block2, "seed")?.[0] ?? 0,
|
|
2303
|
+
jitter: numbersOf(block2, "jitter")?.[0] ?? 0,
|
|
2304
|
+
chance: numbersOf(block2, "chance")?.[0] ?? 1,
|
|
2305
|
+
diagonal: order?.type === "ident" && order.segments[0] === "diagonal",
|
|
2306
|
+
condition: propertyOf(block2, "where"),
|
|
2307
|
+
helpers: block2.entries.flatMap(
|
|
2308
|
+
(entry) => entry.type === "property" && entry.property.value.type === "expr" && !RESERVED.has(entry.property.key) ? [entry.property] : []
|
|
2309
|
+
),
|
|
2310
|
+
templates
|
|
2311
|
+
};
|
|
2312
|
+
}
|
|
2313
|
+
function cellsOf(grid) {
|
|
2137
2314
|
const cells = [];
|
|
2138
|
-
for (let row = 0; row < rows; row++) {
|
|
2139
|
-
for (let col = 0; col < columns; col++) {
|
|
2315
|
+
for (let row = 0; row < grid.rows; row++) {
|
|
2316
|
+
for (let col = 0; col < grid.columns; col++) {
|
|
2140
2317
|
cells.push([col, row]);
|
|
2141
2318
|
}
|
|
2142
2319
|
}
|
|
2143
|
-
|
|
2144
|
-
|
|
2320
|
+
return grid.diagonal ? cells.sort((a, b) => a[0] + a[1] - (b[0] + b[1]) || a[0] - b[0]) : cells;
|
|
2321
|
+
}
|
|
2322
|
+
function enterCell(scope, grid, col, row) {
|
|
2323
|
+
const index = row * grid.columns + col;
|
|
2324
|
+
scope.random = new Random(Math.imul(grid.seed + 1, 2654435761) ^ Math.imul(index + 1, 2246822507));
|
|
2325
|
+
if (grid.chance < 1 && scope.random.next() >= grid.chance) {
|
|
2326
|
+
return false;
|
|
2145
2327
|
}
|
|
2146
|
-
const
|
|
2147
|
-
|
|
2148
|
-
|
|
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
|
-
|
|
2328
|
+
const spread = () => grid.jitter > 0 ? (scope.random.next() * 2 - 1) * grid.jitter : 0;
|
|
2329
|
+
scope.vars = /* @__PURE__ */ new Map([
|
|
2330
|
+
["col", col],
|
|
2331
|
+
["row", row],
|
|
2332
|
+
["index", index],
|
|
2333
|
+
["count", grid.columns * grid.rows],
|
|
2334
|
+
["columns", grid.columns],
|
|
2335
|
+
["rows", grid.rows],
|
|
2336
|
+
["x", round2(grid.origin[0] + col * grid.step[0] + spread())],
|
|
2337
|
+
["y", round2(grid.origin[1] + row * grid.step[1] + spread())]
|
|
2338
|
+
]);
|
|
2339
|
+
return true;
|
|
2340
|
+
}
|
|
2341
|
+
function nameHelpers(scope, helpers) {
|
|
2342
|
+
for (const helper of helpers) {
|
|
2343
|
+
const value = resolveValue(scope, helper.value);
|
|
2344
|
+
if (value.type === "number" || value.type === "string") {
|
|
2345
|
+
scope.vars.set(helper.key, value.value);
|
|
2346
|
+
} else if (value.type === "ident") {
|
|
2347
|
+
scope.vars.set(helper.key, value.segments[0] === "true" ? 1 : 0);
|
|
2348
|
+
} else {
|
|
2349
|
+
fail(scope, `${helper.key} needs a number`);
|
|
2350
|
+
}
|
|
2351
|
+
}
|
|
2352
|
+
}
|
|
2353
|
+
function keepsCell(scope, condition) {
|
|
2354
|
+
return condition?.type !== "expr" || Boolean(condition.items.map((item) => evaluate(scope, item))[0]);
|
|
2355
|
+
}
|
|
2356
|
+
function expandRepeat(block2) {
|
|
2357
|
+
const scope = { vars: /* @__PURE__ */ new Map(), random: new Random(0), label: `Repeat ${block2.name}` };
|
|
2358
|
+
const grid = readGrid(block2, scope);
|
|
2359
|
+
const made = [];
|
|
2360
|
+
for (const [col, row] of cellsOf(grid)) {
|
|
2361
|
+
if (!enterCell(scope, grid, col, row)) {
|
|
2362
|
+
continue;
|
|
2363
|
+
}
|
|
2364
|
+
nameHelpers(scope, grid.helpers);
|
|
2365
|
+
if (!keepsCell(scope, grid.condition)) {
|
|
2366
|
+
continue;
|
|
2367
|
+
}
|
|
2368
|
+
const suffix = grid.rows === 1 ? `_${col}` : `_${col}_${row}`;
|
|
2369
|
+
for (const template of grid.templates) {
|
|
2370
|
+
made.push(instance(scope, template, (name) => `${name}${suffix}`));
|
|
2371
|
+
}
|
|
2372
|
+
}
|
|
2373
|
+
return made;
|
|
2374
|
+
}
|
|
2375
|
+
function expandRepeatBlocks(blocks) {
|
|
2376
|
+
return blocks.flatMap((block2) => {
|
|
2377
|
+
if (block2.kind === "Repeat") {
|
|
2378
|
+
return expandRepeat(block2);
|
|
2379
|
+
}
|
|
2380
|
+
if (block2.kind === "Template" || !block2.entries.some((entry) => entry.type === "block")) {
|
|
2381
|
+
return [block2];
|
|
2382
|
+
}
|
|
2383
|
+
return [
|
|
2384
|
+
{
|
|
2385
|
+
...block2,
|
|
2386
|
+
entries: block2.entries.flatMap(
|
|
2387
|
+
(entry) => entry.type === "block" ? expandRepeatBlocks([entry.block]).map((child) => ({ type: "block", block: child })) : [entry]
|
|
2388
|
+
)
|
|
2174
2389
|
}
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2390
|
+
];
|
|
2391
|
+
});
|
|
2392
|
+
}
|
|
2393
|
+
function hasRepeats(blocks) {
|
|
2394
|
+
return blocks.some(
|
|
2395
|
+
(block2) => block2.kind === "Repeat" || block2.entries.some((entry) => entry.type === "block" && hasRepeats([entry.block]))
|
|
2396
|
+
);
|
|
2397
|
+
}
|
|
2398
|
+
|
|
2399
|
+
// src/sflLanguage/expansion/template.ts
|
|
2400
|
+
var MAX_DEPTH = 4;
|
|
2401
|
+
var MAX_BLOCKS = 1e5;
|
|
2402
|
+
var OWN = /* @__PURE__ */ new Set(["at", "seed"]);
|
|
2403
|
+
var PLACE = /* @__PURE__ */ new Set(["x", "y"]);
|
|
2404
|
+
function hashOf(text) {
|
|
2405
|
+
let hash = 2166136261;
|
|
2406
|
+
for (let index = 0; index < text.length; index++) {
|
|
2407
|
+
hash = Math.imul(hash ^ text.charCodeAt(index), 16777619);
|
|
2408
|
+
}
|
|
2409
|
+
return hash >>> 0;
|
|
2410
|
+
}
|
|
2411
|
+
function collect(blocks, into) {
|
|
2412
|
+
for (const block2 of blocks) {
|
|
2413
|
+
if (block2.kind === "Template") {
|
|
2414
|
+
if (into.has(block2.name)) {
|
|
2415
|
+
throw new Error(`Template ${block2.name}: there is another Template of this name`);
|
|
2180
2416
|
}
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
out.push(instance(scope, template, suffix));
|
|
2417
|
+
if (block2.entries.some((entry) => entry.type === "block" && entry.block.kind === "Repeat")) {
|
|
2418
|
+
throw new Error(`Template ${block2.name}: a Template cannot hold a Repeat, a Repeat can hold a Use`);
|
|
2184
2419
|
}
|
|
2420
|
+
into.set(block2.name, block2);
|
|
2421
|
+
}
|
|
2422
|
+
collect(
|
|
2423
|
+
block2.entries.flatMap((entry) => entry.type === "block" ? [entry.block] : []),
|
|
2424
|
+
into
|
|
2425
|
+
);
|
|
2426
|
+
}
|
|
2427
|
+
}
|
|
2428
|
+
var BlockBudget = class {
|
|
2429
|
+
made = 0;
|
|
2430
|
+
take(count, scope) {
|
|
2431
|
+
this.made += count;
|
|
2432
|
+
if (this.made > MAX_BLOCKS) {
|
|
2433
|
+
fail(scope, "too many blocks");
|
|
2434
|
+
}
|
|
2435
|
+
}
|
|
2436
|
+
};
|
|
2437
|
+
function expandUse(use, templates, depth, budget) {
|
|
2438
|
+
const scope = { vars: /* @__PURE__ */ new Map(), random: new Random(0), label: `Use ${use.name}`, substitute: true };
|
|
2439
|
+
if (depth > MAX_DEPTH) {
|
|
2440
|
+
fail(scope, `Templates are nested more than ${MAX_DEPTH} deep, which may be a Template that uses itself`);
|
|
2441
|
+
}
|
|
2442
|
+
if (use.composition.length !== 1) {
|
|
2443
|
+
fail(scope, "a Use names one Template, as in Use oak : tree");
|
|
2444
|
+
}
|
|
2445
|
+
const template = templates.get(use.composition[0]);
|
|
2446
|
+
if (!template) {
|
|
2447
|
+
fail(scope, `there is no Template ${use.composition[0]}`);
|
|
2448
|
+
}
|
|
2449
|
+
const seed = numbersOf(use, "seed")?.[0] ?? 0;
|
|
2450
|
+
scope.random = new Random(Math.imul(seed + 1, 2654435761) ^ hashOf(use.name));
|
|
2451
|
+
const [x = 0, y = 0] = numbersOf(use, "at") ?? [];
|
|
2452
|
+
scope.vars.set("x", x);
|
|
2453
|
+
scope.vars.set("y", y);
|
|
2454
|
+
const given = new Map(
|
|
2455
|
+
use.entries.flatMap(
|
|
2456
|
+
(entry) => entry.type === "property" && !OWN.has(entry.property.key) ? [[entry.property.key, entry.property.value]] : []
|
|
2457
|
+
)
|
|
2458
|
+
);
|
|
2459
|
+
for (const entry of template.entries) {
|
|
2460
|
+
if (entry.type !== "property") {
|
|
2461
|
+
continue;
|
|
2462
|
+
}
|
|
2463
|
+
const { key, value } = entry.property;
|
|
2464
|
+
if (PLACE.has(key) || OWN.has(key)) {
|
|
2465
|
+
fail(scope, `${key} is the name of something a Use sets, so it cannot be a parameter`);
|
|
2466
|
+
}
|
|
2467
|
+
const chosen = resolveValue(scope, given.get(key) ?? value);
|
|
2468
|
+
given.delete(key);
|
|
2469
|
+
if (chosen.type === "number" || chosen.type === "string") {
|
|
2470
|
+
scope.vars.set(key, chosen.value);
|
|
2471
|
+
} else if (chosen.type === "ident") {
|
|
2472
|
+
scope.vars.set(
|
|
2473
|
+
key,
|
|
2474
|
+
chosen.segments[0] === "true" ? 1 : chosen.segments[0] === "false" ? 0 : chosen.segments.join(".")
|
|
2475
|
+
);
|
|
2476
|
+
} else {
|
|
2477
|
+
fail(scope, `${key} needs a number, a text or a name`);
|
|
2185
2478
|
}
|
|
2186
2479
|
}
|
|
2187
|
-
|
|
2480
|
+
const unknown = [...given.keys()][0];
|
|
2481
|
+
if (unknown !== void 0) {
|
|
2482
|
+
fail(scope, `Template ${template.name} has no parameter ${unknown}`);
|
|
2483
|
+
}
|
|
2484
|
+
const made = template.entries.flatMap(
|
|
2485
|
+
(entry) => entry.type === "block" ? [instance(scope, entry.block, (name) => `${use.name}_${name}`)] : []
|
|
2486
|
+
);
|
|
2487
|
+
budget.take(made.length, scope);
|
|
2488
|
+
return expandIn(made, templates, depth + 1, budget);
|
|
2188
2489
|
}
|
|
2189
|
-
function
|
|
2490
|
+
function expandIn(blocks, templates, depth, budget) {
|
|
2190
2491
|
return blocks.flatMap((block2) => {
|
|
2191
|
-
if (block2.kind === "
|
|
2192
|
-
return
|
|
2492
|
+
if (block2.kind === "Template") {
|
|
2493
|
+
return [];
|
|
2494
|
+
}
|
|
2495
|
+
if (block2.kind === "Use") {
|
|
2496
|
+
return expandUse(block2, templates, depth, budget);
|
|
2193
2497
|
}
|
|
2194
2498
|
if (!block2.entries.some((entry) => entry.type === "block")) {
|
|
2195
2499
|
return [block2];
|
|
@@ -2198,15 +2502,24 @@ function expandBlocks(blocks) {
|
|
|
2198
2502
|
{
|
|
2199
2503
|
...block2,
|
|
2200
2504
|
entries: block2.entries.flatMap(
|
|
2201
|
-
(entry) => entry.type === "block" ? (entry.block
|
|
2202
|
-
type: "block",
|
|
2203
|
-
block: child
|
|
2204
|
-
})) : [entry]
|
|
2505
|
+
(entry) => entry.type === "block" ? expandIn([entry.block], templates, depth, budget).map((child) => ({ type: "block", block: child })) : [entry]
|
|
2205
2506
|
)
|
|
2206
2507
|
}
|
|
2207
2508
|
];
|
|
2208
2509
|
});
|
|
2209
2510
|
}
|
|
2511
|
+
function hasTemplates(blocks) {
|
|
2512
|
+
return blocks.some(
|
|
2513
|
+
(block2) => block2.kind === "Template" || block2.kind === "Use" || block2.entries.some((entry) => entry.type === "block" && hasTemplates([entry.block]))
|
|
2514
|
+
);
|
|
2515
|
+
}
|
|
2516
|
+
function expandUses(blocks) {
|
|
2517
|
+
const templates = /* @__PURE__ */ new Map();
|
|
2518
|
+
collect(blocks, templates);
|
|
2519
|
+
return expandIn(blocks, templates, 0, new BlockBudget());
|
|
2520
|
+
}
|
|
2521
|
+
|
|
2522
|
+
// src/sflLanguage/expansion/expandDocument.ts
|
|
2210
2523
|
function checkNoComputed(blocks) {
|
|
2211
2524
|
for (const block2 of blocks) {
|
|
2212
2525
|
for (const entry of block2.entries) {
|
|
@@ -2224,15 +2537,13 @@ function checkNoComputed(blocks) {
|
|
|
2224
2537
|
}
|
|
2225
2538
|
}
|
|
2226
2539
|
}
|
|
2227
|
-
function
|
|
2228
|
-
const
|
|
2229
|
-
|
|
2230
|
-
);
|
|
2231
|
-
if (!has(doc.blocks)) {
|
|
2540
|
+
function expandDocument(doc) {
|
|
2541
|
+
const repeats = hasRepeats(doc.blocks);
|
|
2542
|
+
if (!repeats && !hasTemplates(doc.blocks)) {
|
|
2232
2543
|
checkNoComputed(doc.blocks);
|
|
2233
2544
|
return doc;
|
|
2234
2545
|
}
|
|
2235
|
-
const expanded = { ...doc, blocks:
|
|
2546
|
+
const expanded = { ...doc, blocks: expandUses(repeats ? expandRepeatBlocks(doc.blocks) : doc.blocks) };
|
|
2236
2547
|
checkNoComputed(expanded.blocks);
|
|
2237
2548
|
return expanded;
|
|
2238
2549
|
}
|
|
@@ -2354,6 +2665,7 @@ var CANVAS_OBJECT_BLOCK_KINDS = [
|
|
|
2354
2665
|
"Entity",
|
|
2355
2666
|
"Shape",
|
|
2356
2667
|
"Text",
|
|
2668
|
+
"Image",
|
|
2357
2669
|
"Container",
|
|
2358
2670
|
"Path",
|
|
2359
2671
|
"Chart",
|
|
@@ -2918,6 +3230,9 @@ function declaredCanvasObjectKind(block2, properties) {
|
|
|
2918
3230
|
if (block2.kind === "Text") {
|
|
2919
3231
|
return "text";
|
|
2920
3232
|
}
|
|
3233
|
+
if (block2.kind === "Image") {
|
|
3234
|
+
return "image";
|
|
3235
|
+
}
|
|
2921
3236
|
if (block2.kind === "Isometric") {
|
|
2922
3237
|
return "isometric";
|
|
2923
3238
|
}
|
|
@@ -2978,13 +3293,14 @@ function readCanvasObjectGeometry(block2, origin, layoutProperty, positionOverri
|
|
|
2978
3293
|
|
|
2979
3294
|
// src/sflSemantic/canvasObjects/processing/presentation.ts
|
|
2980
3295
|
var STRUCTURAL_PROPERTIES = /* @__PURE__ */ new Set(["id", "kind", "text", "shape", "parent", "order", "orientation", "lanes"]);
|
|
3296
|
+
var TUPLE_PROPERTIES = /* @__PURE__ */ new Set(["crop", "imageSize"]);
|
|
2981
3297
|
function readCanvasObjectPresentation(properties) {
|
|
2982
3298
|
const presentation = {};
|
|
2983
3299
|
for (const [key, value] of properties) {
|
|
2984
3300
|
if (STRUCTURAL_PROPERTIES.has(key)) {
|
|
2985
3301
|
continue;
|
|
2986
3302
|
}
|
|
2987
|
-
const text = asString(value);
|
|
3303
|
+
const text = TUPLE_PROPERTIES.has(key) ? tupleValues(value)?.join(",") : asString(value);
|
|
2988
3304
|
if (text !== void 0) {
|
|
2989
3305
|
presentation[key] = text;
|
|
2990
3306
|
}
|
|
@@ -3311,7 +3627,7 @@ function collectBlockDiagnostics(block2, styleBlocks, layoutBlocks, diagnostics)
|
|
|
3311
3627
|
severity: "warning",
|
|
3312
3628
|
code: "unresolved-style-or-layout",
|
|
3313
3629
|
ownerId: block2.name,
|
|
3314
|
-
message: `"${reference}" is not a Style or Layout defined at the top level of the document \
|
|
3630
|
+
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.`
|
|
3315
3631
|
});
|
|
3316
3632
|
}
|
|
3317
3633
|
}
|
|
@@ -3407,7 +3723,7 @@ function collectUnsupportedChartTypes(doc) {
|
|
|
3407
3723
|
severity: "warning",
|
|
3408
3724
|
code: "unsupported-chart-type",
|
|
3409
3725
|
ownerId: block2.name,
|
|
3410
|
-
message: `Unsupported chart type '${declared}' \
|
|
3726
|
+
message: `Unsupported chart type '${declared}' \u2014 drawn as a plain series plot. Supported: ${CHART_TYPES.join(", ")}.`
|
|
3411
3727
|
});
|
|
3412
3728
|
}
|
|
3413
3729
|
}
|
|
@@ -3430,7 +3746,7 @@ function collectEmptySeries(doc) {
|
|
|
3430
3746
|
severity: "warning",
|
|
3431
3747
|
code: "series-without-values",
|
|
3432
3748
|
ownerId: series.name,
|
|
3433
|
-
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 \
|
|
3749
|
+
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.`
|
|
3434
3750
|
});
|
|
3435
3751
|
}
|
|
3436
3752
|
}
|
|
@@ -3456,7 +3772,7 @@ function collectUnsupportedGridShapes(doc) {
|
|
|
3456
3772
|
severity: "warning",
|
|
3457
3773
|
code: "unsupported-grid-shape",
|
|
3458
3774
|
ownerId: block2.name,
|
|
3459
|
-
message: `gridShape: circle isn't supported on '${chartType}' \
|
|
3775
|
+
message: `gridShape: circle isn't supported on '${chartType}' \u2014 drawn with the standard rectangular grid instead. Supported: ${[...OPTIONAL_CIRCULAR_GRID_CHART_TYPES].join(", ")}.`
|
|
3460
3776
|
});
|
|
3461
3777
|
}
|
|
3462
3778
|
}
|
|
@@ -3499,6 +3815,7 @@ function collectUnsupportedComponentTypes(sflDocument) {
|
|
|
3499
3815
|
var OBJECTS = /* @__PURE__ */ new Set([
|
|
3500
3816
|
"Shape",
|
|
3501
3817
|
"Text",
|
|
3818
|
+
"Image",
|
|
3502
3819
|
"Container",
|
|
3503
3820
|
"Chart",
|
|
3504
3821
|
"Path",
|
|
@@ -3586,7 +3903,7 @@ function resolveCanvasState(document) {
|
|
|
3586
3903
|
|
|
3587
3904
|
// src/sflSemantic/sflToCanvasState.ts
|
|
3588
3905
|
function sflToCanvasState(source) {
|
|
3589
|
-
return resolveCanvasState(
|
|
3906
|
+
return resolveCanvasState(expandDocument(parseSource(source)));
|
|
3590
3907
|
}
|
|
3591
3908
|
|
|
3592
3909
|
// src/svg/domContract/version.ts
|
|
@@ -4731,63 +5048,6 @@ function createPieSlicePath(geometry, angles, cornerRadius = 0, gapPx = 0) {
|
|
|
4731
5048
|
return cornerRadius > 0 ? roundedDonutSlicePath(geometry, geometry.innerRadius, outerAngles, innerAngles, cornerRadius) : donutSlicePath(geometry, geometry.innerRadius, outerAngles, innerAngles);
|
|
4732
5049
|
}
|
|
4733
5050
|
|
|
4734
|
-
// src/model/color/conversion.ts
|
|
4735
|
-
var hexToRgb2 = (hex) => {
|
|
4736
|
-
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})?$/i.exec(hex);
|
|
4737
|
-
if (!result) {
|
|
4738
|
-
return { r: 255, g: 255, b: 255, a: 1 };
|
|
4739
|
-
}
|
|
4740
|
-
return {
|
|
4741
|
-
r: parseInt(result[1], 16),
|
|
4742
|
-
g: parseInt(result[2], 16),
|
|
4743
|
-
b: parseInt(result[3], 16),
|
|
4744
|
-
a: result[4] === void 0 ? 1 : parseInt(result[4], 16) / 255
|
|
4745
|
-
};
|
|
4746
|
-
};
|
|
4747
|
-
var rgbToHex2 = (r, g, b, a) => {
|
|
4748
|
-
const channel = (x) => {
|
|
4749
|
-
const hex = Math.max(0, Math.min(255, Math.round(x))).toString(16);
|
|
4750
|
-
return hex.length === 1 ? `0${hex}` : hex;
|
|
4751
|
-
};
|
|
4752
|
-
const alphaChannel = a === void 0 || a >= 1 ? "" : channel(a * 255);
|
|
4753
|
-
return `#${channel(r)}${channel(g)}${channel(b)}${alphaChannel}`;
|
|
4754
|
-
};
|
|
4755
|
-
|
|
4756
|
-
// src/model/color/interpolation.ts
|
|
4757
|
-
function mixHexColors(start, end, ratio) {
|
|
4758
|
-
const startRgb = hexToRgb2(start);
|
|
4759
|
-
const endRgb = hexToRgb2(end);
|
|
4760
|
-
const startAlpha = startRgb.a ?? 1;
|
|
4761
|
-
const endAlpha = endRgb.a ?? 1;
|
|
4762
|
-
return rgbToHex2(
|
|
4763
|
-
Math.round(startRgb.r + (endRgb.r - startRgb.r) * ratio),
|
|
4764
|
-
Math.round(startRgb.g + (endRgb.g - startRgb.g) * ratio),
|
|
4765
|
-
Math.round(startRgb.b + (endRgb.b - startRgb.b) * ratio),
|
|
4766
|
-
startAlpha + (endAlpha - startAlpha) * ratio
|
|
4767
|
-
);
|
|
4768
|
-
}
|
|
4769
|
-
function interpolateHexColorStops(stops, position) {
|
|
4770
|
-
const sortedStops = [...stops].sort((first2, second) => first2.position - second.position);
|
|
4771
|
-
const first = sortedStops[0];
|
|
4772
|
-
const last = sortedStops[sortedStops.length - 1];
|
|
4773
|
-
if (position <= first.position) {
|
|
4774
|
-
return first.color;
|
|
4775
|
-
}
|
|
4776
|
-
if (position >= last.position) {
|
|
4777
|
-
return last.color;
|
|
4778
|
-
}
|
|
4779
|
-
for (let index = 0; index < sortedStops.length - 1; index++) {
|
|
4780
|
-
const start = sortedStops[index];
|
|
4781
|
-
const end = sortedStops[index + 1];
|
|
4782
|
-
if (position >= start.position && position <= end.position) {
|
|
4783
|
-
const range = end.position - start.position;
|
|
4784
|
-
const ratio = range === 0 ? 0 : (position - start.position) / range;
|
|
4785
|
-
return mixHexColors(start.color, end.color, ratio);
|
|
4786
|
-
}
|
|
4787
|
-
}
|
|
4788
|
-
return last.color;
|
|
4789
|
-
}
|
|
4790
|
-
|
|
4791
5051
|
// src/renderScene/charts/primitives/defaults.ts
|
|
4792
5052
|
var CHART_COLORS = ["#7c3aed", "#0ea5e9", "#f97316", "#10b981", "#ec4899", "#eab308"];
|
|
4793
5053
|
var DEFAULT_ZONE_FILL = "#94a3b8";
|
|
@@ -4866,16 +5126,11 @@ function computeBoxplotStats(values) {
|
|
|
4866
5126
|
}
|
|
4867
5127
|
|
|
4868
5128
|
// src/renderScene/color.ts
|
|
4869
|
-
function
|
|
4870
|
-
|
|
4871
|
-
return void 0;
|
|
4872
|
-
}
|
|
4873
|
-
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));
|
|
4874
|
-
const [red, green, blue] = channels;
|
|
4875
|
-
return [red, green, blue].some((channel) => Number.isNaN(channel)) ? void 0 : [red, green, blue];
|
|
5129
|
+
function hexToRgb2(hex) {
|
|
5130
|
+
return hex?.startsWith("#") ? parseHexRgb(hex) ?? void 0 : void 0;
|
|
4876
5131
|
}
|
|
4877
5132
|
function colorWithAlpha(hex, alpha) {
|
|
4878
|
-
const rgb =
|
|
5133
|
+
const rgb = hexToRgb2(hex);
|
|
4879
5134
|
const clamped = Math.max(0, Math.min(1, alpha));
|
|
4880
5135
|
if (!rgb) {
|
|
4881
5136
|
return clamped <= 0 ? "transparent" : hex ?? "transparent";
|
|
@@ -4883,10 +5138,6 @@ function colorWithAlpha(hex, alpha) {
|
|
|
4883
5138
|
const [red, green, blue] = rgb;
|
|
4884
5139
|
return `rgba(${red}, ${green}, ${blue}, ${clamped})`;
|
|
4885
5140
|
}
|
|
4886
|
-
function rgbToHex3(red, green, blue) {
|
|
4887
|
-
const channel = (value) => Math.round(Math.max(0, Math.min(255, value))).toString(16).padStart(2, "0");
|
|
4888
|
-
return `#${channel(red)}${channel(green)}${channel(blue)}`;
|
|
4889
|
-
}
|
|
4890
5141
|
function rgbToHsl(red, green, blue) {
|
|
4891
5142
|
const r = red / 255;
|
|
4892
5143
|
const g = green / 255;
|
|
@@ -4952,7 +5203,7 @@ var SAME_HUE_LIGHT_MIN_LIGHTNESS = 0.78;
|
|
|
4952
5203
|
var SAME_HUE_LIGHT_MAX_LIGHTNESS = 0.92;
|
|
4953
5204
|
var SAME_HUE_MIN_CONTRAST = 3;
|
|
4954
5205
|
function contrastTextColor(hex) {
|
|
4955
|
-
const rgb =
|
|
5206
|
+
const rgb = hexToRgb2(hex);
|
|
4956
5207
|
if (!rgb) {
|
|
4957
5208
|
return "#0f172a";
|
|
4958
5209
|
}
|
|
@@ -4968,10 +5219,10 @@ function contrastTextColor(hex) {
|
|
|
4968
5219
|
);
|
|
4969
5220
|
const variant = hslToRgb(hue, saturation, targetLightness);
|
|
4970
5221
|
const ratio = contrastRatio(relativeLuminance(red, green, blue), relativeLuminance(...variant));
|
|
4971
|
-
return ratio >= SAME_HUE_MIN_CONTRAST ?
|
|
5222
|
+
return ratio >= SAME_HUE_MIN_CONTRAST ? rgbToHex(...variant) : fallback;
|
|
4972
5223
|
}
|
|
4973
5224
|
function sameHueContrastColor(hex, fallback) {
|
|
4974
|
-
const rgb =
|
|
5225
|
+
const rgb = hexToRgb2(hex);
|
|
4975
5226
|
if (!rgb) {
|
|
4976
5227
|
return fallback;
|
|
4977
5228
|
}
|
|
@@ -4984,14 +5235,14 @@ function sameHueContrastColor(hex, fallback) {
|
|
|
4984
5235
|
SAME_HUE_LIGHT_MAX_LIGHTNESS,
|
|
4985
5236
|
Math.max(lightness + SAME_HUE_LIGHTNESS_GAP, SAME_HUE_LIGHT_MIN_LIGHTNESS)
|
|
4986
5237
|
);
|
|
4987
|
-
return
|
|
5238
|
+
return rgbToHex(...hslToRgb(hue, saturation, targetLightness));
|
|
4988
5239
|
}
|
|
4989
5240
|
function isLightColor(hex) {
|
|
4990
|
-
const rgb =
|
|
5241
|
+
const rgb = hexToRgb2(hex);
|
|
4991
5242
|
return rgb ? rgbToHsl(...rgb)[2] > 0.5 : false;
|
|
4992
5243
|
}
|
|
4993
5244
|
function sameHueTint(hex, targetLightness) {
|
|
4994
|
-
const rgb =
|
|
5245
|
+
const rgb = hexToRgb2(hex);
|
|
4995
5246
|
if (!rgb) {
|
|
4996
5247
|
return void 0;
|
|
4997
5248
|
}
|
|
@@ -4999,7 +5250,7 @@ function sameHueTint(hex, targetLightness) {
|
|
|
4999
5250
|
if (saturation === 0) {
|
|
5000
5251
|
return void 0;
|
|
5001
5252
|
}
|
|
5002
|
-
return
|
|
5253
|
+
return rgbToHex(...hslToRgb(hue, saturation, targetLightness));
|
|
5003
5254
|
}
|
|
5004
5255
|
|
|
5005
5256
|
// src/renderScene/charts/primitives/colors.ts
|
|
@@ -5783,6 +6034,6 @@ function localShapePath(type, x, y, width, height) {
|
|
|
5783
6034
|
}
|
|
5784
6035
|
}
|
|
5785
6036
|
|
|
5786
|
-
export { AXIS_COS, AXIS_SIN, BAR_LABEL, CATEGORY_LABEL_ROW, CHART_COLORS, CHART_TITLE_PROP, CHART_TYPES, COMPONENT_CATEGORIES, CORNER_RADIUS_ATTR, DEFAULT_FONT, DEFAULT_HEATMAP_ZONES, DEFAULT_HEX_RADIUS, DEFAULT_ROLLING_NUMBER_STYLE, DEFAULT_ZONE_FILL, DOM_CONTRACT_VERSION, EMPTY_BOUNDS, ISOMETRIC_LABEL_OFFSET_ATTR, ISOMETRIC_SIZE_ATTR, LABEL_WIDTH, LEADER_INSET, PATH_CLOSED_ATTR, PATH_POINTS_ATTR, PATH_POINT_INDEX_ATTR, PATH_TENSION_ATTR, SQUARE_CORNER_ATTR, SYMBOL_BOUNDS_ATTR, SYMBOL_POINTS_ATTR, SYMBOL_TENSION_ATTR, VISIBLE_ISOMETRIC_FACES, angleForAxisValue, axisBands, axisLabelProp, barCategoryCount, barLabelSize, barPath, barShapePath, bottomRoundedRectPath, boxBounds, calculateLinkRoute, canonicalizeSource, categoryProp, chartText, chartTicks, cleanFootprint, clipSegmentToRect, colorWithAlpha, componentRegistryVersion, componentTypes, computeBoxplotStats, contrastTextColor, cornersRoundedRectPath, createPieGeometry, createPieSlicePath, createVerticalErrorWhiskerNode, deriveFaceFills, edgePointToward, elementCenter, ellipsizeToWidth, errorBarRange, estimateTextWidth,
|
|
5787
|
-
//# sourceMappingURL=chunk-
|
|
5788
|
-
//# sourceMappingURL=chunk-
|
|
6037
|
+
export { AXIS_COS, AXIS_SIN, BAR_LABEL, CATEGORY_LABEL_ROW, CHART_COLORS, CHART_TITLE_PROP, CHART_TYPES, COMPONENT_CATEGORIES, CORNER_RADIUS_ATTR, DEFAULT_FONT, DEFAULT_HEATMAP_ZONES, DEFAULT_HEX_RADIUS, DEFAULT_ROLLING_NUMBER_STYLE, DEFAULT_ZONE_FILL, DOM_CONTRACT_VERSION, EMPTY_BOUNDS, ISOMETRIC_LABEL_OFFSET_ATTR, ISOMETRIC_SIZE_ATTR, LABEL_WIDTH, LEADER_INSET, PATH_CLOSED_ATTR, PATH_POINTS_ATTR, PATH_POINT_INDEX_ATTR, PATH_TENSION_ATTR, SQUARE_CORNER_ATTR, SYMBOL_BOUNDS_ATTR, SYMBOL_POINTS_ATTR, SYMBOL_TENSION_ATTR, VISIBLE_ISOMETRIC_FACES, angleForAxisValue, axisBands, axisLabelProp, barCategoryCount, barLabelSize, barPath, barShapePath, bottomRoundedRectPath, boxBounds, calculateLinkRoute, canonicalizeSource, categoryProp, chartText, chartTicks, cleanFootprint, clipSegmentToRect, colorWithAlpha, componentRegistryVersion, componentTypes, computeBoxplotStats, contrastTextColor, cornersRoundedRectPath, createPieGeometry, createPieSlicePath, createVerticalErrorWhiskerNode, deriveFaceFills, edgePointToward, elementCenter, ellipsizeToWidth, errorBarRange, estimateTextWidth, expandDocument, extrudeFootprint, finite, flattenPath, formatBarLabel, formatFieldValue, formatRollingNumber, freeformPathData, gapInsetAngle, getComponentDescriptor, getLineMidpoint, heuristicRichMeasure, horizontalRows, hsvToRgb, interpolateHexColorStops, isBuiltInComponentType, isChartObject, isDimensionObject, isGenericComponent, isHorizontalBar, isIsometricObject, isLightColor, isPathObject, isSwimlaneObject, isometricBounds, isometricFaceCenter, isometricFaces, isometricTopFaceCenter, labelAboveFrame, labelBelowFrame, labelGapDash, labelTilt, leftRoundedRectPath, linePathData, localShapePath, mapChartValue, maxApexCornerRadius, maxPieCornerRadius, paint, parseHexRgb, parseSource, pathBounds, pathToSymbol, personLabelArea, pieApexRadius, pieArcPoint, pieUsesInnerArc, pillCornerRadius, pillPath, pointAtNormalizedPort, pointAtPort, radarCategoryCount, radarPointAt, radarRadius, radarRadiusForValue, radarSeriesPath, radarValueAtPoint, radarVertexPoint, registerComponentDescriptor, relativeOffsetOnRectangleSide, renderPieLabels, representativeColor, resolveChartShadow, resolvePieRadii, resolveRollingNumberStyle, rgbToHex, rgbToHsv, rightRoundedRectPath, rotatedBounds, roundedBarPath, roundedOrthogonalPathData, roundedPolygonPath, rowTop, ruleAtProp, ruleTextProp, sameHueContrastColor, sameHueTint, segmentedBarPath, seriesColorProp, seriesLabelOffsetXProp, seriesLabelOffsetYProp, seriesLabelProp, seriesValueColorProp, seriesValueProp, sflToCanvasState, shadeFill, stackRank, stackSequence, stackedSegment, symbolToPath, tag, tiltedLabelRoom, tokenizeSource, topRoundedRectPath, wrapText, zoneColorAtValue };
|
|
6038
|
+
//# sourceMappingURL=chunk-G6IW2IX3.js.map
|
|
6039
|
+
//# sourceMappingURL=chunk-G6IW2IX3.js.map
|