@lumiastream/ui 0.2.8-alpha.5 → 0.2.8-alpha.7

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.d.ts CHANGED
@@ -498,6 +498,8 @@ type OverlayLayerBounds = {
498
498
  zIndex?: number;
499
499
  matrix?: string;
500
500
  clipPath?: string;
501
+ autoWidth?: boolean;
502
+ autoHeight?: boolean;
501
503
  };
502
504
  type OverlayLayerState = {
503
505
  id: string;
@@ -606,6 +608,7 @@ interface SEText {
606
608
  scrolling?: {
607
609
  direction?: string;
608
610
  speed?: number;
611
+ enabled?: boolean;
609
612
  };
610
613
  css?: Record<string, unknown>;
611
614
  }
package/dist/index.js CHANGED
@@ -2292,7 +2292,7 @@ function variableCompletionOptions(context, variables) {
2292
2292
  }
2293
2293
 
2294
2294
  // src/utils/codeMirrorlinterOptions.ts
2295
- import * as globals from "globals";
2295
+ import globals from "globals";
2296
2296
  var browserGlobals = Object.fromEntries(
2297
2297
  Object.entries(globals.browser).map(([key, value]) => [
2298
2298
  key,
@@ -3237,11 +3237,21 @@ function listenerToLumiaVariable(listener) {
3237
3237
  return m[listener] ?? listener.replace(/-/g, "_");
3238
3238
  }
3239
3239
  function seCssToBounds(css, defaults = { width: 600, height: 200 }, canvas) {
3240
+ let widthIsAuto = false;
3241
+ let heightIsAuto = false;
3240
3242
  const toPx = (v, fallback, axis) => {
3241
- if (v == null) return fallback;
3243
+ if (v == null) {
3244
+ if (axis === "width") widthIsAuto = true;
3245
+ else if (axis === "height") heightIsAuto = true;
3246
+ return fallback;
3247
+ }
3242
3248
  if (typeof v === "number") return v;
3243
3249
  const s = v.trim();
3244
- if (s === "auto" || s === "") return fallback;
3250
+ if (s === "auto" || s === "") {
3251
+ if (axis === "width") widthIsAuto = true;
3252
+ else if (axis === "height") heightIsAuto = true;
3253
+ return fallback;
3254
+ }
3245
3255
  if (s.endsWith("%")) {
3246
3256
  const pct = parseFloat(s);
3247
3257
  if (canvas && axis && Number.isFinite(pct)) {
@@ -3255,6 +3265,8 @@ function seCssToBounds(css, defaults = { width: 600, height: 200 }, canvas) {
3255
3265
  };
3256
3266
  const width = toPx(css.width, defaults.width, "width");
3257
3267
  const height = toPx(css.height, defaults.height, "height");
3268
+ const autoWidth = widthIsAuto;
3269
+ const autoHeight = heightIsAuto;
3258
3270
  let x = toPx(css.left, 0, "width");
3259
3271
  let y = toPx(css.top, 0, "height");
3260
3272
  if (typeof css.transform === "string" && css.transform.includes("translate")) {
@@ -3280,7 +3292,9 @@ function seCssToBounds(css, defaults = { width: 600, height: 200 }, canvas) {
3280
3292
  width,
3281
3293
  height,
3282
3294
  opacity: css.opacity ?? 1,
3283
- zIndex: css["z-index"] ?? 0
3295
+ zIndex: css["z-index"] ?? 0,
3296
+ autoWidth,
3297
+ autoHeight
3284
3298
  };
3285
3299
  }
3286
3300
  var LUMIA_DEFAULT_SIZES = {
@@ -3290,7 +3304,11 @@ var LUMIA_DEFAULT_SIZES = {
3290
3304
  audio: { width: 200, height: 200 },
3291
3305
  slideshow: { width: 400, height: 220 },
3292
3306
  alert: { width: 700, height: 600 },
3293
- goal: { width: 740, height: 80 },
3307
+ // 80 was too short for the SE-style slim goal layout (label + bar + "Ends
3308
+ // in" sublabel needs ~125 px of vertical space). Bumped so editor-canvas
3309
+ // rendering (which doesn't honor autoHeight) doesn't clip the sublabel
3310
+ // after import.
3311
+ goal: { width: 740, height: 130 },
3294
3312
  timer: { width: 740, height: 80 },
3295
3313
  chatbox: { width: 375, height: 470 },
3296
3314
  eventlist: { width: 375, height: 470 },
@@ -3324,7 +3342,7 @@ function translateVariationCondition(seType, seCondition, requirement) {
3324
3342
  if (seCondition === "ATLEAST" && requirement != null) {
3325
3343
  return { conditionType: "GREATER_NUMBER", condition: requirement };
3326
3344
  }
3327
- return null;
3345
+ return { conditionType: "RANDOM", condition: 100 };
3328
3346
  }
3329
3347
  var LUMIA_LAYOUTS = /* @__PURE__ */ new Set(["column", "row", "onlyImage", "onlyText", "imageOver", "textOver"]);
3330
3348
  function translateLayout(seLayout) {
@@ -3352,7 +3370,13 @@ function buildUnit(widget, lumiaType, moduleExtras) {
3352
3370
  height: bounds.height,
3353
3371
  scale: [1, 1],
3354
3372
  opacity: bounds.opacity,
3355
- zIndex: bounds.zIndex
3373
+ zIndex: bounds.zIndex,
3374
+ // Per-axis flags — only the SE axis that was actually `auto`
3375
+ // collapses in render. The SE cheer goal is the canonical case:
3376
+ // width: "700px" + height: "auto" → numeric width stays at 700,
3377
+ // height collapses to content.
3378
+ ...bounds.autoWidth ? { autoWidth: true } : {},
3379
+ ...bounds.autoHeight ? { autoHeight: true } : {}
3356
3380
  }
3357
3381
  };
3358
3382
  const module = {
@@ -3374,6 +3398,19 @@ function buildUnit(widget, lumiaType, moduleExtras) {
3374
3398
  }
3375
3399
 
3376
3400
  // src/se-import/mappers/basic.ts
3401
+ function seExtraTextCss(seCss, scrolling) {
3402
+ const extra = {};
3403
+ if (typeof seCss["text-decoration"] === "string") extra.textDecoration = seCss["text-decoration"];
3404
+ if (typeof seCss["text-transform"] === "string") extra.textTransform = seCss["text-transform"];
3405
+ if (seCss["-webkit-text-stroke-color"]) extra["-webkit-text-stroke-color"] = seCss["-webkit-text-stroke-color"];
3406
+ if (seCss["-webkit-text-stroke-width"] != null) extra["-webkit-text-stroke-width"] = seCss["-webkit-text-stroke-width"];
3407
+ if (scrolling?.enabled) {
3408
+ extra.scroll = true;
3409
+ const speed = Number(scrolling.speed);
3410
+ if (Number.isFinite(speed) && speed > 0) extra.scrollSpeed = speed * 600;
3411
+ }
3412
+ return extra;
3413
+ }
3377
3414
  function mapText(widget) {
3378
3415
  const value = translateSeText(widget.text?.value ?? "");
3379
3416
  const seCss = widget.text?.css ?? {};
@@ -3390,7 +3427,8 @@ function mapText(widget) {
3390
3427
  color: seCss["color"] ?? "#ffffff",
3391
3428
  textShadow: seCss["text-shadow"] ?? "rgb(0, 0, 0) 1px 1px 1px",
3392
3429
  lineHeight: seCss["line-height"] ?? 1,
3393
- background: "transparent"
3430
+ background: "transparent",
3431
+ ...seExtraTextCss(seCss, widget.text?.scrolling)
3394
3432
  }
3395
3433
  });
3396
3434
  }
@@ -3443,7 +3481,8 @@ function mapReadout(widget, fallbackVar) {
3443
3481
  color: seCss["color"] ?? "#ffffff",
3444
3482
  textShadow: seCss["text-shadow"] ?? "rgb(0, 0, 0) 1px 1px 1px",
3445
3483
  lineHeight: seCss["line-height"] ?? 1,
3446
- background: "transparent"
3484
+ background: "transparent",
3485
+ ...seExtraTextCss(seCss, widget.text?.scrolling)
3447
3486
  }
3448
3487
  });
3449
3488
  }
@@ -3521,7 +3560,7 @@ function buildAlertEvent(seEvent, seEventType) {
3521
3560
  const textShadow = shadowEnabled ? importedTextShadow : "none";
3522
3561
  const marginTopRaw = Number(css["margin-top"]);
3523
3562
  const pushTextUp = Number.isFinite(marginTopRaw) ? -marginTopRaw : 0;
3524
- const variations = (seEvent.variations ?? []).map((variation) => buildAlertVariation(variation, seEventType)).filter((v) => v != null);
3563
+ const variations = (seEvent.variations ?? []).map((variation) => buildAlertVariation(variation, seEventType, seEvent)).filter((v) => v != null);
3525
3564
  const defaultDuration = (seEventType && SE_DEFAULT_DURATION_BY_EVENT[seEventType]) ?? 8;
3526
3565
  return {
3527
3566
  on: seEvent.enabled !== false,
@@ -3618,10 +3657,12 @@ function buildAlertEvent(seEvent, seEventType) {
3618
3657
  variations
3619
3658
  };
3620
3659
  }
3621
- function buildAlertVariation(v, seEventType) {
3660
+ function buildAlertVariation(v, seEventType, parentSettings) {
3622
3661
  const translated = translateVariationCondition(v.type ?? null, v.condition ?? null, v.requirement ?? null);
3623
3662
  if (!translated) return null;
3624
- const base = buildAlertEvent(v.settings, seEventType);
3663
+ const { variations: _parentVariations, ...parentInheritable } = parentSettings ?? {};
3664
+ const mergedSettings = deepMergeSeSettings(parentSettings ? parentInheritable : void 0, v.settings);
3665
+ const base = buildAlertEvent(mergedSettings, seEventType);
3625
3666
  return {
3626
3667
  name: v.name ?? "Variation",
3627
3668
  on: v.enabled !== false,
@@ -3632,6 +3673,22 @@ function buildAlertVariation(v, seEventType) {
3632
3673
  ...base
3633
3674
  };
3634
3675
  }
3676
+ function deepMergeSeSettings(parent, variation) {
3677
+ if (parent == null) return variation;
3678
+ if (variation == null) return parent;
3679
+ if (typeof parent !== "object" || typeof variation !== "object") return variation;
3680
+ if (Array.isArray(parent) || Array.isArray(variation)) return variation;
3681
+ const out = { ...parent };
3682
+ for (const [k, vv] of Object.entries(variation)) {
3683
+ if (vv === void 0) continue;
3684
+ if (vv && typeof vv === "object" && !Array.isArray(vv) && parent[k] && typeof parent[k] === "object" && !Array.isArray(parent[k])) {
3685
+ out[k] = deepMergeSeSettings(parent[k], vv);
3686
+ } else {
3687
+ out[k] = vv;
3688
+ }
3689
+ }
3690
+ return out;
3691
+ }
3635
3692
  function mapAlertBox(widget, opts = {}) {
3636
3693
  const v = widget.variables ?? {};
3637
3694
  const events = {};
@@ -3672,8 +3729,11 @@ function mapGoal(widget) {
3672
3729
  return buildUnit(widget, "goal", {
3673
3730
  content: {
3674
3731
  version: 1,
3675
- // Matches GoalTypes enum in components/Modules/Views/Goal/types.ts.
3676
- type: "bar",
3732
+ // `slim` reproduces SE's default goal look — label above a thin
3733
+ // track, with `0` / `goalAmount` anchoring the bar's edges and the
3734
+ // live `current` floating at the percentage position. See
3735
+ // components/Modules/Views/Goal/types.ts:GoalTypes.SLIM.
3736
+ type: "slim",
3677
3737
  label: translateSeText(v.title ?? "Goal"),
3678
3738
  subLabel: "",
3679
3739
  // The Goal module renders this template literal with {{current}} + {{goal}} substituted.
@@ -4952,6 +5012,7 @@ var SEAuthError = class extends Error {
4952
5012
  this.code = code;
4953
5013
  this.name = "SEAuthError";
4954
5014
  }
5015
+ code;
4955
5016
  };
4956
5017
  function decodeBase64Url(s) {
4957
5018
  const b64 = s.replace(/-/g, "+").replace(/_/g, "/");
@@ -4993,6 +5054,7 @@ var SEClient = class _SEClient {
4993
5054
  constructor(claims) {
4994
5055
  this.claims = claims;
4995
5056
  }
5057
+ claims;
4996
5058
  static fromJwt(jwt) {
4997
5059
  return new _SEClient(decodeJwtPayload(jwt));
4998
5060
  }
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@lumiastream/ui",
3
- "version": "0.2.8-alpha.5",
3
+ "version": "0.2.8-alpha.7",
4
4
  "author": "Lumia Stream",
5
5
  "license": "ISC",
6
6
  "description": "Lumia UI Kit",
7
- "packageManager": "pnpm@10.32.1",
7
+ "packageManager": "npm@11.9.0",
8
8
  "type": "module",
9
9
  "main": "dist/index.js",
10
10
  "module": "dist/index.js",
@@ -23,23 +23,35 @@
23
23
  "build": "tsup src/index.ts",
24
24
  "build-storybook": "storybook build",
25
25
  "watch": "tsup src/index.ts --watch",
26
- "release": "changeset && changeset tag && pnpm build && pnpm publish",
27
- "prepublishOnly": "pnpm build",
28
- "postpublish": "pnpm store prune && node ./scripts/postpublish-install.mjs"
26
+ "release": "changeset && changeset tag && npm run build && npm publish",
27
+ "prepublishOnly": "npm run build",
28
+ "postpublish": "npm cache clean --force && node ./scripts/postpublish-install.mjs"
29
29
  },
30
30
  "peerDependencies": {
31
31
  "@codemirror/autocomplete": "^6.0.0",
32
+ "@emotion/react": "^11.14.0",
33
+ "@emotion/styled": "^11.14.1",
34
+ "@mui/icons-material": "^9.0.0",
35
+ "@mui/material": "^9.0.0",
32
36
  "react": "^17.0.0 || ^18.0.0 || ^19.0.0",
33
- "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0"
37
+ "react-dom": "^17.0.0 || ^18.0.0 || ^19.0.0",
38
+ "react-hook-form": "^7.62.0"
34
39
  },
35
40
  "devDependencies": {
36
41
  "@codemirror/autocomplete": "^6.20.1",
42
+ "@emotion/react": "^11.14.0",
43
+ "@emotion/styled": "^11.14.1",
44
+ "@mui/icons-material": "^9.0.0",
45
+ "@mui/material": "^9.0.0",
37
46
  "@storybook/builder-vite": "^10.2.17",
38
47
  "@storybook/react-vite": "^10.2.17",
39
48
  "@types/node": "^25.5.0",
40
49
  "@types/react": "^19.2.14",
41
50
  "@types/react-dom": "19.2.3",
42
51
  "postcss": "^8.5.8",
52
+ "react": "^19.2.0",
53
+ "react-dom": "^19.2.0",
54
+ "react-hook-form": "^7.73.1",
43
55
  "sass-embedded": "^1.99.0",
44
56
  "storybook": "^10.2.17",
45
57
  "tsup": "^8.5.1",
@@ -47,16 +59,11 @@
47
59
  "vite": "^8.0.8"
48
60
  },
49
61
  "dependencies": {
50
- "@emotion/react": "^11.14.0",
51
- "@emotion/styled": "^11.14.1",
52
62
  "@lumiastream/lumia-translations": "1.15.4",
53
- "@lumiastream/lumia-types": "^3.2.7",
54
- "@mui/icons-material": "^9.0.0",
55
- "@mui/material": "^9.0.0",
63
+ "@lumiastream/lumia-types": "^3.3.7-alpha.2",
56
64
  "classnames": "^2.5.1",
57
65
  "globals": "^17.4.0",
58
66
  "nanoid": "^5.1.11",
59
- "react-best-gradient-color-picker": "^3.0.14",
60
- "react-hook-form": "^7.73.1"
67
+ "react-best-gradient-color-picker": "^3.0.14"
61
68
  }
62
69
  }