@lumiastream/ui 0.7.0 → 0.7.3

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/index.js CHANGED
@@ -5261,7 +5261,8 @@ var TIPJAR_DEFAULT_CONTENT_FIELDS = {
5261
5261
  chat: false
5262
5262
  },
5263
5263
  chat: {
5264
- useViewerAvatars: true
5264
+ useViewerAvatars: true,
5265
+ useChatEmotes: false
5265
5266
  },
5266
5267
  display: {
5267
5268
  showEventMessages: false,
@@ -5505,7 +5506,7 @@ var SE_LISTENER_TO_LUMIA_CATEGORY = {
5505
5506
  "superchat-recent": "superchats",
5506
5507
  "hypetrain-latest": "hypetrain"
5507
5508
  };
5508
- function computeAllowedEventsFromSEListeners(seListeners, explicitListener) {
5509
+ function collectEnabledSEListeners(seListeners, explicitListener) {
5509
5510
  const enabled = [];
5510
5511
  if (seListeners && typeof seListeners === "object" && !Array.isArray(seListeners)) {
5511
5512
  for (const [k, v] of Object.entries(seListeners)) {
@@ -5517,6 +5518,19 @@ function computeAllowedEventsFromSEListeners(seListeners, explicitListener) {
5517
5518
  if (typeof explicitListener === "string" && explicitListener && !enabled.includes(explicitListener)) {
5518
5519
  enabled.push(explicitListener);
5519
5520
  }
5521
+ return enabled;
5522
+ }
5523
+ function seWidgetIsCheer(widget) {
5524
+ if (typeof widget.type === "string" && widget.type.includes("cheer")) return true;
5525
+ const listeners = collectEnabledSEListeners(widget.listeners, widget.listener);
5526
+ const fromVars = widget.variables?.listener;
5527
+ if (typeof fromVars === "string" && fromVars) listeners.push(fromVars);
5528
+ return listeners.some(
5529
+ (listener) => SE_LISTENER_TO_LUMIA_CATEGORY[listener] === LumiaEventListTypes.BITS
5530
+ );
5531
+ }
5532
+ function computeAllowedEventsFromSEListeners(seListeners, explicitListener) {
5533
+ const enabled = collectEnabledSEListeners(seListeners, explicitListener);
5520
5534
  if (enabled.length === 0) return void 0;
5521
5535
  const allowedCategories = /* @__PURE__ */ new Set();
5522
5536
  for (const listener of enabled) {
@@ -5542,6 +5556,15 @@ function seTemplateToMarqueeTemplate(seTemplate) {
5542
5556
  if (typeof seTemplate !== "string" || !seTemplate.trim()) return void 0;
5543
5557
  return translateSeText(seTemplate);
5544
5558
  }
5559
+ function ensureCheermoteTemplate(template) {
5560
+ const fallback = "{{username}}: {{cheermote}}{{amount}} ";
5561
+ if (!template || !template.trim()) return fallback;
5562
+ if (template.includes("{{cheermote}}")) return template;
5563
+ if (template.includes("{{amount}}")) {
5564
+ return template.replace("{{amount}}", "{{cheermote}}{{amount}}");
5565
+ }
5566
+ return `${template.replace(/\s+$/, "")} {{cheermote}}{{amount}} `;
5567
+ }
5545
5568
  function mapEventList(widget, ctx) {
5546
5569
  const v = widget.variables ?? {};
5547
5570
  const allowedEvents = computeAllowedEventsFromSEListeners(widget.listeners, widget.listener);
@@ -5549,7 +5572,9 @@ function mapEventList(widget, ctx) {
5549
5572
  const seText = widget.text;
5550
5573
  const scrolling = seText?.scrolling;
5551
5574
  const isMarquee = !!(scrolling && scrolling.enabled === true);
5552
- const itemTemplate = isMarquee ? seTemplateToMarqueeTemplate(seText?.value) : void 0;
5575
+ const isCheerMarquee = isMarquee && seWidgetIsCheer(widget);
5576
+ const baseItemTemplate = isMarquee ? seTemplateToMarqueeTemplate(seText?.value) : void 0;
5577
+ const itemTemplate = isCheerMarquee ? ensureCheermoteTemplate(baseItemTemplate) : baseItemTemplate;
5553
5578
  const marqueeSpeed = isMarquee ? seScrollSpeedToPixelsPerSecond(scrolling?.speed) : void 0;
5554
5579
  const marqueeDirection = isMarquee ? scrolling?.direction === "right" ? "right" : "left" : void 0;
5555
5580
  const theme = isMarquee ? "marquee" : v.theme ?? "simple";
@@ -6556,36 +6581,61 @@ function mapUnsupportedAsText(widget, ctx) {
6556
6581
  var SE_TYPE_TO_CATEGORY = {
6557
6582
  cheer: "bits",
6558
6583
  sub: "subs",
6584
+ subscriber: "subs",
6559
6585
  follower: "follows",
6560
6586
  raid: "raids",
6561
6587
  tip: "tips"
6562
6588
  };
6589
+ function isUnsupportedSETipVariation(seKey, variation) {
6590
+ return seKey === "tip" && variation.condition === "EXACT" && variation.amount === 4.2;
6591
+ }
6592
+ function isSubscriberGiftVariation(seKey, variation) {
6593
+ if (seKey !== "sub" && seKey !== "subscriber") return false;
6594
+ const condition = typeof variation.condition === "string" ? variation.condition.toUpperCase() : "";
6595
+ const name = typeof variation.name === "string" ? variation.name.toLowerCase() : "";
6596
+ return condition === "GIFT" || name.includes("gift");
6597
+ }
6598
+ function categoryForSEVariation(seKey, variation) {
6599
+ if (isSubscriberGiftVariation(seKey, variation)) return "gifts";
6600
+ return SE_TYPE_TO_CATEGORY[seKey];
6601
+ }
6563
6602
  function liftSESpritesIntoTiers(types) {
6564
6603
  const out = {};
6565
- if (!types) return out;
6604
+ if (!types) {
6605
+ return out;
6606
+ }
6566
6607
  for (const [seKey, block] of Object.entries(types)) {
6567
- const cat = SE_TYPE_TO_CATEGORY[seKey];
6568
- if (!cat) continue;
6608
+ if (!SE_TYPE_TO_CATEGORY[seKey]) {
6609
+ continue;
6610
+ }
6611
+ if (seKey === "cheer") {
6612
+ continue;
6613
+ }
6569
6614
  const variations = block?.variations ?? [];
6570
6615
  const usable = variations.filter(
6571
- (v) => typeof (v?.preview ?? v?.src) === "string" && (v.preview ?? v.src ?? "").length > 0
6616
+ (v) => !isUnsupportedSETipVariation(seKey, v) && typeof (v?.preview ?? v?.src) === "string" && (v.preview ?? v.src ?? "").length > 0
6572
6617
  );
6573
- const flagged = usable.filter((v) => v.default === true);
6574
- const picked = flagged.length > 0 ? flagged : usable;
6575
- const seenAmounts = /* @__PURE__ */ new Set();
6576
- const tiers = [];
6577
- for (const v of picked) {
6618
+ for (const v of usable) {
6619
+ const cat = categoryForSEVariation(seKey, v);
6620
+ if (!cat) continue;
6578
6621
  const amount = typeof v.amount === "number" && v.amount > 0 ? v.amount : 1;
6579
- if (seenAmounts.has(amount)) continue;
6580
- seenAmounts.add(amount);
6581
- tiers.push({
6622
+ const isSpritesheet = v.isSpritesheet === true || v.srcType === "spritesheet";
6623
+ const frameWidth = typeof v.frames?.[0] === "number" && v.frames[0] > 0 ? v.frames[0] : void 0;
6624
+ const frameHeight = typeof v.frames?.[1] === "number" && v.frames[1] > 0 ? v.frames[1] : void 0;
6625
+ const frameCount = typeof v.frames?.[2] === "number" && v.frames[2] > 0 ? v.frames[2] : void 0;
6626
+ const tier = {
6627
+ ...typeof v.name === "string" && v.name.length > 0 ? { name: v.name } : {},
6582
6628
  minAmount: amount,
6583
- imageUrl: v.preview ?? v.src,
6584
- scale: typeof v.cheerSize === "number" && v.cheerSize > 0 ? v.cheerSize : 1
6585
- });
6629
+ imageUrl: isSpritesheet ? v.src : v.preview ?? v.src,
6630
+ scale: typeof v.cheerSize === "number" && v.cheerSize > 0 ? v.cheerSize : 1,
6631
+ ...v.condition === "EXACT" || v.condition === "ATLEAST" ? { condition: v.condition } : {},
6632
+ ...isSpritesheet && frameWidth && frameHeight && frameCount ? { useSpritesheet: true, frameWidth, frameHeight, frameCount } : {}
6633
+ };
6634
+ out[cat] = [...out[cat] ?? [], tier];
6586
6635
  }
6636
+ }
6637
+ for (const tiers of Object.values(out)) {
6587
6638
  tiers.sort((a, b) => a.minAmount - b.minAmount);
6588
- if (tiers.length > 0) out[cat] = tiers;
6589
6639
  }
6590
6640
  return out;
6591
6641
  }
@@ -6612,15 +6662,30 @@ function categoriesFromListeners(listeners) {
6612
6662
  redemptions: false,
6613
6663
  chat: false
6614
6664
  };
6615
- if (!listeners) return events;
6665
+ if (!listeners) {
6666
+ return events;
6667
+ }
6616
6668
  const onListeners = Array.isArray(listeners) ? listeners : Object.entries(listeners).filter(([, on]) => on === true).map(([k]) => k);
6617
6669
  for (const l of onListeners) {
6618
6670
  const cat = LISTENER_TO_CATEGORY[l];
6619
6671
  if (cat) events[cat] = true;
6620
6672
  }
6621
- if (events.subs) events.resubs = true;
6673
+ if (events.subs) {
6674
+ events.resubs = true;
6675
+ events.gifts = true;
6676
+ }
6622
6677
  return events;
6623
6678
  }
6679
+ function chatEmotesEnabled(v) {
6680
+ const candidates = {
6681
+ chatEmotes: v.chatEmotes,
6682
+ useChatEmotes: v.useChatEmotes,
6683
+ showChatEmotes: v.showChatEmotes,
6684
+ enableChatEmotes: v.enableChatEmotes
6685
+ };
6686
+ const enabled = Object.values(candidates).some((value) => value === true);
6687
+ return enabled;
6688
+ }
6624
6689
  function mapHypeCup(widget, ctx) {
6625
6690
  const v = widget.variables ?? {};
6626
6691
  const widgetWidth = typeof v.width === "number" && v.width > 0 ? v.width : parsePx(widget.css?.width);
@@ -6631,6 +6696,7 @@ function mapHypeCup(widget, ctx) {
6631
6696
  const maxBodies = typeof v.recentEvents === "number" && v.recentEvents > 0 ? Math.min(300, Math.max(10, v.recentEvents)) : 80;
6632
6697
  const duration = typeof v.duration === "number" && v.duration > 0 ? Math.min(15, Math.max(1, v.duration)) : 3;
6633
6698
  const sprites = liftSESpritesIntoTiers(v.types);
6699
+ const useChatEmotes = chatEmotesEnabled(v);
6634
6700
  return buildUnit(
6635
6701
  widget,
6636
6702
  "tipjar",
@@ -6655,11 +6721,14 @@ function mapHypeCup(widget, ctx) {
6655
6721
  maxBodies
6656
6722
  },
6657
6723
  tokens: {
6658
- defaultRadius: 16
6724
+ // Imported SE hype cups visually match better at 26px than the older
6725
+ // Lumia default, especially for the 125px tip spritesheets.
6726
+ defaultRadius: 26
6659
6727
  },
6660
6728
  events: categoriesFromListeners(widget.listeners),
6661
6729
  chat: {
6662
- useViewerAvatars: true
6730
+ useViewerAvatars: true,
6731
+ useChatEmotes
6663
6732
  },
6664
6733
  display: {
6665
6734
  showWireframes: !!v.showWireframes,
package/dist/se-import.js CHANGED
@@ -2181,7 +2181,8 @@ var TIPJAR_DEFAULT_CONTENT_FIELDS = {
2181
2181
  chat: false
2182
2182
  },
2183
2183
  chat: {
2184
- useViewerAvatars: true
2184
+ useViewerAvatars: true,
2185
+ useChatEmotes: false
2185
2186
  },
2186
2187
  display: {
2187
2188
  showEventMessages: false,
@@ -2425,7 +2426,7 @@ var SE_LISTENER_TO_LUMIA_CATEGORY = {
2425
2426
  "superchat-recent": "superchats",
2426
2427
  "hypetrain-latest": "hypetrain"
2427
2428
  };
2428
- function computeAllowedEventsFromSEListeners(seListeners, explicitListener) {
2429
+ function collectEnabledSEListeners(seListeners, explicitListener) {
2429
2430
  const enabled = [];
2430
2431
  if (seListeners && typeof seListeners === "object" && !Array.isArray(seListeners)) {
2431
2432
  for (const [k, v] of Object.entries(seListeners)) {
@@ -2437,6 +2438,19 @@ function computeAllowedEventsFromSEListeners(seListeners, explicitListener) {
2437
2438
  if (typeof explicitListener === "string" && explicitListener && !enabled.includes(explicitListener)) {
2438
2439
  enabled.push(explicitListener);
2439
2440
  }
2441
+ return enabled;
2442
+ }
2443
+ function seWidgetIsCheer(widget) {
2444
+ if (typeof widget.type === "string" && widget.type.includes("cheer")) return true;
2445
+ const listeners = collectEnabledSEListeners(widget.listeners, widget.listener);
2446
+ const fromVars = widget.variables?.listener;
2447
+ if (typeof fromVars === "string" && fromVars) listeners.push(fromVars);
2448
+ return listeners.some(
2449
+ (listener) => SE_LISTENER_TO_LUMIA_CATEGORY[listener] === LumiaEventListTypes.BITS
2450
+ );
2451
+ }
2452
+ function computeAllowedEventsFromSEListeners(seListeners, explicitListener) {
2453
+ const enabled = collectEnabledSEListeners(seListeners, explicitListener);
2440
2454
  if (enabled.length === 0) return void 0;
2441
2455
  const allowedCategories = /* @__PURE__ */ new Set();
2442
2456
  for (const listener of enabled) {
@@ -2462,6 +2476,15 @@ function seTemplateToMarqueeTemplate(seTemplate) {
2462
2476
  if (typeof seTemplate !== "string" || !seTemplate.trim()) return void 0;
2463
2477
  return translateSeText(seTemplate);
2464
2478
  }
2479
+ function ensureCheermoteTemplate(template) {
2480
+ const fallback = "{{username}}: {{cheermote}}{{amount}} ";
2481
+ if (!template || !template.trim()) return fallback;
2482
+ if (template.includes("{{cheermote}}")) return template;
2483
+ if (template.includes("{{amount}}")) {
2484
+ return template.replace("{{amount}}", "{{cheermote}}{{amount}}");
2485
+ }
2486
+ return `${template.replace(/\s+$/, "")} {{cheermote}}{{amount}} `;
2487
+ }
2465
2488
  function mapEventList(widget, ctx) {
2466
2489
  const v = widget.variables ?? {};
2467
2490
  const allowedEvents = computeAllowedEventsFromSEListeners(widget.listeners, widget.listener);
@@ -2469,7 +2492,9 @@ function mapEventList(widget, ctx) {
2469
2492
  const seText = widget.text;
2470
2493
  const scrolling = seText?.scrolling;
2471
2494
  const isMarquee = !!(scrolling && scrolling.enabled === true);
2472
- const itemTemplate = isMarquee ? seTemplateToMarqueeTemplate(seText?.value) : void 0;
2495
+ const isCheerMarquee = isMarquee && seWidgetIsCheer(widget);
2496
+ const baseItemTemplate = isMarquee ? seTemplateToMarqueeTemplate(seText?.value) : void 0;
2497
+ const itemTemplate = isCheerMarquee ? ensureCheermoteTemplate(baseItemTemplate) : baseItemTemplate;
2473
2498
  const marqueeSpeed = isMarquee ? seScrollSpeedToPixelsPerSecond(scrolling?.speed) : void 0;
2474
2499
  const marqueeDirection = isMarquee ? scrolling?.direction === "right" ? "right" : "left" : void 0;
2475
2500
  const theme = isMarquee ? "marquee" : v.theme ?? "simple";
@@ -3476,36 +3501,61 @@ function mapUnsupportedAsText(widget, ctx) {
3476
3501
  var SE_TYPE_TO_CATEGORY = {
3477
3502
  cheer: "bits",
3478
3503
  sub: "subs",
3504
+ subscriber: "subs",
3479
3505
  follower: "follows",
3480
3506
  raid: "raids",
3481
3507
  tip: "tips"
3482
3508
  };
3509
+ function isUnsupportedSETipVariation(seKey, variation) {
3510
+ return seKey === "tip" && variation.condition === "EXACT" && variation.amount === 4.2;
3511
+ }
3512
+ function isSubscriberGiftVariation(seKey, variation) {
3513
+ if (seKey !== "sub" && seKey !== "subscriber") return false;
3514
+ const condition = typeof variation.condition === "string" ? variation.condition.toUpperCase() : "";
3515
+ const name = typeof variation.name === "string" ? variation.name.toLowerCase() : "";
3516
+ return condition === "GIFT" || name.includes("gift");
3517
+ }
3518
+ function categoryForSEVariation(seKey, variation) {
3519
+ if (isSubscriberGiftVariation(seKey, variation)) return "gifts";
3520
+ return SE_TYPE_TO_CATEGORY[seKey];
3521
+ }
3483
3522
  function liftSESpritesIntoTiers(types) {
3484
3523
  const out = {};
3485
- if (!types) return out;
3524
+ if (!types) {
3525
+ return out;
3526
+ }
3486
3527
  for (const [seKey, block] of Object.entries(types)) {
3487
- const cat = SE_TYPE_TO_CATEGORY[seKey];
3488
- if (!cat) continue;
3528
+ if (!SE_TYPE_TO_CATEGORY[seKey]) {
3529
+ continue;
3530
+ }
3531
+ if (seKey === "cheer") {
3532
+ continue;
3533
+ }
3489
3534
  const variations = block?.variations ?? [];
3490
3535
  const usable = variations.filter(
3491
- (v) => typeof (v?.preview ?? v?.src) === "string" && (v.preview ?? v.src ?? "").length > 0
3536
+ (v) => !isUnsupportedSETipVariation(seKey, v) && typeof (v?.preview ?? v?.src) === "string" && (v.preview ?? v.src ?? "").length > 0
3492
3537
  );
3493
- const flagged = usable.filter((v) => v.default === true);
3494
- const picked = flagged.length > 0 ? flagged : usable;
3495
- const seenAmounts = /* @__PURE__ */ new Set();
3496
- const tiers = [];
3497
- for (const v of picked) {
3538
+ for (const v of usable) {
3539
+ const cat = categoryForSEVariation(seKey, v);
3540
+ if (!cat) continue;
3498
3541
  const amount = typeof v.amount === "number" && v.amount > 0 ? v.amount : 1;
3499
- if (seenAmounts.has(amount)) continue;
3500
- seenAmounts.add(amount);
3501
- tiers.push({
3542
+ const isSpritesheet = v.isSpritesheet === true || v.srcType === "spritesheet";
3543
+ const frameWidth = typeof v.frames?.[0] === "number" && v.frames[0] > 0 ? v.frames[0] : void 0;
3544
+ const frameHeight = typeof v.frames?.[1] === "number" && v.frames[1] > 0 ? v.frames[1] : void 0;
3545
+ const frameCount = typeof v.frames?.[2] === "number" && v.frames[2] > 0 ? v.frames[2] : void 0;
3546
+ const tier = {
3547
+ ...typeof v.name === "string" && v.name.length > 0 ? { name: v.name } : {},
3502
3548
  minAmount: amount,
3503
- imageUrl: v.preview ?? v.src,
3504
- scale: typeof v.cheerSize === "number" && v.cheerSize > 0 ? v.cheerSize : 1
3505
- });
3549
+ imageUrl: isSpritesheet ? v.src : v.preview ?? v.src,
3550
+ scale: typeof v.cheerSize === "number" && v.cheerSize > 0 ? v.cheerSize : 1,
3551
+ ...v.condition === "EXACT" || v.condition === "ATLEAST" ? { condition: v.condition } : {},
3552
+ ...isSpritesheet && frameWidth && frameHeight && frameCount ? { useSpritesheet: true, frameWidth, frameHeight, frameCount } : {}
3553
+ };
3554
+ out[cat] = [...out[cat] ?? [], tier];
3506
3555
  }
3556
+ }
3557
+ for (const tiers of Object.values(out)) {
3507
3558
  tiers.sort((a, b) => a.minAmount - b.minAmount);
3508
- if (tiers.length > 0) out[cat] = tiers;
3509
3559
  }
3510
3560
  return out;
3511
3561
  }
@@ -3532,15 +3582,30 @@ function categoriesFromListeners(listeners) {
3532
3582
  redemptions: false,
3533
3583
  chat: false
3534
3584
  };
3535
- if (!listeners) return events;
3585
+ if (!listeners) {
3586
+ return events;
3587
+ }
3536
3588
  const onListeners = Array.isArray(listeners) ? listeners : Object.entries(listeners).filter(([, on]) => on === true).map(([k]) => k);
3537
3589
  for (const l of onListeners) {
3538
3590
  const cat = LISTENER_TO_CATEGORY[l];
3539
3591
  if (cat) events[cat] = true;
3540
3592
  }
3541
- if (events.subs) events.resubs = true;
3593
+ if (events.subs) {
3594
+ events.resubs = true;
3595
+ events.gifts = true;
3596
+ }
3542
3597
  return events;
3543
3598
  }
3599
+ function chatEmotesEnabled(v) {
3600
+ const candidates = {
3601
+ chatEmotes: v.chatEmotes,
3602
+ useChatEmotes: v.useChatEmotes,
3603
+ showChatEmotes: v.showChatEmotes,
3604
+ enableChatEmotes: v.enableChatEmotes
3605
+ };
3606
+ const enabled = Object.values(candidates).some((value) => value === true);
3607
+ return enabled;
3608
+ }
3544
3609
  function mapHypeCup(widget, ctx) {
3545
3610
  const v = widget.variables ?? {};
3546
3611
  const widgetWidth = typeof v.width === "number" && v.width > 0 ? v.width : parsePx(widget.css?.width);
@@ -3551,6 +3616,7 @@ function mapHypeCup(widget, ctx) {
3551
3616
  const maxBodies = typeof v.recentEvents === "number" && v.recentEvents > 0 ? Math.min(300, Math.max(10, v.recentEvents)) : 80;
3552
3617
  const duration = typeof v.duration === "number" && v.duration > 0 ? Math.min(15, Math.max(1, v.duration)) : 3;
3553
3618
  const sprites = liftSESpritesIntoTiers(v.types);
3619
+ const useChatEmotes = chatEmotesEnabled(v);
3554
3620
  return buildUnit(
3555
3621
  widget,
3556
3622
  "tipjar",
@@ -3575,11 +3641,14 @@ function mapHypeCup(widget, ctx) {
3575
3641
  maxBodies
3576
3642
  },
3577
3643
  tokens: {
3578
- defaultRadius: 16
3644
+ // Imported SE hype cups visually match better at 26px than the older
3645
+ // Lumia default, especially for the 125px tip spritesheets.
3646
+ defaultRadius: 26
3579
3647
  },
3580
3648
  events: categoriesFromListeners(widget.listeners),
3581
3649
  chat: {
3582
- useViewerAvatars: true
3650
+ useViewerAvatars: true,
3651
+ useChatEmotes
3583
3652
  },
3584
3653
  display: {
3585
3654
  showWireframes: !!v.showWireframes,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lumiastream/ui",
3
- "version": "0.7.0",
3
+ "version": "0.7.3",
4
4
  "author": "Lumia Stream",
5
5
  "license": "ISC",
6
6
  "description": "Lumia UI Kit",
@@ -128,8 +128,8 @@
128
128
  "vitest": "^4.1.6"
129
129
  },
130
130
  "dependencies": {
131
- "@lumiastream/lumia-translations": "1.16.5",
132
- "@lumiastream/lumia-types": "3.6.6",
131
+ "@lumiastream/lumia-translations": "1.16.6",
132
+ "@lumiastream/lumia-types": "3.6.8",
133
133
  "classnames": "^2.5.1",
134
134
  "globals": "^17.4.0",
135
135
  "nanoid": "^5.1.11",