@mushi-mushi/web 1.6.0 → 1.7.1
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.cjs +235 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +9 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +235 -4
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -1417,6 +1417,145 @@ function getWidgetStyles(theme) {
|
|
|
1417
1417
|
font-size: 10.5px;
|
|
1418
1418
|
}
|
|
1419
1419
|
|
|
1420
|
+
/* \u2500\u2500\u2500 Banner launcher (trigger: 'banner') \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
1421
|
+
|
|
1422
|
+
.mushi-banner {
|
|
1423
|
+
position: fixed;
|
|
1424
|
+
left: 0;
|
|
1425
|
+
right: 0;
|
|
1426
|
+
height: 36px;
|
|
1427
|
+
display: flex;
|
|
1428
|
+
align-items: center;
|
|
1429
|
+
justify-content: center;
|
|
1430
|
+
gap: 10px;
|
|
1431
|
+
padding: 0 16px;
|
|
1432
|
+
font-family: ${fontMono};
|
|
1433
|
+
font-size: 11.5px;
|
|
1434
|
+
letter-spacing: 0.04em;
|
|
1435
|
+
white-space: nowrap;
|
|
1436
|
+
overflow: hidden;
|
|
1437
|
+
z-index: var(--mushi-banner-z, 99998);
|
|
1438
|
+
animation: mushi-banner-slide-in 0.3s ${easeStamp} both;
|
|
1439
|
+
}
|
|
1440
|
+
|
|
1441
|
+
.mushi-banner.top { top: 0; }
|
|
1442
|
+
.mushi-banner.bottom { bottom: 0; }
|
|
1443
|
+
|
|
1444
|
+
/* --- neon variant (electric lime \u2014 dev / beta tool aesthetic) --- */
|
|
1445
|
+
.mushi-banner.neon {
|
|
1446
|
+
background: #0FFF50;
|
|
1447
|
+
color: #0a1a0a;
|
|
1448
|
+
border-bottom: 1.5px solid #00C43A;
|
|
1449
|
+
}
|
|
1450
|
+
.mushi-banner.neon.bottom {
|
|
1451
|
+
border-top: 1.5px solid #00C43A;
|
|
1452
|
+
border-bottom: none;
|
|
1453
|
+
}
|
|
1454
|
+
.mushi-banner.neon .mushi-banner-btn {
|
|
1455
|
+
background: rgba(0,0,0,0.14);
|
|
1456
|
+
color: #0a1a0a;
|
|
1457
|
+
border: 1px solid rgba(0,0,0,0.22);
|
|
1458
|
+
}
|
|
1459
|
+
.mushi-banner.neon .mushi-banner-btn:hover {
|
|
1460
|
+
background: rgba(0,0,0,0.22);
|
|
1461
|
+
}
|
|
1462
|
+
|
|
1463
|
+
/* --- brand variant (vermillion \u2014 editorial, app-quality) --- */
|
|
1464
|
+
.mushi-banner.brand {
|
|
1465
|
+
background: ${vermillion};
|
|
1466
|
+
color: #fff;
|
|
1467
|
+
border-bottom: 1.5px solid ${isDark ? "#C4321E" : "#B52F1F"};
|
|
1468
|
+
}
|
|
1469
|
+
.mushi-banner.brand.bottom {
|
|
1470
|
+
border-top: 1.5px solid ${isDark ? "#C4321E" : "#B52F1F"};
|
|
1471
|
+
border-bottom: none;
|
|
1472
|
+
}
|
|
1473
|
+
.mushi-banner.brand .mushi-banner-btn {
|
|
1474
|
+
background: rgba(255,255,255,0.18);
|
|
1475
|
+
color: #fff;
|
|
1476
|
+
border: 1px solid rgba(255,255,255,0.32);
|
|
1477
|
+
}
|
|
1478
|
+
.mushi-banner.brand .mushi-banner-btn:hover {
|
|
1479
|
+
background: rgba(255,255,255,0.28);
|
|
1480
|
+
}
|
|
1481
|
+
|
|
1482
|
+
/* --- subtle variant (hairline, muted \u2014 least disruptive) --- */
|
|
1483
|
+
.mushi-banner.subtle {
|
|
1484
|
+
background: ${isDark ? "rgba(242,235,221,0.06)" : "rgba(14,13,11,0.04)"};
|
|
1485
|
+
color: ${inkMuted};
|
|
1486
|
+
border-bottom: 1px solid ${rule};
|
|
1487
|
+
}
|
|
1488
|
+
.mushi-banner.subtle.bottom {
|
|
1489
|
+
border-top: 1px solid ${rule};
|
|
1490
|
+
border-bottom: none;
|
|
1491
|
+
}
|
|
1492
|
+
.mushi-banner.subtle .mushi-banner-btn {
|
|
1493
|
+
background: ${isDark ? "rgba(242,235,221,0.10)" : "rgba(14,13,11,0.07)"};
|
|
1494
|
+
color: ${ink};
|
|
1495
|
+
border: 1px solid ${rule};
|
|
1496
|
+
}
|
|
1497
|
+
.mushi-banner.subtle .mushi-banner-btn:hover {
|
|
1498
|
+
background: ${isDark ? "rgba(242,235,221,0.16)" : "rgba(14,13,11,0.12)"};
|
|
1499
|
+
}
|
|
1500
|
+
|
|
1501
|
+
.mushi-banner-label {
|
|
1502
|
+
flex: 1;
|
|
1503
|
+
text-align: center;
|
|
1504
|
+
overflow: hidden;
|
|
1505
|
+
text-overflow: ellipsis;
|
|
1506
|
+
}
|
|
1507
|
+
|
|
1508
|
+
.mushi-banner-btn {
|
|
1509
|
+
display: inline-flex;
|
|
1510
|
+
align-items: center;
|
|
1511
|
+
gap: 4px;
|
|
1512
|
+
padding: 3px 10px;
|
|
1513
|
+
border-radius: 3px;
|
|
1514
|
+
cursor: pointer;
|
|
1515
|
+
font: inherit;
|
|
1516
|
+
letter-spacing: inherit;
|
|
1517
|
+
transition: background 0.15s ease, opacity 0.15s ease;
|
|
1518
|
+
flex-shrink: 0;
|
|
1519
|
+
height: 24px;
|
|
1520
|
+
line-height: 1;
|
|
1521
|
+
}
|
|
1522
|
+
.mushi-banner-btn:focus-visible {
|
|
1523
|
+
outline: 2px solid ${vermillion};
|
|
1524
|
+
outline-offset: 2px;
|
|
1525
|
+
}
|
|
1526
|
+
|
|
1527
|
+
.mushi-banner-dismiss {
|
|
1528
|
+
background: transparent !important;
|
|
1529
|
+
border: none !important;
|
|
1530
|
+
opacity: 0.65;
|
|
1531
|
+
cursor: pointer;
|
|
1532
|
+
font-size: 14px;
|
|
1533
|
+
line-height: 1;
|
|
1534
|
+
padding: 4px 8px;
|
|
1535
|
+
margin-left: auto;
|
|
1536
|
+
flex-shrink: 0;
|
|
1537
|
+
color: inherit;
|
|
1538
|
+
border-radius: 3px;
|
|
1539
|
+
transition: opacity 0.15s, background 0.15s;
|
|
1540
|
+
}
|
|
1541
|
+
.mushi-banner-dismiss:hover {
|
|
1542
|
+
opacity: 1;
|
|
1543
|
+
background: rgba(0,0,0,0.12) !important;
|
|
1544
|
+
}
|
|
1545
|
+
.mushi-banner.neon .mushi-banner-dismiss:hover { background: rgba(0,0,0,0.18) !important; }
|
|
1546
|
+
|
|
1547
|
+
@keyframes mushi-banner-slide-in {
|
|
1548
|
+
from { transform: translateY(calc(-1 * 100%)); opacity: 0.5; }
|
|
1549
|
+
to { transform: translateY(0); opacity: 1; }
|
|
1550
|
+
}
|
|
1551
|
+
.mushi-banner.bottom {
|
|
1552
|
+
animation-name: mushi-banner-slide-in-bottom;
|
|
1553
|
+
}
|
|
1554
|
+
@keyframes mushi-banner-slide-in-bottom {
|
|
1555
|
+
from { transform: translateY(100%); opacity: 0.5; }
|
|
1556
|
+
to { transform: translateY(0); opacity: 1; }
|
|
1557
|
+
}
|
|
1558
|
+
|
|
1420
1559
|
@media (prefers-reduced-motion: reduce) {
|
|
1421
1560
|
*,
|
|
1422
1561
|
*::before,
|
|
@@ -1455,7 +1594,7 @@ function isSubmitShortcut(e) {
|
|
|
1455
1594
|
function escapeHtml(value) {
|
|
1456
1595
|
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
1457
1596
|
}
|
|
1458
|
-
var MushiWidget = class {
|
|
1597
|
+
var MushiWidget = class _MushiWidget {
|
|
1459
1598
|
constructor(config = {}, callbacks, sdkVersion = "0.7.0") {
|
|
1460
1599
|
this.sdkVersion = sdkVersion;
|
|
1461
1600
|
this.config = {
|
|
@@ -1475,6 +1614,7 @@ var MushiWidget = class {
|
|
|
1475
1614
|
locale: config.locale ?? "auto",
|
|
1476
1615
|
zIndex: config.zIndex ?? 99999,
|
|
1477
1616
|
trigger: config.trigger ?? "auto",
|
|
1617
|
+
bannerConfig: config.bannerConfig ?? {},
|
|
1478
1618
|
attachToSelector: config.attachToSelector ?? "",
|
|
1479
1619
|
inset: config.inset ?? {},
|
|
1480
1620
|
respectSafeArea: config.respectSafeArea ?? true,
|
|
@@ -1564,6 +1704,8 @@ var MushiWidget = class {
|
|
|
1564
1704
|
* Drives a different success copy so the user knows the report
|
|
1565
1705
|
* hasn't actually reached the console yet. */
|
|
1566
1706
|
lastSubmitQueuedOffline = false;
|
|
1707
|
+
/** Whether the user has clicked ✕ on the header banner this session. */
|
|
1708
|
+
bannerDismissed = false;
|
|
1567
1709
|
mount() {
|
|
1568
1710
|
if (this.host.isConnected) return;
|
|
1569
1711
|
document.body.appendChild(this.host);
|
|
@@ -1872,7 +2014,7 @@ var MushiWidget = class {
|
|
|
1872
2014
|
shouldRenderTrigger() {
|
|
1873
2015
|
if (!this.triggerVisible) return false;
|
|
1874
2016
|
if (this.triggerHiddenByScroll) return false;
|
|
1875
|
-
if (this.config.trigger === "manual" || this.config.trigger === "hidden" || this.config.trigger === "attach") {
|
|
2017
|
+
if (this.config.trigger === "manual" || this.config.trigger === "hidden" || this.config.trigger === "attach" || this.config.trigger === "banner") {
|
|
1876
2018
|
return false;
|
|
1877
2019
|
}
|
|
1878
2020
|
if (this.isMobileSmartHidden()) return false;
|
|
@@ -1881,6 +2023,81 @@ var MushiWidget = class {
|
|
|
1881
2023
|
const action = this.config.environments[this.detectEnvironment()];
|
|
1882
2024
|
return action !== "never" && action !== "manual";
|
|
1883
2025
|
}
|
|
2026
|
+
/** Height of the banner in px — kept in sync with the CSS `.mushi-banner` height (36px). */
|
|
2027
|
+
static BANNER_HEIGHT = 36;
|
|
2028
|
+
/** CSS property applied to document.body so host-app content doesn't slide under the banner. */
|
|
2029
|
+
static BODY_NUDGE_PROP = "--mushi-banner-offset";
|
|
2030
|
+
applyBodyNudge(position) {
|
|
2031
|
+
const h = `${_MushiWidget.BANNER_HEIGHT}px`;
|
|
2032
|
+
if (position === "top") {
|
|
2033
|
+
document.documentElement.style.setProperty(_MushiWidget.BODY_NUDGE_PROP, h);
|
|
2034
|
+
if (!document.body.style.paddingTop) {
|
|
2035
|
+
document.body.style.paddingTop = h;
|
|
2036
|
+
document.body.dataset.mushiBannerNudged = "top";
|
|
2037
|
+
}
|
|
2038
|
+
} else {
|
|
2039
|
+
document.documentElement.style.setProperty(_MushiWidget.BODY_NUDGE_PROP, h);
|
|
2040
|
+
if (!document.body.style.paddingBottom) {
|
|
2041
|
+
document.body.style.paddingBottom = h;
|
|
2042
|
+
document.body.dataset.mushiBannerNudged = "bottom";
|
|
2043
|
+
}
|
|
2044
|
+
}
|
|
2045
|
+
}
|
|
2046
|
+
removeBodyNudge() {
|
|
2047
|
+
document.documentElement.style.removeProperty(_MushiWidget.BODY_NUDGE_PROP);
|
|
2048
|
+
const nudged = document.body.dataset.mushiBannerNudged;
|
|
2049
|
+
if (nudged === "top") {
|
|
2050
|
+
document.body.style.paddingTop = "";
|
|
2051
|
+
delete document.body.dataset.mushiBannerNudged;
|
|
2052
|
+
} else if (nudged === "bottom") {
|
|
2053
|
+
document.body.style.paddingBottom = "";
|
|
2054
|
+
delete document.body.dataset.mushiBannerNudged;
|
|
2055
|
+
}
|
|
2056
|
+
}
|
|
2057
|
+
renderBanner() {
|
|
2058
|
+
if (this.config.trigger !== "banner") return;
|
|
2059
|
+
if (this.bannerDismissed) {
|
|
2060
|
+
this.removeBodyNudge();
|
|
2061
|
+
return;
|
|
2062
|
+
}
|
|
2063
|
+
if (!this.triggerVisible) return;
|
|
2064
|
+
if (this.isRouteHidden()) return;
|
|
2065
|
+
const bc = this.config.bannerConfig ?? {};
|
|
2066
|
+
const variant = bc.variant ?? "brand";
|
|
2067
|
+
const position = bc.position ?? "top";
|
|
2068
|
+
const bugLabel = bc.bugCta ?? "\u{1F41B} Report a bug";
|
|
2069
|
+
const showFeat = bc.featureCta !== false;
|
|
2070
|
+
const featLabel = bc.featureCtaLabel ?? "\u2728 Request feature";
|
|
2071
|
+
const zIdx = bc.zIndex ?? (this.config.zIndex ?? 99999) - 1;
|
|
2072
|
+
const banner = document.createElement("div");
|
|
2073
|
+
banner.className = `mushi-banner ${variant} ${position}`;
|
|
2074
|
+
banner.style.setProperty("--mushi-banner-z", String(zIdx));
|
|
2075
|
+
banner.setAttribute("role", "banner");
|
|
2076
|
+
const bugBtn = document.createElement("button");
|
|
2077
|
+
bugBtn.className = "mushi-banner-btn";
|
|
2078
|
+
bugBtn.textContent = bugLabel;
|
|
2079
|
+
bugBtn.addEventListener("click", () => this.open());
|
|
2080
|
+
const dismissBtn = document.createElement("button");
|
|
2081
|
+
dismissBtn.className = "mushi-banner-dismiss";
|
|
2082
|
+
dismissBtn.textContent = "\u2715";
|
|
2083
|
+
dismissBtn.setAttribute("aria-label", "Dismiss feedback banner");
|
|
2084
|
+
dismissBtn.addEventListener("click", () => {
|
|
2085
|
+
this.bannerDismissed = true;
|
|
2086
|
+
this.removeBodyNudge();
|
|
2087
|
+
this.render();
|
|
2088
|
+
});
|
|
2089
|
+
banner.appendChild(bugBtn);
|
|
2090
|
+
if (showFeat) {
|
|
2091
|
+
const featBtn = document.createElement("button");
|
|
2092
|
+
featBtn.className = "mushi-banner-btn";
|
|
2093
|
+
featBtn.textContent = featLabel;
|
|
2094
|
+
featBtn.addEventListener("click", () => this.open({ featureRequest: true }));
|
|
2095
|
+
banner.appendChild(featBtn);
|
|
2096
|
+
}
|
|
2097
|
+
banner.appendChild(dismissBtn);
|
|
2098
|
+
this.shadow.appendChild(banner);
|
|
2099
|
+
this.applyBodyNudge(position);
|
|
2100
|
+
}
|
|
1884
2101
|
effectiveTrigger() {
|
|
1885
2102
|
if (!this.config.smartHide || typeof window === "undefined") return this.config.trigger;
|
|
1886
2103
|
const smart = this.config.smartHide === true ? { onMobile: "edge-tab" } : this.config.smartHide;
|
|
@@ -1919,6 +2136,7 @@ var MushiWidget = class {
|
|
|
1919
2136
|
const style = document.createElement("style");
|
|
1920
2137
|
style.textContent = getWidgetStyles(theme);
|
|
1921
2138
|
this.shadow.appendChild(style);
|
|
2139
|
+
this.renderBanner();
|
|
1922
2140
|
if (this.shouldRenderTrigger()) {
|
|
1923
2141
|
const effectiveTrigger = this.effectiveTrigger();
|
|
1924
2142
|
const trigger = document.createElement("button");
|
|
@@ -4423,7 +4641,7 @@ function createProactiveManager(config = {}) {
|
|
|
4423
4641
|
|
|
4424
4642
|
// src/version.ts
|
|
4425
4643
|
var MUSHI_SDK_PACKAGE = "@mushi-mushi/web";
|
|
4426
|
-
var MUSHI_SDK_VERSION = "1.
|
|
4644
|
+
var MUSHI_SDK_VERSION = "1.7.1" ;
|
|
4427
4645
|
|
|
4428
4646
|
// src/mushi.ts
|
|
4429
4647
|
var instance = null;
|
|
@@ -5259,13 +5477,26 @@ function createInstance(config) {
|
|
|
5259
5477
|
}
|
|
5260
5478
|
function mergeRuntimeConfig(config, runtime) {
|
|
5261
5479
|
const nativeTrigger = runtime.native?.triggerMode;
|
|
5262
|
-
const
|
|
5480
|
+
const runtimeLauncher = runtime.widget?.launcher;
|
|
5481
|
+
const widgetTrigger = runtimeLauncher ?? runtime.widget?.trigger ?? (nativeTrigger === "none" || nativeTrigger === "shake" ? "manual" : void 0);
|
|
5482
|
+
const runtimeBannerVariant = runtime.widget?.bannerVariant;
|
|
5483
|
+
const runtimeBannerPosition = runtime.widget?.bannerPosition;
|
|
5484
|
+
const runtimeBannerBugCta = runtime.widget?.bannerBugCta;
|
|
5485
|
+
const runtimeBannerFeatureCta = runtime.widget?.bannerFeatureCta;
|
|
5486
|
+
const derivedBannerConfig = runtimeBannerVariant || runtimeBannerPosition || runtimeBannerBugCta != null || runtimeBannerFeatureCta != null ? {
|
|
5487
|
+
...config.widget?.bannerConfig ?? {},
|
|
5488
|
+
...runtimeBannerVariant ? { variant: runtimeBannerVariant } : {},
|
|
5489
|
+
...runtimeBannerPosition ? { position: runtimeBannerPosition } : {},
|
|
5490
|
+
...runtimeBannerBugCta != null ? { bugCta: runtimeBannerBugCta ?? void 0 } : {},
|
|
5491
|
+
...runtimeBannerFeatureCta != null ? { featureCta: runtimeBannerFeatureCta } : {}
|
|
5492
|
+
} : void 0;
|
|
5263
5493
|
return {
|
|
5264
5494
|
...config,
|
|
5265
5495
|
widget: {
|
|
5266
5496
|
...config.widget,
|
|
5267
5497
|
...runtime.widget,
|
|
5268
5498
|
...widgetTrigger ? { trigger: widgetTrigger } : {},
|
|
5499
|
+
...derivedBannerConfig ? { bannerConfig: derivedBannerConfig } : {},
|
|
5269
5500
|
// betaMode is local-only: set by the host app, not the dashboard.
|
|
5270
5501
|
// Restore it after the runtime spread so it is never silently cleared.
|
|
5271
5502
|
...config.widget?.betaMode ? { betaMode: config.widget.betaMode } : {}
|