@mhosaic/feedback 0.7.1 → 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.
@@ -30,6 +30,9 @@ function createApiClient(options) {
30
30
  if (payload.user?.id) {
31
31
  form.append("user", JSON.stringify(payload.user));
32
32
  }
33
+ if (payload.widget_version) {
34
+ form.append("widget_version", payload.widget_version);
35
+ }
33
36
  const response = await fetcher(`${endpoint}/api/feedback/v1/reports/`, {
34
37
  method: "POST",
35
38
  headers: { Authorization: `Bearer ${options.apiKey}` },
@@ -605,8 +608,28 @@ import { useCallback } from "preact/hooks";
605
608
 
606
609
  // src/widget/Fab.tsx
607
610
  import { jsx } from "preact/jsx-runtime";
611
+ function ChatBubbleIcon() {
612
+ return /* @__PURE__ */ jsx(
613
+ "svg",
614
+ {
615
+ width: "24",
616
+ height: "24",
617
+ viewBox: "0 0 24 24",
618
+ fill: "none",
619
+ "aria-hidden": "true",
620
+ focusable: "false",
621
+ children: /* @__PURE__ */ jsx(
622
+ "path",
623
+ {
624
+ d: "M21 11.5a8.38 8.38 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.38 8.38 0 0 1-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 0 1-.9-3.8 8.5 8.5 0 0 1 4.7-7.6 8.38 8.38 0 0 1 3.8-.9h.5a8.48 8.48 0 0 1 8 8v.5z",
625
+ fill: "currentColor"
626
+ }
627
+ )
628
+ }
629
+ );
630
+ }
608
631
  function Fab({ label, onClick }) {
609
- return /* @__PURE__ */ jsx("button", { type: "button", class: "fab", "aria-label": label, onClick, children: "\u{1F4AC}" });
632
+ return /* @__PURE__ */ jsx("button", { type: "button", class: "fab", "aria-label": label, title: label, onClick, children: /* @__PURE__ */ jsx(ChatBubbleIcon, {}) });
610
633
  }
611
634
 
612
635
  // src/widget/Form.tsx
@@ -1601,28 +1624,60 @@ var WIDGET_STYLES = `
1601
1624
  }
1602
1625
  }
1603
1626
 
1627
+ /* FAB \u2014 56px (Material standard), two-layer elevation, scale-on-press,
1628
+ custom SVG icon (no emoji \u2014 emoji renders inconsistently across OSes
1629
+ and can't inherit color). */
1604
1630
  .fab {
1605
1631
  position: fixed;
1606
1632
  bottom: 24px;
1607
1633
  right: 24px;
1608
- width: 52px;
1609
- height: 52px;
1634
+ width: 56px;
1635
+ height: 56px;
1610
1636
  border-radius: 999px;
1611
1637
  background: var(--mfb-accent);
1612
1638
  color: var(--mfb-accent-contrast);
1613
1639
  border: none;
1614
1640
  cursor: pointer;
1615
- box-shadow: 0 4px 14px rgba(0, 0, 0, 0.18);
1616
- font-size: 22px;
1641
+ /* Two-layer elevation: ambient (soft, large) + key (tighter, near). */
1642
+ box-shadow:
1643
+ 0 4px 12px rgba(0, 0, 0, 0.08),
1644
+ 0 2px 4px rgba(0, 0, 0, 0.12);
1617
1645
  display: grid;
1618
1646
  place-items: center;
1619
- transition: transform 120ms ease, box-shadow 120ms ease;
1647
+ transition: transform 180ms cubic-bezier(0.4, 0, 0.2, 1),
1648
+ box-shadow 180ms cubic-bezier(0.4, 0, 0.2, 1);
1649
+ }
1650
+
1651
+ .fab:hover {
1652
+ transform: translateY(-2px);
1653
+ box-shadow:
1654
+ 0 8px 24px rgba(0, 0, 0, 0.12),
1655
+ 0 3px 6px rgba(0, 0, 0, 0.16);
1656
+ }
1657
+ .fab:active {
1658
+ transform: translateY(0) scale(0.96);
1659
+ box-shadow:
1660
+ 0 3px 8px rgba(0, 0, 0, 0.10),
1661
+ 0 1px 2px rgba(0, 0, 0, 0.14);
1662
+ }
1663
+ .fab:focus-visible {
1664
+ outline: 2px solid var(--mfb-accent-contrast);
1665
+ outline-offset: 3px;
1666
+ box-shadow:
1667
+ 0 0 0 4px var(--mfb-accent),
1668
+ 0 4px 12px rgba(0, 0, 0, 0.08),
1669
+ 0 2px 4px rgba(0, 0, 0, 0.12);
1670
+ }
1671
+ @media (prefers-color-scheme: dark) {
1672
+ /* Slightly desaturate so the FAB doesn't glow against dark backgrounds. */
1673
+ .fab { box-shadow:
1674
+ 0 4px 12px rgba(0, 0, 0, 0.32),
1675
+ 0 2px 4px rgba(0, 0, 0, 0.40); }
1676
+ }
1677
+ @media (prefers-reduced-motion: reduce) {
1678
+ .fab { transition: none; }
1679
+ .fab:hover, .fab:active { transform: none; }
1620
1680
  }
1621
-
1622
- .fab:hover { transform: translateY(-1px); box-shadow: 0 6px 18px rgba(0, 0, 0, 0.24); }
1623
- .fab:active { transform: translateY(0) scale(0.96); box-shadow: 0 3px 10px rgba(0, 0, 0, 0.22); }
1624
- .fab:focus-visible { outline: 2px solid #fff; outline-offset: 3px; box-shadow: 0 0 0 4px var(--mfb-accent), 0 4px 14px rgba(0, 0, 0, 0.18); }
1625
- @media (prefers-reduced-motion: reduce) { .fab { transition: none; } .fab:hover, .fab:active { transform: none; } }
1626
1681
 
1627
1682
  .backdrop {
1628
1683
  position: fixed;
@@ -1636,11 +1691,16 @@ var WIDGET_STYLES = `
1636
1691
  background: var(--mfb-bg);
1637
1692
  border-radius: calc(var(--mfb-radius) * 1.5);
1638
1693
  box-shadow: 0 20px 48px rgba(0, 0, 0, 0.25);
1639
- width: min(420px, 92vw);
1640
- padding: 20px;
1694
+ /* 440px is the industry sweet spot for short forms \u2014 Linear, Plain,
1695
+ Sentry all sit in the 420-480 range. 92vw caps it on narrow screens. */
1696
+ width: min(440px, 92vw);
1697
+ /* 24px is shadcn's default; gives every input room to breathe. */
1698
+ padding: 24px;
1641
1699
  display: flex;
1642
1700
  flex-direction: column;
1643
- gap: 12px;
1701
+ /* 18px between major blocks (h2 \u2192 field \u2192 field \u2192 footer). Within a
1702
+ field group, .field uses a tighter 6px label-to-input gap. */
1703
+ gap: 18px;
1644
1704
  position: relative;
1645
1705
  /* Cap modal height on short viewports (mobile landscape, tiny laptops)
1646
1706
  so the form scrolls inside the modal rather than overflowing the
@@ -1649,7 +1709,23 @@ var WIDGET_STYLES = `
1649
1709
  overflow-y: auto;
1650
1710
  }
1651
1711
 
1652
- .modal h2 { margin: 0 0 4px; font-size: 18px; font-weight: 600; padding-right: 28px; }
1712
+ .modal h2 {
1713
+ margin: 0;
1714
+ font-size: 17px;
1715
+ font-weight: 600;
1716
+ padding-right: 28px;
1717
+ letter-spacing: -0.01em;
1718
+ }
1719
+
1720
+ /* The form sits inside .modal as a single flex child, so the modal-level
1721
+ gap doesn't separate the form's *own* children. Mirror the column +
1722
+ gap pattern on the form itself; 22px lands in the middle of the
1723
+ 20-24px field-to-field range the design critic recommended. */
1724
+ .modal form {
1725
+ display: flex;
1726
+ flex-direction: column;
1727
+ gap: 22px;
1728
+ }
1653
1729
 
1654
1730
  .modal-close {
1655
1731
  position: absolute;
@@ -1671,15 +1747,22 @@ var WIDGET_STYLES = `
1671
1747
  .modal-close:hover { background: var(--mfb-surface); color: var(--mfb-text); }
1672
1748
  .modal-close:focus-visible { outline: 2px solid var(--mfb-accent); outline-offset: 2px; }
1673
1749
 
1674
- .field { display: flex; flex-direction: column; gap: 4px; font-size: 13px; }
1750
+ /* Each field group: label (13px medium, muted) + input (14px regular)
1751
+ stacked with a 6px gap. The 18px modal-level gap separates groups. */
1752
+ .field { display: flex; flex-direction: column; gap: 6px; font-size: 13px; }
1675
1753
 
1676
- .field label { color: var(--mfb-text-muted); }
1754
+ .field label {
1755
+ color: var(--mfb-text-muted);
1756
+ font-weight: 500;
1757
+ font-size: 12px;
1758
+ letter-spacing: 0.01em;
1759
+ }
1677
1760
 
1678
1761
  .field input, .field select, .field textarea {
1679
1762
  font-family: inherit;
1680
1763
  font-size: 14px;
1681
1764
  color: inherit;
1682
- padding: 8px 10px;
1765
+ padding: 9px 12px;
1683
1766
  border: 1px solid var(--mfb-border);
1684
1767
  border-radius: var(--mfb-radius);
1685
1768
  background: var(--mfb-surface);
@@ -1703,28 +1786,44 @@ var WIDGET_STYLES = `
1703
1786
  background-position: right 10px center;
1704
1787
  }
1705
1788
 
1706
- .field textarea { min-height: 88px; resize: vertical; }
1789
+ .field textarea { min-height: 96px; resize: vertical; line-height: 1.45; }
1707
1790
 
1708
- .row { display: flex; gap: 8px; }
1791
+ .row { display: flex; gap: 12px; }
1709
1792
  .row > * { flex: 1; }
1710
1793
 
1711
- .actions { display: flex; gap: 8px; justify-content: flex-end; padding-top: 8px; }
1794
+ /* Footer separation: border-top + 16px breathing room, Stripe/Linear pattern.
1795
+ Stops Cancel/Send from floating against the dropzone or page-URL footer. */
1796
+ .actions {
1797
+ display: flex;
1798
+ gap: 8px;
1799
+ justify-content: flex-end;
1800
+ padding-top: 16px;
1801
+ margin-top: 4px;
1802
+ border-top: 1px solid var(--mfb-border);
1803
+ }
1712
1804
 
1713
1805
  .btn {
1714
- padding: 8px 14px;
1806
+ padding: 9px 16px;
1715
1807
  border-radius: var(--mfb-radius);
1716
1808
  border: 1px solid var(--mfb-border);
1717
1809
  background: var(--mfb-bg);
1718
1810
  color: var(--mfb-text);
1719
1811
  font: inherit;
1812
+ font-weight: 500;
1720
1813
  cursor: pointer;
1814
+ transition: background 120ms ease, border-color 120ms ease;
1721
1815
  }
1816
+ .btn:hover { background: var(--mfb-surface); }
1722
1817
 
1723
1818
  .btn--primary {
1724
1819
  background: var(--mfb-accent);
1725
1820
  color: var(--mfb-accent-contrast);
1726
1821
  border-color: var(--mfb-accent);
1727
1822
  }
1823
+ .btn--primary:hover {
1824
+ background: color-mix(in srgb, var(--mfb-accent) 88%, black);
1825
+ border-color: color-mix(in srgb, var(--mfb-accent) 88%, black);
1826
+ }
1728
1827
 
1729
1828
  .btn[disabled] { opacity: 0.6; cursor: not-allowed; }
1730
1829
 
@@ -1748,7 +1847,7 @@ var WIDGET_STYLES = `
1748
1847
  .screenshot-dropzone {
1749
1848
  border: 1px dashed var(--mfb-border);
1750
1849
  border-radius: var(--mfb-radius);
1751
- padding: 14px 12px;
1850
+ padding: 18px 14px;
1752
1851
  text-align: center;
1753
1852
  cursor: pointer;
1754
1853
  background: var(--mfb-surface);
@@ -1821,12 +1920,12 @@ var WIDGET_STYLES = `
1821
1920
  text-transform: uppercase;
1822
1921
  font-weight: 600;
1823
1922
  letter-spacing: 0.04em;
1923
+ font-size: 10px;
1824
1924
  }
1825
1925
  .page-context-url {
1826
1926
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
1827
- background: var(--mfb-surface);
1828
- padding: 4px 6px;
1829
- border-radius: 4px;
1927
+ font-size: 11px;
1928
+ color: var(--mfb-text-muted);
1830
1929
  flex: 1;
1831
1930
  overflow: hidden;
1832
1931
  text-overflow: ellipsis;
@@ -2402,6 +2501,9 @@ function createFeedback(config) {
2402
2501
  capture_method: screenshot ? manualScreenshot ? "manual" : "html2canvas" : "none",
2403
2502
  technical_context
2404
2503
  };
2504
+ if ("0.7.3") {
2505
+ payload.widget_version = "0.7.3";
2506
+ }
2405
2507
  if (screenshot) payload.screenshot = screenshot;
2406
2508
  if (values.synthetic) payload.synthetic = true;
2407
2509
  if (user?.id !== void 0 && user.id !== null && user.id !== "") {
@@ -2486,4 +2588,4 @@ function createFeedback(config) {
2486
2588
  export {
2487
2589
  createFeedback
2488
2590
  };
2489
- //# sourceMappingURL=chunk-F3FVKCBE.mjs.map
2591
+ //# sourceMappingURL=chunk-2VBGH64F.mjs.map