@lumiastream/ui 0.8.2 → 0.8.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/se-import.js CHANGED
@@ -4839,7 +4839,7 @@ async function diagnoseSEAuth(jwt) {
4839
4839
  }
4840
4840
 
4841
4841
  // src/se-import/ui/SEImportWizard.tsx
4842
- import { useCallback as useCallback4, useEffect as useEffect10, useMemo as useMemo8, useRef as useRef9, useState as useState13 } from "react";
4842
+ import { useCallback as useCallback4, useEffect as useEffect10, useMemo as useMemo8, useRef as useRef9, useState as useState14 } from "react";
4843
4843
 
4844
4844
  // src/components/LSButton/LSButton.tsx
4845
4845
  import Button from "@mui/material/Button";
@@ -8088,6 +8088,7 @@ function EventListItem({
8088
8088
  avatar,
8089
8089
  fallbackAvatar,
8090
8090
  timestamp,
8091
+ amountBadge,
8091
8092
  platformIcon,
8092
8093
  alertIcon,
8093
8094
  eventType,
@@ -8136,6 +8137,14 @@ function EventListItem({
8136
8137
  style: accentColor ? { color: accentColor } : void 0,
8137
8138
  children: resolvedAlertIcon
8138
8139
  }
8140
+ ) : null,
8141
+ amountBadge != null && amountBadge !== false ? /* @__PURE__ */ jsx24(
8142
+ "span",
8143
+ {
8144
+ className: "ls-eventlist-item__amount-badge",
8145
+ style: accentColor ? { color: accentColor, backgroundColor: `color-mix(in srgb, ${accentColor} 18%, transparent)`, borderColor: `color-mix(in srgb, ${accentColor} 45%, transparent)` } : void 0,
8146
+ children: amountBadge
8147
+ }
8139
8148
  ) : null
8140
8149
  ] }),
