@signalsupport/sdk 0.0.0-stage → 0.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/LICENSE +21 -0
- package/README.md +373 -2
- package/dist/chunks/app-7692BILt.js +2 -0
- package/dist/chunks/app-7692BILt.js.map +1 -0
- package/dist/chunks/constants-ClGbEpjT.js +2 -0
- package/dist/chunks/constants-ClGbEpjT.js.map +1 -0
- package/dist/chunks/support-x7N-k02b.js +4 -0
- package/dist/chunks/support-x7N-k02b.js.map +1 -0
- package/dist/chunks/widget-Bxsz5StK.js +2 -0
- package/dist/chunks/widget-Bxsz5StK.js.map +1 -0
- package/dist/client.d.ts +99 -0
- package/dist/constants.d.ts +2 -0
- package/dist/errors.d.ts +25 -0
- package/dist/evidence.d.ts +87 -0
- package/dist/iife.d.ts +12 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.js +1 -0
- package/dist/model.d.ts +201 -0
- package/dist/react.d.ts +26 -0
- package/dist/react.js +2 -0
- package/dist/react.js.map +1 -0
- package/dist/reporter.d.ts +14 -0
- package/dist/server.d.ts +54 -0
- package/dist/server.js +2 -0
- package/dist/server.js.map +1 -0
- package/dist/session.d.ts +29 -0
- package/dist/signal.iife.js +4 -0
- package/dist/signal.iife.js.map +1 -0
- package/dist/support.d.ts +108 -0
- package/dist/trail.d.ts +27 -0
- package/dist/widget/app.d.ts +31 -0
- package/dist/widget/copy.d.ts +104 -0
- package/dist/widget/ctx.d.ts +75 -0
- package/dist/widget/icons.d.ts +38 -0
- package/dist/widget/index.d.ts +111 -0
- package/dist/widget/index.js +1 -0
- package/dist/widget/parts.d.ts +28 -0
- package/dist/widget/pick.d.ts +30 -0
- package/dist/widget/screens/faq.d.ts +8 -0
- package/dist/widget/screens/feedback.d.ts +11 -0
- package/dist/widget/screens/home.d.ts +12 -0
- package/dist/widget/screens/report.d.ts +9 -0
- package/dist/widget/screens/reports.d.ts +26 -0
- package/dist/widget/store.d.ts +31 -0
- package/dist/widget/styles.d.ts +10 -0
- package/dist/widget/theme.d.ts +57 -0
- package/dist/widget/ui.d.ts +58 -0
- package/package.json +73 -4
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The panel's stylesheet, inside its own shadow root.
|
|
3
|
+
*
|
|
4
|
+
* ⚠ SHADOW DOM, SO NOTHING LEAKS EITHER WAY. The product's CSS cannot reach in
|
|
5
|
+
* (a global `button { … }` or a reset will not restyle the panel) and nothing
|
|
6
|
+
* here can reach out. The product's font still inherits through, which is what
|
|
7
|
+
* makes `font: inherit` look native. Every colour, radius and size is a token
|
|
8
|
+
* from the theme.
|
|
9
|
+
*/
|
|
10
|
+
export declare const STYLES = "\n/* Reset everything the page could push in, except the font: the panel should\n speak in the product's typeface, so that one is inherited on purpose. */\n:host { all: initial; font-family: inherit; }\n.sg-root { font-family: var(--sg-font); font-size: var(--sg-size); line-height: 1.5; color: var(--sg-text);\n -webkit-font-smoothing: antialiased; }\n.sg-root *, .sg-root *::before, .sg-root *::after { box-sizing: border-box; }\n.sg-root button, .sg-root input, .sg-root textarea { font: inherit; color: inherit; }\n.sg-root :focus-visible { outline: 2px solid var(--sg-accent); outline-offset: 2px; }\n\n/* ---------------------------------------------------------- launcher */\n.sg-launcher { position: fixed; bottom: 20px; z-index: var(--sg-z); display: inline-flex; align-items: center; gap: 8px;\n height: 44px; padding: 0 16px 0 14px; border: 0; border-radius: 999px; cursor: pointer;\n background: var(--sg-accent); color: var(--sg-accent-text); font-weight: 600; font-size: calc(var(--sg-size) + 0.5px);\n box-shadow: 0 10px 30px -10px color-mix(in srgb, var(--sg-accent) 70%, black), 0 2px 6px rgba(0,0,0,0.18);\n transition: transform .16s ease, box-shadow .16s ease; }\n.sg-launcher:hover { transform: translateY(-1px); }\n.sg-launcher.sg-right { right: 20px; } .sg-launcher.sg-left { left: 20px; }\n.sg-launcher[data-hidden=\"true\"] { opacity: 0; pointer-events: none; transform: scale(.9); }\n.sg-badge { min-width: 18px; height: 18px; padding: 0 5px; border-radius: 999px; background: var(--sg-danger); color: #fff;\n font-size: 11px; font-weight: 700; display: inline-flex; align-items: center; justify-content: center; line-height: 1; }\n.sg-launcher .sg-badge { margin-left: 2px; box-shadow: 0 0 0 2px var(--sg-accent); }\n\n/* ------------------------------------------------------------ frame */\n.sg-scrim { position: fixed; inset: 0; z-index: var(--sg-z); background: var(--sg-scrim); opacity: 0; transition: opacity .18s ease;\n backdrop-filter: blur(1.5px); }\n.sg-open .sg-scrim { opacity: 1; }\n.sg-panel { position: fixed; z-index: calc(var(--sg-z) + 1); display: flex; flex-direction: column; overflow: hidden;\n background: var(--sg-bg); color: var(--sg-text); border: 1px solid var(--sg-border); box-shadow: var(--sg-shadow);\n transition: transform .24s cubic-bezier(.22,1,.36,1), opacity .2s ease; }\n.sg-panel[hidden] { display: none; }\n/* The panel takes focus on open so Tab starts inside it; the container itself needs no ring. */\n.sg-panel:focus { outline: none; }\n.sg-drawer { top: 0; bottom: 0; width: min(var(--sg-width), 100vw); border-top: 0; border-bottom: 0; }\n.sg-drawer.sg-right { right: 0; border-right: 0; transform: translateX(100%); }\n.sg-drawer.sg-left { left: 0; border-left: 0; transform: translateX(-100%); }\n.sg-open .sg-drawer { transform: none; }\n.sg-modal { left: 50%; top: 50%; width: min(560px, calc(100vw - 32px)); height: min(720px, calc(100vh - 48px));\n border-radius: calc(var(--sg-radius) + 4px); transform: translate(-50%, -48%) scale(.98); opacity: 0; }\n.sg-open .sg-modal { transform: translate(-50%, -50%); opacity: 1; }\n.sg-popover { bottom: 80px; width: min(calc(var(--sg-width) - 40px), calc(100vw - 32px)); height: min(680px, calc(100vh - 110px));\n border-radius: calc(var(--sg-radius) + 4px); transform: translateY(12px) scale(.98); opacity: 0; transform-origin: bottom right; }\n.sg-popover.sg-right { right: 20px; } .sg-popover.sg-left { left: 20px; transform-origin: bottom left; }\n.sg-open .sg-popover { transform: none; opacity: 1; }\n.sg-sheet { left: 0; right: 0; bottom: 0; height: min(88vh, 760px); border-radius: calc(var(--sg-radius) + 6px) calc(var(--sg-radius) + 6px) 0 0;\n border-bottom: 0; transform: translateY(100%); }\n.sg-open .sg-sheet { transform: none; }\n.sg-grabber { width: 36px; height: 4px; border-radius: 4px; background: var(--sg-border); margin: 8px auto 0; flex: none; }\n.sg-accentline { position: absolute; inset: 0 0 auto 0; height: 1px; pointer-events: none;\n background: linear-gradient(90deg, var(--sg-accent), color-mix(in srgb, var(--sg-accent) 30%, transparent), transparent); }\n\n/* -------------------------------------------------------- structure */\n.sg-header { display: flex; align-items: center; gap: 10px; padding: 12px 14px; border-bottom: 1px solid var(--sg-border); flex: none; position: relative; }\n.sg-brand { width: 28px; height: 28px; border-radius: var(--sg-radius-sm); object-fit: contain; flex: none; }\n.sg-head-text { min-width: 0; flex: 1; }\n.sg-title { margin: 0; font-size: calc(var(--sg-size) + 1.5px); font-weight: 650; letter-spacing: -0.01em; line-height: 1.25;\n white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n.sg-sub { margin: 1px 0 0; font-size: calc(var(--sg-size) - 2.5px); color: var(--sg-dim); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n.sg-iconbtn { width: 30px; height: 30px; border: 0; background: transparent; border-radius: var(--sg-radius-sm); color: var(--sg-muted);\n display: inline-flex; align-items: center; justify-content: center; cursor: pointer; flex: none; }\n.sg-iconbtn:hover { background: var(--sg-raised); color: var(--sg-text); }\n.sg-body { flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior: contain; }\n.sg-pad { padding: 14px 16px; }\n.sg-stack > * + * { margin-top: 14px; }\n.sg-footer { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 10px 14px;\n border-top: 1px solid var(--sg-border); flex: none; }\n.sg-section { padding: 14px 16px; }\n.sg-section + .sg-section { border-top: 1px solid var(--sg-border); }\n.sg-section-head { display: flex; align-items: baseline; justify-content: space-between; margin-bottom: 10px; }\n.sg-section-title { margin: 0; font-size: calc(var(--sg-size) - 2px); font-weight: 650; letter-spacing: .06em; text-transform: uppercase; color: var(--sg-dim); }\n.sg-muted { color: var(--sg-muted); } .sg-dim { color: var(--sg-dim); }\n.sg-small { font-size: calc(var(--sg-size) - 1.5px); }\n.sg-mono { font-family: var(--sg-mono); font-size: calc(var(--sg-size) - 2px); letter-spacing: .02em; }\n.sg-p { margin: 0; }\n\n/* ----------------------------------------------------------- actions */\n.sg-action { width: 100%; display: flex; align-items: center; gap: 12px; padding: 11px 12px; border: 1px solid var(--sg-border);\n border-radius: var(--sg-radius); background: var(--sg-surface); cursor: pointer; text-align: left; transition: background .12s ease, border-color .12s ease; }\n.sg-action + .sg-action { margin-top: 8px; }\n.sg-action:hover { background: var(--sg-raised); border-color: color-mix(in srgb, var(--sg-accent) 35%, var(--sg-border)); }\n.sg-action-text { flex: 1; min-width: 0; }\n.sg-action-label { display: block; font-weight: 600; }\n.sg-action-hint { display: block; font-size: calc(var(--sg-size) - 1.5px); color: var(--sg-dim); }\n.sg-chev { color: var(--sg-dim); flex: none; }\n.sg-tile { width: 34px; height: 34px; border-radius: var(--sg-radius-sm); display: inline-flex; align-items: center; justify-content: center; flex: none; }\n.sg-tile.sg-sm { width: 28px; height: 28px; }\n.sg-tile-img { width: 20px; height: 20px; object-fit: contain; }\na.sg-action { color: inherit; text-decoration: none; }\n\n/* Host content, in the host's own styles. The wrapper only spaces it. */\n.sg-slot { padding: 12px 16px 0; }\n.sg-slot-header { padding: 0; display: flex; align-items: center; flex: none; }\n.sg-slot-footer { padding: 10px 14px; border-top: 1px solid var(--sg-border); flex: none; }\n.sg-slot-sent { padding: 18px 0 0; width: 100%; }\n.sg-slot-home-bottom { padding: 12px 16px 16px; }\n\n/* tones */\n.sg-t-accent { --sg-tone: var(--sg-accent); } .sg-t-info { --sg-tone: var(--sg-info); } .sg-t-warn { --sg-tone: var(--sg-warning); }\n.sg-t-danger { --sg-tone: var(--sg-danger); } .sg-t-success { --sg-tone: var(--sg-success); } .sg-t-neutral { --sg-tone: var(--sg-muted); }\n.sg-tile[class*=\"sg-t-\"] { color: var(--sg-tone); background: color-mix(in srgb, var(--sg-tone) 15%, transparent); }\n.sg-pill { display: inline-flex; align-items: center; gap: 5px; padding: 2px 8px; border-radius: 999px; white-space: nowrap;\n font-size: calc(var(--sg-size) - 2.5px); font-weight: 600; color: var(--sg-tone); background: color-mix(in srgb, var(--sg-tone) 14%, transparent);\n border: 1px solid color-mix(in srgb, var(--sg-tone) 30%, transparent); }\n.sg-banner { display: flex; gap: 10px; align-items: flex-start; padding: 11px 12px; border-radius: var(--sg-radius);\n background: color-mix(in srgb, var(--sg-tone) 11%, transparent); border: 1px solid color-mix(in srgb, var(--sg-tone) 32%, transparent); }\n.sg-banner-title { margin: 0; font-weight: 600; } .sg-banner-body { margin: 2px 0 0; color: var(--sg-muted); font-size: calc(var(--sg-size) - 1px); }\nbutton.sg-banner { width: 100%; text-align: left; cursor: pointer; }\n\n/* ---------------------------------------------------------- controls */\n.sg-btn { display: inline-flex; align-items: center; justify-content: center; gap: 7px; height: 34px; padding: 0 14px; border-radius: var(--sg-radius-sm);\n border: 1px solid transparent; background: var(--sg-accent); color: var(--sg-accent-text); font-weight: 600; cursor: pointer; white-space: nowrap;\n transition: filter .12s ease, opacity .12s ease; }\n.sg-btn:hover { filter: brightness(1.08); }\n.sg-btn:disabled { opacity: .45; cursor: default; filter: none; }\n.sg-btn-ghost { background: transparent; color: var(--sg-muted); border-color: var(--sg-border); }\n.sg-btn-ghost:hover { background: var(--sg-raised); color: var(--sg-text); filter: none; }\n.sg-btn-danger { background: transparent; color: var(--sg-danger); border-color: color-mix(in srgb, var(--sg-danger) 40%, transparent); }\n.sg-link { border: 0; background: none; padding: 0; color: var(--sg-accent); cursor: pointer; font-weight: 600; font-size: calc(var(--sg-size) - 1px); }\n.sg-link:hover { text-decoration: underline; }\n.sg-quiet-link { align-self: flex-start; border: 0; background: none; padding: 0; color: var(--sg-dim); cursor: pointer; font: inherit; font-size: calc(var(--sg-size) - 1.5px); text-decoration: underline; text-underline-offset: 3px; text-decoration-color: color-mix(in srgb, currentColor 40%, transparent); }\n.sg-quiet-link:hover { color: var(--sg-text); }\n.sg-closed { border-top: 1px solid var(--sg-border); }\n.sg-closed > summary, .sg-closed-link { display: flex; align-items: center; gap: 6px; width: 100%; padding: 12px 16px; list-style: none; cursor: pointer;\n border: 0; background: none; color: var(--sg-muted); font: inherit; font-weight: 600; font-size: calc(var(--sg-size) - 1.5px); text-align: left; }\n.sg-closed > summary::-webkit-details-marker { display: none; }\n.sg-closed > summary:hover, .sg-closed-link:hover { color: var(--sg-text); }\n.sg-closed > summary svg { transition: transform .15s ease; }\n.sg-closed[open] > summary svg { transform: rotate(90deg); }\n.sg-closed-link { justify-content: space-between; border-top: 1px solid var(--sg-border); }\n.sg-back { border: 0; background: none; padding: 0; color: var(--sg-muted); cursor: pointer; display: inline-flex; align-items: center; gap: 4px; }\n.sg-back:hover { color: var(--sg-text); }\n.sg-field { display: block; }\n.sg-label { display: block; font-weight: 600; margin-bottom: 4px; }\n.sg-hint { display: block; color: var(--sg-dim); font-size: calc(var(--sg-size) - 1.5px); margin-top: 4px; }\n.sg-err { display: block; color: var(--sg-danger); font-size: calc(var(--sg-size) - 1.5px); margin-top: 4px; }\n.sg-input, .sg-textarea { width: 100%; border: 1px solid var(--sg-border); background: var(--sg-surface); border-radius: var(--sg-radius-sm);\n padding: 8px 10px; outline: none; transition: border-color .12s ease, box-shadow .12s ease; }\n.sg-textarea { min-height: 84px; resize: vertical; line-height: 1.45; }\n.sg-input:focus, .sg-textarea:focus { border-color: var(--sg-accent); box-shadow: 0 0 0 3px color-mix(in srgb, var(--sg-accent) 22%, transparent); }\n.sg-input::placeholder, .sg-textarea::placeholder { color: var(--sg-dim); }\n.sg-invalid { border-color: var(--sg-danger) !important; }\n.sg-chips { display: flex; flex-wrap: wrap; gap: 6px; }\n.sg-chip { display: inline-flex; align-items: center; gap: 6px; padding: 5px 10px; border-radius: 999px; border: 1px solid var(--sg-border);\n background: var(--sg-surface); cursor: pointer; font-size: calc(var(--sg-size) - 1px); }\n.sg-chip:hover { background: var(--sg-raised); }\n.sg-chip[aria-pressed=\"true\"], .sg-chip[aria-checked=\"true\"] { border-color: var(--sg-accent); background: color-mix(in srgb, var(--sg-accent) 16%, transparent); color: var(--sg-text); }\n.sg-dot { width: 7px; height: 7px; border-radius: 999px; background: var(--sg-tone, var(--sg-accent)); flex: none; display: inline-block; }\n\n/* -------------------------------------------------------- step rail */\n.sg-steps { display: flex; padding: 12px 16px 10px; border-bottom: 1px solid var(--sg-border); flex: none; }\n.sg-step { flex: 1; min-width: 0; display: flex; flex-direction: column; align-items: center; }\n.sg-step-line { display: flex; align-items: center; width: 100%; }\n.sg-step-seg { flex: 1; height: 1px; background: var(--sg-border); }\n.sg-step-seg.sg-on { background: color-mix(in srgb, var(--sg-accent) 70%, transparent); }\n.sg-step-seg.sg-none { background: transparent; }\n.sg-step-node { width: 20px; height: 20px; border-radius: 999px; border: 1px solid var(--sg-border); display: inline-flex; align-items: center;\n justify-content: center; font-size: 10px; font-weight: 700; color: var(--sg-dim); flex: none; }\n.sg-step-node.sg-now { background: var(--sg-accent); border-color: var(--sg-accent); color: var(--sg-accent-text);\n box-shadow: 0 0 14px -2px color-mix(in srgb, var(--sg-accent) 85%, transparent); }\n.sg-step-node.sg-done { background: color-mix(in srgb, var(--sg-accent) 20%, transparent); border-color: color-mix(in srgb, var(--sg-accent) 60%, transparent); color: var(--sg-accent); }\n.sg-step-label { margin-top: 5px; font-size: calc(var(--sg-size) - 3px); color: var(--sg-dim); letter-spacing: .02em; }\n.sg-step-label.sg-now { color: var(--sg-text); font-weight: 600; }\n\n/* --------------------------------------------------- evidence cards */\n.sg-card { border: 1px solid var(--sg-border); border-radius: var(--sg-radius); background: var(--sg-surface); overflow: hidden; }\n.sg-card + .sg-card { margin-top: 8px; }\n.sg-card-head { display: flex; align-items: flex-start; gap: 10px; padding: 10px 12px; }\n.sg-card-text { flex: 1; min-width: 0; }\n.sg-card-title { margin: 0; font-weight: 600; }\n.sg-card-sum { margin: 1px 0 0; color: var(--sg-dim); font-size: calc(var(--sg-size) - 1.5px); }\n.sg-card-body { padding: 0 12px 12px; }\n.sg-card.sg-off .sg-card-body, .sg-card.sg-off .sg-card-title { opacity: .55; }\n.sg-switch { position: relative; width: 34px; height: 20px; border-radius: 999px; border: 0; background: var(--sg-raised); cursor: pointer; flex: none;\n box-shadow: inset 0 0 0 1px var(--sg-border); transition: background .15s ease; }\n.sg-switch::after { content: ''; position: absolute; top: 3px; left: 3px; width: 14px; height: 14px; border-radius: 999px; background: var(--sg-muted);\n transition: transform .15s ease, background .15s ease; }\n.sg-switch[aria-checked=\"true\"] { background: var(--sg-accent); box-shadow: none; }\n.sg-switch[aria-checked=\"true\"]::after { transform: translateX(14px); background: var(--sg-accent-text); }\n.sg-shot { display: block; width: 100%; max-height: 220px; object-fit: contain; border-radius: var(--sg-radius-sm); border: 1px solid var(--sg-border); background: var(--sg-bg); }\n.sg-json { margin: 0; max-height: 180px; overflow: auto; padding: 8px 10px; border-radius: var(--sg-radius-sm); background: var(--sg-bg);\n border: 1px solid var(--sg-border); font-family: var(--sg-mono); font-size: calc(var(--sg-size) - 2.5px); line-height: 1.5; color: var(--sg-muted); white-space: pre-wrap; word-break: break-word; }\n.sg-steplist { margin: 0; padding: 0; list-style: none; }\n.sg-steplist li { display: flex; gap: 8px; font-size: calc(var(--sg-size) - 1px); padding: 2px 0; }\n.sg-steplist .sg-when { width: 54px; flex: none; text-align: right; color: var(--sg-dim); font-size: calc(var(--sg-size) - 2.5px); padding-top: 1px; }\n.sg-steplist .sg-err-step { color: var(--sg-danger); }\n.sg-review dt { font-size: calc(var(--sg-size) - 3px); text-transform: uppercase; letter-spacing: .07em; color: var(--sg-dim); font-weight: 650; }\n.sg-review dd { margin: 2px 0 12px; white-space: pre-wrap; word-break: break-word; }\n.sg-attached { margin: 0; padding: 0; list-style: none; }\n.sg-attached li { display: flex; gap: 8px; align-items: center; padding: 2px 0; }\n\n/* ------------------------------------------------------------ lists */\n.sg-list { margin: 0; padding: 0; list-style: none; }\n.sg-row { width: 100%; display: flex; gap: 10px; align-items: flex-start; padding: 11px 16px; border: 0; background: transparent; cursor: pointer; text-align: left; }\n.sg-row:hover { background: var(--sg-surface); }\n.sg-list li + li .sg-row { border-top: 1px solid var(--sg-border); }\n.sg-row-main { flex: 1; min-width: 0; }\n.sg-row-top { display: flex; align-items: flex-start; gap: 8px; }\n.sg-row-title { flex: 1; min-width: 0; font-weight: 550; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n.sg-row-meta { margin-top: 2px; color: var(--sg-dim); font-size: calc(var(--sg-size) - 2.5px); display: flex; gap: 6px; flex-wrap: wrap; align-items: center; }\n.sg-row-cta { margin-top: 6px; display: inline-flex; align-items: center; gap: 6px; padding: 3px 8px; border-radius: var(--sg-radius-sm);\n font-size: calc(var(--sg-size) - 2px); font-weight: 600; color: var(--sg-tone); background: color-mix(in srgb, var(--sg-tone) 13%, transparent); }\n.sg-empty { text-align: center; padding: 34px 20px; }\n.sg-empty-icon { width: 44px; height: 44px; border-radius: 999px; border: 1px solid var(--sg-border); display: inline-flex; align-items: center; justify-content: center; color: var(--sg-dim); }\n\n/* ---------------------------------------------------- lifecycle rail */\n.sg-rail { display: flex; align-items: flex-start; }\n.sg-rail-stage { flex: 1; min-width: 0; display: flex; flex-direction: column; align-items: center; text-align: center; }\n.sg-rail-line { display: flex; align-items: center; width: 100%; }\n.sg-rail-seg { flex: 1; height: 2px; border-radius: 2px; background: var(--sg-border); }\n.sg-rail-seg.sg-on { background: var(--sg-tone, var(--sg-accent)); }\n.sg-rail-seg.sg-none { background: transparent; }\n.sg-rail-node { width: 12px; height: 12px; border-radius: 999px; border: 2px solid var(--sg-border); background: var(--sg-bg); flex: none; }\n.sg-rail-node.sg-on { border-color: var(--sg-tone, var(--sg-accent)); background: var(--sg-tone, var(--sg-accent)); }\n.sg-rail-node.sg-here { box-shadow: 0 0 0 4px color-mix(in srgb, var(--sg-tone, var(--sg-accent)) 25%, transparent); }\n.sg-rail-node.sg-yours { border-color: var(--sg-tone, var(--sg-accent)); border-style: dashed; }\n.sg-rail-node.sg-pulse { animation: sg-pulse 1.6s ease-in-out infinite; }\n.sg-rail-label { margin-top: 6px; font-size: calc(var(--sg-size) - 3px); color: var(--sg-dim); line-height: 1.2; }\n.sg-rail-label.sg-on { color: var(--sg-text); }\n.sg-rail-box { padding: 12px 10px 10px; border-radius: var(--sg-radius); border: 1px solid var(--sg-border);\n background: linear-gradient(180deg, var(--sg-surface), transparent); }\n@keyframes sg-pulse { 0%,100% { box-shadow: 0 0 0 3px color-mix(in srgb, var(--sg-tone, var(--sg-accent)) 15%, transparent); }\n 50% { box-shadow: 0 0 0 7px color-mix(in srgb, var(--sg-tone, var(--sg-accent)) 28%, transparent); } }\n\n/* ----------------------------------------------------- conversation */\n.sg-thread { display: flex; flex-direction: column; gap: 10px; }\n.sg-event { display: flex; align-items: center; gap: 8px; color: var(--sg-dim); font-size: calc(var(--sg-size) - 2px); }\n.sg-event::before, .sg-event::after { content: ''; flex: 1; height: 1px; background: var(--sg-border); }\n.sg-msg { max-width: 88%; padding: 9px 11px; border-radius: var(--sg-radius); white-space: pre-wrap; word-break: break-word; }\n.sg-msg-meta { display: block; font-size: calc(var(--sg-size) - 3px); color: var(--sg-dim); margin-bottom: 2px; }\n.sg-msg.sg-team { align-self: flex-start; background: var(--sg-surface); border: 1px solid var(--sg-border); border-top-left-radius: 4px; }\n.sg-msg.sg-you { align-self: flex-end; background: color-mix(in srgb, var(--sg-accent) 18%, var(--sg-bg));\n border: 1px solid color-mix(in srgb, var(--sg-accent) 35%, transparent); border-top-right-radius: 4px; }\n.sg-composer { display: flex; gap: 8px; align-items: flex-end; padding: 10px 14px; border-top: 1px solid var(--sg-border); flex: none; }\n.sg-composer .sg-textarea { min-height: 38px; max-height: 140px; }\n\n/* -------------------------------------------------------- confirmed */\n.sg-confirm { height: 100%; display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; padding: 24px; }\n.sg-ring { width: 50px; height: 50px; border-radius: 999px; display: inline-flex; align-items: center; justify-content: center; color: var(--sg-success);\n background: color-mix(in srgb, var(--sg-success) 12%, transparent); border: 1px solid color-mix(in srgb, var(--sg-success) 40%, transparent); }\n.sg-ref { margin-top: 8px; padding: 3px 10px; border-radius: 999px; border: 1px solid var(--sg-border); background: var(--sg-surface); font-family: var(--sg-mono); font-size: calc(var(--sg-size) - 2px); }\n\n/* ------------------------------------------------------------- faq */\n.sg-faq { border: 1px solid var(--sg-border); border-radius: var(--sg-radius); background: var(--sg-surface); }\n.sg-faq + .sg-faq { margin-top: 8px; }\n.sg-faq summary { list-style: none; cursor: pointer; padding: 10px 12px; font-weight: 600; display: flex; gap: 8px; align-items: center; }\n.sg-faq summary::-webkit-details-marker { display: none; }\n.sg-faq summary .sg-chev { margin-left: auto; transition: transform .15s ease; }\n.sg-faq[open] summary .sg-chev { transform: rotate(90deg); }\n.sg-faq-a { padding: 0 12px 12px; color: var(--sg-muted); white-space: pre-wrap; }\n\n.sg-skeleton { height: 46px; border-radius: var(--sg-radius-sm); background: var(--sg-surface); margin: 8px 16px; animation: sg-shimmer 1.2s ease-in-out infinite; }\n@keyframes sg-shimmer { 50% { opacity: .55; } }\n.sg-spin { width: 14px; height: 14px; border-radius: 999px; border: 2px solid currentColor; border-right-color: transparent; animation: sg-rot .7s linear infinite; }\n@keyframes sg-rot { to { transform: rotate(360deg); } }\n.sg-refresh.sg-busy svg { animation: sg-rot .7s linear infinite; }\n.sg-sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }\n\n/* A phone gets a sheet whatever the layout asked for: a drawer at 375px is\n a full screen without a way to see what is behind it. */\n@media (max-width: 560px) {\n .sg-panel.sg-drawer, .sg-panel.sg-modal, .sg-panel.sg-popover { left: 0; right: 0; top: auto; bottom: 0; width: 100%; height: min(90vh, 760px);\n border-radius: calc(var(--sg-radius) + 6px) calc(var(--sg-radius) + 6px) 0 0; border: 1px solid var(--sg-border); border-bottom: 0;\n transform: translateY(100%); opacity: 1; }\n .sg-open .sg-panel { transform: none; }\n .sg-launcher { bottom: calc(16px + env(safe-area-inset-bottom)); }\n}\n/* ------------------------------------------------------------ capture mode */\n/* The bar sits over the product while the person goes to the screen they mean.\n The root is visibility:hidden then; this opts back in. Small and centred so it\n covers as little of the product as it can. */\n.sg-pickbar { visibility: visible; position: fixed; top: 12px; left: 50%; transform: translateX(-50%);\n z-index: calc(var(--sg-z) + 2); display: flex; align-items: center; gap: 10px; max-width: calc(100vw - 24px);\n padding: 6px 6px 6px 14px; border-radius: 999px; background: var(--sg-bg); color: var(--sg-text);\n border: 1px solid var(--sg-border); box-shadow: var(--sg-shadow); }\n.sg-pickdot { flex: none; width: 8px; height: 8px; border-radius: 50%; background: var(--sg-accent);\n box-shadow: 0 0 0 0 color-mix(in srgb, var(--sg-accent) 60%, transparent); animation: sg-pickpulse 1.6s ease-out infinite; }\n@keyframes sg-pickpulse { 70% { box-shadow: 0 0 0 7px transparent; } 100% { box-shadow: 0 0 0 0 transparent; } }\n.sg-pickhint { min-width: 0; font-size: calc(var(--sg-size) - 0.5px); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n.sg-pickbar .sg-btn { border-radius: 999px; }\n.sg-pickbar .sg-btn-ghost { padding: 0 12px; }\n/* A phone: the bar takes the width, the hint gets two lines, Cancel is its \u00D7 alone. */\n@media (max-width: 480px) {\n .sg-pickbar { left: 12px; right: 12px; transform: none; border-radius: 22px; }\n .sg-pickhint { flex: 1; white-space: normal; line-height: 1.25; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }\n .sg-pick-cancel-label { display: none; }\n .sg-pickbar .sg-btn-ghost { padding: 0; width: 34px; }\n}\n@media (max-width: 480px) and (pointer: coarse) { .sg-pickbar .sg-btn-ghost { width: 44px; } }\n/* A finger, not a cursor: every control gets a 44px target (WCAG 2.5.5, Apple\n HIG), and text fields at least 16px so iOS does not zoom the page on focus.\n Visual sizes stay; where a control is drawn small, its hit area grows. */\n@media (pointer: coarse) {\n .sg-iconbtn { width: 44px; height: 44px; }\n .sg-btn { height: 44px; padding: 0 16px; }\n .sg-chip { min-height: 44px; padding: 8px 14px; }\n .sg-link, .sg-back, .sg-quiet-link { min-height: 44px; display: inline-flex; align-items: center; }\n .sg-closed > summary, .sg-closed-link { min-height: 44px; }\n .sg-switch::before { content: ''; position: absolute; inset: -12px -5px; }\n /* .sg-root-qualified: the base rule giving form fields \"font: inherit\" is\n .sg-root input, which outranks a bare class and kept them at 12.5px. */\n .sg-root .sg-input, .sg-root .sg-textarea { font-size: max(16px, var(--sg-size)); }\n .sg-input { min-height: 44px; }\n .sg-composer .sg-textarea { min-height: 44px; }\n .sg-faq summary { min-height: 44px; }\n .sg-row, .sg-action { min-height: 44px; }\n}\n@media (prefers-reduced-motion: reduce) {\n .sg-panel, .sg-scrim, .sg-launcher { transition: none; }\n .sg-rail-node.sg-pulse, .sg-skeleton, .sg-spin, .sg-refresh.sg-busy svg, .sg-pickdot { animation: none; }\n}\n";
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How the panel looks, as data.
|
|
3
|
+
*
|
|
4
|
+
* A theme is a set of tokens, and every pixel of the panel is drawn from them,
|
|
5
|
+
* so a brand changes the whole thing by naming a few colours. Presets cover
|
|
6
|
+
* the common kinds of product; anything not named falls back to the preset.
|
|
7
|
+
* `scheme: 'auto'` follows the operating system and switches live.
|
|
8
|
+
*/
|
|
9
|
+
export interface Theme {
|
|
10
|
+
/** `auto` follows the operating system. */
|
|
11
|
+
scheme: 'dark' | 'light' | 'auto';
|
|
12
|
+
/** The brand colour: primary buttons, the active step, focus. */
|
|
13
|
+
accent: string;
|
|
14
|
+
/** Text on the accent. */
|
|
15
|
+
accentText: string;
|
|
16
|
+
/** The panel itself. */
|
|
17
|
+
background: string;
|
|
18
|
+
/** Cards and inputs on the panel. */
|
|
19
|
+
surface: string;
|
|
20
|
+
/** A card on a card, hover. */
|
|
21
|
+
raised: string;
|
|
22
|
+
border: string;
|
|
23
|
+
text: string;
|
|
24
|
+
muted: string;
|
|
25
|
+
dim: string;
|
|
26
|
+
success: string;
|
|
27
|
+
warning: string;
|
|
28
|
+
danger: string;
|
|
29
|
+
info: string;
|
|
30
|
+
/** Corner radius of cards, in px. Buttons and inputs follow it. */
|
|
31
|
+
radius: number;
|
|
32
|
+
/** `inherit` uses the product's own font, which is usually what looks native. */
|
|
33
|
+
font: string;
|
|
34
|
+
mono: string;
|
|
35
|
+
/** Base text size, in px. */
|
|
36
|
+
fontSize: number;
|
|
37
|
+
/** Panel width for the drawer and popover, in px. */
|
|
38
|
+
width: number;
|
|
39
|
+
shadow: string;
|
|
40
|
+
/** The dimming behind a drawer, modal or sheet. */
|
|
41
|
+
scrim: string;
|
|
42
|
+
}
|
|
43
|
+
export type PresetName = 'midnight' | 'daylight' | 'studio' | 'paper';
|
|
44
|
+
export declare const PRESETS: Record<PresetName, Theme>;
|
|
45
|
+
export type ThemeInput = PresetName | (Partial<Theme> & {
|
|
46
|
+
preset?: PresetName;
|
|
47
|
+
});
|
|
48
|
+
/**
|
|
49
|
+
* The theme to draw with, right now.
|
|
50
|
+
*
|
|
51
|
+
* With `scheme: 'auto'` the colours come from the dark or light preset
|
|
52
|
+
* matching the system, and only the brand colours the caller named carry
|
|
53
|
+
* across, so a single `accent` produces a good panel in both.
|
|
54
|
+
*/
|
|
55
|
+
export declare function resolveTheme(input: ThemeInput | undefined, prefersDark: boolean): Theme;
|
|
56
|
+
/** The theme as CSS custom properties on the panel's root. */
|
|
57
|
+
export declare function themeVars(t: Theme): string;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/** @jsxImportSource preact */
|
|
2
|
+
import type { ComponentChildren, Ref } from 'preact';
|
|
3
|
+
import type { StatusView, Tone } from '../model.js';
|
|
4
|
+
import { type IconName } from './icons.js';
|
|
5
|
+
/** The few pieces every screen shares. Classes only; every value is a theme token. */
|
|
6
|
+
export declare function Tile({ icon, tone, small }: {
|
|
7
|
+
icon: IconName;
|
|
8
|
+
tone: Tone;
|
|
9
|
+
small?: boolean;
|
|
10
|
+
}): import("preact").JSX.Element;
|
|
11
|
+
export declare function Pill({ tone, children }: {
|
|
12
|
+
tone: Tone;
|
|
13
|
+
children: ComponentChildren;
|
|
14
|
+
}): import("preact").JSX.Element;
|
|
15
|
+
export declare function Button({ children, onClick, variant, disabled, busy, icon, type, testId, btnRef, label, }: {
|
|
16
|
+
children: ComponentChildren;
|
|
17
|
+
onClick?: () => void;
|
|
18
|
+
variant?: 'primary' | 'ghost' | 'danger';
|
|
19
|
+
disabled?: boolean;
|
|
20
|
+
busy?: boolean;
|
|
21
|
+
icon?: IconName;
|
|
22
|
+
type?: 'button' | 'submit';
|
|
23
|
+
testId?: string;
|
|
24
|
+
btnRef?: Ref<HTMLButtonElement>;
|
|
25
|
+
/** An accessible name, for when the visible label can be hidden (the capture bar's Cancel on a phone). */
|
|
26
|
+
label?: string;
|
|
27
|
+
}): import("preact").JSX.Element;
|
|
28
|
+
export declare function Field({ label, hint, error, children, }: {
|
|
29
|
+
label: string;
|
|
30
|
+
hint?: string;
|
|
31
|
+
error?: string | null;
|
|
32
|
+
children: ComponentChildren;
|
|
33
|
+
}): import("preact").JSX.Element;
|
|
34
|
+
/**
|
|
35
|
+
* Where a host's own content appears. A native `<slot>`, so the content stays
|
|
36
|
+
* in the host's document: its CSS styles it and its framework renders it. Only
|
|
37
|
+
* drawn when filled, so an unused slot leaves no gap.
|
|
38
|
+
*/
|
|
39
|
+
export declare function SlotPoint({ name, filled }: {
|
|
40
|
+
name: string;
|
|
41
|
+
filled: ReadonlySet<string>;
|
|
42
|
+
}): import("preact").JSX.Element | null;
|
|
43
|
+
export declare function Switch({ on, onChange, label }: {
|
|
44
|
+
on: boolean;
|
|
45
|
+
onChange: (on: boolean) => void;
|
|
46
|
+
label: string;
|
|
47
|
+
}): import("preact").JSX.Element;
|
|
48
|
+
/**
|
|
49
|
+
* A report's journey as a drawn path.
|
|
50
|
+
*
|
|
51
|
+
* The line between the nodes is the information: "how far along is this, and
|
|
52
|
+
* what comes next" is the question someone opening their own report has, and
|
|
53
|
+
* a status word alone cannot answer it. The last node is theirs, dashed until
|
|
54
|
+
* it is their turn.
|
|
55
|
+
*/
|
|
56
|
+
export declare function Rail({ view }: {
|
|
57
|
+
view: StatusView;
|
|
58
|
+
}): import("preact").JSX.Element;
|
package/package.json
CHANGED
|
@@ -1,6 +1,75 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@signalsupport/sdk",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.7.1",
|
|
4
|
+
"description": "Support inside your product, backed by Signal: report issues with evidence, follow them, hear back, and confirm the fix. A themeable panel for any framework, a headless core, and server helpers.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"sideEffects": false,
|
|
8
|
+
"main": "./dist/index.js",
|
|
9
|
+
"module": "./dist/index.js",
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"import": "./dist/index.js",
|
|
15
|
+
"default": "./dist/index.js"
|
|
16
|
+
},
|
|
17
|
+
"./widget": {
|
|
18
|
+
"types": "./dist/widget/index.d.ts",
|
|
19
|
+
"import": "./dist/widget/index.js",
|
|
20
|
+
"default": "./dist/widget/index.js"
|
|
21
|
+
},
|
|
22
|
+
"./react": {
|
|
23
|
+
"types": "./dist/react.d.ts",
|
|
24
|
+
"import": "./dist/react.js",
|
|
25
|
+
"default": "./dist/react.js"
|
|
26
|
+
},
|
|
27
|
+
"./server": {
|
|
28
|
+
"types": "./dist/server.d.ts",
|
|
29
|
+
"import": "./dist/server.js",
|
|
30
|
+
"default": "./dist/server.js"
|
|
31
|
+
},
|
|
32
|
+
"./package.json": "./package.json"
|
|
33
|
+
},
|
|
34
|
+
"files": [
|
|
35
|
+
"dist",
|
|
36
|
+
"README.md",
|
|
37
|
+
"LICENSE"
|
|
38
|
+
],
|
|
39
|
+
"scripts": {
|
|
40
|
+
"build": "vite build && vite build --mode iife && tsc -p tsconfig.build.json --emitDeclarationOnly",
|
|
41
|
+
"typecheck": "tsc -p tsconfig.build.json --noEmit",
|
|
42
|
+
"size": "node scripts/size.mjs",
|
|
43
|
+
"check": "npx --yes publint@latest --pack npm --strict && npx --yes @arethetypeswrong/cli@latest --pack . --profile esm-only",
|
|
44
|
+
"prepublishOnly": "npm run build && npm run size"
|
|
45
|
+
},
|
|
46
|
+
"keywords": [
|
|
47
|
+
"signal",
|
|
48
|
+
"support",
|
|
49
|
+
"bug-report",
|
|
50
|
+
"feedback",
|
|
51
|
+
"widget",
|
|
52
|
+
"help-center",
|
|
53
|
+
"triage"
|
|
54
|
+
],
|
|
55
|
+
"publishConfig": {
|
|
56
|
+
"access": "public"
|
|
57
|
+
},
|
|
58
|
+
"engines": {
|
|
59
|
+
"node": ">=18"
|
|
60
|
+
},
|
|
61
|
+
"unpkg": "./dist/signal.iife.js",
|
|
62
|
+
"jsdelivr": "./dist/signal.iife.js",
|
|
63
|
+
"peerDependencies": {
|
|
64
|
+
"react": ">=17"
|
|
65
|
+
},
|
|
66
|
+
"peerDependenciesMeta": {
|
|
67
|
+
"react": {
|
|
68
|
+
"optional": true
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
"homepage": "https://signal.character.xyz",
|
|
72
|
+
"devDependencies": {
|
|
73
|
+
"preact": "^10"
|
|
74
|
+
}
|
|
75
|
+
}
|