@lumiastream/ui 0.5.3 → 0.5.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/LSButton.js +1 -1
- package/dist/LSCheckbox.js +1 -1
- package/dist/LSColorPicker.js +18 -31
- package/dist/LSDatePicker.js +18 -31
- package/dist/LSFontPicker.js +11 -20
- package/dist/LSInput.d.ts +0 -4
- package/dist/LSInput.js +18 -31
- package/dist/LSMultiSelect.js +21 -39
- package/dist/LSRadio.js +1 -1
- package/dist/LSSelect.js +11 -23
- package/dist/LSSliderInput.js +27 -40
- package/dist/LSTextField.d.ts +4 -5
- package/dist/LSTextField.js +5 -13
- package/dist/LSVariableInputField.js +47 -74
- package/dist/components.d.ts +1 -0
- package/dist/components.js +86 -140
- package/dist/index.d.ts +2 -1
- package/dist/index.js +938 -598
- package/dist/se-import.d.ts +9 -3
- package/dist/se-import.js +927 -581
- package/package.json +1 -1
package/dist/se-import.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/se-import/index.ts
|
|
2
|
-
import { nanoid as
|
|
2
|
+
import { nanoid as nanoid8 } from "nanoid";
|
|
3
3
|
|
|
4
4
|
// src/se-import/translate.ts
|
|
5
5
|
var SE_TO_LUMIA_PLACEHOLDER = {
|
|
@@ -1050,26 +1050,55 @@ function mapText(widget, ctx) {
|
|
|
1050
1050
|
ctx
|
|
1051
1051
|
);
|
|
1052
1052
|
}
|
|
1053
|
+
function seInnerAutoFit(widget, innerCss, mode) {
|
|
1054
|
+
const isInnerAutoWidth = innerCss?.width === "auto";
|
|
1055
|
+
const isInnerAutoHeight = innerCss?.height === "auto";
|
|
1056
|
+
if (mode === "width-drives-both") {
|
|
1057
|
+
if (!isInnerAutoWidth) return {};
|
|
1058
|
+
return { objectFit: "contain", autoWidth: true, autoHeight: true };
|
|
1059
|
+
}
|
|
1060
|
+
if (!isInnerAutoWidth && !isInnerAutoHeight) return {};
|
|
1061
|
+
const result = { objectFit: "contain" };
|
|
1062
|
+
if (isInnerAutoWidth && !isExplicitPxSize(widget.css?.width))
|
|
1063
|
+
result.autoWidth = true;
|
|
1064
|
+
if (isInnerAutoHeight && !isExplicitPxSize(widget.css?.height))
|
|
1065
|
+
result.autoHeight = true;
|
|
1066
|
+
return result;
|
|
1067
|
+
}
|
|
1068
|
+
function applySeAutoFitBounds(unit, fit) {
|
|
1069
|
+
const bounds = unit.layer.bounds;
|
|
1070
|
+
if (fit.autoWidth) bounds.autoWidth = true;
|
|
1071
|
+
if (fit.autoHeight) bounds.autoHeight = true;
|
|
1072
|
+
}
|
|
1053
1073
|
function mapImage(widget, ctx) {
|
|
1074
|
+
const fit = seInnerAutoFit(widget, widget.image?.css, "inner-axis-gated");
|
|
1054
1075
|
const unit = buildUnit(
|
|
1055
1076
|
widget,
|
|
1056
1077
|
"image",
|
|
1057
1078
|
{
|
|
1058
1079
|
content: {
|
|
1059
1080
|
src: widget.image?.src ?? "",
|
|
1060
|
-
loop: true
|
|
1081
|
+
loop: true,
|
|
1082
|
+
...fit.objectFit ? { objectFit: fit.objectFit } : {}
|
|
1061
1083
|
}
|
|
1062
1084
|
},
|
|
1063
1085
|
ctx
|
|
1064
1086
|
);
|
|
1065
|
-
|
|
1066
|
-
const innerHeight = widget.image?.css?.height;
|
|
1067
|
-
const bounds = unit.layer.bounds;
|
|
1068
|
-
if (innerWidth === "auto") bounds.autoWidth = true;
|
|
1069
|
-
if (innerHeight === "auto") bounds.autoHeight = true;
|
|
1087
|
+
applySeAutoFitBounds(unit, fit);
|
|
1070
1088
|
return unit;
|
|
1071
1089
|
}
|
|
1090
|
+
function isExplicitPxSize(value) {
|
|
1091
|
+
if (value == null) return false;
|
|
1092
|
+
if (typeof value === "number") return Number.isFinite(value) && value > 0;
|
|
1093
|
+
if (typeof value !== "string") return false;
|
|
1094
|
+
const s = value.trim().toLowerCase();
|
|
1095
|
+
if (s === "" || s === "auto") return false;
|
|
1096
|
+
if (s.endsWith("%")) return false;
|
|
1097
|
+
const parsed = parseFloat(s);
|
|
1098
|
+
return Number.isFinite(parsed) && parsed > 0;
|
|
1099
|
+
}
|
|
1072
1100
|
function mapVideo(widget, ctx) {
|
|
1101
|
+
const fit = seInnerAutoFit(widget, widget.video?.css, "width-drives-both");
|
|
1073
1102
|
const unit = buildUnit(
|
|
1074
1103
|
widget,
|
|
1075
1104
|
"video",
|
|
@@ -1083,6 +1112,7 @@ function mapVideo(widget, ctx) {
|
|
|
1083
1112
|
},
|
|
1084
1113
|
ctx
|
|
1085
1114
|
);
|
|
1115
|
+
applySeAutoFitBounds(unit, fit);
|
|
1086
1116
|
unit.layer.bounds.autoHeight = true;
|
|
1087
1117
|
return unit;
|
|
1088
1118
|
}
|
|
@@ -1142,118 +1172,157 @@ function mapReadout(widget, fallbackVar, ctx) {
|
|
|
1142
1172
|
|
|
1143
1173
|
// src/se-import/mappers/alert.ts
|
|
1144
1174
|
import { LumiaAlertConfigs } from "@lumiastream/lumia-types";
|
|
1175
|
+
import { nanoid as nanoid2 } from "nanoid";
|
|
1176
|
+
|
|
1177
|
+
// src/se-import/import-utils.ts
|
|
1178
|
+
function pxToNumber(raw, fallback) {
|
|
1179
|
+
if (typeof raw === "number" && Number.isFinite(raw)) return raw;
|
|
1180
|
+
if (typeof raw !== "string") return fallback;
|
|
1181
|
+
const trimmed = raw.trim();
|
|
1182
|
+
if (!trimmed) return fallback;
|
|
1183
|
+
if (trimmed.endsWith("px")) {
|
|
1184
|
+
const n2 = parseFloat(trimmed.slice(0, -2));
|
|
1185
|
+
return Number.isFinite(n2) ? n2 : fallback;
|
|
1186
|
+
}
|
|
1187
|
+
const n = parseFloat(trimmed);
|
|
1188
|
+
return Number.isFinite(n) ? n : fallback;
|
|
1189
|
+
}
|
|
1190
|
+
function parseDurationMs(raw, fallbackMs) {
|
|
1191
|
+
if (typeof raw === "number" && Number.isFinite(raw)) return raw;
|
|
1192
|
+
if (typeof raw !== "string") return fallbackMs;
|
|
1193
|
+
const trimmed = raw.trim();
|
|
1194
|
+
if (!trimmed) return fallbackMs;
|
|
1195
|
+
if (trimmed.endsWith("ms")) {
|
|
1196
|
+
const n2 = parseFloat(trimmed.slice(0, -2));
|
|
1197
|
+
return Number.isFinite(n2) ? n2 : fallbackMs;
|
|
1198
|
+
}
|
|
1199
|
+
if (trimmed.endsWith("s")) {
|
|
1200
|
+
const n2 = parseFloat(trimmed.slice(0, -1));
|
|
1201
|
+
return Number.isFinite(n2) ? n2 * 1e3 : fallbackMs;
|
|
1202
|
+
}
|
|
1203
|
+
const n = parseFloat(trimmed);
|
|
1204
|
+
return Number.isFinite(n) ? n : fallbackMs;
|
|
1205
|
+
}
|
|
1206
|
+
function buildImportDescription(head, sourceUrl) {
|
|
1207
|
+
if (typeof sourceUrl === "string" && sourceUrl.trim().length > 0) {
|
|
1208
|
+
return `${head}
|
|
1209
|
+
Source: ${sourceUrl.trim()}`;
|
|
1210
|
+
}
|
|
1211
|
+
return head;
|
|
1212
|
+
}
|
|
1145
1213
|
|
|
1146
1214
|
// src/se-import/mappers/provider-alerts.ts
|
|
1215
|
+
import { LumiaAlertValues } from "@lumiastream/lumia-types";
|
|
1147
1216
|
var ALERT_BOX_KEYS = {
|
|
1148
1217
|
twitch: {
|
|
1149
|
-
follower: [
|
|
1150
|
-
subscriber: [
|
|
1151
|
-
tip: [
|
|
1152
|
-
cheer: [
|
|
1153
|
-
raid: [
|
|
1154
|
-
merch: [
|
|
1155
|
-
purchase: [
|
|
1156
|
-
charityCampaignDonation: [
|
|
1218
|
+
follower: [LumiaAlertValues.TWITCH_FOLLOWER],
|
|
1219
|
+
subscriber: [LumiaAlertValues.TWITCH_SUBSCRIBER],
|
|
1220
|
+
tip: [LumiaAlertValues.LUMIASTREAM_DONATION, LumiaAlertValues.STREAMELEMENTS_DONATION],
|
|
1221
|
+
cheer: [LumiaAlertValues.TWITCH_BITS],
|
|
1222
|
+
raid: [LumiaAlertValues.TWITCH_RAID],
|
|
1223
|
+
merch: [LumiaAlertValues.FOURTHWALL_SHOPORDER],
|
|
1224
|
+
purchase: [LumiaAlertValues.FOURTHWALL_SHOPORDER],
|
|
1225
|
+
charityCampaignDonation: [LumiaAlertValues.TWITCH_CHARITY_DONATION]
|
|
1157
1226
|
},
|
|
1158
1227
|
kick: {
|
|
1159
|
-
follower: [
|
|
1160
|
-
subscriber: [
|
|
1161
|
-
tip: [
|
|
1162
|
-
cheer: [
|
|
1163
|
-
raid: [
|
|
1164
|
-
host: [
|
|
1165
|
-
merch: [
|
|
1166
|
-
purchase: [
|
|
1228
|
+
follower: [LumiaAlertValues.KICK_FOLLOWER],
|
|
1229
|
+
subscriber: [LumiaAlertValues.KICK_SUBSCRIBER],
|
|
1230
|
+
tip: [LumiaAlertValues.LUMIASTREAM_DONATION, LumiaAlertValues.STREAMELEMENTS_DONATION],
|
|
1231
|
+
cheer: [LumiaAlertValues.KICK_KICKS],
|
|
1232
|
+
raid: [LumiaAlertValues.KICK_HOST],
|
|
1233
|
+
host: [LumiaAlertValues.KICK_HOST],
|
|
1234
|
+
merch: [LumiaAlertValues.FOURTHWALL_SHOPORDER],
|
|
1235
|
+
purchase: [LumiaAlertValues.FOURTHWALL_SHOPORDER]
|
|
1167
1236
|
},
|
|
1168
1237
|
youtube: {
|
|
1169
|
-
follower: [
|
|
1170
|
-
subscriber: [
|
|
1171
|
-
tip: [
|
|
1172
|
-
cheer: [
|
|
1173
|
-
merch: [
|
|
1174
|
-
purchase: [
|
|
1238
|
+
follower: [LumiaAlertValues.YOUTUBE_SUBSCRIBER],
|
|
1239
|
+
subscriber: [LumiaAlertValues.YOUTUBE_MEMBER],
|
|
1240
|
+
tip: [LumiaAlertValues.LUMIASTREAM_DONATION, LumiaAlertValues.STREAMELEMENTS_DONATION],
|
|
1241
|
+
cheer: [LumiaAlertValues.YOUTUBE_SUPERCHAT],
|
|
1242
|
+
merch: [LumiaAlertValues.FOURTHWALL_SHOPORDER],
|
|
1243
|
+
purchase: [LumiaAlertValues.FOURTHWALL_SHOPORDER]
|
|
1175
1244
|
}
|
|
1176
1245
|
};
|
|
1177
1246
|
var KAPPAGEN_KEYS = {
|
|
1178
1247
|
twitch: {
|
|
1179
|
-
follower:
|
|
1180
|
-
subscriber:
|
|
1181
|
-
cheer:
|
|
1182
|
-
raid:
|
|
1183
|
-
tip:
|
|
1248
|
+
follower: LumiaAlertValues.TWITCH_FOLLOWER,
|
|
1249
|
+
subscriber: LumiaAlertValues.TWITCH_SUBSCRIBER,
|
|
1250
|
+
cheer: LumiaAlertValues.TWITCH_BITS,
|
|
1251
|
+
raid: LumiaAlertValues.TWITCH_RAID,
|
|
1252
|
+
tip: LumiaAlertValues.LUMIASTREAM_DONATION
|
|
1184
1253
|
},
|
|
1185
1254
|
kick: {
|
|
1186
|
-
follower:
|
|
1187
|
-
subscriber:
|
|
1188
|
-
cheer:
|
|
1189
|
-
raid:
|
|
1190
|
-
tip:
|
|
1255
|
+
follower: LumiaAlertValues.KICK_FOLLOWER,
|
|
1256
|
+
subscriber: LumiaAlertValues.KICK_SUBSCRIBER,
|
|
1257
|
+
cheer: LumiaAlertValues.KICK_KICKS,
|
|
1258
|
+
raid: LumiaAlertValues.KICK_HOST,
|
|
1259
|
+
tip: LumiaAlertValues.LUMIASTREAM_DONATION
|
|
1191
1260
|
},
|
|
1192
1261
|
youtube: {
|
|
1193
|
-
follower:
|
|
1194
|
-
subscriber:
|
|
1195
|
-
cheer:
|
|
1196
|
-
tip:
|
|
1262
|
+
follower: LumiaAlertValues.YOUTUBE_SUBSCRIBER,
|
|
1263
|
+
subscriber: LumiaAlertValues.YOUTUBE_MEMBER,
|
|
1264
|
+
cheer: LumiaAlertValues.YOUTUBE_SUPERCHAT,
|
|
1265
|
+
tip: LumiaAlertValues.LUMIASTREAM_DONATION
|
|
1197
1266
|
}
|
|
1198
1267
|
};
|
|
1199
1268
|
var STREAMBOSS_LISTENER_KEYS = {
|
|
1200
1269
|
twitch: {
|
|
1201
|
-
"follower-latest": [
|
|
1202
|
-
"subscriber-latest": [
|
|
1203
|
-
"tip-latest": [
|
|
1204
|
-
"cheer-latest": [
|
|
1205
|
-
"raid-latest": [
|
|
1270
|
+
"follower-latest": [LumiaAlertValues.TWITCH_FOLLOWER],
|
|
1271
|
+
"subscriber-latest": [LumiaAlertValues.TWITCH_SUBSCRIBER],
|
|
1272
|
+
"tip-latest": [LumiaAlertValues.LUMIASTREAM_DONATION, LumiaAlertValues.STREAMELEMENTS_DONATION],
|
|
1273
|
+
"cheer-latest": [LumiaAlertValues.TWITCH_BITS],
|
|
1274
|
+
"raid-latest": [LumiaAlertValues.TWITCH_RAID]
|
|
1206
1275
|
},
|
|
1207
1276
|
kick: {
|
|
1208
|
-
"follower-latest": [
|
|
1209
|
-
"subscriber-latest": [
|
|
1210
|
-
"tip-latest": [
|
|
1211
|
-
"cheer-latest": [
|
|
1212
|
-
"raid-latest": [
|
|
1277
|
+
"follower-latest": [LumiaAlertValues.KICK_FOLLOWER],
|
|
1278
|
+
"subscriber-latest": [LumiaAlertValues.KICK_SUBSCRIBER],
|
|
1279
|
+
"tip-latest": [LumiaAlertValues.LUMIASTREAM_DONATION, LumiaAlertValues.STREAMELEMENTS_DONATION],
|
|
1280
|
+
"cheer-latest": [LumiaAlertValues.KICK_KICKS],
|
|
1281
|
+
"raid-latest": [LumiaAlertValues.KICK_HOST]
|
|
1213
1282
|
},
|
|
1214
1283
|
youtube: {
|
|
1215
|
-
"follower-latest": [
|
|
1216
|
-
"subscriber-latest": [
|
|
1217
|
-
"tip-latest": [
|
|
1218
|
-
"cheer-latest": [
|
|
1284
|
+
"follower-latest": [LumiaAlertValues.YOUTUBE_SUBSCRIBER],
|
|
1285
|
+
"subscriber-latest": [LumiaAlertValues.YOUTUBE_MEMBER],
|
|
1286
|
+
"tip-latest": [LumiaAlertValues.LUMIASTREAM_DONATION, LumiaAlertValues.STREAMELEMENTS_DONATION],
|
|
1287
|
+
"cheer-latest": [LumiaAlertValues.YOUTUBE_SUPERCHAT]
|
|
1219
1288
|
}
|
|
1220
1289
|
};
|
|
1221
1290
|
var CURATED_ALERTS = {
|
|
1222
1291
|
twitch: [
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1292
|
+
LumiaAlertValues.TWITCH_FOLLOWER,
|
|
1293
|
+
LumiaAlertValues.TWITCH_SUBSCRIBER,
|
|
1294
|
+
LumiaAlertValues.TWITCH_GIFT_SUBSCRIPTION,
|
|
1295
|
+
LumiaAlertValues.TWITCH_BITS,
|
|
1296
|
+
LumiaAlertValues.TWITCH_BITS_COMBO,
|
|
1297
|
+
LumiaAlertValues.TWITCH_RAID,
|
|
1298
|
+
LumiaAlertValues.TWITCH_POINTS,
|
|
1299
|
+
LumiaAlertValues.TWITCH_REDEMPTION,
|
|
1300
|
+
LumiaAlertValues.TWITCH_CHARITY_DONATION,
|
|
1301
|
+
LumiaAlertValues.TWITCH_HYPETRAIN_STARTED,
|
|
1302
|
+
LumiaAlertValues.TWITCH_CLIP,
|
|
1303
|
+
LumiaAlertValues.TWITCH_SHOUTOUT_RECEIVE,
|
|
1304
|
+
LumiaAlertValues.TWITCH_WATCH_STREAK,
|
|
1305
|
+
LumiaAlertValues.TWITCH_FIRST_CHATTER,
|
|
1306
|
+
LumiaAlertValues.TWITCH_EXTENSION
|
|
1238
1307
|
],
|
|
1239
1308
|
kick: [
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1309
|
+
LumiaAlertValues.KICK_FOLLOWER,
|
|
1310
|
+
LumiaAlertValues.KICK_SUBSCRIBER,
|
|
1311
|
+
LumiaAlertValues.KICK_GIFT_SUBSCRIPTION,
|
|
1312
|
+
LumiaAlertValues.KICK_KICKS,
|
|
1313
|
+
LumiaAlertValues.KICK_HOST,
|
|
1314
|
+
LumiaAlertValues.KICK_POINTS,
|
|
1315
|
+
LumiaAlertValues.KICK_FIRST_CHATTER
|
|
1247
1316
|
],
|
|
1248
1317
|
youtube: [
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1318
|
+
LumiaAlertValues.YOUTUBE_SUBSCRIBER,
|
|
1319
|
+
LumiaAlertValues.YOUTUBE_MEMBER,
|
|
1320
|
+
LumiaAlertValues.YOUTUBE_GIFT_MEMBERS,
|
|
1321
|
+
LumiaAlertValues.YOUTUBE_SUPERCHAT,
|
|
1322
|
+
LumiaAlertValues.YOUTUBE_SUPERSTICKER,
|
|
1323
|
+
LumiaAlertValues.YOUTUBE_GIFTS,
|
|
1324
|
+
LumiaAlertValues.YOUTUBE_LIKE,
|
|
1325
|
+
LumiaAlertValues.YOUTUBE_FIRST_CHATTER
|
|
1257
1326
|
]
|
|
1258
1327
|
};
|
|
1259
1328
|
function curatedAlertsFor(provider = "twitch") {
|
|
@@ -1321,8 +1390,12 @@ function buildAlertEvent(seEvent, seEventType) {
|
|
|
1321
1390
|
const shadowEnabled = text.enableShadow !== false;
|
|
1322
1391
|
const importedTextShadow = css["text-shadow"] ?? "rgba(0, 0, 0, 0.8) 1px 1px 1px";
|
|
1323
1392
|
const textShadow = shadowEnabled ? importedTextShadow : "none";
|
|
1324
|
-
const
|
|
1325
|
-
const pushTextUp =
|
|
1393
|
+
const allowPush = seLayoutUsesPushText(seEvent.layout);
|
|
1394
|
+
const pushTextUp = allowPush ? pxToNumber(css["margin-top"], 0) : 0;
|
|
1395
|
+
const pushTextLeft = allowPush ? pxToNumber(css["margin-left"], 0) : 0;
|
|
1396
|
+
const usesColumnLayout = !seEvent.layout || seEvent.layout === "column";
|
|
1397
|
+
const usesRowLayout = seEvent.layout === "row";
|
|
1398
|
+
const tightLayout = allowPush && (usesColumnLayout || usesRowLayout);
|
|
1326
1399
|
const variations = (seEvent.variations ?? []).map((variation) => buildAlertVariation(variation, seEventType, seEvent)).filter((v) => v != null);
|
|
1327
1400
|
const defaultDuration = (seEventType && SE_DEFAULT_DURATION_BY_EVENT[seEventType]) ?? 8;
|
|
1328
1401
|
return {
|
|
@@ -1349,7 +1422,7 @@ function buildAlertEvent(seEvent, seEventType) {
|
|
|
1349
1422
|
showBrandIcon: true
|
|
1350
1423
|
},
|
|
1351
1424
|
settings: { duration: (seEvent.duration ?? defaultDuration) * 1e3 },
|
|
1352
|
-
layout: { value: translateLayout(seEvent.layout), css: {}, customCss: "", pushTextUp, pushTextLeft:
|
|
1425
|
+
layout: { value: translateLayout(seEvent.layout), css: {}, customCss: "", pushTextUp, pushTextLeft, tight: tightLayout },
|
|
1353
1426
|
text: {
|
|
1354
1427
|
css: {
|
|
1355
1428
|
fontFamily: css["font-family"] ?? "Roboto",
|
|
@@ -1358,6 +1431,10 @@ function buildAlertEvent(seEvent, seEventType) {
|
|
|
1358
1431
|
fontWeight: css["font-weight"] ?? "bold",
|
|
1359
1432
|
textShadow,
|
|
1360
1433
|
textAlign: css["text-align"] ?? "center"
|
|
1434
|
+
// SE's per-event `margin-top` / `margin-left` are routed to
|
|
1435
|
+
// `layout.pushTextUp` / `layout.pushTextLeft` above (not
|
|
1436
|
+
// stamped on `text.css`) so they land in the alert editor's
|
|
1437
|
+
// dedicated sliders. See the long comment near `pushTextUp`.
|
|
1361
1438
|
},
|
|
1362
1439
|
messageCss,
|
|
1363
1440
|
content: { value: translateSeText(text.message ?? "") }
|
|
@@ -1427,6 +1504,15 @@ function buildAlertVariation(v, seEventType, parentSettings) {
|
|
|
1427
1504
|
const mergedSettings = deepMergeSeSettings(parentSettings ? parentInheritable : void 0, v.settings);
|
|
1428
1505
|
const base = buildAlertEvent(mergedSettings, seEventType);
|
|
1429
1506
|
return {
|
|
1507
|
+
// Stable per-variation ID. Lumia's alert editor (Settings.tsx) auto-
|
|
1508
|
+
// stamps a nanoid on first open for any variation missing an id, but
|
|
1509
|
+
// that leaves a window where the imported overlay's variations have
|
|
1510
|
+
// no stable key — list components rendering them key on
|
|
1511
|
+
// `variation.id || variation.name || idx` and adjacent variations
|
|
1512
|
+
// with the same name collide. Stamping at import time gives every
|
|
1513
|
+
// variation a stable identity from save #1 without waiting for the
|
|
1514
|
+
// editor's first mount.
|
|
1515
|
+
id: nanoid2(),
|
|
1430
1516
|
name: v.name ?? "Variation",
|
|
1431
1517
|
on: v.enabled !== false,
|
|
1432
1518
|
randomChance: v.chance ?? 100,
|
|
@@ -1510,7 +1596,7 @@ function mapSingleAlert(widget, lumiaAlertKey, ctx) {
|
|
|
1510
1596
|
css: { ...topCss, ...innerCss }
|
|
1511
1597
|
};
|
|
1512
1598
|
}
|
|
1513
|
-
const built = buildAlertEvent(merged);
|
|
1599
|
+
const built = buildAlertEvent(merged, void 0);
|
|
1514
1600
|
const events = {
|
|
1515
1601
|
[lumiaAlertKey]: built
|
|
1516
1602
|
};
|
|
@@ -1656,7 +1742,7 @@ function mapGoal(widget, ctx) {
|
|
|
1656
1742
|
}
|
|
1657
1743
|
|
|
1658
1744
|
// src/se-import/mappers/custom.ts
|
|
1659
|
-
import { nanoid as
|
|
1745
|
+
import { nanoid as nanoid3 } from "nanoid";
|
|
1660
1746
|
var SOURCE_TO_LUMIA_FIELD_TYPE = {
|
|
1661
1747
|
text: "input",
|
|
1662
1748
|
number: "number",
|
|
@@ -1746,7 +1832,7 @@ function mapCustom(widget, ctx) {
|
|
|
1746
1832
|
// imports — codeId is the scoping key for variables, storage, and
|
|
1747
1833
|
// event listeners. Mint a fresh nanoid so every imported widget
|
|
1748
1834
|
// has its own scope.
|
|
1749
|
-
codeId:
|
|
1835
|
+
codeId: nanoid3(),
|
|
1750
1836
|
html: v.html ?? "",
|
|
1751
1837
|
css: v.css ?? "",
|
|
1752
1838
|
js: v.js ?? "",
|
|
@@ -1883,6 +1969,63 @@ var TIPJAR_DEFAULT_MODULE = {
|
|
|
1883
1969
|
version: 1,
|
|
1884
1970
|
content: TIPJAR_DEFAULT_CONTENT_FIELDS
|
|
1885
1971
|
};
|
|
1972
|
+
var EVENTLIST_DEFAULT_CONTENT_FIELDS = {
|
|
1973
|
+
version: 2,
|
|
1974
|
+
eventListType: {},
|
|
1975
|
+
theme: "basic",
|
|
1976
|
+
themeConfig: {},
|
|
1977
|
+
borderRadius: "10px",
|
|
1978
|
+
condensedText: true,
|
|
1979
|
+
src: "",
|
|
1980
|
+
// Category blacklist — events whose Lumia type appears here are
|
|
1981
|
+
// hidden. SL `show_<type>: false` maps to inserting the equivalent
|
|
1982
|
+
// Lumia category here.
|
|
1983
|
+
filters: [],
|
|
1984
|
+
sites: [],
|
|
1985
|
+
maxItemsToShow: 20,
|
|
1986
|
+
removeAfter: 0,
|
|
1987
|
+
reverse: false,
|
|
1988
|
+
horizontal: false,
|
|
1989
|
+
animations: {
|
|
1990
|
+
enterAnimation: "fadeIn",
|
|
1991
|
+
exitAnimation: "fadeOut",
|
|
1992
|
+
enterAnimationDuration: 1e3,
|
|
1993
|
+
exitAnimationDuration: 1e3,
|
|
1994
|
+
enterAnimationDelay: 0,
|
|
1995
|
+
exitAnimationDelay: 0
|
|
1996
|
+
},
|
|
1997
|
+
showDetailedText: true,
|
|
1998
|
+
hideAlertMessage: false,
|
|
1999
|
+
showAlertIcon: true,
|
|
2000
|
+
showSiteIcon: false,
|
|
2001
|
+
showUserAvatar: false,
|
|
2002
|
+
fadeOutAfterDelay: false,
|
|
2003
|
+
fadeOutDelayTime: 5,
|
|
2004
|
+
image: "",
|
|
2005
|
+
itemGap: 16,
|
|
2006
|
+
audio: {
|
|
2007
|
+
enter: "",
|
|
2008
|
+
volume: 1
|
|
2009
|
+
}
|
|
2010
|
+
};
|
|
2011
|
+
var EVENTLIST_DEFAULT_MODULE = {
|
|
2012
|
+
version: 2,
|
|
2013
|
+
content: EVENTLIST_DEFAULT_CONTENT_FIELDS,
|
|
2014
|
+
css: {
|
|
2015
|
+
borderRadius: "0px",
|
|
2016
|
+
borderStyle: "solid",
|
|
2017
|
+
borderWidth: "0px",
|
|
2018
|
+
borderColor: "transparent",
|
|
2019
|
+
fontSize: 16,
|
|
2020
|
+
lineHeight: 1.2,
|
|
2021
|
+
textAlign: "left",
|
|
2022
|
+
fontFamily: "Roboto",
|
|
2023
|
+
fontWeight: "normal",
|
|
2024
|
+
color: "#ffffff",
|
|
2025
|
+
textShadow: "",
|
|
2026
|
+
background: "transparent"
|
|
2027
|
+
}
|
|
2028
|
+
};
|
|
1886
2029
|
|
|
1887
2030
|
// src/se-import/mappers/misc.ts
|
|
1888
2031
|
function mapChatboxTheme(seTheme) {
|
|
@@ -2169,7 +2312,11 @@ function mapEventList(widget, ctx) {
|
|
|
2169
2312
|
...isMarquee ? { marqueeItemGap: 24 } : {},
|
|
2170
2313
|
showAlertIcon: !isMarquee,
|
|
2171
2314
|
showSiteIcon: !isMarquee,
|
|
2172
|
-
|
|
2315
|
+
// SE event lists are text-only (`{name}: {amount}` rows for tip-recent,
|
|
2316
|
+
// follower-recent, etc.) — no avatar column. Mirror that on import so
|
|
2317
|
+
// the streamer's layout matches what they had in SE; they can re-enable
|
|
2318
|
+
// avatars from the Eventlist settings panel if they want.
|
|
2319
|
+
showUserAvatar: false,
|
|
2173
2320
|
showDetailedText: false,
|
|
2174
2321
|
hideAlertMessage: false
|
|
2175
2322
|
}
|
|
@@ -3832,11 +3979,6 @@ function rewriteAssetURLs(overlay, mapping) {
|
|
|
3832
3979
|
};
|
|
3833
3980
|
}
|
|
3834
3981
|
var MAX_MIRROR_ASSET_BYTES = 100 * 1024 * 1024;
|
|
3835
|
-
function looksLikeCorsError2(err) {
|
|
3836
|
-
if (!(err instanceof TypeError)) return false;
|
|
3837
|
-
const msg = (err.message ?? "").toLowerCase();
|
|
3838
|
-
return msg.includes("failed to fetch") || msg.includes("networkerror") || msg.includes("network error") || msg.includes("cors") || msg.includes("access-control") || err.message.length > 0;
|
|
3839
|
-
}
|
|
3840
3982
|
async function mirrorOneAsset(url, upload, signal, proxyAssetFetch) {
|
|
3841
3983
|
const blob = await fetchAssetBlob(url, signal, proxyAssetFetch);
|
|
3842
3984
|
if (signal?.aborted) throw new DOMException("Aborted", "AbortError");
|
|
@@ -3868,7 +4010,7 @@ async function fetchAssetBlob(url, signal, proxyAssetFetch) {
|
|
|
3868
4010
|
return res.blob();
|
|
3869
4011
|
}
|
|
3870
4012
|
if (signal?.aborted) throw new DOMException("Aborted", "AbortError");
|
|
3871
|
-
if (proxyAssetFetch &&
|
|
4013
|
+
if (proxyAssetFetch && looksLikeCorsError(directErr)) {
|
|
3872
4014
|
try {
|
|
3873
4015
|
return await proxyAssetFetch(url);
|
|
3874
4016
|
} catch (proxyErr) {
|
|
@@ -3919,7 +4061,7 @@ function guessMime(name) {
|
|
|
3919
4061
|
}
|
|
3920
4062
|
|
|
3921
4063
|
// src/se-import/transplant.ts
|
|
3922
|
-
import { nanoid as
|
|
4064
|
+
import { nanoid as nanoid4 } from "nanoid";
|
|
3923
4065
|
function cloneModuleForTransplant(srcModule, newId) {
|
|
3924
4066
|
const clonedContent = srcModule.content ? structuredClone(srcModule.content) : srcModule.content;
|
|
3925
4067
|
if (srcModule.settings?.type === "custom" && clonedContent) {
|
|
@@ -3937,7 +4079,7 @@ function transplantLayer(source, sourceLayerId) {
|
|
|
3937
4079
|
const srcLayer = layers.find((l) => l.id === sourceLayerId);
|
|
3938
4080
|
const srcModule = modules[sourceLayerId];
|
|
3939
4081
|
if (!srcLayer || !srcModule) return null;
|
|
3940
|
-
const rootNewId =
|
|
4082
|
+
const rootNewId = nanoid4();
|
|
3941
4083
|
if (srcLayer.type !== "group") {
|
|
3942
4084
|
const layer = { ...srcLayer, id: rootNewId };
|
|
3943
4085
|
const module = cloneModuleForTransplant(srcModule, rootNewId);
|
|
@@ -3955,7 +4097,7 @@ function transplantLayer(source, sourceLayerId) {
|
|
|
3955
4097
|
if (seen.has(child.id)) continue;
|
|
3956
4098
|
seen.add(child.id);
|
|
3957
4099
|
descendants.push(child);
|
|
3958
|
-
idRemap.set(child.id,
|
|
4100
|
+
idRemap.set(child.id, nanoid4());
|
|
3959
4101
|
if (child.type === "group") queue.push(child.id);
|
|
3960
4102
|
}
|
|
3961
4103
|
}
|
|
@@ -4373,9 +4515,6 @@ var LSInput = forwardRef(
|
|
|
4373
4515
|
inputAfterText,
|
|
4374
4516
|
maxWidth,
|
|
4375
4517
|
className = "",
|
|
4376
|
-
InputProps: inputPropsProp,
|
|
4377
|
-
InputLabelProps: inputLabelPropsProp,
|
|
4378
|
-
inputProps: htmlInputPropsProp,
|
|
4379
4518
|
slotProps: slotPropsProp,
|
|
4380
4519
|
onChange,
|
|
4381
4520
|
onChangeStart,
|
|
@@ -4410,25 +4549,11 @@ var LSInput = forwardRef(
|
|
|
4410
4549
|
onChange?.(event, sanitizedValue);
|
|
4411
4550
|
onChangeEnd?.(event, sanitizedValue);
|
|
4412
4551
|
};
|
|
4413
|
-
const
|
|
4414
|
-
const
|
|
4415
|
-
const
|
|
4416
|
-
|
|
4417
|
-
|
|
4418
|
-
endAdornment: resolvedEndAdornment,
|
|
4419
|
-
readOnly: rest.readOnly ?? inputPropsProp?.readOnly,
|
|
4420
|
-
sx: {
|
|
4421
|
-
...inputPropsProp?.sx ?? {},
|
|
4422
|
-
"& input, & textarea": {
|
|
4423
|
-
textAlign: centerText ? "center" : void 0,
|
|
4424
|
-
color: textColor ?? void 0
|
|
4425
|
-
}
|
|
4426
|
-
}
|
|
4427
|
-
};
|
|
4428
|
-
const inputLabelProps = {
|
|
4429
|
-
shrink: true,
|
|
4430
|
-
...inputLabelPropsProp
|
|
4431
|
-
};
|
|
4552
|
+
const callerInputSlot = slotPropsProp?.input ?? {};
|
|
4553
|
+
const callerHtmlInputSlot = slotPropsProp?.htmlInput ?? {};
|
|
4554
|
+
const callerInputLabelSlot = slotPropsProp?.inputLabel ?? {};
|
|
4555
|
+
const resolvedStartAdornment = callerInputSlot.startAdornment ?? (startAdornment ? /* @__PURE__ */ jsx2(InputAdornment, { position: "start", children: startAdornment }) : inputBeforeText ? /* @__PURE__ */ jsx2(InputAdornment, { position: "start", children: /* @__PURE__ */ jsx2("span", { className: "mui-ls-input-affix", children: inputBeforeText }) }) : void 0);
|
|
4556
|
+
const resolvedEndAdornment = callerInputSlot.endAdornment ?? (endAdornment ? /* @__PURE__ */ jsx2(InputAdornment, { position: "end", children: endAdornment }) : inputAfterText ? /* @__PURE__ */ jsx2(InputAdornment, { position: "end", children: /* @__PURE__ */ jsx2("span", { className: "mui-ls-input-affix", children: inputAfterText }) }) : void 0);
|
|
4432
4557
|
const helperContent = helperText ?? (typeof error === "string" ? error : "");
|
|
4433
4558
|
const hasError = typeof error === "string" ? true : Boolean(error);
|
|
4434
4559
|
const resolvedMaxWidth = maxWidth ?? style?.maxWidth;
|
|
@@ -4436,20 +4561,24 @@ var LSInput = forwardRef(
|
|
|
4436
4561
|
const slotProps = {
|
|
4437
4562
|
...slotPropsProp ?? {},
|
|
4438
4563
|
input: {
|
|
4439
|
-
...
|
|
4440
|
-
|
|
4564
|
+
...callerInputSlot,
|
|
4565
|
+
startAdornment: resolvedStartAdornment,
|
|
4566
|
+
endAdornment: resolvedEndAdornment,
|
|
4567
|
+
readOnly: rest.readOnly ?? callerInputSlot.readOnly,
|
|
4441
4568
|
sx: {
|
|
4442
|
-
...
|
|
4443
|
-
|
|
4569
|
+
...callerInputSlot.sx ?? {},
|
|
4570
|
+
"& input, & textarea": {
|
|
4571
|
+
textAlign: centerText ? "center" : void 0,
|
|
4572
|
+
color: textColor ?? void 0
|
|
4573
|
+
}
|
|
4444
4574
|
}
|
|
4445
4575
|
},
|
|
4446
4576
|
inputLabel: {
|
|
4447
|
-
|
|
4448
|
-
...
|
|
4577
|
+
shrink: true,
|
|
4578
|
+
...callerInputLabelSlot
|
|
4449
4579
|
},
|
|
4450
4580
|
htmlInput: {
|
|
4451
|
-
...
|
|
4452
|
-
...htmlInputPropsProp ?? {}
|
|
4581
|
+
...callerHtmlInputSlot
|
|
4453
4582
|
}
|
|
4454
4583
|
};
|
|
4455
4584
|
const TextFieldComponent = TextField;
|
|
@@ -4639,15 +4768,15 @@ var LSSliderInput = ({
|
|
|
4639
4768
|
onChange: (_event, nextValue) => handleInputChange({ target: { value: nextValue ?? "" } }),
|
|
4640
4769
|
value: displayValue ?? "",
|
|
4641
4770
|
inputAfterText,
|
|
4642
|
-
|
|
4643
|
-
...inputProps?.
|
|
4644
|
-
|
|
4645
|
-
|
|
4646
|
-
|
|
4647
|
-
|
|
4648
|
-
|
|
4649
|
-
|
|
4650
|
-
|
|
4771
|
+
slotProps: {
|
|
4772
|
+
...inputProps?.slotProps ?? {},
|
|
4773
|
+
htmlInput: {
|
|
4774
|
+
...inputProps?.slotProps?.htmlInput ?? {},
|
|
4775
|
+
min: displayMinimum,
|
|
4776
|
+
max: displayMaximum,
|
|
4777
|
+
step: displayStep,
|
|
4778
|
+
inputMode: stepPrecision > 0 ? "decimal" : "numeric"
|
|
4779
|
+
}
|
|
4651
4780
|
},
|
|
4652
4781
|
fullWidth: hideSlider ? fullWidth : false,
|
|
4653
4782
|
$noMinHeight: false,
|
|
@@ -4711,6 +4840,16 @@ var LSSelect = ({
|
|
|
4711
4840
|
border: "1px solid var(--neutralDark4)",
|
|
4712
4841
|
borderRadius: "var(--radius, 1rem)",
|
|
4713
4842
|
boxShadow: "0 16px 32px rgba(0, 0, 0, 0.32)",
|
|
4843
|
+
"& .MuiList-root": {
|
|
4844
|
+
backgroundColor: "var(--neutralDark2)"
|
|
4845
|
+
},
|
|
4846
|
+
"& .MuiListSubheader-root": {
|
|
4847
|
+
backgroundColor: "var(--neutralDark1)",
|
|
4848
|
+
color: "var(--neutralLight2)"
|
|
4849
|
+
},
|
|
4850
|
+
"& .MuiMenuItem-root": {
|
|
4851
|
+
color: "var(--neutralLight1)"
|
|
4852
|
+
},
|
|
4714
4853
|
...MenuProps?.slotProps?.paper?.sx
|
|
4715
4854
|
}
|
|
4716
4855
|
},
|
|
@@ -4722,28 +4861,6 @@ var LSSelect = ({
|
|
|
4722
4861
|
...MenuProps?.slotProps?.list?.sx
|
|
4723
4862
|
}
|
|
4724
4863
|
}
|
|
4725
|
-
},
|
|
4726
|
-
PaperProps: {
|
|
4727
|
-
...MenuProps?.PaperProps ?? {},
|
|
4728
|
-
sx: {
|
|
4729
|
-
background: "var(--neutralDark2) !important",
|
|
4730
|
-
backgroundColor: "var(--neutralDark2)",
|
|
4731
|
-
color: "var(--neutralLight1)",
|
|
4732
|
-
border: "1px solid var(--neutralDark4)",
|
|
4733
|
-
borderRadius: "var(--radius, 1rem)",
|
|
4734
|
-
boxShadow: "0 16px 32px rgba(0, 0, 0, 0.32)",
|
|
4735
|
-
"& .MuiList-root": {
|
|
4736
|
-
backgroundColor: "var(--neutralDark2)"
|
|
4737
|
-
},
|
|
4738
|
-
"& .MuiListSubheader-root": {
|
|
4739
|
-
backgroundColor: "var(--neutralDark1)",
|
|
4740
|
-
color: "var(--neutralLight2)"
|
|
4741
|
-
},
|
|
4742
|
-
"& .MuiMenuItem-root": {
|
|
4743
|
-
color: "var(--neutralLight1)"
|
|
4744
|
-
},
|
|
4745
|
-
...MenuProps?.PaperProps?.sx
|
|
4746
|
-
}
|
|
4747
4864
|
}
|
|
4748
4865
|
};
|
|
4749
4866
|
return /* @__PURE__ */ jsxs2(
|
|
@@ -4856,14 +4973,7 @@ LSDatePicker.displayName = "LSDatePicker";
|
|
|
4856
4973
|
import { KeyboardArrowDown } from "@mui/icons-material";
|
|
4857
4974
|
import Autocomplete from "@mui/material/Autocomplete";
|
|
4858
4975
|
import TextField2 from "@mui/material/TextField";
|
|
4859
|
-
import {
|
|
4860
|
-
memo,
|
|
4861
|
-
startTransition,
|
|
4862
|
-
useEffect as useEffect3,
|
|
4863
|
-
useMemo as useMemo2,
|
|
4864
|
-
useRef as useRef2,
|
|
4865
|
-
useState as useState3
|
|
4866
|
-
} from "react";
|
|
4976
|
+
import { memo, startTransition, useEffect as useEffect3, useMemo as useMemo2, useRef as useRef2, useState as useState3 } from "react";
|
|
4867
4977
|
import { jsx as jsx8 } from "react/jsx-runtime";
|
|
4868
4978
|
var LSFontPicker = memo(function LSFontPicker2({
|
|
4869
4979
|
value,
|
|
@@ -4921,9 +5031,7 @@ var LSFontPicker = memo(function LSFontPicker2({
|
|
|
4921
5031
|
popupIcon: /* @__PURE__ */ jsx8(KeyboardArrowDown, {}),
|
|
4922
5032
|
isOptionEqualToValue: (option, selectedValue) => option === selectedValue,
|
|
4923
5033
|
onChange: (_event, newValue) => {
|
|
4924
|
-
handleValueChange(
|
|
4925
|
-
typeof newValue === "string" ? newValue : `${newValue ?? ""}`
|
|
4926
|
-
);
|
|
5034
|
+
handleValueChange(typeof newValue === "string" ? newValue : `${newValue ?? ""}`);
|
|
4927
5035
|
},
|
|
4928
5036
|
onInputChange: (_event, newInputValue, reason) => {
|
|
4929
5037
|
if (reason === "input" || reason === "clear") {
|
|
@@ -4980,11 +5088,7 @@ var LSFontPicker = memo(function LSFontPicker2({
|
|
|
4980
5088
|
);
|
|
4981
5089
|
},
|
|
4982
5090
|
renderInput: (params) => {
|
|
4983
|
-
const {
|
|
4984
|
-
InputLabelProps: paramsInputLabelProps,
|
|
4985
|
-
InputProps: paramsInputProps,
|
|
4986
|
-
...restParams
|
|
4987
|
-
} = params;
|
|
5091
|
+
const { slotProps: paramsSlotProps = {}, ...restParams } = params;
|
|
4988
5092
|
return /* @__PURE__ */ jsx8(
|
|
4989
5093
|
TextFieldComponent,
|
|
4990
5094
|
{
|
|
@@ -5001,12 +5105,16 @@ var LSFontPicker = memo(function LSFontPicker2({
|
|
|
5001
5105
|
}
|
|
5002
5106
|
},
|
|
5003
5107
|
slotProps: {
|
|
5108
|
+
...paramsSlotProps,
|
|
5004
5109
|
inputLabel: {
|
|
5005
|
-
|
|
5006
|
-
|
|
5110
|
+
...paramsSlotProps.inputLabel ?? {},
|
|
5111
|
+
shrink: true
|
|
5007
5112
|
},
|
|
5008
5113
|
input: {
|
|
5009
|
-
...
|
|
5114
|
+
...paramsSlotProps.input ?? {}
|
|
5115
|
+
},
|
|
5116
|
+
htmlInput: {
|
|
5117
|
+
...paramsSlotProps.htmlInput ?? {}
|
|
5010
5118
|
}
|
|
5011
5119
|
}
|
|
5012
5120
|
}
|
|
@@ -5050,7 +5158,8 @@ import { forwardRef as forwardRef4 } from "react";
|
|
|
5050
5158
|
import { jsx as jsx11 } from "react/jsx-runtime";
|
|
5051
5159
|
var LSTextField = forwardRef4(
|
|
5052
5160
|
(props, ref) => {
|
|
5053
|
-
const {
|
|
5161
|
+
const { slotProps, ...rest } = props;
|
|
5162
|
+
const paramsInputLabel = slotProps?.inputLabel ?? {};
|
|
5054
5163
|
return /* @__PURE__ */ jsx11(
|
|
5055
5164
|
TextField3,
|
|
5056
5165
|
{
|
|
@@ -5059,18 +5168,9 @@ var LSTextField = forwardRef4(
|
|
|
5059
5168
|
className: "mui-ls-input",
|
|
5060
5169
|
slotProps: {
|
|
5061
5170
|
...slotProps ?? {},
|
|
5062
|
-
input: {
|
|
5063
|
-
...slotProps?.input ?? {},
|
|
5064
|
-
...InputProps ?? {},
|
|
5065
|
-
sx: {
|
|
5066
|
-
...slotProps?.input?.sx ?? {},
|
|
5067
|
-
...InputProps?.sx ?? {}
|
|
5068
|
-
}
|
|
5069
|
-
},
|
|
5070
5171
|
inputLabel: {
|
|
5071
|
-
...
|
|
5072
|
-
shrink: true
|
|
5073
|
-
...InputLabelProps ?? {}
|
|
5172
|
+
...paramsInputLabel,
|
|
5173
|
+
shrink: true
|
|
5074
5174
|
}
|
|
5075
5175
|
},
|
|
5076
5176
|
ref
|
|
@@ -6223,14 +6323,12 @@ var VariableInputTextField = forwardRef5(
|
|
|
6223
6323
|
containerRef,
|
|
6224
6324
|
showVariableIcon
|
|
6225
6325
|
}, ref) => {
|
|
6226
|
-
const
|
|
6227
|
-
const
|
|
6228
|
-
const inputPropsSlotInputProps = inputProps?.slotProps?.input ?? {};
|
|
6229
|
-
const paramsSlotInputProps = params?.slotProps?.input ?? {};
|
|
6326
|
+
const inputPropsSlotInput = inputProps?.slotProps?.input ?? {};
|
|
6327
|
+
const paramsSlotInput = params?.slotProps?.input ?? {};
|
|
6230
6328
|
const explicitStartAdornment = inputProps?.startAdornment;
|
|
6231
6329
|
const resolvedExplicitStartAdornment = explicitStartAdornment ? /* @__PURE__ */ jsx12(InputAdornment2, { position: "start", children: explicitStartAdornment }) : void 0;
|
|
6232
|
-
const startAdornment =
|
|
6233
|
-
const endAdornment =
|
|
6330
|
+
const startAdornment = paramsSlotInput.startAdornment ?? inputPropsSlotInput.startAdornment ?? resolvedExplicitStartAdornment;
|
|
6331
|
+
const endAdornment = paramsSlotInput.endAdornment ?? inputPropsSlotInput.endAdornment;
|
|
6234
6332
|
return /* @__PURE__ */ jsx12(
|
|
6235
6333
|
LSTextField,
|
|
6236
6334
|
{
|
|
@@ -6252,31 +6350,27 @@ var VariableInputTextField = forwardRef5(
|
|
|
6252
6350
|
onChange: onChange ? (e) => onChange(e.target.value) : void 0,
|
|
6253
6351
|
...inputProps,
|
|
6254
6352
|
...params,
|
|
6255
|
-
|
|
6256
|
-
...
|
|
6257
|
-
...
|
|
6258
|
-
|
|
6259
|
-
|
|
6260
|
-
|
|
6261
|
-
|
|
6262
|
-
endAdornment
|
|
6263
|
-
|
|
6264
|
-
Tooltip,
|
|
6265
|
-
|
|
6266
|
-
|
|
6267
|
-
|
|
6268
|
-
|
|
6269
|
-
|
|
6270
|
-
|
|
6271
|
-
|
|
6272
|
-
|
|
6273
|
-
|
|
6274
|
-
|
|
6275
|
-
|
|
6276
|
-
)
|
|
6277
|
-
}
|
|
6278
|
-
) : null
|
|
6279
|
-
] })
|
|
6353
|
+
slotProps: {
|
|
6354
|
+
...inputProps?.slotProps ?? {},
|
|
6355
|
+
...params?.slotProps ?? {},
|
|
6356
|
+
input: {
|
|
6357
|
+
...inputPropsSlotInput,
|
|
6358
|
+
...paramsSlotInput,
|
|
6359
|
+
startAdornment,
|
|
6360
|
+
endAdornment: /* @__PURE__ */ jsxs5(Fragment3, { children: [
|
|
6361
|
+
endAdornment ?? null,
|
|
6362
|
+
showVariableIcon ? /* @__PURE__ */ jsx12(Tooltip, { title: t("chatbot.allowed-variables", "Allowed Variables"), children: /* @__PURE__ */ jsx12(
|
|
6363
|
+
InputAdornment2,
|
|
6364
|
+
{
|
|
6365
|
+
position: "end",
|
|
6366
|
+
onClick: clickedVariableIcon,
|
|
6367
|
+
ref: containerRef,
|
|
6368
|
+
className: "ls-variable-input-adornment",
|
|
6369
|
+
children: "{}"
|
|
6370
|
+
}
|
|
6371
|
+
) }) : null
|
|
6372
|
+
] })
|
|
6373
|
+
}
|
|
6280
6374
|
},
|
|
6281
6375
|
inputRef: ref
|
|
6282
6376
|
}
|
|
@@ -6441,7 +6535,74 @@ function readSLProvider(response) {
|
|
|
6441
6535
|
}
|
|
6442
6536
|
|
|
6443
6537
|
// src/sl-import/mappers/alert-box.ts
|
|
6444
|
-
import { nanoid as
|
|
6538
|
+
import { nanoid as nanoid6 } from "nanoid";
|
|
6539
|
+
import { LumiaAlertValues as LumiaAlertValues2 } from "@lumiastream/lumia-types";
|
|
6540
|
+
|
|
6541
|
+
// src/se-import/import-envelope.ts
|
|
6542
|
+
import { nanoid as nanoid5 } from "nanoid";
|
|
6543
|
+
function buildModuleEnvelope(opts) {
|
|
6544
|
+
const id = opts.id ?? nanoid5();
|
|
6545
|
+
const locked = opts.locked ?? false;
|
|
6546
|
+
const visible = opts.visible ?? true;
|
|
6547
|
+
const layer = {
|
|
6548
|
+
id,
|
|
6549
|
+
...opts.parentGroupId !== void 0 ? { group: opts.parentGroupId } : {},
|
|
6550
|
+
...opts.type_layer ? { type: opts.type_layer } : {},
|
|
6551
|
+
state: {
|
|
6552
|
+
visible,
|
|
6553
|
+
locked,
|
|
6554
|
+
...opts.expanded !== void 0 ? { expanded: opts.expanded } : {}
|
|
6555
|
+
},
|
|
6556
|
+
bounds: {
|
|
6557
|
+
x: opts.bounds.x,
|
|
6558
|
+
y: opts.bounds.y,
|
|
6559
|
+
width: opts.bounds.width,
|
|
6560
|
+
height: opts.bounds.height,
|
|
6561
|
+
scale: [1, 1],
|
|
6562
|
+
...opts.zIndex !== void 0 ? { zIndex: opts.zIndex } : {}
|
|
6563
|
+
}
|
|
6564
|
+
};
|
|
6565
|
+
const module = {
|
|
6566
|
+
id,
|
|
6567
|
+
version: opts.version ?? 1,
|
|
6568
|
+
loaded: true,
|
|
6569
|
+
settings: { type: opts.type, title: opts.title, locked },
|
|
6570
|
+
lights: opts.lights ?? [],
|
|
6571
|
+
css: opts.css ?? {},
|
|
6572
|
+
content: opts.content ?? {},
|
|
6573
|
+
variables: opts.variables ?? {},
|
|
6574
|
+
events: opts.events ?? {},
|
|
6575
|
+
...opts.alert !== void 0 ? { alert: opts.alert } : {}
|
|
6576
|
+
};
|
|
6577
|
+
return { id, layer, module };
|
|
6578
|
+
}
|
|
6579
|
+
var IMPORT_META_KEY = "importMeta";
|
|
6580
|
+
function stampImportMetaMerge(module, meta) {
|
|
6581
|
+
const existing = module.content?.[IMPORT_META_KEY] ?? {};
|
|
6582
|
+
module.content = {
|
|
6583
|
+
...module.content ?? {},
|
|
6584
|
+
[IMPORT_META_KEY]: {
|
|
6585
|
+
importedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6586
|
+
...existing,
|
|
6587
|
+
...meta
|
|
6588
|
+
}
|
|
6589
|
+
};
|
|
6590
|
+
}
|
|
6591
|
+
function customHtmlReviewItem(moduleId, importSourceType, settings, reason) {
|
|
6592
|
+
return {
|
|
6593
|
+
moduleId,
|
|
6594
|
+
// ReviewItem's `seWidget` is typed against SEWidget but the review
|
|
6595
|
+
// UI just reads `.type` and `.settings`. Cast through unknown is
|
|
6596
|
+
// the only place we touch the shape mismatch; widening the
|
|
6597
|
+
// ReviewItem type is a future cleanup.
|
|
6598
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
6599
|
+
seWidget: { type: importSourceType, settings },
|
|
6600
|
+
status: "template",
|
|
6601
|
+
reason
|
|
6602
|
+
};
|
|
6603
|
+
}
|
|
6604
|
+
|
|
6605
|
+
// src/sl-import/mappers/alert-box.ts
|
|
6445
6606
|
var SL_EVENT_ROUTING = {
|
|
6446
6607
|
// Platform-native — provider routes (Twitch / Kick / YouTube).
|
|
6447
6608
|
follow: { pickProviderKeys: "follower" },
|
|
@@ -6453,47 +6614,35 @@ var SL_EVENT_ROUTING = {
|
|
|
6453
6614
|
// `subscriber` here is YouTube subscribe (free); `sponsor` is YouTube
|
|
6454
6615
|
// channel membership; `fanfunding` is YouTube superchat. SL ships these
|
|
6455
6616
|
// even on Twitch-primary accounts so we always map them.
|
|
6456
|
-
subscriber: { keys: [
|
|
6457
|
-
sponsor: { keys: [
|
|
6458
|
-
fanfunding: { keys: [
|
|
6459
|
-
super_sticker: { keys: [
|
|
6617
|
+
subscriber: { keys: [LumiaAlertValues2.YOUTUBE_SUBSCRIBER] },
|
|
6618
|
+
sponsor: { keys: [LumiaAlertValues2.YOUTUBE_MEMBER] },
|
|
6619
|
+
fanfunding: { keys: [LumiaAlertValues2.YOUTUBE_SUPERCHAT] },
|
|
6620
|
+
super_sticker: { keys: [LumiaAlertValues2.YOUTUBE_SUPERSTICKER] },
|
|
6460
6621
|
// Donation / tip channels — Lumia ships dedicated alert keys for each
|
|
6461
6622
|
// integration. `donation` itself fans out to `streamlabs-donation` AND
|
|
6462
6623
|
// `lumiastream-donation` so the imported alert fires regardless of which
|
|
6463
6624
|
// channel the donation actually came in on.
|
|
6464
|
-
donation: { keys: [
|
|
6465
|
-
eldonation: { keys: [
|
|
6466
|
-
tiltifydonation: { keys: [
|
|
6467
|
-
donordrivedonation: { keys: [
|
|
6468
|
-
justgivingdonation: { keys: [
|
|
6469
|
-
pledge: { keys: [
|
|
6625
|
+
donation: { keys: [LumiaAlertValues2.STREAMLABS_DONATION, LumiaAlertValues2.LUMIASTREAM_DONATION] },
|
|
6626
|
+
eldonation: { keys: [LumiaAlertValues2.EXTRALIFE_DONATION] },
|
|
6627
|
+
tiltifydonation: { keys: [LumiaAlertValues2.TILTIFY_DONATION] },
|
|
6628
|
+
donordrivedonation: { keys: [LumiaAlertValues2.DONORDRIVE_DONATION] },
|
|
6629
|
+
justgivingdonation: { keys: [LumiaAlertValues2.STREAMLABS_DONATION] },
|
|
6630
|
+
pledge: { keys: [LumiaAlertValues2.PATREON_PLEDGE] },
|
|
6470
6631
|
// Charity / merch / loyalty / prime gifting — SL-flavored channels with
|
|
6471
6632
|
// matching Lumia keys.
|
|
6472
|
-
streamlabscharitydonation: { keys: [
|
|
6473
|
-
twitchcharitydonation: { keys: [
|
|
6474
|
-
merch: { keys: [
|
|
6475
|
-
loyalty_store_redemption: { keys: [
|
|
6476
|
-
prime_sub_gift: { keys: [
|
|
6477
|
-
treat: { keys: [
|
|
6633
|
+
streamlabscharitydonation: { keys: [LumiaAlertValues2.STREAMLABS_CHARITY] },
|
|
6634
|
+
twitchcharitydonation: { keys: [LumiaAlertValues2.TWITCH_CHARITY_DONATION] },
|
|
6635
|
+
merch: { keys: [LumiaAlertValues2.STREAMLABS_MERCH] },
|
|
6636
|
+
loyalty_store_redemption: { keys: [LumiaAlertValues2.STREAMLABS_REDEMPTION] },
|
|
6637
|
+
prime_sub_gift: { keys: [LumiaAlertValues2.STREAMLABS_PRIMEGIFT] },
|
|
6638
|
+
treat: { keys: [LumiaAlertValues2.TREATSTREAM_TREAT] },
|
|
6478
6639
|
// TikTok-flavored (jewel gift is TikTok-ish in concept).
|
|
6479
|
-
jewel_gift: { keys: [
|
|
6640
|
+
jewel_gift: { keys: [LumiaAlertValues2.TIKTOK_GIFT] }
|
|
6480
6641
|
};
|
|
6481
6642
|
function getField(settings, prefix, field) {
|
|
6482
6643
|
const key = `${prefix}_${field}`;
|
|
6483
6644
|
return settings[key];
|
|
6484
6645
|
}
|
|
6485
|
-
function pxToNumber(raw, fallback) {
|
|
6486
|
-
if (typeof raw === "number" && Number.isFinite(raw)) return raw;
|
|
6487
|
-
if (typeof raw !== "string") return fallback;
|
|
6488
|
-
const trimmed = raw.trim();
|
|
6489
|
-
if (!trimmed) return fallback;
|
|
6490
|
-
if (trimmed.endsWith("px")) {
|
|
6491
|
-
const n2 = parseFloat(trimmed.slice(0, -2));
|
|
6492
|
-
return Number.isFinite(n2) ? n2 : fallback;
|
|
6493
|
-
}
|
|
6494
|
-
const n = parseFloat(trimmed);
|
|
6495
|
-
return Number.isFinite(n) ? n : fallback;
|
|
6496
|
-
}
|
|
6497
6646
|
function translateLayout2(slLayout) {
|
|
6498
6647
|
switch (slLayout) {
|
|
6499
6648
|
case "above":
|
|
@@ -6603,9 +6752,7 @@ function buildBaseAlertEvent(settings, prefix, defaultMessage) {
|
|
|
6603
6752
|
tts: {
|
|
6604
6753
|
enabled: getField(settings, prefix, "tts_enabled") ?? false,
|
|
6605
6754
|
voice: getField(settings, prefix, "tts_language") ?? "Brian",
|
|
6606
|
-
volume: clampVolume(
|
|
6607
|
-
getField(settings, prefix, "tts_volume") ?? 75
|
|
6608
|
-
),
|
|
6755
|
+
volume: clampVolume(getField(settings, prefix, "tts_volume") ?? 75),
|
|
6609
6756
|
minAmount: getField(settings, prefix, "tts_min_amount") ?? 0
|
|
6610
6757
|
},
|
|
6611
6758
|
variations: []
|
|
@@ -6620,10 +6767,7 @@ function readSecondaryMessageConfig(settings, prefix, primaryFontFamily) {
|
|
|
6620
6767
|
const enabled = settings[showKey];
|
|
6621
6768
|
if (enabled !== true) return null;
|
|
6622
6769
|
const fontFamily = getField(settings, secondaryPrefix, "message_font") ?? primaryFontFamily;
|
|
6623
|
-
const fontSize = pxToNumber(
|
|
6624
|
-
getField(settings, secondaryPrefix, "message_font_size"),
|
|
6625
|
-
20
|
|
6626
|
-
);
|
|
6770
|
+
const fontSize = pxToNumber(getField(settings, secondaryPrefix, "message_font_size"), 20);
|
|
6627
6771
|
const fontWeight = getField(settings, secondaryPrefix, "message_font_weight") ?? 400;
|
|
6628
6772
|
const fontColor = getField(settings, secondaryPrefix, "message_font_color") ?? "#FFFFFF";
|
|
6629
6773
|
return {
|
|
@@ -6650,11 +6794,20 @@ function translateSLVariationCondition(v) {
|
|
|
6650
6794
|
const numericData = typeof data === "number" ? data : Number(data);
|
|
6651
6795
|
switch (v.condition) {
|
|
6652
6796
|
case "RANDOM":
|
|
6653
|
-
return {
|
|
6797
|
+
return {
|
|
6798
|
+
conditionType: "RANDOM",
|
|
6799
|
+
condition: Number.isFinite(numericData) ? numericData : 100
|
|
6800
|
+
};
|
|
6654
6801
|
case "MIN_BITS_USED":
|
|
6655
|
-
return {
|
|
6802
|
+
return {
|
|
6803
|
+
conditionType: "GREATER_NUMBER",
|
|
6804
|
+
condition: Number.isFinite(numericData) ? numericData : 0
|
|
6805
|
+
};
|
|
6656
6806
|
case "EXACT_BITS_USED":
|
|
6657
|
-
return {
|
|
6807
|
+
return {
|
|
6808
|
+
conditionType: "EQUAL_NUMBER",
|
|
6809
|
+
condition: Number.isFinite(numericData) ? numericData : 0
|
|
6810
|
+
};
|
|
6658
6811
|
case "MIN_MONTHS_SUBSCRIBED":
|
|
6659
6812
|
return {
|
|
6660
6813
|
conditionType: "SUBSCRIBED_MONTHS_GREATER",
|
|
@@ -6719,6 +6872,14 @@ function buildVariationEvent(v, parentBase) {
|
|
|
6719
6872
|
if (s.hideAnimation) inherited.animations.alertExitAnimation = s.hideAnimation;
|
|
6720
6873
|
if (s.layout) inherited.layout.value = translateLayout2(s.layout);
|
|
6721
6874
|
return {
|
|
6875
|
+
// Reuse SL's own `uuid` when present so re-importing the same SL
|
|
6876
|
+
// alert-box keeps the variation identity stable across import
|
|
6877
|
+
// runs. SL always emits a uuid in their config (every fixture we've
|
|
6878
|
+
// seen has one); fall back to nanoid for the edge case of a
|
|
6879
|
+
// hand-crafted / older payload that omits it. Matches the SE
|
|
6880
|
+
// alert mapper's variation-id pattern — see Settings.tsx auto-fill
|
|
6881
|
+
// note there for why a stable id matters from save #1.
|
|
6882
|
+
id: typeof v.uuid === "string" && v.uuid.length > 0 ? v.uuid : nanoid6(),
|
|
6722
6883
|
name: v.name ?? "Variation",
|
|
6723
6884
|
on: v.paused !== true,
|
|
6724
6885
|
randomChance: 100,
|
|
@@ -6784,11 +6945,7 @@ function buildSLAlertBox(settings, options = {}) {
|
|
|
6784
6945
|
for (const [prefix, routing] of Object.entries(SL_EVENT_ROUTING)) {
|
|
6785
6946
|
const lumiaKeys = routing.pickProviderKeys ? alertBoxKeysFor(routing.pickProviderKeys, provider) : routing.keys ?? [];
|
|
6786
6947
|
if (lumiaKeys.length === 0) continue;
|
|
6787
|
-
const built = buildBaseAlertEvent(
|
|
6788
|
-
settings,
|
|
6789
|
-
prefix,
|
|
6790
|
-
DEFAULT_MESSAGES[prefix] ?? "{name}"
|
|
6791
|
-
);
|
|
6948
|
+
const built = buildBaseAlertEvent(settings, prefix, DEFAULT_MESSAGES[prefix] ?? "{name}");
|
|
6792
6949
|
if (!built) continue;
|
|
6793
6950
|
const variationKey = VARIATION_KEY_FOR_PREFIX[prefix];
|
|
6794
6951
|
const variations = variationKey ? settings[variationKey] : void 0;
|
|
@@ -6805,53 +6962,32 @@ function buildSLAlertBox(settings, options = {}) {
|
|
|
6805
6962
|
channelsImported.push(prefix);
|
|
6806
6963
|
if (firstEvent == null) firstEvent = built;
|
|
6807
6964
|
}
|
|
6808
|
-
const id = nanoid4();
|
|
6809
|
-
const layer = {
|
|
6810
|
-
id,
|
|
6811
|
-
state: { visible: true, locked: false },
|
|
6812
|
-
bounds: { x: 100, y: 100, width: 700, height: 600, scale: [1, 1] }
|
|
6813
|
-
};
|
|
6814
6965
|
const baseAlert = firstEvent ? stripEventOnlyFields(firstEvent) : {};
|
|
6815
|
-
const module = {
|
|
6816
|
-
|
|
6817
|
-
|
|
6818
|
-
|
|
6819
|
-
settings: { type: "alert", title: "Streamlabs Alerts", locked: false },
|
|
6820
|
-
lights: [],
|
|
6821
|
-
css: {},
|
|
6822
|
-
content: {},
|
|
6823
|
-
variables: {},
|
|
6824
|
-
events: {},
|
|
6966
|
+
const { layer, module } = buildModuleEnvelope({
|
|
6967
|
+
type: "alert",
|
|
6968
|
+
title: "Streamlabs Alerts",
|
|
6969
|
+
bounds: { x: 100, y: 100, width: 700, height: 600 },
|
|
6825
6970
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
6826
6971
|
alert: { ...baseAlert, events }
|
|
6827
|
-
};
|
|
6972
|
+
});
|
|
6828
6973
|
return { layer, module, channelsImported };
|
|
6829
6974
|
}
|
|
6830
6975
|
function stripEventOnlyFields(event) {
|
|
6831
|
-
const {
|
|
6976
|
+
const {
|
|
6977
|
+
on: _on,
|
|
6978
|
+
variations: _variations,
|
|
6979
|
+
matchEmptyCondition: _mec,
|
|
6980
|
+
...base
|
|
6981
|
+
} = event;
|
|
6832
6982
|
return base;
|
|
6833
6983
|
}
|
|
6834
6984
|
|
|
6835
6985
|
// src/sl-import/mappers/tip-jar.ts
|
|
6836
|
-
import { nanoid as nanoid5 } from "nanoid";
|
|
6837
|
-
function pxToNumber2(raw, fallback) {
|
|
6838
|
-
if (typeof raw === "number" && Number.isFinite(raw)) return raw;
|
|
6839
|
-
if (typeof raw !== "string") return fallback;
|
|
6840
|
-
const trimmed = raw.trim();
|
|
6841
|
-
if (!trimmed) return fallback;
|
|
6842
|
-
if (trimmed.endsWith("px")) {
|
|
6843
|
-
const n2 = parseFloat(trimmed.slice(0, -2));
|
|
6844
|
-
return Number.isFinite(n2) ? n2 : fallback;
|
|
6845
|
-
}
|
|
6846
|
-
const n = parseFloat(trimmed);
|
|
6847
|
-
return Number.isFinite(n) ? n : fallback;
|
|
6848
|
-
}
|
|
6849
6986
|
function buildSLTipJar(settings) {
|
|
6850
|
-
const id = nanoid5();
|
|
6851
6987
|
const backgroundColor = settings.background?.color ?? "transparent";
|
|
6852
6988
|
const textColor = settings.text?.color ?? "#FFFFFF";
|
|
6853
6989
|
const fontFamily = settings.text?.font ?? "Open Sans";
|
|
6854
|
-
const fontSize =
|
|
6990
|
+
const fontSize = pxToNumber(settings.text?.size, 32);
|
|
6855
6991
|
const types = settings.types ?? {};
|
|
6856
6992
|
const tipsConfig = types.tips ?? {};
|
|
6857
6993
|
const slEvents = {
|
|
@@ -6867,17 +7003,11 @@ function buildSLTipJar(settings) {
|
|
|
6867
7003
|
...TIPJAR_DEFAULT_MODULE.content.display,
|
|
6868
7004
|
showEventMessages: settings.text?.show !== false
|
|
6869
7005
|
};
|
|
6870
|
-
const layer = {
|
|
6871
|
-
|
|
6872
|
-
|
|
6873
|
-
bounds: { x: 100, y: 100, width: 600, height: 700
|
|
6874
|
-
};
|
|
6875
|
-
const module = {
|
|
6876
|
-
id,
|
|
7006
|
+
const { layer, module } = buildModuleEnvelope({
|
|
7007
|
+
type: "tipjar",
|
|
7008
|
+
title: "Streamlabs Tip Jar",
|
|
7009
|
+
bounds: { x: 100, y: 100, width: 600, height: 700 },
|
|
6877
7010
|
version: TIPJAR_DEFAULT_MODULE.version,
|
|
6878
|
-
loaded: true,
|
|
6879
|
-
settings: { type: "tipjar", title: "Streamlabs Tip Jar", locked: false },
|
|
6880
|
-
lights: [],
|
|
6881
7011
|
css: {
|
|
6882
7012
|
fontFamily,
|
|
6883
7013
|
fontSize,
|
|
@@ -6898,12 +7028,7 @@ function buildSLTipJar(settings) {
|
|
|
6898
7028
|
source: "streamlabs",
|
|
6899
7029
|
widgetType: "tip_jar",
|
|
6900
7030
|
importedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
6901
|
-
// SL jar type doesn't have a 1:1 mapping to Lumia's preset
|
|
6902
|
-
// vocabulary (cup-01, cup-02, …). Stashed for review.
|
|
6903
7031
|
slJarType: settings.jar?.type ?? null,
|
|
6904
|
-
// SL tier coin tiers — Lumia's sprite tiers are per-event and
|
|
6905
|
-
// configured in the sprite editor; the user re-creates these
|
|
6906
|
-
// manually. Stored here so they're not lost.
|
|
6907
7032
|
slTipTiers: Array.isArray(tipsConfig.tiers) ? tipsConfig.tiers.map((t) => ({
|
|
6908
7033
|
minimumAmount: t.minimum_amount,
|
|
6909
7034
|
imageSrc: t.image_src ?? null
|
|
@@ -6911,15 +7036,12 @@ function buildSLTipJar(settings) {
|
|
|
6911
7036
|
slMinimumTipAmount: tipsConfig.minimum_amount ?? null,
|
|
6912
7037
|
slHadCustomHtml: settings.custom_html_enabled === true
|
|
6913
7038
|
}
|
|
6914
|
-
}
|
|
6915
|
-
|
|
6916
|
-
events: {}
|
|
6917
|
-
};
|
|
7039
|
+
}
|
|
7040
|
+
});
|
|
6918
7041
|
return { layer, module };
|
|
6919
7042
|
}
|
|
6920
7043
|
|
|
6921
7044
|
// src/sl-import/mappers/goal.ts
|
|
6922
|
-
import { nanoid as nanoid6 } from "nanoid";
|
|
6923
7045
|
var GOAL_SOURCE_MAP = {
|
|
6924
7046
|
follower_goal: "follower",
|
|
6925
7047
|
sub_goal: "subscriber",
|
|
@@ -6932,69 +7054,262 @@ var GOAL_TITLE_MAP = {
|
|
|
6932
7054
|
donation_goal: "Donation Goal",
|
|
6933
7055
|
bit_goal: "Bits Goal"
|
|
6934
7056
|
};
|
|
6935
|
-
|
|
6936
|
-
|
|
6937
|
-
|
|
6938
|
-
|
|
6939
|
-
|
|
6940
|
-
|
|
6941
|
-
const n2 = parseFloat(trimmed.slice(0, -2));
|
|
6942
|
-
return Number.isFinite(n2) ? n2 : fallback;
|
|
6943
|
-
}
|
|
6944
|
-
const n = parseFloat(trimmed);
|
|
6945
|
-
return Number.isFinite(n) ? n : fallback;
|
|
6946
|
-
}
|
|
7057
|
+
var GOAL_CURRENT_TEMPLATE = {
|
|
7058
|
+
follower_goal: "{{twitch_total_follower_count}}",
|
|
7059
|
+
sub_goal: "{{twitch_total_subscriber_count}}",
|
|
7060
|
+
donation_goal: "{{total_donation_amount}}",
|
|
7061
|
+
bit_goal: "{{twitch_total_bits_count}}"
|
|
7062
|
+
};
|
|
6947
7063
|
function buildSLGoal(settings, widgetType) {
|
|
6948
|
-
const id = nanoid6();
|
|
6949
7064
|
const goalSource = GOAL_SOURCE_MAP[widgetType] ?? "follower";
|
|
6950
7065
|
const defaultTitle = GOAL_TITLE_MAP[widgetType] ?? "Goal";
|
|
7066
|
+
const currentTemplate = GOAL_CURRENT_TEMPLATE[widgetType] ?? "";
|
|
7067
|
+
const requiresReview = settings.custom_enabled === true;
|
|
6951
7068
|
const title = typeof settings.title === "string" ? settings.title : defaultTitle;
|
|
6952
7069
|
const goalAmount = typeof settings.goal === "number" ? settings.goal : 100;
|
|
6953
7070
|
const currentAmount = typeof settings.current === "number" ? settings.current : 0;
|
|
6954
7071
|
const startingAmount = typeof settings.starting_amount === "number" ? settings.starting_amount : 0;
|
|
6955
|
-
const endsAt = typeof settings.ends_at === "string" ? settings.ends_at :
|
|
7072
|
+
const endsAt = typeof settings.ends_at === "string" ? settings.ends_at : "";
|
|
6956
7073
|
const barColor = settings.bar_color ?? "#32C3A6";
|
|
6957
|
-
const
|
|
7074
|
+
const barBgColor = settings.bar_bg_color ?? "#181818";
|
|
7075
|
+
const widgetBgColor = settings.background_color ?? "transparent";
|
|
6958
7076
|
const textColor = settings.text_color ?? "#FFFFFF";
|
|
6959
7077
|
const barTextColor = settings.bar_text_color ?? textColor;
|
|
6960
7078
|
const fontFamily = settings.font ?? "Open Sans";
|
|
6961
|
-
const
|
|
6962
|
-
|
|
6963
|
-
|
|
6964
|
-
|
|
6965
|
-
|
|
6966
|
-
|
|
6967
|
-
|
|
6968
|
-
version: 1,
|
|
6969
|
-
loaded: true,
|
|
6970
|
-
settings: { type: "goal", title, locked: false },
|
|
6971
|
-
lights: [],
|
|
7079
|
+
const fontSize = pxToNumber(settings.font_size, 24);
|
|
7080
|
+
const barThickness = pxToNumber(settings.bar_thickness, 48);
|
|
7081
|
+
const layerHeight = Math.max(60, barThickness + 32);
|
|
7082
|
+
const { layer, module } = buildModuleEnvelope({
|
|
7083
|
+
type: "goal",
|
|
7084
|
+
title,
|
|
7085
|
+
bounds: { x: 100, y: 100, width: 740, height: layerHeight },
|
|
6972
7086
|
css: {
|
|
6973
7087
|
fontFamily,
|
|
6974
7088
|
color: textColor,
|
|
6975
|
-
background:
|
|
7089
|
+
background: widgetBgColor,
|
|
7090
|
+
fontSize
|
|
6976
7091
|
},
|
|
7092
|
+
// Use Lumia's canonical goal field names — `targetGoal` (string),
|
|
7093
|
+
// `current` (template string), `display`, `filledColor` /
|
|
7094
|
+
// `unfilledColor`. The prior schema used invented field names
|
|
7095
|
+
// (`goalAmount`, `barColor`) that the renderer ignored.
|
|
6977
7096
|
content: {
|
|
6978
|
-
|
|
6979
|
-
|
|
6980
|
-
|
|
6981
|
-
|
|
6982
|
-
|
|
6983
|
-
|
|
6984
|
-
|
|
6985
|
-
|
|
6986
|
-
|
|
6987
|
-
|
|
6988
|
-
|
|
7097
|
+
version: 1,
|
|
7098
|
+
type: "bar",
|
|
7099
|
+
label: title,
|
|
7100
|
+
subLabel: "",
|
|
7101
|
+
display: "{{current}} / {{goal}}",
|
|
7102
|
+
current: currentAmount > 0 ? String(currentAmount) : currentTemplate,
|
|
7103
|
+
targetGoal: String(goalAmount),
|
|
7104
|
+
image: "",
|
|
7105
|
+
audio: {
|
|
7106
|
+
decrement: "",
|
|
7107
|
+
increment: "",
|
|
7108
|
+
goal: "",
|
|
7109
|
+
goalFailed: "",
|
|
7110
|
+
volume: 1
|
|
7111
|
+
},
|
|
7112
|
+
endDate: endsAt,
|
|
7113
|
+
goalAnimation: "",
|
|
7114
|
+
goalAnimationLoop: true,
|
|
7115
|
+
unfilledColor: barBgColor,
|
|
7116
|
+
filledColor: barColor,
|
|
7117
|
+
alignItemsToEdges: false,
|
|
7118
|
+
border: "solid 1px transparent",
|
|
7119
|
+
borderRadius: "40px",
|
|
7120
|
+
highlightColor: "inherit",
|
|
7121
|
+
importMeta: {
|
|
7122
|
+
source: "streamlabs",
|
|
7123
|
+
widgetType,
|
|
7124
|
+
importedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7125
|
+
goalSource,
|
|
7126
|
+
slLayout: settings.layout ?? null,
|
|
7127
|
+
slBarTextColor: barTextColor,
|
|
7128
|
+
slBarThickness: barThickness,
|
|
7129
|
+
slStartingAmount: startingAmount,
|
|
7130
|
+
slHadCustomHtml: settings.custom_enabled === true
|
|
7131
|
+
}
|
|
7132
|
+
}
|
|
7133
|
+
});
|
|
7134
|
+
return { layer, module, requiresReview };
|
|
7135
|
+
}
|
|
7136
|
+
|
|
7137
|
+
// src/sl-import/mappers/chat-box.ts
|
|
7138
|
+
function buildSitesArray(settings) {
|
|
7139
|
+
const defaultSites = [...CHATBOX_DEFAULT_MODULE.content.sites];
|
|
7140
|
+
const drop = /* @__PURE__ */ new Set();
|
|
7141
|
+
if (settings.show_bttv_emotes === false) drop.add("bttv");
|
|
7142
|
+
if (settings.show_franker_emotes === false) drop.add("ffz");
|
|
7143
|
+
if (settings.show_7tv_emotes === false) drop.add("seventv");
|
|
7144
|
+
if (settings.twitch_enabled === false) drop.add("twitch");
|
|
7145
|
+
if (settings.youtube_enabled === false) drop.add("youtube");
|
|
7146
|
+
if (settings.facebook_enabled === false) drop.add("facebook");
|
|
7147
|
+
if (settings.tiktok_enabled === false) drop.add("tiktok");
|
|
7148
|
+
if (settings.kick_enabled === false) drop.add("kick");
|
|
7149
|
+
if (drop.size === 0) return defaultSites;
|
|
7150
|
+
return defaultSites.filter((s) => !drop.has(s));
|
|
7151
|
+
}
|
|
7152
|
+
function buildSLChatBox(settings) {
|
|
7153
|
+
const requiresReview = settings.custom_enabled === true;
|
|
7154
|
+
const backgroundColor = settings.background_color ?? "transparent";
|
|
7155
|
+
const textColor = settings.text_color ?? "#FFFFFF";
|
|
7156
|
+
const textSize = pxToNumber(settings.text_size, 16);
|
|
7157
|
+
const fadeOutAfterDelay = settings.always_show_messages !== true;
|
|
7158
|
+
const fadeOutDelayTime = fadeOutAfterDelay ? Math.max(1, Math.round((settings.message_hide_delay ?? 15e3) / 1e3)) : 0;
|
|
7159
|
+
const sites = buildSitesArray(settings);
|
|
7160
|
+
const { layer, module } = buildModuleEnvelope({
|
|
7161
|
+
type: "chatbox",
|
|
7162
|
+
title: "Streamlabs Chat Box",
|
|
7163
|
+
bounds: { x: 100, y: 100, width: 375, height: 470 },
|
|
7164
|
+
version: CHATBOX_DEFAULT_MODULE.version,
|
|
7165
|
+
css: {
|
|
7166
|
+
background: backgroundColor,
|
|
7167
|
+
color: textColor,
|
|
7168
|
+
fontSize: textSize
|
|
6989
7169
|
},
|
|
6990
|
-
|
|
6991
|
-
|
|
6992
|
-
|
|
6993
|
-
|
|
7170
|
+
content: {
|
|
7171
|
+
// Spread canonical defaults FIRST so the renderer's dereferences
|
|
7172
|
+
// (chatboxStreamingSite.<platform>.themeConfig, animations,
|
|
7173
|
+
// chatboxStreamingSite.<platform>.message, etc.) all exist.
|
|
7174
|
+
...CHATBOX_DEFAULT_MODULE.content,
|
|
7175
|
+
// Then override the bits SL controls.
|
|
7176
|
+
sites,
|
|
7177
|
+
fadeOutAfterDelay,
|
|
7178
|
+
fadeOutDelayTime,
|
|
7179
|
+
// SL keeps history forever by default — `always_show_messages`
|
|
7180
|
+
// implies the streamer wants a permanent scrollback. Lumia
|
|
7181
|
+
// exposes that as `permanent: true`.
|
|
7182
|
+
permanent: settings.always_show_messages === true,
|
|
7183
|
+
// Preserve the SL-specific provenance for the review step.
|
|
7184
|
+
importMeta: {
|
|
7185
|
+
source: "streamlabs",
|
|
7186
|
+
widgetType: "chat_box",
|
|
7187
|
+
importedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7188
|
+
slTheme: settings.theme ?? null,
|
|
7189
|
+
slHadCustomHtml: settings.custom_enabled === true,
|
|
7190
|
+
slHidesCommonBots: settings.hide_common_chat_bots === true,
|
|
7191
|
+
slHidesCommands: settings.hide_commands === true,
|
|
7192
|
+
slMutedChatters: settings.muted_chatters ?? "",
|
|
7193
|
+
slMessageShowDelayMs: settings.message_show_delay ?? 0
|
|
7194
|
+
}
|
|
7195
|
+
}
|
|
7196
|
+
});
|
|
7197
|
+
return { layer, module, requiresReview };
|
|
7198
|
+
}
|
|
7199
|
+
|
|
7200
|
+
// src/sl-import/mappers/event-list.ts
|
|
7201
|
+
var SL_SHOW_FLAG_TO_LUMIA_FILTER = {
|
|
7202
|
+
show_follows: "follower",
|
|
7203
|
+
show_subscriptions: "subscribers",
|
|
7204
|
+
show_resubs: "subscribers",
|
|
7205
|
+
show_sub_gifts: "gifts",
|
|
7206
|
+
show_subscribers: "subscribers",
|
|
7207
|
+
show_sponsors: "subscribers",
|
|
7208
|
+
// YouTube channel members
|
|
7209
|
+
show_sponsor_gifts: "gifts",
|
|
7210
|
+
show_bits: "bits",
|
|
7211
|
+
show_donations: "donation",
|
|
7212
|
+
show_pledges: "donation",
|
|
7213
|
+
// Patreon
|
|
7214
|
+
show_eldonations: "donation",
|
|
7215
|
+
show_tiltifydonations: "donation",
|
|
7216
|
+
show_donordrivedonations: "donation",
|
|
7217
|
+
show_justgivingdonations: "donation",
|
|
7218
|
+
show_streamlabscharitydonations: "donation",
|
|
7219
|
+
show_twitchcharitydonations: "donation",
|
|
7220
|
+
show_twitch_charity: "donation",
|
|
7221
|
+
show_treats: "donation",
|
|
7222
|
+
// TreatStream
|
|
7223
|
+
show_merch: "purchases",
|
|
7224
|
+
show_raids: "raids",
|
|
7225
|
+
show_hosts: "raids",
|
|
7226
|
+
show_redemptions: "redemption",
|
|
7227
|
+
show_fanfundings: "superchats",
|
|
7228
|
+
// YouTube Super Chat
|
|
7229
|
+
show_super_stickers: "superstickers",
|
|
7230
|
+
show_jewel_gifts: "stars"
|
|
7231
|
+
// TikTok-flavored, closest analogue
|
|
7232
|
+
};
|
|
7233
|
+
function buildFilters(settings) {
|
|
7234
|
+
const drop = /* @__PURE__ */ new Set();
|
|
7235
|
+
for (const [slFlag, lumiaCategory] of Object.entries(SL_SHOW_FLAG_TO_LUMIA_FILTER)) {
|
|
7236
|
+
if (settings[slFlag] === false) {
|
|
7237
|
+
drop.add(lumiaCategory);
|
|
7238
|
+
}
|
|
7239
|
+
}
|
|
7240
|
+
return Array.from(drop);
|
|
7241
|
+
}
|
|
7242
|
+
function buildSLEventList(settings) {
|
|
7243
|
+
const requiresReview = settings.custom_enabled === true;
|
|
7244
|
+
const backgroundColor = settings.background_color ?? "transparent";
|
|
7245
|
+
const textColor = settings.text_color ?? "#FFFFFF";
|
|
7246
|
+
const textSize = pxToNumber(settings.text_size, 16);
|
|
7247
|
+
const fontFamily = settings.font_family ?? "Roboto";
|
|
7248
|
+
const maxEvents = typeof settings.max_events === "number" && settings.max_events > 0 ? settings.max_events : EVENTLIST_DEFAULT_MODULE.content.maxItemsToShow;
|
|
7249
|
+
const enterAnimation = settings.show_animation ?? "fadeIn";
|
|
7250
|
+
const exitAnimation = settings.hide_animation ?? "fadeOut";
|
|
7251
|
+
const animationDuration = typeof settings.animation_speed === "number" ? settings.animation_speed : 1e3;
|
|
7252
|
+
const filters = buildFilters(settings);
|
|
7253
|
+
const { layer, module } = buildModuleEnvelope({
|
|
7254
|
+
type: "eventlist",
|
|
7255
|
+
title: "Streamlabs Event List",
|
|
7256
|
+
bounds: { x: 100, y: 100, width: 375, height: 470 },
|
|
7257
|
+
version: EVENTLIST_DEFAULT_MODULE.version,
|
|
7258
|
+
css: {
|
|
7259
|
+
...EVENTLIST_DEFAULT_MODULE.css,
|
|
7260
|
+
background: backgroundColor,
|
|
7261
|
+
color: textColor,
|
|
7262
|
+
fontSize: textSize,
|
|
7263
|
+
fontFamily
|
|
7264
|
+
},
|
|
7265
|
+
content: {
|
|
7266
|
+
// Spread canonical defaults FIRST so the renderer's dereferences
|
|
7267
|
+
// don't crash on missing nested objects.
|
|
7268
|
+
...EVENTLIST_DEFAULT_MODULE.content,
|
|
7269
|
+
maxItemsToShow: maxEvents,
|
|
7270
|
+
// SL's `flip_y` corresponds to Lumia's `reverse` (newest item
|
|
7271
|
+
// at the bottom vs the top). SL's `flip_x` flips the alignment
|
|
7272
|
+
// to right; Lumia covers that via css.textAlign but doesn't
|
|
7273
|
+
// have a per-module horizontal flip — stash as importMeta for
|
|
7274
|
+
// the review step.
|
|
7275
|
+
reverse: settings.flip_y === true,
|
|
7276
|
+
// SL's `keep_history: false` means events disappear after the
|
|
7277
|
+
// fade time; map to `fadeOutAfterDelay: true` with the fade
|
|
7278
|
+
// time SL configured.
|
|
7279
|
+
fadeOutAfterDelay: settings.keep_history === false,
|
|
7280
|
+
fadeOutDelayTime: typeof settings.fade_time === "number" && settings.fade_time > 0 ? Math.max(1, Math.round(settings.fade_time / 1e3)) : EVENTLIST_DEFAULT_MODULE.content.fadeOutDelayTime,
|
|
7281
|
+
animations: {
|
|
7282
|
+
...EVENTLIST_DEFAULT_MODULE.content.animations,
|
|
7283
|
+
enterAnimation,
|
|
7284
|
+
exitAnimation,
|
|
7285
|
+
enterAnimationDuration: animationDuration,
|
|
7286
|
+
exitAnimationDuration: animationDuration
|
|
7287
|
+
},
|
|
7288
|
+
filters,
|
|
7289
|
+
importMeta: {
|
|
7290
|
+
source: "streamlabs",
|
|
7291
|
+
widgetType: "event_list",
|
|
7292
|
+
importedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7293
|
+
slTheme: settings.theme ?? null,
|
|
7294
|
+
slThemeColor: settings.theme_color ?? null,
|
|
7295
|
+
slFlipX: settings.flip_x === true,
|
|
7296
|
+
slHadCustomHtml: settings.custom_enabled === true,
|
|
7297
|
+
// Per-event-type minimums SL filters by — Lumia's eventlist
|
|
7298
|
+
// has no equivalent thresholding; preserve so the streamer
|
|
7299
|
+
// can recreate via the alert module's variation conditions.
|
|
7300
|
+
slHostViewerMinimum: settings.host_viewer_minimum ?? 0,
|
|
7301
|
+
slBitsMinimum: settings.bits_minimum ?? 0,
|
|
7302
|
+
slRaidRaiderMinimum: settings.raid_raider_minimum ?? 0
|
|
7303
|
+
}
|
|
7304
|
+
}
|
|
7305
|
+
});
|
|
7306
|
+
return { layer, module, requiresReview };
|
|
6994
7307
|
}
|
|
6995
7308
|
|
|
6996
7309
|
// src/sl-import/sl-dispatch.ts
|
|
6997
|
-
|
|
7310
|
+
function buildSLDescription(widgetType, sourceUrl) {
|
|
7311
|
+
return buildImportDescription(`Imported from Streamlabs ${widgetType}`, sourceUrl);
|
|
7312
|
+
}
|
|
6998
7313
|
var GOAL_WIDGET_TYPES = /* @__PURE__ */ new Set([
|
|
6999
7314
|
"follower_goal",
|
|
7000
7315
|
"sub_goal",
|
|
@@ -7002,8 +7317,6 @@ var GOAL_WIDGET_TYPES = /* @__PURE__ */ new Set([
|
|
|
7002
7317
|
"bit_goal"
|
|
7003
7318
|
]);
|
|
7004
7319
|
var PLACEHOLDER_WIDGET_TYPES = /* @__PURE__ */ new Set([
|
|
7005
|
-
"chat_box",
|
|
7006
|
-
"event_list",
|
|
7007
7320
|
"donation_ticker",
|
|
7008
7321
|
"stream_boss",
|
|
7009
7322
|
"credits",
|
|
@@ -7013,8 +7326,6 @@ var PLACEHOLDER_WIDGET_TYPES = /* @__PURE__ */ new Set([
|
|
|
7013
7326
|
"streamlabels"
|
|
7014
7327
|
]);
|
|
7015
7328
|
var PLACEHOLDER_REASONS = {
|
|
7016
|
-
chat_box: "Lumia has a native chatbox module \u2014 set it up directly rather than importing the SL config.",
|
|
7017
|
-
event_list: "Lumia has a native eventlist module \u2014 set it up directly rather than importing the SL config.",
|
|
7018
7329
|
donation_ticker: "No native Lumia equivalent yet \u2014 imported as a placeholder text layer.",
|
|
7019
7330
|
stream_boss: "Lumia has a native streamboss module \u2014 set it up directly rather than importing the SL config.",
|
|
7020
7331
|
credits: "Lumia has a native credits module \u2014 set it up directly rather than importing the SL config.",
|
|
@@ -7023,19 +7334,14 @@ var PLACEHOLDER_REASONS = {
|
|
|
7023
7334
|
sub_train: "No native Lumia equivalent yet \u2014 imported as a placeholder text layer.",
|
|
7024
7335
|
streamlabels: "Use Lumia template variables (e.g. {{twitch_last_follower}}) inside a Text module instead of importing the SL streamlabels config."
|
|
7025
7336
|
};
|
|
7337
|
+
var CUSTOM_HTML_REVIEW_REASON = "The Streamlabs widget used custom HTML/CSS/JS that Lumia cannot host. The native Lumia module is the right starting point \u2014 recreate the styling there. The original SL settings are stashed under module.content.importMeta for reference.";
|
|
7026
7338
|
function stampImportMeta(module, widgetType, role, extra = {}) {
|
|
7027
|
-
|
|
7028
|
-
|
|
7029
|
-
|
|
7030
|
-
|
|
7031
|
-
|
|
7032
|
-
|
|
7033
|
-
role,
|
|
7034
|
-
importedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7035
|
-
...existing,
|
|
7036
|
-
...extra
|
|
7037
|
-
}
|
|
7038
|
-
};
|
|
7339
|
+
stampImportMetaMerge(module, {
|
|
7340
|
+
source: "streamlabs",
|
|
7341
|
+
widgetType,
|
|
7342
|
+
role,
|
|
7343
|
+
...extra
|
|
7344
|
+
});
|
|
7039
7345
|
}
|
|
7040
7346
|
function buildPlaceholder(widgetType) {
|
|
7041
7347
|
const id = nanoid7();
|
|
@@ -7067,7 +7373,7 @@ function buildPlaceholder(widgetType) {
|
|
|
7067
7373
|
};
|
|
7068
7374
|
return { layer, module };
|
|
7069
7375
|
}
|
|
7070
|
-
function importStreamlabsWidget(response, widgetType) {
|
|
7376
|
+
function importStreamlabsWidget(response, widgetType, options = {}) {
|
|
7071
7377
|
if (!isSLWidgetConfigResponse(response)) {
|
|
7072
7378
|
throw new Error(
|
|
7073
7379
|
"Streamlabs response is missing the expected `settings` envelope. The widget may be private or the response format may have changed."
|
|
@@ -7117,9 +7423,61 @@ function importStreamlabsWidget(response, widgetType) {
|
|
|
7117
7423
|
coverage.mappings.push({
|
|
7118
7424
|
seType: `streamlabs:${widgetType}`,
|
|
7119
7425
|
lumiaType: "goal",
|
|
7120
|
-
status: "direct",
|
|
7426
|
+
status: built.requiresReview ? "partial" : "direct",
|
|
7121
7427
|
count: 1
|
|
7122
7428
|
});
|
|
7429
|
+
if (built.requiresReview) {
|
|
7430
|
+
reviewItems.push(
|
|
7431
|
+
customHtmlReviewItem(
|
|
7432
|
+
built.module.id,
|
|
7433
|
+
`streamlabs-${widgetType}`,
|
|
7434
|
+
response.settings,
|
|
7435
|
+
CUSTOM_HTML_REVIEW_REASON
|
|
7436
|
+
)
|
|
7437
|
+
);
|
|
7438
|
+
}
|
|
7439
|
+
} else if (widgetType === "chat_box") {
|
|
7440
|
+
const built = buildSLChatBox(response.settings);
|
|
7441
|
+
stampImportMeta(built.module, widgetType, "chatbox");
|
|
7442
|
+
layers.push(built.layer);
|
|
7443
|
+
modules[built.layer.id] = built.module;
|
|
7444
|
+
coverage.mappings.push({
|
|
7445
|
+
seType: "streamlabs:chat_box",
|
|
7446
|
+
lumiaType: "chatbox",
|
|
7447
|
+
status: built.requiresReview ? "partial" : "direct",
|
|
7448
|
+
count: 1
|
|
7449
|
+
});
|
|
7450
|
+
if (built.requiresReview) {
|
|
7451
|
+
reviewItems.push(
|
|
7452
|
+
customHtmlReviewItem(
|
|
7453
|
+
built.module.id,
|
|
7454
|
+
"streamlabs-chat_box",
|
|
7455
|
+
response.settings,
|
|
7456
|
+
CUSTOM_HTML_REVIEW_REASON
|
|
7457
|
+
)
|
|
7458
|
+
);
|
|
7459
|
+
}
|
|
7460
|
+
} else if (widgetType === "event_list") {
|
|
7461
|
+
const built = buildSLEventList(response.settings);
|
|
7462
|
+
stampImportMeta(built.module, widgetType, "eventlist");
|
|
7463
|
+
layers.push(built.layer);
|
|
7464
|
+
modules[built.layer.id] = built.module;
|
|
7465
|
+
coverage.mappings.push({
|
|
7466
|
+
seType: "streamlabs:event_list",
|
|
7467
|
+
lumiaType: "eventlist",
|
|
7468
|
+
status: built.requiresReview ? "partial" : "direct",
|
|
7469
|
+
count: 1
|
|
7470
|
+
});
|
|
7471
|
+
if (built.requiresReview) {
|
|
7472
|
+
reviewItems.push(
|
|
7473
|
+
customHtmlReviewItem(
|
|
7474
|
+
built.module.id,
|
|
7475
|
+
"streamlabs-event_list",
|
|
7476
|
+
response.settings,
|
|
7477
|
+
CUSTOM_HTML_REVIEW_REASON
|
|
7478
|
+
)
|
|
7479
|
+
);
|
|
7480
|
+
}
|
|
7123
7481
|
} else if (PLACEHOLDER_WIDGET_TYPES.has(widgetType)) {
|
|
7124
7482
|
const placeholder = buildPlaceholder(widgetType);
|
|
7125
7483
|
const reason = PLACEHOLDER_REASONS[widgetType] ?? "No native Lumia mapping yet.";
|
|
@@ -7168,7 +7526,7 @@ function importStreamlabsWidget(response, widgetType) {
|
|
|
7168
7526
|
uuid: "",
|
|
7169
7527
|
listen_id: "",
|
|
7170
7528
|
name: overlayName,
|
|
7171
|
-
description:
|
|
7529
|
+
description: buildSLDescription(widgetType, options.sourceUrl),
|
|
7172
7530
|
settings: {
|
|
7173
7531
|
metadata: { width: 1920, height: 1080 },
|
|
7174
7532
|
layers,
|
|
@@ -8752,7 +9110,12 @@ function SEImportWizard({
|
|
|
8752
9110
|
);
|
|
8753
9111
|
}
|
|
8754
9112
|
importedOverlays.push({
|
|
8755
|
-
result: importSEBootstrap(bootstrap
|
|
9113
|
+
result: importSEBootstrap(bootstrap, {
|
|
9114
|
+
// JWT-flow imports don't come from a pasted URL; synthesize
|
|
9115
|
+
// the SE dashboard URL so the description still carries a
|
|
9116
|
+
// useful traceback. Same shape SE editor links use.
|
|
9117
|
+
sourceUrl: `https://streamelements.com/dashboard/overlays/${overlayId}/editor`
|
|
9118
|
+
}),
|
|
8756
9119
|
summary
|
|
8757
9120
|
});
|
|
8758
9121
|
}
|
|
@@ -8797,7 +9160,9 @@ function SEImportWizard({
|
|
|
8797
9160
|
"StreamElements returned a payload that doesn't look like an overlay bootstrap."
|
|
8798
9161
|
);
|
|
8799
9162
|
}
|
|
8800
|
-
const imported = importSEBootstrap(bootstrap
|
|
9163
|
+
const imported = importSEBootstrap(bootstrap, {
|
|
9164
|
+
sourceUrl: `https://streamelements.com/dashboard/overlays/${overlayId}/editor`
|
|
9165
|
+
});
|
|
8801
9166
|
setBatchImports([{ result: imported, summary }]);
|
|
8802
9167
|
setResult(imported);
|
|
8803
9168
|
setAssetUrls(findSEAssetURLs(imported.overlay));
|
|
@@ -8885,7 +9250,9 @@ function SEImportWizard({
|
|
|
8885
9250
|
"Streamlabs returned a response that does not look like a widget config payload."
|
|
8886
9251
|
);
|
|
8887
9252
|
}
|
|
8888
|
-
const imported = importStreamlabsWidget(raw, slParts.widgetType
|
|
9253
|
+
const imported = importStreamlabsWidget(raw, slParts.widgetType, {
|
|
9254
|
+
sourceUrl: url
|
|
9255
|
+
});
|
|
8889
9256
|
setBatchImports([]);
|
|
8890
9257
|
setResult(imported);
|
|
8891
9258
|
setAssetUrls(findSEAssetURLs(imported.overlay));
|
|
@@ -8926,7 +9293,7 @@ function SEImportWizard({
|
|
|
8926
9293
|
"StreamElements returned a response that does not look like an Element widget payload."
|
|
8927
9294
|
);
|
|
8928
9295
|
}
|
|
8929
|
-
const imported = importElementOverlay(raw);
|
|
9296
|
+
const imported = importElementOverlay(raw, { sourceUrl: url });
|
|
8930
9297
|
setBatchImports([]);
|
|
8931
9298
|
setResult(imported);
|
|
8932
9299
|
setAssetUrls(findSEAssetURLs(imported.overlay));
|
|
@@ -8974,7 +9341,7 @@ function SEImportWizard({
|
|
|
8974
9341
|
...parts,
|
|
8975
9342
|
proxyFetch: bindings.proxyFetch
|
|
8976
9343
|
});
|
|
8977
|
-
const imported = importSEBootstrap(bootstrap);
|
|
9344
|
+
const imported = importSEBootstrap(bootstrap, { sourceUrl: url });
|
|
8978
9345
|
setBatchImports([]);
|
|
8979
9346
|
setResult(imported);
|
|
8980
9347
|
setAssetUrls(findSEAssetURLs(imported.overlay));
|
|
@@ -9633,7 +10000,7 @@ function extractErrorMessage(err) {
|
|
|
9633
10000
|
}
|
|
9634
10001
|
|
|
9635
10002
|
// src/se-import/element-dispatch.ts
|
|
9636
|
-
import {
|
|
10003
|
+
import { LumiaAlertValues as LumiaAlertValues3 } from "@lumiastream/lumia-types";
|
|
9637
10004
|
|
|
9638
10005
|
// src/se-import/element-types.ts
|
|
9639
10006
|
function isSEElementResponse(value) {
|
|
@@ -9877,34 +10244,8 @@ function translateAnimationName(name, fallback) {
|
|
|
9877
10244
|
if (PINNED_ANIMATION_MAP[name]) return PINNED_ANIMATION_MAP[name];
|
|
9878
10245
|
return name.replace(/-([a-z])/g, (_m, c) => c.toUpperCase());
|
|
9879
10246
|
}
|
|
9880
|
-
|
|
9881
|
-
|
|
9882
|
-
if (typeof raw !== "string") return fallbackMs;
|
|
9883
|
-
const trimmed = raw.trim();
|
|
9884
|
-
if (!trimmed) return fallbackMs;
|
|
9885
|
-
if (trimmed.endsWith("ms")) {
|
|
9886
|
-
const n2 = parseFloat(trimmed.slice(0, -2));
|
|
9887
|
-
return Number.isFinite(n2) ? n2 : fallbackMs;
|
|
9888
|
-
}
|
|
9889
|
-
if (trimmed.endsWith("s")) {
|
|
9890
|
-
const n2 = parseFloat(trimmed.slice(0, -1));
|
|
9891
|
-
return Number.isFinite(n2) ? n2 * 1e3 : fallbackMs;
|
|
9892
|
-
}
|
|
9893
|
-
const n = parseFloat(trimmed);
|
|
9894
|
-
return Number.isFinite(n) ? n : fallbackMs;
|
|
9895
|
-
}
|
|
9896
|
-
function parsePx2(raw) {
|
|
9897
|
-
if (typeof raw === "number" && Number.isFinite(raw)) return raw;
|
|
9898
|
-
if (typeof raw !== "string") return NaN;
|
|
9899
|
-
const trimmed = raw.trim();
|
|
9900
|
-
if (!trimmed) return NaN;
|
|
9901
|
-
if (trimmed.endsWith("px")) {
|
|
9902
|
-
const n2 = parseFloat(trimmed.slice(0, -2));
|
|
9903
|
-
return Number.isFinite(n2) ? n2 : NaN;
|
|
9904
|
-
}
|
|
9905
|
-
const n = parseFloat(trimmed);
|
|
9906
|
-
return Number.isFinite(n) ? n : NaN;
|
|
9907
|
-
}
|
|
10247
|
+
var parseAnimationDurationMs = parseDurationMs;
|
|
10248
|
+
var parsePx2 = (raw) => pxToNumber(raw, NaN);
|
|
9908
10249
|
function findFieldByType(fields, type) {
|
|
9909
10250
|
if (!fields) return void 0;
|
|
9910
10251
|
for (const f of Object.values(fields)) {
|
|
@@ -9980,6 +10321,47 @@ function buildAnimations(title) {
|
|
|
9980
10321
|
const visibleDurationMs = enterDelay + enterDuration + staticDuration + exitDuration;
|
|
9981
10322
|
return { animations, visibleDurationMs: visibleDurationMs || DEFAULT_DURATION_MS };
|
|
9982
10323
|
}
|
|
10324
|
+
function resolveFieldBoundsInCanvas(style, canvas, textContent) {
|
|
10325
|
+
if (!style) return null;
|
|
10326
|
+
const x = parsePx2(style.left);
|
|
10327
|
+
const y = parsePx2(style.top);
|
|
10328
|
+
const hasXY = Number.isFinite(x) || Number.isFinite(y);
|
|
10329
|
+
if (!hasXY && style.width == null && style.height == null) return null;
|
|
10330
|
+
const sx = Number.isFinite(x) ? x : 0;
|
|
10331
|
+
const sy = Number.isFinite(y) ? y : 0;
|
|
10332
|
+
let width = parsePx2(style.width);
|
|
10333
|
+
let height = parsePx2(style.height);
|
|
10334
|
+
if (!Number.isFinite(width)) width = Math.max(1, canvas.width - sx);
|
|
10335
|
+
if (!Number.isFinite(height)) {
|
|
10336
|
+
if (typeof textContent === "string") {
|
|
10337
|
+
const lineCount = (textContent.match(/\n/g)?.length ?? 0) + 1;
|
|
10338
|
+
const lhPx = parsePx2(style.lineHeight) || parsePx2(style["line-height"]);
|
|
10339
|
+
const fsPx = parsePx2(style.fontSize);
|
|
10340
|
+
let effectiveLh = lhPx;
|
|
10341
|
+
if (!Number.isFinite(effectiveLh) || effectiveLh < 8) {
|
|
10342
|
+
effectiveLh = Number.isFinite(fsPx) ? fsPx * 1.3 : 24 * 1.3;
|
|
10343
|
+
}
|
|
10344
|
+
height = Math.max(1, lineCount * effectiveLh);
|
|
10345
|
+
} else {
|
|
10346
|
+
height = Math.max(1, canvas.height - sy);
|
|
10347
|
+
}
|
|
10348
|
+
}
|
|
10349
|
+
return { x: sx, y: sy, width, height };
|
|
10350
|
+
}
|
|
10351
|
+
function unionBounds(boxes) {
|
|
10352
|
+
if (boxes.length === 0) return null;
|
|
10353
|
+
let minX = Infinity;
|
|
10354
|
+
let minY = Infinity;
|
|
10355
|
+
let maxX = -Infinity;
|
|
10356
|
+
let maxY = -Infinity;
|
|
10357
|
+
for (const b of boxes) {
|
|
10358
|
+
minX = Math.min(minX, b.x);
|
|
10359
|
+
minY = Math.min(minY, b.y);
|
|
10360
|
+
maxX = Math.max(maxX, b.x + b.width);
|
|
10361
|
+
maxY = Math.max(maxY, b.y + b.height);
|
|
10362
|
+
}
|
|
10363
|
+
return { x: minX, y: minY, width: maxX - minX, height: maxY - minY };
|
|
10364
|
+
}
|
|
9983
10365
|
function buildElementAlertEvent(state, options = {}) {
|
|
9984
10366
|
const compositeFields = state.settings?.compositeFields;
|
|
9985
10367
|
const titleField = findFieldByType(compositeFields, "text");
|
|
@@ -9997,6 +10379,31 @@ function buildElementAlertEvent(state, options = {}) {
|
|
|
9997
10379
|
const titleStyle = titleField?.style;
|
|
9998
10380
|
const highlightColor = titleField?.highlightedStyle?.color ?? null;
|
|
9999
10381
|
const { animations, visibleDurationMs } = buildAnimations(titleField);
|
|
10382
|
+
const canvas = options.canvas ?? { width: 1920, height: 1080 };
|
|
10383
|
+
const mediaBounds = resolveFieldBoundsInCanvas(mainAsset?.style, canvas);
|
|
10384
|
+
const textBounds = resolveFieldBoundsInCanvas(titleStyle, canvas, rawMessage);
|
|
10385
|
+
const collected = [];
|
|
10386
|
+
if (mediaBounds) collected.push(mediaBounds);
|
|
10387
|
+
if (textBounds) collected.push(textBounds);
|
|
10388
|
+
let layerBounds = unionBounds(collected);
|
|
10389
|
+
if (!layerBounds) {
|
|
10390
|
+
layerBounds = {
|
|
10391
|
+
x: Math.round(canvas.width * 0.6),
|
|
10392
|
+
y: Math.round(canvas.height * 0.15),
|
|
10393
|
+
width: 400,
|
|
10394
|
+
height: 300
|
|
10395
|
+
};
|
|
10396
|
+
}
|
|
10397
|
+
let pushTextUp = 0;
|
|
10398
|
+
let pushTextLeft = 0;
|
|
10399
|
+
if (textBounds) {
|
|
10400
|
+
const desiredTextTopInLayer = textBounds.y - layerBounds.y;
|
|
10401
|
+
const naturalTextTopInLayer = Math.max(0, (layerBounds.height - textBounds.height) / 2);
|
|
10402
|
+
pushTextUp = Math.round(desiredTextTopInLayer - naturalTextTopInLayer);
|
|
10403
|
+
const desiredTextLeftInLayer = textBounds.x - layerBounds.x;
|
|
10404
|
+
const naturalTextLeftInLayer = Math.max(0, (layerBounds.width - textBounds.width) / 2);
|
|
10405
|
+
pushTextLeft = Math.round(desiredTextLeftInLayer - naturalTextLeftInLayer);
|
|
10406
|
+
}
|
|
10000
10407
|
const event = {
|
|
10001
10408
|
on: true,
|
|
10002
10409
|
// `'custom'` lowercase is load-bearing in Lumia's AlertBoxHandler —
|
|
@@ -10015,7 +10422,11 @@ function buildElementAlertEvent(state, options = {}) {
|
|
|
10015
10422
|
showBrandIcon: true
|
|
10016
10423
|
},
|
|
10017
10424
|
settings: { duration: visibleDurationMs },
|
|
10018
|
-
|
|
10425
|
+
// `textOver` matches SE Element's text-on-video render pattern.
|
|
10426
|
+
// `imageOver` / `column` / `row` would all stack the text outside
|
|
10427
|
+
// the media, which is the bug this layout fixes (text rendered
|
|
10428
|
+
// below the alert graphic instead of overlaid on it).
|
|
10429
|
+
layout: { value: "textOver", css: {}, customCss: "", pushTextUp, pushTextLeft },
|
|
10019
10430
|
text: {
|
|
10020
10431
|
css: titleCss(titleStyle),
|
|
10021
10432
|
messageCss: {},
|
|
@@ -10037,44 +10448,13 @@ function buildElementAlertEvent(state, options = {}) {
|
|
|
10037
10448
|
},
|
|
10038
10449
|
variations: []
|
|
10039
10450
|
};
|
|
10040
|
-
|
|
10041
|
-
let bounds;
|
|
10042
|
-
if (style) {
|
|
10043
|
-
const x = parsePx2(style.left);
|
|
10044
|
-
const y = parsePx2(style.top);
|
|
10045
|
-
const width = parsePx2(style.width);
|
|
10046
|
-
const height = parsePx2(style.height);
|
|
10047
|
-
if (Number.isFinite(x) && Number.isFinite(y) && Number.isFinite(width)) {
|
|
10048
|
-
bounds = {
|
|
10049
|
-
x,
|
|
10050
|
-
y,
|
|
10051
|
-
width,
|
|
10052
|
-
// Height isn't always present on video Main Assets (the video
|
|
10053
|
-
// aspect-ratios itself from the source). Fall back to a
|
|
10054
|
-
// reasonable default that matches SE's preview row.
|
|
10055
|
-
height: Number.isFinite(height) ? height : Math.round(width * 0.75)
|
|
10056
|
-
};
|
|
10057
|
-
}
|
|
10058
|
-
}
|
|
10059
|
-
return { event, bounds };
|
|
10451
|
+
return { event, bounds: layerBounds };
|
|
10060
10452
|
}
|
|
10061
10453
|
|
|
10062
10454
|
// src/se-import/mappers/element-scene.ts
|
|
10063
|
-
import { nanoid as nanoid8 } from "nanoid";
|
|
10064
10455
|
var TEXT_FALLBACK = { width: 400, height: 50 };
|
|
10065
10456
|
var IMAGE_FALLBACK = { width: 300, height: 100 };
|
|
10066
|
-
|
|
10067
|
-
if (typeof raw === "number" && Number.isFinite(raw)) return raw;
|
|
10068
|
-
if (typeof raw !== "string") return NaN;
|
|
10069
|
-
const trimmed = raw.trim();
|
|
10070
|
-
if (!trimmed) return NaN;
|
|
10071
|
-
if (trimmed.endsWith("px")) {
|
|
10072
|
-
const n2 = parseFloat(trimmed.slice(0, -2));
|
|
10073
|
-
return Number.isFinite(n2) ? n2 : NaN;
|
|
10074
|
-
}
|
|
10075
|
-
const n = parseFloat(trimmed);
|
|
10076
|
-
return Number.isFinite(n) ? n : NaN;
|
|
10077
|
-
}
|
|
10457
|
+
var parsePx3 = (raw) => pxToNumber(raw, NaN);
|
|
10078
10458
|
function styleToBounds(style, type, canvas) {
|
|
10079
10459
|
const x = Number.isFinite(parsePx3(style?.left)) ? parsePx3(style?.left) : 0;
|
|
10080
10460
|
const y = Number.isFinite(parsePx3(style?.top)) ? parsePx3(style?.top) : 0;
|
|
@@ -10110,33 +10490,17 @@ function styleToBounds(style, type, canvas) {
|
|
|
10110
10490
|
}
|
|
10111
10491
|
return { x, y, width, height };
|
|
10112
10492
|
}
|
|
10113
|
-
function
|
|
10114
|
-
|
|
10115
|
-
|
|
10116
|
-
|
|
10117
|
-
|
|
10118
|
-
bounds: {
|
|
10119
|
-
x: bounds.x,
|
|
10120
|
-
y: bounds.y,
|
|
10121
|
-
width: bounds.width,
|
|
10122
|
-
height: bounds.height,
|
|
10123
|
-
scale: [1, 1],
|
|
10124
|
-
zIndex
|
|
10125
|
-
}
|
|
10126
|
-
};
|
|
10127
|
-
}
|
|
10128
|
-
function buildModule(id, type, title, content, css = {}) {
|
|
10129
|
-
return {
|
|
10130
|
-
id,
|
|
10131
|
-
version: 1,
|
|
10132
|
-
loaded: true,
|
|
10133
|
-
settings: { type, title, locked: false },
|
|
10134
|
-
lights: [],
|
|
10135
|
-
css,
|
|
10493
|
+
function buildChild(groupId, zIndex, bounds, type, title, content, css = {}) {
|
|
10494
|
+
const { layer, module } = buildModuleEnvelope({
|
|
10495
|
+
type,
|
|
10496
|
+
title,
|
|
10497
|
+
bounds,
|
|
10136
10498
|
content,
|
|
10137
|
-
|
|
10138
|
-
|
|
10139
|
-
|
|
10499
|
+
css,
|
|
10500
|
+
parentGroupId: groupId,
|
|
10501
|
+
zIndex
|
|
10502
|
+
});
|
|
10503
|
+
return { layer, module };
|
|
10140
10504
|
}
|
|
10141
10505
|
function textStyleToCss(style) {
|
|
10142
10506
|
const s = style ?? {};
|
|
@@ -10151,80 +10515,69 @@ function textStyleToCss(style) {
|
|
|
10151
10515
|
return out;
|
|
10152
10516
|
}
|
|
10153
10517
|
function mapCompositeField(name, field, groupId, zIndex, provider, canvas) {
|
|
10154
|
-
const id = nanoid8();
|
|
10155
10518
|
switch (field.type) {
|
|
10156
10519
|
case "video": {
|
|
10157
|
-
const bounds = styleToBounds(field.style, "video", canvas);
|
|
10158
|
-
const layer = buildLayer(id, groupId, bounds, zIndex);
|
|
10159
10520
|
const src = pickFieldMediaHref(field.media, "video/");
|
|
10160
10521
|
const volume = typeof field.volume === "number" ? field.volume : 1;
|
|
10161
|
-
|
|
10162
|
-
|
|
10163
|
-
|
|
10164
|
-
|
|
10165
|
-
|
|
10166
|
-
|
|
10167
|
-
|
|
10168
|
-
|
|
10522
|
+
return buildChild(
|
|
10523
|
+
groupId,
|
|
10524
|
+
zIndex,
|
|
10525
|
+
styleToBounds(field.style, "video", canvas),
|
|
10526
|
+
"video",
|
|
10527
|
+
name,
|
|
10528
|
+
{ src, volume, loop: true, autoplay: true, muted: volume === 0 }
|
|
10529
|
+
);
|
|
10169
10530
|
}
|
|
10170
10531
|
case "image": {
|
|
10171
|
-
const bounds = styleToBounds(field.style, "image", canvas);
|
|
10172
|
-
const layer = buildLayer(id, groupId, bounds, zIndex);
|
|
10173
10532
|
const src = pickFieldMediaHref(field.media, "image/");
|
|
10174
|
-
|
|
10175
|
-
|
|
10533
|
+
return buildChild(
|
|
10534
|
+
groupId,
|
|
10535
|
+
zIndex,
|
|
10536
|
+
styleToBounds(field.style, "image", canvas),
|
|
10537
|
+
"image",
|
|
10538
|
+
name,
|
|
10539
|
+
{ src }
|
|
10540
|
+
);
|
|
10176
10541
|
}
|
|
10177
10542
|
case "text": {
|
|
10178
|
-
const bounds = styleToBounds(field.style, "text", canvas);
|
|
10179
|
-
const layer = buildLayer(id, groupId, bounds, zIndex);
|
|
10180
10543
|
const raw = field.text?.[0]?.content ?? "";
|
|
10181
10544
|
const value = substituteElementTokens(raw, { provider });
|
|
10182
|
-
|
|
10183
|
-
|
|
10545
|
+
return buildChild(
|
|
10546
|
+
groupId,
|
|
10547
|
+
zIndex,
|
|
10548
|
+
styleToBounds(field.style, "text", canvas),
|
|
10184
10549
|
"text",
|
|
10185
10550
|
name,
|
|
10186
10551
|
{ value, highlightColor: "inherit" },
|
|
10187
10552
|
textStyleToCss(field.style)
|
|
10188
10553
|
);
|
|
10189
|
-
return { layer, module };
|
|
10190
10554
|
}
|
|
10191
10555
|
case "audio": {
|
|
10192
|
-
const layer = buildLayer(id, groupId, { x: 0, y: 0, width: 1, height: 1 }, zIndex);
|
|
10193
10556
|
const src = pickFieldMediaHref(field.media, "audio/");
|
|
10194
10557
|
const volume = typeof field.volume === "number" ? field.volume : 0.5;
|
|
10195
|
-
|
|
10196
|
-
|
|
10558
|
+
return buildChild(
|
|
10559
|
+
groupId,
|
|
10560
|
+
zIndex,
|
|
10561
|
+
{ x: 0, y: 0, width: 1, height: 1 },
|
|
10562
|
+
"audio",
|
|
10563
|
+
name,
|
|
10564
|
+
{ src, volume, loop: false }
|
|
10565
|
+
);
|
|
10197
10566
|
}
|
|
10198
10567
|
default:
|
|
10199
10568
|
return null;
|
|
10200
10569
|
}
|
|
10201
10570
|
}
|
|
10202
10571
|
function buildElementScene(state, options) {
|
|
10203
|
-
const groupId = nanoid8();
|
|
10204
10572
|
const groupTitle = typeof state.displayName === "string" && state.displayName || state.referenceId || "Scene";
|
|
10205
|
-
const groupLayer = {
|
|
10206
|
-
id: groupId,
|
|
10573
|
+
const { id: groupId, layer: groupLayer, module: groupModule } = buildModuleEnvelope({
|
|
10207
10574
|
type: "group",
|
|
10208
|
-
|
|
10209
|
-
bounds: {
|
|
10210
|
-
|
|
10211
|
-
|
|
10212
|
-
|
|
10213
|
-
|
|
10214
|
-
scale: [1, 1]
|
|
10215
|
-
},
|
|
10216
|
-
state: { visible: true, locked: false, expanded: false }
|
|
10217
|
-
};
|
|
10218
|
-
const groupModule = {
|
|
10219
|
-
id: groupId,
|
|
10220
|
-
loaded: true,
|
|
10221
|
-
settings: { type: "group", title: groupTitle },
|
|
10222
|
-
lights: [],
|
|
10223
|
-
css: {},
|
|
10224
|
-
content: {},
|
|
10225
|
-
variables: {},
|
|
10226
|
-
events: {}
|
|
10227
|
-
};
|
|
10575
|
+
title: groupTitle,
|
|
10576
|
+
bounds: { x: 0, y: 0, width: options.canvas.width, height: options.canvas.height },
|
|
10577
|
+
type_layer: "group",
|
|
10578
|
+
parentGroupId: null,
|
|
10579
|
+
expanded: false
|
|
10580
|
+
});
|
|
10228
10581
|
const children = [];
|
|
10229
10582
|
const fields = state.settings?.compositeFields ?? {};
|
|
10230
10583
|
let zIndex = 1;
|
|
@@ -10243,7 +10596,12 @@ function buildElementScene(state, options) {
|
|
|
10243
10596
|
}
|
|
10244
10597
|
|
|
10245
10598
|
// src/se-import/element-dispatch.ts
|
|
10246
|
-
|
|
10599
|
+
function buildElementDescription(widgetInstanceId, sourceUrl) {
|
|
10600
|
+
return buildImportDescription(
|
|
10601
|
+
`Imported from StreamElements Element widget ${widgetInstanceId}`,
|
|
10602
|
+
sourceUrl
|
|
10603
|
+
);
|
|
10604
|
+
}
|
|
10247
10605
|
function elementAlertKindToLumiaKeys(kind, provider) {
|
|
10248
10606
|
switch (kind) {
|
|
10249
10607
|
case "follower":
|
|
@@ -10262,9 +10620,9 @@ function elementAlertKindToLumiaKeys(kind, provider) {
|
|
|
10262
10620
|
return alertBoxKeysFor("charityCampaignDonation", provider);
|
|
10263
10621
|
case "subscriberGift":
|
|
10264
10622
|
case "communityGiftPurchase": {
|
|
10265
|
-
if (provider === "twitch") return [
|
|
10266
|
-
if (provider === "kick") return [
|
|
10267
|
-
if (provider === "youtube") return [
|
|
10623
|
+
if (provider === "twitch") return [LumiaAlertValues3.TWITCH_GIFT_SUBSCRIPTION];
|
|
10624
|
+
if (provider === "kick") return [LumiaAlertValues3.KICK_GIFT_SUBSCRIPTION];
|
|
10625
|
+
if (provider === "youtube") return [LumiaAlertValues3.YOUTUBE_GIFT_MEMBERS];
|
|
10268
10626
|
return alertBoxKeysFor("subscriber", provider);
|
|
10269
10627
|
}
|
|
10270
10628
|
default:
|
|
@@ -10279,7 +10637,7 @@ function buildCombinedAlertModule(alertStates, provider, canvas) {
|
|
|
10279
10637
|
for (const state of alertStates) {
|
|
10280
10638
|
const cls = classifyConfigState(state);
|
|
10281
10639
|
if (cls.kind !== "alert") continue;
|
|
10282
|
-
const { event, bounds: bounds2 } = buildElementAlertEvent(state, { provider });
|
|
10640
|
+
const { event, bounds: bounds2 } = buildElementAlertEvent(state, { provider, canvas });
|
|
10283
10641
|
const keys = elementAlertKindToLumiaKeys(cls.alertKind, provider);
|
|
10284
10642
|
if (keys.length === 0) continue;
|
|
10285
10643
|
for (const key of keys) {
|
|
@@ -10291,61 +10649,42 @@ function buildCombinedAlertModule(alertStates, provider, canvas) {
|
|
|
10291
10649
|
}
|
|
10292
10650
|
}
|
|
10293
10651
|
if (Object.keys(events).length === 0) return null;
|
|
10294
|
-
const id = nanoid9();
|
|
10295
10652
|
const bounds = firstBounds ?? {
|
|
10296
10653
|
x: Math.round(canvas.width * 0.6),
|
|
10297
10654
|
y: Math.round(canvas.height * 0.15),
|
|
10298
10655
|
width: 400,
|
|
10299
10656
|
height: 300
|
|
10300
10657
|
};
|
|
10301
|
-
const layer = {
|
|
10302
|
-
id,
|
|
10303
|
-
state: { visible: true, locked: false },
|
|
10304
|
-
bounds: {
|
|
10305
|
-
x: bounds.x,
|
|
10306
|
-
y: bounds.y,
|
|
10307
|
-
width: bounds.width,
|
|
10308
|
-
height: bounds.height,
|
|
10309
|
-
scale: [1, 1]
|
|
10310
|
-
}
|
|
10311
|
-
};
|
|
10312
10658
|
const baseAlert = firstEvent ? stripEventOnlyFields2(firstEvent) : {};
|
|
10313
|
-
const module = {
|
|
10314
|
-
|
|
10315
|
-
|
|
10316
|
-
|
|
10317
|
-
settings: { type: "alert", title: "Alerts (Element import)", locked: false },
|
|
10318
|
-
lights: [],
|
|
10319
|
-
css: {},
|
|
10320
|
-
content: {},
|
|
10321
|
-
variables: {},
|
|
10322
|
-
events: {},
|
|
10659
|
+
const { layer, module } = buildModuleEnvelope({
|
|
10660
|
+
type: "alert",
|
|
10661
|
+
title: "Alerts (Element import)",
|
|
10662
|
+
bounds,
|
|
10323
10663
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
10324
10664
|
alert: { ...baseAlert, events }
|
|
10325
|
-
};
|
|
10665
|
+
});
|
|
10326
10666
|
return { layer, module };
|
|
10327
10667
|
}
|
|
10328
10668
|
function stripEventOnlyFields2(event) {
|
|
10329
|
-
const {
|
|
10669
|
+
const {
|
|
10670
|
+
on: _on,
|
|
10671
|
+
variations: _variations,
|
|
10672
|
+
matchEmptyCondition: _mec,
|
|
10673
|
+
...base
|
|
10674
|
+
} = event;
|
|
10330
10675
|
return base;
|
|
10331
10676
|
}
|
|
10332
10677
|
function stampImportMeta2(module, state, role) {
|
|
10333
|
-
module
|
|
10334
|
-
|
|
10335
|
-
|
|
10336
|
-
|
|
10337
|
-
|
|
10338
|
-
|
|
10339
|
-
|
|
10340
|
-
displayName: state?.displayName,
|
|
10341
|
-
importedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
10342
|
-
}
|
|
10343
|
-
};
|
|
10678
|
+
stampImportMetaMerge(module, {
|
|
10679
|
+
source: "streamelements-element",
|
|
10680
|
+
role,
|
|
10681
|
+
referenceId: state?.referenceId,
|
|
10682
|
+
categoryId: state?.categoryId,
|
|
10683
|
+
displayName: state?.displayName
|
|
10684
|
+
});
|
|
10344
10685
|
}
|
|
10345
|
-
function importElementOverlay(response) {
|
|
10346
|
-
const configData = parseElementConfigData(
|
|
10347
|
-
response.widgetInstanceConfigVersion.configData
|
|
10348
|
-
);
|
|
10686
|
+
function importElementOverlay(response, options = {}) {
|
|
10687
|
+
const configData = parseElementConfigData(response.widgetInstanceConfigVersion.configData);
|
|
10349
10688
|
if (!configData) {
|
|
10350
10689
|
throw new Error(
|
|
10351
10690
|
"StreamElements Element response carries an invalid configData payload. The widget may be corrupted or the response format may have changed."
|
|
@@ -10415,7 +10754,10 @@ function importElementOverlay(response) {
|
|
|
10415
10754
|
uuid: "",
|
|
10416
10755
|
listen_id: "",
|
|
10417
10756
|
name: response.widgetInstance.displayName ? `[SE Element] ${response.widgetInstance.displayName}` : `Imported from StreamElements Element (${response.widgetInstance.widgetInstanceId})`,
|
|
10418
|
-
description:
|
|
10757
|
+
description: buildElementDescription(
|
|
10758
|
+
response.widgetInstance.widgetInstanceId,
|
|
10759
|
+
options.sourceUrl
|
|
10760
|
+
),
|
|
10419
10761
|
settings: {
|
|
10420
10762
|
metadata: { width: canvas.width, height: canvas.height },
|
|
10421
10763
|
layers,
|
|
@@ -10429,7 +10771,7 @@ function importElementOverlay(response) {
|
|
|
10429
10771
|
}
|
|
10430
10772
|
|
|
10431
10773
|
// src/se-import/index.ts
|
|
10432
|
-
var
|
|
10774
|
+
var IMPORT_META_KEY2 = "importMeta";
|
|
10433
10775
|
var REVIEW_REASONS = {
|
|
10434
10776
|
"se-widget-bit-boss": "No native Lumia equivalent \u2014 bit boss fight bar with HP/damage states.",
|
|
10435
10777
|
// `se-widget-hype-cup` intentionally omitted — it now routes to the native
|
|
@@ -10459,6 +10801,10 @@ function reasonFor(seType, status, flaggedOff) {
|
|
|
10459
10801
|
if (flaggedOff && FLAG_OFF_REASONS[seType]) return FLAG_OFF_REASONS[seType];
|
|
10460
10802
|
return REVIEW_REASONS[seType] ?? (status === "template" ? "Imported as a generic template stub." : "No native mapping yet \u2014 imported as a labelled text placeholder.");
|
|
10461
10803
|
}
|
|
10804
|
+
function buildSEBootstrapDescription(overlayId, sourceUrl) {
|
|
10805
|
+
const head = overlayId ? `Imported from StreamElements overlay ${overlayId}` : "Imported from StreamElements";
|
|
10806
|
+
return buildImportDescription(head, sourceUrl);
|
|
10807
|
+
}
|
|
10462
10808
|
function extractSEOverlayId(input) {
|
|
10463
10809
|
const trimmed = input.trim();
|
|
10464
10810
|
const m = trimmed.match(/[0-9a-f]{24}/i);
|
|
@@ -10513,7 +10859,7 @@ function isSEBootstrap(value) {
|
|
|
10513
10859
|
const o = v.overlay;
|
|
10514
10860
|
return Array.isArray(o.widgets);
|
|
10515
10861
|
}
|
|
10516
|
-
function importSEBootstrap(bootstrap) {
|
|
10862
|
+
function importSEBootstrap(bootstrap, options = {}) {
|
|
10517
10863
|
const seOverlay = bootstrap.overlay;
|
|
10518
10864
|
const widgets = seOverlay?.widgets ?? [];
|
|
10519
10865
|
const coverage = {
|
|
@@ -10536,7 +10882,7 @@ function importSEBootstrap(bootstrap) {
|
|
|
10536
10882
|
if (w.type !== "se-widget-group") continue;
|
|
10537
10883
|
const uid = w.variables?.uid;
|
|
10538
10884
|
if (typeof uid !== "string") continue;
|
|
10539
|
-
const lumiaGroupId =
|
|
10885
|
+
const lumiaGroupId = nanoid8();
|
|
10540
10886
|
seUidToLumiaGroupId[uid] = lumiaGroupId;
|
|
10541
10887
|
groupWidgetByUid[uid] = w;
|
|
10542
10888
|
}
|
|
@@ -10575,7 +10921,7 @@ function importSEBootstrap(bootstrap) {
|
|
|
10575
10921
|
lights: [],
|
|
10576
10922
|
css: {},
|
|
10577
10923
|
content: {
|
|
10578
|
-
[
|
|
10924
|
+
[IMPORT_META_KEY2]: {
|
|
10579
10925
|
source: "streamelements",
|
|
10580
10926
|
widgetType: w.type,
|
|
10581
10927
|
importedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -10613,7 +10959,7 @@ function importSEBootstrap(bootstrap) {
|
|
|
10613
10959
|
if (result.status === "placeholder" || result.status === "template") {
|
|
10614
10960
|
module.content = {
|
|
10615
10961
|
...module.content ?? {},
|
|
10616
|
-
[
|
|
10962
|
+
[IMPORT_META_KEY2]: {
|
|
10617
10963
|
source: "streamelements",
|
|
10618
10964
|
widgetType: w.type,
|
|
10619
10965
|
importedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -10653,7 +10999,7 @@ function importSEBootstrap(bootstrap) {
|
|
|
10653
10999
|
uuid: "",
|
|
10654
11000
|
listen_id: "",
|
|
10655
11001
|
name: seOverlay?.name ? `[SE] ${seOverlay.name}` : `Imported from StreamElements (${seOverlay?._id ?? ""})`,
|
|
10656
|
-
description: seOverlay?._id
|
|
11002
|
+
description: buildSEBootstrapDescription(seOverlay?._id, options.sourceUrl),
|
|
10657
11003
|
settings: {
|
|
10658
11004
|
metadata: {
|
|
10659
11005
|
width: seOverlay?.settings?.width ?? 1920,
|
|
@@ -10701,7 +11047,7 @@ function applyReviewAction(result, moduleId, action, payload) {
|
|
|
10701
11047
|
bounds: existingLayer.bounds,
|
|
10702
11048
|
state: existingLayer.state
|
|
10703
11049
|
};
|
|
10704
|
-
const importMeta2 = existing2.content?.[
|
|
11050
|
+
const importMeta2 = existing2.content?.[IMPORT_META_KEY2];
|
|
10705
11051
|
const mergedLights = (existing2.lights?.length ?? 0) > 0 ? existing2.lights : transplant.module.lights;
|
|
10706
11052
|
const mergedEvents = existing2.events && Object.keys(existing2.events).length > 0 ? { ...transplant.module.events, ...existing2.events } : transplant.module.events;
|
|
10707
11053
|
const mergedVariables = existing2.variables && Object.keys(existing2.variables).length > 0 ? { ...transplant.module.variables, ...existing2.variables } : transplant.module.variables;
|
|
@@ -10713,7 +11059,7 @@ function applyReviewAction(result, moduleId, action, payload) {
|
|
|
10713
11059
|
variables: mergedVariables,
|
|
10714
11060
|
content: {
|
|
10715
11061
|
...transplant.module.content ?? {},
|
|
10716
|
-
[
|
|
11062
|
+
[IMPORT_META_KEY2]: importMeta2
|
|
10717
11063
|
}
|
|
10718
11064
|
};
|
|
10719
11065
|
const rootOldNewId = transplant.layer.id;
|
|
@@ -10741,7 +11087,7 @@ function applyReviewAction(result, moduleId, action, payload) {
|
|
|
10741
11087
|
const existing = modules[moduleId];
|
|
10742
11088
|
const generated = payload;
|
|
10743
11089
|
if (!existing || !generated) return result;
|
|
10744
|
-
const importMeta = existing.content?.[
|
|
11090
|
+
const importMeta = existing.content?.[IMPORT_META_KEY2];
|
|
10745
11091
|
const replaced = {
|
|
10746
11092
|
...existing,
|
|
10747
11093
|
settings: { ...existing.settings ?? {}, type: "custom" },
|
|
@@ -10755,7 +11101,7 @@ function applyReviewAction(result, moduleId, action, payload) {
|
|
|
10755
11101
|
data: parseLooseJson(generated.data) ?? {},
|
|
10756
11102
|
configs: parseLooseJson(generated.configs) ?? [],
|
|
10757
11103
|
flavor: "ai-generated",
|
|
10758
|
-
[
|
|
11104
|
+
[IMPORT_META_KEY2]: importMeta
|
|
10759
11105
|
}
|
|
10760
11106
|
};
|
|
10761
11107
|
modules[moduleId] = replaced;
|