8141
8150
  /* @__PURE__ */ jsxs14("div", { className: "ls-eventlist-item__body", children: [
@@ -8154,7 +8163,7 @@ function EventListItem({
8154
8163
  EventListItem.displayName = "EventListItem";
8155
8164
 
8156
8165
  // src/components/EventList/EventList.tsx
8157
- import { useEffect as useEffect7, useRef as useRef7 } from "react";
8166
+ import { useEffect as useEffect7, useRef as useRef7, useState as useState9 } from "react";
8158
8167
  import classNames14 from "classnames";
8159
8168
  import { jsx as jsx25, jsxs as jsxs15 } from "react/jsx-runtime";
8160
8169
  var PIN_THRESHOLD = 24;
@@ -8176,10 +8185,15 @@ function EventList({
8176
8185
  newestAt = "top",
8177
8186
  onEndReached,
8178
8187
  endReachedThreshold = 24,
8188
+ showNewItemsPill = false,
8189
+ newItemsPillText,
8179
8190
  className
8180
8191
  }) {
8181
8192
  const listRef = useRef7(null);
8182
8193
  const pinnedRef = useRef7(true);
8194
+ const prevNewestIdRef = useRef7(null);
8195
+ const newItemsInitedRef = useRef7(false);
8196
+ const [unreadCount, setUnreadCount] = useState9(0);
8183
8197
  useEffect7(() => {
8184
8198
  const el = listRef.current;
8185
8199
  if (!autoScroll || !el || !pinnedRef.current) {
@@ -8187,6 +8201,34 @@ function EventList({
8187
8201
  }
8188
8202
  el.scrollTop = newestAt === "top" ? 0 : el.scrollHeight;
8189
8203
  }, [items, autoScroll, newestAt]);
8204
+ useEffect7(() => {
8205
+ if (!showNewItemsPill) {
8206
+ return;
8207
+ }
8208
+ const newestId = (newestAt === "top" ? items[0]?.id : items[items.length - 1]?.id) ?? null;
8209
+ const prevNewestId = prevNewestIdRef.current;
8210
+ let added = 0;
8211
+ if (prevNewestId != null && newestId != null && newestId !== prevNewestId) {
8212
+ const idx = newestAt === "top" ? items.findIndex((item) => item.id === prevNewestId) : items.length - 1 - [...items].reverse().findIndex((item) => item.id === prevNewestId);
8213
+ added = newestAt === "top" ? idx > 0 ? idx : 0 : idx >= 0 && idx < items.length - 1 ? items.length - 1 - idx : 0;
8214
+ }
8215
+ prevNewestIdRef.current = newestId;
8216
+ if (!newItemsInitedRef.current) {
8217
+ newItemsInitedRef.current = true;
8218
+ return;
8219
+ }
8220
+ if (added > 0 && !pinnedRef.current) {
8221
+ setUnreadCount((count) => count + added);
8222
+ }
8223
+ }, [items, showNewItemsPill, newestAt]);
8224
+ const scrollToNewest = () => {
8225
+ const el = listRef.current;
8226
+ if (el) {
8227
+ el.scrollTo({ top: newestAt === "top" ? 0 : el.scrollHeight, behavior: "smooth" });
8228
+ }
8229
+ pinnedRef.current = true;
8230
+ setUnreadCount(0);
8231
+ };
8190
8232
  const handleScroll = () => {
8191
8233
  const el = listRef.current;
8192
8234
  if (!el) {
@@ -8196,43 +8238,50 @@ function EventList({
8196
8238
  const distanceFromNewest = newestAt === "top" ? el.scrollTop : distanceFromEnd;
8197
8239
  const distanceFromOldest = newestAt === "top" ? distanceFromEnd : el.scrollTop;
8198
8240
  pinnedRef.current = distanceFromNewest <= PIN_THRESHOLD;
8241
+ if (pinnedRef.current && unreadCount > 0) {
8242
+ setUnreadCount(0);
8243
+ }
8199
8244
  if (onEndReached && distanceFromOldest <= endReachedThreshold) {
8200
8245
  onEndReached();
8201
8246
  }
8202
8247
  };
8203
- return /* @__PURE__ */ jsx25("div", { className: classNames14("ls-eventlist", className), id, children: items.length === 0 ? /* @__PURE__ */ jsxs15("div", { className: classNames14("ls-eventlist__empty", emptyClassName), children: [
8204
- emptyIcon ? /* @__PURE__ */ jsx25("span", { className: "ls-eventlist__empty-icon", children: emptyIcon }) : null,
8205
- /* @__PURE__ */ jsx25("span", { children: emptyText })
8206
- ] }) : /* @__PURE__ */ jsx25(
8207
- "div",
8208
- {
8209
- className: "ls-eventlist__list",
8210
- ref: listRef,
8211
- onScroll: handleScroll,
8212
- style: itemGap != null ? { gap: typeof itemGap === "number" ? `${itemGap}px` : itemGap } : void 0,
8213
- children: items.map((item) => /* @__PURE__ */ jsx25("div", { className: "ls-eventlist__row", children: /* @__PURE__ */ jsx25(
8214
- EventListItem,
8215
- {
8216
- username: item.username,
8217
- message: item.message,
8218
- userMessage: item.userMessage,
8219
- avatar: item.avatar,
8220
- fallbackAvatar: item.fallbackAvatar ?? fallbackAvatar,
8221
- timestamp: item.timestamp,
8222
- platformIcon: showPlatformIcons ? item.platformIcon ?? (item.platform ? /* @__PURE__ */ jsx25(PlatformIcon, { platform: item.platform }) : void 0) : void 0,
8223
- alertIcon: item.alertIcon,
8224
- eventType: item.eventType,
8225
- accentColor: item.accentColor,
8226
- colorFullBackground,
8227
- showAvatar: showAvatars,
8228
- showTimestamp: showTimestamps,
8229
- showMessage: showMessages,
8230
- actions: showActions ? item.actions : void 0,
8231
- onUsernameClick: item.onUsernameClick
8232
- }
8233
- ) }, item.id))
8234
- }
8235
- ) });
8248
+ return /* @__PURE__ */ jsxs15("div", { className: classNames14("ls-eventlist", className), id, children: [
8249
+ showNewItemsPill && unreadCount > 0 ? /* @__PURE__ */ jsx25("button", { type: "button", className: classNames14("ls-eventlist__new-pill", { "ls-eventlist__new-pill--bottom": newestAt === "bottom" }), onClick: scrollToNewest, children: newItemsPillText ? newItemsPillText(unreadCount) : `${unreadCount} new` }) : null,
8250
+ items.length === 0 ? /* @__PURE__ */ jsxs15("div", { className: classNames14("ls-eventlist__empty", emptyClassName), children: [
8251
+ emptyIcon ? /* @__PURE__ */ jsx25("span", { className: "ls-eventlist__empty-icon", children: emptyIcon }) : null,
8252
+ /* @__PURE__ */ jsx25("span", { children: emptyText })
8253
+ ] }) : /* @__PURE__ */ jsx25(
8254
+ "div",
8255
+ {
8256
+ className: "ls-eventlist__list",
8257
+ ref: listRef,
8258
+ onScroll: handleScroll,
8259
+ style: itemGap != null ? { gap: typeof itemGap === "number" ? `${itemGap}px` : itemGap } : void 0,
8260
+ children: items.map((item) => /* @__PURE__ */ jsx25("div", { className: "ls-eventlist__row", children: /* @__PURE__ */ jsx25(
8261
+ EventListItem,
8262
+ {
8263
+ username: item.username,
8264
+ message: item.message,
8265
+ userMessage: item.userMessage,
8266
+ avatar: item.avatar,
8267
+ fallbackAvatar: item.fallbackAvatar ?? fallbackAvatar,
8268
+ timestamp: item.timestamp,
8269
+ amountBadge: item.amountBadge,
8270
+ platformIcon: showPlatformIcons ? item.platformIcon ?? (item.platform ? /* @__PURE__ */ jsx25(PlatformIcon, { platform: item.platform }) : void 0) : void 0,
8271
+ alertIcon: item.alertIcon,
8272
+ eventType: item.eventType,
8273
+ accentColor: item.accentColor,
8274
+ colorFullBackground,
8275
+ showAvatar: showAvatars,
8276
+ showTimestamp: showTimestamps,
8277
+ showMessage: showMessages,
8278
+ actions: showActions ? item.actions : void 0,
8279
+ onUsernameClick: item.onUsernameClick
8280
+ }
8281
+ ) }, item.id))
8282
+ }
8283
+ )
8284
+ ] });
8236
8285
  }
8237
8286
  EventList.displayName = "EventList";
8238
8287
 
@@ -8341,7 +8390,7 @@ StreamStatusPanel.displayName = "StreamStatusPanel";
8341
8390
 
8342
8391
  // src/components/ViewersList/ViewersList.tsx
8343
8392
  import * as React from "react";
8344
- import { useMemo as useMemo5, useState as useState9 } from "react";
8393
+ import { useMemo as useMemo5, useState as useState10 } from "react";
8345
8394
  import classNames16 from "classnames";
8346
8395
  import { jsx as jsx27, jsxs as jsxs17 } from "react/jsx-runtime";
8347
8396
  function ViewersList({
@@ -8360,7 +8409,7 @@ function ViewersList({
8360
8409
  id,
8361
8410
  className
8362
8411
  }) {
8363
- const [query, setQuery] = useState9("");
8412
+ const [query, setQuery] = useState10("");
8364
8413
  const internalSearch = showSearch && !searchSlot;
8365
8414
  const filtered = useMemo5(
8366
8415
  () => internalSearch && query ? viewers.filter((viewer) => viewer.username.toLowerCase().includes(query.toLowerCase())) : viewers,
@@ -8646,7 +8695,7 @@ function ModQueueItem({
8646
8695
  ModQueueItem.displayName = "ModQueueItem";
8647
8696
 
8648
8697
  // src/components/ModQueueList/ModQueueList.tsx
8649
- import { useMemo as useMemo6, useState as useState10 } from "react";
8698
+ import { useMemo as useMemo6, useState as useState11 } from "react";
8650
8699
  import ButtonBase from "@mui/material/ButtonBase";
8651
8700
  import classNames20 from "classnames";
8652
8701
 
@@ -8720,7 +8769,7 @@ function ModQueueList({
8720
8769
  onDeny,
8721
8770
  className
8722
8771
  }) {
8723
- const [internalQuery, setInternalQuery] = useState10("");
8772
+ const [internalQuery, setInternalQuery] = useState11("");
8724
8773
  const query = searchValue !== void 0 ? searchValue : internalQuery;
8725
8774
  const handleSearchChange = (value) => {
8726
8775
  if (searchValue === void 0) {
@@ -8807,7 +8856,7 @@ function ModActivityLog({ logs, emptyText, onClear, clearLabel = "Clear logs", a
8807
8856
  ModActivityLog.displayName = "ModActivityLog";
8808
8857
 
8809
8858
  // src/components/SongRequestList/SongRequestList.tsx
8810
- import { useState as useState11 } from "react";
8859
+ import { useState as useState12 } from "react";
8811
8860
  import classNames22 from "classnames";
8812
8861
  import { jsx as jsx35, jsxs as jsxs25 } from "react/jsx-runtime";
8813
8862
  function SongRequestList({
@@ -8828,7 +8877,7 @@ function SongRequestList({
8828
8877
  emptyText,
8829
8878
  className
8830
8879
  }) {
8831
- const [addValue, setAddValue] = useState11("");
8880
+ const [addValue, setAddValue] = useState12("");
8832
8881
  const submitAdd = () => {
8833
8882
  const query = addValue.trim();
8834
8883
  if (!query || addDisabled || !onAddSong) {
@@ -8906,13 +8955,13 @@ function SongRequestList({
8906
8955
  SongRequestList.displayName = "SongRequestList";
8907
8956
 
8908
8957
  // src/se-import/ui/MarketplacePicker.tsx
8909
- import { useEffect as useEffect9, useMemo as useMemo7, useState as useState12 } from "react";
8958
+ import { useEffect as useEffect9, useMemo as useMemo7, useState as useState13 } from "react";
8910
8959
  import { jsx as jsx36, jsxs as jsxs26 } from "react/jsx-runtime";
8911
8960
  function MarketplacePicker({ seWidgetType, fetchMarketplaceOverlay, CustomEmbed, onPick, onCancel }) {
8912
8961
  const candidateIds = useMemo7(() => getMarketplaceCandidates(seWidgetType), [seWidgetType]);
8913
- const [candidates, setCandidates] = useState12(() => candidateIds.map((id) => ({ id, loading: true })));
8914
- const [activeId, setActiveId] = useState12(candidateIds[0] ?? null);
8915
- const [activeLayerId, setActiveLayerId] = useState12(null);
8962
+ const [candidates, setCandidates] = useState13(() => candidateIds.map((id) => ({ id, loading: true })));
8963
+ const [activeId, setActiveId] = useState13(candidateIds[0] ?? null);
8964
+ const [activeLayerId, setActiveLayerId] = useState13(null);
8916
8965
  useEffect9(() => {
8917
8966
  let cancelled = false;
8918
8967
  candidateIds.forEach(async (id) => {
@@ -11418,8 +11467,8 @@ var CUSTOM_WIDGET_TABS = [
11418
11467
  ];
11419
11468
  function CustomWidgetCard({ widget }) {
11420
11469
  const tabs = CUSTOM_WIDGET_TABS.filter(({ key }) => widget[key].trim().length > 0);
11421
- const [activeKey, setActiveKey] = useState13(tabs[0]?.key ?? "js");
11422
- const [copied, setCopied] = useState13(false);
11470
+ const [activeKey, setActiveKey] = useState14(tabs[0]?.key ?? "js");
11471
+ const [copied, setCopied] = useState14(false);
11423
11472
  const value = widget[activeKey] ?? "";
11424
11473
  useEffect10(() => setCopied(false), [activeKey]);
11425
11474
  const handleCopy = useCallback4(() => {
@@ -11544,47 +11593,47 @@ function SEImportWizard({
11544
11593
  CustomEmbed,
11545
11594
  isAdmin
11546
11595
  } = bindings;
11547
- const [step, setStep] = useState13(
11596
+ const [step, setStep] = useState14(
11548
11597
  initialStep ?? (initialUrl ? "url" : initialJwt ? "connect" : "mode")
11549
11598
  );
11550
- const [entryMode, setEntryMode] = useState13(
11599
+ const [entryMode, setEntryMode] = useState14(
11551
11600
  initialStep === "url" ? "url" : initialStep === "connect" ? "jwt" : initialUrl ? "url" : initialJwt ? "jwt" : null
11552
11601
  );
11553
- const [jwt, setJwt] = useState13(initialJwt);
11554
- const [seClient, setSeClient] = useState13(null);
11555
- const [channels, setChannels] = useState13(null);
11556
- const [selectedChannelId, setSelectedChannelId] = useState13(null);
11557
- const [connectError, setConnectError] = useState13(null);
11558
- const [connecting, setConnecting] = useState13(false);
11559
- const [overlayList, setOverlayList] = useState13(
11602
+ const [jwt, setJwt] = useState14(initialJwt);
11603
+ const [seClient, setSeClient] = useState14(null);
11604
+ const [channels, setChannels] = useState14(null);
11605
+ const [selectedChannelId, setSelectedChannelId] = useState14(null);
11606
+ const [connectError, setConnectError] = useState14(null);
11607
+ const [connecting, setConnecting] = useState14(false);
11608
+ const [overlayList, setOverlayList] = useState14(
11560
11609
  initialOverlayList?.length ? initialOverlayList : null
11561
11610
  );
11562
- const [overlaysLoading, setOverlaysLoading] = useState13(false);
11563
- const [overlaysError, setOverlaysError] = useState13(null);
11564
- const [selectedOverlayIds, setSelectedOverlayIds] = useState13(/* @__PURE__ */ new Set());
11565
- const [activeOverlaySummaries, setActiveOverlaySummaries] = useState13([]);
11566
- const [activeOverlayPreview, setActiveOverlayPreview] = useState13();
11567
- const [url, setUrl] = useState13(initialUrl);
11568
- const [loadError, setLoadError] = useState13(null);
11569
- const [loading, setLoading] = useState13(false);
11570
- const [result, setResult] = useState13(null);
11571
- const [batchImports, setBatchImports] = useState13([]);
11572
- const [originalReviewItems, setOriginalReviewItems] = useState13([]);
11573
- const [options, setOptions] = useState13({
11611
+ const [overlaysLoading, setOverlaysLoading] = useState14(false);
11612
+ const [overlaysError, setOverlaysError] = useState14(null);
11613
+ const [selectedOverlayIds, setSelectedOverlayIds] = useState14(/* @__PURE__ */ new Set());
11614
+ const [activeOverlaySummaries, setActiveOverlaySummaries] = useState14([]);
11615
+ const [activeOverlayPreview, setActiveOverlayPreview] = useState14();
11616
+ const [url, setUrl] = useState14(initialUrl);
11617
+ const [loadError, setLoadError] = useState14(null);
11618
+ const [loading, setLoading] = useState14(false);
11619
+ const [result, setResult] = useState14(null);
11620
+ const [batchImports, setBatchImports] = useState14([]);
11621
+ const [originalReviewItems, setOriginalReviewItems] = useState14([]);
11622
+ const [options, setOptions] = useState14({
11574
11623
  mirrorAssets: true,
11575
11624
  name: ""
11576
11625
  });
11577
- const [mirrorRows, setMirrorRows] = useState13([]);
11578
- const [mirrorRunning, setMirrorRunning] = useState13(false);
11579
- const [rowStates, setRowStates] = useState13({});
11580
- const [reviewIndex, setReviewIndex] = useState13(0);
11581
- const [importing, setImporting] = useState13(false);
11582
- const [marketplacePickerOpen, setMarketplacePickerOpen] = useState13(false);
11626
+ const [mirrorRows, setMirrorRows] = useState14([]);
11627
+ const [mirrorRunning, setMirrorRunning] = useState14(false);
11628
+ const [rowStates, setRowStates] = useState14({});
11629
+ const [reviewIndex, setReviewIndex] = useState14(0);
11630
+ const [importing, setImporting] = useState14(false);
11631
+ const [marketplacePickerOpen, setMarketplacePickerOpen] = useState14(false);
11583
11632
  const mirrorStartedRef = useRef9(false);
11584
11633
  const mirrorAbortRef = useRef9(null);
11585
11634
  const initialOverlayImportStartedRef = useRef9(false);
11586
11635
  const filenameCacheRef = useRef9(/* @__PURE__ */ new Map());
11587
- const [assetUrls, setAssetUrls] = useState13([]);
11636
+ const [assetUrls, setAssetUrls] = useState14([]);
11588
11637
  const currentItem = originalReviewItems[reviewIndex];
11589
11638
  const currentRow = currentItem ? rowStates[currentItem.moduleId] ?? { state: "pending" } : void 0;
11590
11639
  const handleConnect = useCallback4(async () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lumiastream/ui",
3
- "version": "0.8.2",
3
+ "version": "0.8.3",
4
4
  "author": "Lumia Stream",
5
5
  "license": "ISC",
6
6
  "description": "Lumia UI Kit",
@@ -153,6 +153,7 @@
153
153
  "watch": "tsup --watch",
154
154
  "test": "vitest run",
155
155
  "test:watch": "vitest",
156
+ "link-local": "npm run build && node ./scripts/link-local.mjs",
156
157
  "release": "changeset && changeset tag && npm run build && npm publish",
157
158
  "prepublishOnly": "npm run build",
158
159
  "postpublish": "npm cache clean --force && node ./scripts/postpublish-install.mjs",