@mrrocket/sdk 0.4.0 → 0.9.0
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/CHANGELOG.md +43 -0
- package/README.md +137 -8
- package/dist/api-client.d.ts +213 -0
- package/dist/api-client.js +67 -0
- package/dist/api-client.js.map +1 -0
- package/dist/api.d.ts +9 -109
- package/dist/api.js +7 -62
- package/dist/api.js.map +1 -1
- package/dist/browser/mrrocket-flows.js +64 -0
- package/dist/browser/mrrocket-messenger.js +313 -0
- package/dist/browser/mrrocket-push.js +1 -0
- package/dist/browser/mrrocket-replay.js +3 -3
- package/dist/browser/mrrocket-sw.js +1 -0
- package/dist/browser/mrrocket.js +2 -1
- package/dist/browser.d.ts +3 -2
- package/dist/browser.js +6 -1
- package/dist/browser.js.map +1 -1
- package/dist/capture.d.ts +1 -13
- package/dist/capture.js +1 -22
- package/dist/capture.js.map +1 -1
- package/dist/client.d.ts +36 -1
- package/dist/client.js +161 -6
- package/dist/client.js.map +1 -1
- package/dist/context.d.ts +10 -0
- package/dist/context.js.map +1 -1
- package/dist/core.d.ts +64 -3
- package/dist/core.js +54 -2
- package/dist/core.js.map +1 -1
- package/dist/feedback.d.ts +19 -4
- package/dist/feedback.js +655 -190
- package/dist/feedback.js.map +1 -1
- package/dist/flows-ui.d.ts +23 -0
- package/dist/flows-ui.js +384 -0
- package/dist/flows-ui.js.map +1 -0
- package/dist/flows-web.d.ts +19 -0
- package/dist/flows-web.js +42 -0
- package/dist/flows-web.js.map +1 -0
- package/dist/flows.d.ts +222 -0
- package/dist/flows.js +409 -0
- package/dist/flows.js.map +1 -0
- package/dist/index.d.ts +5 -2
- package/dist/index.js +13 -1
- package/dist/index.js.map +1 -1
- package/dist/messenger-ui.d.ts +47 -0
- package/dist/messenger-ui.js +583 -0
- package/dist/messenger-ui.js.map +1 -0
- package/dist/messenger.d.ts +37 -0
- package/dist/messenger.js +69 -0
- package/dist/messenger.js.map +1 -0
- package/dist/proxy.d.ts +34 -1
- package/dist/proxy.js +14 -1
- package/dist/proxy.js.map +1 -1
- package/dist/push-web.d.ts +43 -0
- package/dist/push-web.js +81 -0
- package/dist/push-web.js.map +1 -0
- package/dist/rage.d.ts +14 -0
- package/dist/rage.js +27 -0
- package/dist/rage.js.map +1 -0
- package/dist/react-native/index.d.cts +640 -3
- package/dist/react-native/index.d.ts +640 -3
- package/dist/react-native/index.js +2015 -34
- package/dist/react-native/index.js.map +1 -1
- package/dist/styles-css.d.ts +6 -0
- package/dist/styles-css.js +327 -0
- package/dist/styles-css.js.map +1 -0
- package/dist/styles.d.ts +1 -2
- package/dist/styles.js +3 -134
- package/dist/styles.js.map +1 -1
- package/dist/ui.d.ts +3 -0
- package/dist/ui.js +12 -0
- package/dist/ui.js.map +1 -1
- package/package.json +20 -4
package/dist/styles.js
CHANGED
|
@@ -2,142 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
// src/styles.ts
|
|
4
4
|
import { useEffect } from "react";
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
.ckw-root{--ckw-accent:#3f76ff;--ckw-accent-ink:#fff;--ckw-bg:#fff;--ckw-bg2:#f7f7f8;--ckw-bg3:#eeeff1;--ckw-fg:#1c1d20;--ckw-fg2:#5d6068;--ckw-fg3:#8b8e96;--ckw-line:#e4e5e8;--ckw-danger:#d92d20;--ckw-shadow:0 8px 30px rgba(16,18,24,.16);
|
|
8
|
-
font-size:14px;line-height:1.45;font-family:inherit;color:var(--ckw-fg);box-sizing:border-box;-webkit-font-smoothing:antialiased}
|
|
9
|
-
.ckw-root[data-theme=dark]{--ckw-bg:#17181b;--ckw-bg2:#1f2024;--ckw-bg3:#292a30;--ckw-fg:#f1f2f4;--ckw-fg2:#b0b3ba;--ckw-fg3:#7e818a;--ckw-line:#2e2f35;--ckw-shadow:0 8px 30px rgba(0,0,0,.5)}
|
|
10
|
-
@media (prefers-color-scheme:dark){.ckw-root[data-theme=auto]{--ckw-bg:#17181b;--ckw-bg2:#1f2024;--ckw-bg3:#292a30;--ckw-fg:#f1f2f4;--ckw-fg2:#b0b3ba;--ckw-fg3:#7e818a;--ckw-line:#2e2f35;--ckw-shadow:0 8px 30px rgba(0,0,0,.5)}}
|
|
11
|
-
.ckw-root *,.ckw-root *::before,.ckw-root *::after{box-sizing:border-box}
|
|
12
|
-
.ckw-root button,.ckw-root input,.ckw-root select,.ckw-root textarea{font:inherit;color:inherit;margin:0}
|
|
13
|
-
.ckw-root button{cursor:pointer}
|
|
14
|
-
.ckw-root :focus-visible{outline:2px solid var(--ckw-accent);outline-offset:2px}
|
|
15
|
-
.ckw-board{width:100%;max-width:760px;margin:0 auto;background:var(--ckw-bg);min-width:0}
|
|
16
|
-
.ckw-head{display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap;margin-bottom:12px}
|
|
17
|
-
.ckw-title{font-size:20px;font-weight:600;margin:0;letter-spacing:-.01em}
|
|
18
|
-
.ckw-sub{color:var(--ckw-fg2);margin:2px 0 0;font-size:13px}
|
|
19
|
-
.ckw-btn{display:inline-flex;align-items:center;justify-content:center;gap:6px;height:32px;padding:0 12px;border-radius:8px;border:1px solid var(--ckw-line);background:var(--ckw-bg);font-weight:500;font-size:13px;white-space:nowrap}
|
|
20
|
-
.ckw-btn:hover{background:var(--ckw-bg2)}
|
|
21
|
-
.ckw-btn[disabled]{opacity:.55;cursor:not-allowed}
|
|
22
|
-
.ckw-btn-primary{background:var(--ckw-accent);border-color:var(--ckw-accent);color:var(--ckw-accent-ink)}
|
|
23
|
-
.ckw-btn-primary:hover{background:var(--ckw-accent);filter:brightness(1.08)}
|
|
24
|
-
.ckw-btn-ghost{border-color:transparent;background:transparent;color:var(--ckw-fg2)}
|
|
25
|
-
.ckw-icon{width:16px;height:16px;flex:none;display:block}
|
|
26
|
-
.ckw-tabs{display:flex;gap:4px;border-bottom:1px solid var(--ckw-line);margin-bottom:12px;overflow-x:auto}
|
|
27
|
-
.ckw-tab{background:none;border:0;border-bottom:2px solid transparent;padding:8px 10px;margin-bottom:-1px;color:var(--ckw-fg2);font-weight:500;font-size:13px;white-space:nowrap}
|
|
28
|
-
.ckw-tab[aria-selected=true]{color:var(--ckw-fg);border-bottom-color:var(--ckw-accent)}
|
|
29
|
-
.ckw-tools{display:flex;gap:8px;flex-wrap:wrap;align-items:center;margin-bottom:10px}
|
|
30
|
-
.ckw-input,.ckw-select,.ckw-textarea{width:100%;border:1px solid var(--ckw-line);border-radius:8px;background:var(--ckw-bg);padding:7px 10px;font-size:14px;min-height:34px}
|
|
31
|
-
.ckw-input::placeholder,.ckw-textarea::placeholder{color:var(--ckw-fg3)}
|
|
32
|
-
.ckw-textarea{resize:vertical;min-height:72px}
|
|
33
|
-
.ckw-search{flex:1 1 160px;min-width:0}
|
|
34
|
-
.ckw-seg{display:inline-flex;border:1px solid var(--ckw-line);border-radius:8px;overflow:hidden}
|
|
35
|
-
.ckw-seg button{border:0;background:var(--ckw-bg);padding:0 10px;height:32px;font-size:13px;color:var(--ckw-fg2)}
|
|
36
|
-
.ckw-seg button[aria-pressed=true]{background:var(--ckw-bg3);color:var(--ckw-fg);font-weight:500}
|
|
37
|
-
.ckw-chips{display:flex;gap:6px;flex-wrap:wrap;margin-bottom:10px}
|
|
38
|
-
.ckw-chip{border:1px solid var(--ckw-line);background:var(--ckw-bg);border-radius:999px;padding:3px 10px;font-size:12px;color:var(--ckw-fg2)}
|
|
39
|
-
.ckw-chip[aria-pressed=true]{background:var(--ckw-fg);color:var(--ckw-bg);border-color:var(--ckw-fg)}
|
|
40
|
-
.ckw-list{list-style:none;margin:0;padding:0;border:1px solid var(--ckw-line);border-radius:8px;overflow:hidden}
|
|
41
|
-
.ckw-list>li+li{border-top:1px solid var(--ckw-line)}
|
|
42
|
-
.ckw-row{display:flex;gap:12px;align-items:flex-start;padding:10px 12px;background:var(--ckw-bg)}
|
|
43
|
-
.ckw-row:hover{background:var(--ckw-bg2)}
|
|
44
|
-
.ckw-vote{flex:none;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:0;width:44px;min-height:48px;border:1px solid var(--ckw-line);border-radius:8px;background:var(--ckw-bg);font-size:13px;font-weight:600;font-variant-numeric:tabular-nums;padding:4px 0;color:var(--ckw-fg2)}
|
|
45
|
-
.ckw-vote:hover{border-color:var(--ckw-accent);color:var(--ckw-accent)}
|
|
46
|
-
.ckw-vote[aria-pressed=true]{background:var(--ckw-accent);border-color:var(--ckw-accent);color:var(--ckw-accent-ink)}
|
|
47
|
-
.ckw-vote-sm{width:auto;min-height:0;flex-direction:row;gap:4px;padding:2px 8px}
|
|
48
|
-
.ckw-main{flex:1;min-width:0;text-align:left}
|
|
49
|
-
.ckw-link{display:block;width:100%;text-align:left;background:none;border:0;padding:0;font-weight:600;font-size:14px;color:var(--ckw-fg);overflow-wrap:anywhere}
|
|
50
|
-
.ckw-link:hover{color:var(--ckw-accent)}
|
|
51
|
-
.ckw-excerpt{margin:2px 0 0;color:var(--ckw-fg2);font-size:13px;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;overflow-wrap:anywhere}
|
|
52
|
-
.ckw-meta{display:flex;gap:8px;align-items:center;margin-top:6px;color:var(--ckw-fg3);font-size:12px;flex-wrap:wrap}
|
|
53
|
-
.ckw-pill{display:inline-flex;align-items:center;border-radius:999px;padding:1px 8px;font-size:11px;font-weight:600;background:var(--ckw-bg3);color:var(--ckw-fg2)}
|
|
54
|
-
.ckw-pill[data-s=planned]{background:rgba(63,118,255,.14);color:#3f76ff}
|
|
55
|
-
.ckw-pill[data-s=progress]{background:rgba(245,158,11,.16);color:#b45309}
|
|
56
|
-
.ckw-pill[data-s=shipped]{background:rgba(22,163,74,.15);color:#15803d}
|
|
57
|
-
.ckw-root[data-theme=dark] .ckw-pill[data-s=progress]{color:#fbbf24}
|
|
58
|
-
.ckw-root[data-theme=dark] .ckw-pill[data-s=shipped]{color:#4ade80}
|
|
59
|
-
@media (prefers-color-scheme:dark){.ckw-root[data-theme=auto] .ckw-pill[data-s=progress]{color:#fbbf24}.ckw-root[data-theme=auto] .ckw-pill[data-s=shipped]{color:#4ade80}}
|
|
60
|
-
.ckw-stat{display:inline-flex;align-items:center;gap:4px}
|
|
61
|
-
.ckw-empty{border:1px dashed var(--ckw-line);border-radius:8px;padding:28px 16px;text-align:center;color:var(--ckw-fg2)}
|
|
62
|
-
.ckw-error{border:1px solid color-mix(in srgb,var(--ckw-danger) 40%,transparent);background:color-mix(in srgb,var(--ckw-danger) 8%,transparent);color:var(--ckw-danger);border-radius:8px;padding:8px 10px;font-size:13px;display:flex;gap:8px;align-items:center;justify-content:space-between;margin-bottom:10px}
|
|
63
|
-
.ckw-skel{height:68px;border-radius:8px;background:var(--ckw-bg2);animation:ckw-sh 1.2s ease-in-out infinite;margin-bottom:6px}
|
|
64
|
-
@keyframes ckw-sh{50%{opacity:.5}}
|
|
65
|
-
@media (prefers-reduced-motion:reduce){.ckw-skel{animation:none}.ckw-root *{transition:none!important}}
|
|
66
|
-
.ckw-form{display:flex;flex-direction:column;gap:10px;border:1px solid var(--ckw-line);border-radius:8px;padding:12px;margin-bottom:12px;background:var(--ckw-bg)}
|
|
67
|
-
.ckw-field{display:flex;flex-direction:column;gap:4px}
|
|
68
|
-
.ckw-label{font-size:12px;font-weight:600;color:var(--ckw-fg2)}
|
|
69
|
-
.ckw-actions{display:flex;gap:8px;justify-content:flex-end}
|
|
70
|
-
.ckw-dupes{border:1px solid var(--ckw-line);border-radius:8px;background:var(--ckw-bg2);padding:8px 10px;font-size:13px}
|
|
71
|
-
.ckw-dupes p{margin:0 0 4px;color:var(--ckw-fg2);font-size:12px}
|
|
72
|
-
.ckw-dupe{display:flex;gap:8px;align-items:center;justify-content:space-between;padding:3px 0}
|
|
73
|
-
.ckw-dupe span{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
74
|
-
.ckw-cols{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:12px}
|
|
75
|
-
@media (max-width:640px){.ckw-cols{grid-template-columns:1fr}}
|
|
76
|
-
.ckw-col h3{font-size:12px;text-transform:uppercase;letter-spacing:.04em;color:var(--ckw-fg2);margin:0 0 8px;display:flex;gap:6px;align-items:center}
|
|
77
|
-
.ckw-card{border:1px solid var(--ckw-line);border-radius:8px;padding:10px;margin-bottom:8px;background:var(--ckw-bg)}
|
|
78
|
-
.ckw-card .ckw-link{margin-bottom:6px}
|
|
79
|
-
.ckw-entry{padding:12px 0;border-bottom:1px solid var(--ckw-line)}
|
|
80
|
-
.ckw-entry time{font-size:12px;color:var(--ckw-fg3)}
|
|
81
|
-
.ckw-entry h3{font-size:15px;margin:2px 0 4px}
|
|
82
|
-
.ckw-entry p{margin:0;color:var(--ckw-fg2);white-space:pre-wrap;overflow-wrap:anywhere}
|
|
83
|
-
.ckw-back{margin-bottom:8px;padding-left:4px}
|
|
84
|
-
.ckw-detail-head{display:flex;gap:12px;align-items:flex-start}
|
|
85
|
-
.ckw-detail-head h2{margin:0 0 4px;font-size:18px;overflow-wrap:anywhere}
|
|
86
|
-
.ckw-body{white-space:pre-wrap;overflow-wrap:anywhere;color:var(--ckw-fg2);margin:12px 0}
|
|
87
|
-
.ckw-h{font-size:13px;font-weight:600;margin:16px 0 8px}
|
|
88
|
-
.ckw-comment{padding:8px 0;border-top:1px solid var(--ckw-line)}
|
|
89
|
-
.ckw-comment b{font-size:13px}
|
|
90
|
-
.ckw-comment p{margin:2px 0 0;white-space:pre-wrap;overflow-wrap:anywhere}
|
|
91
|
-
.ckw-team{margin-left:6px;background:var(--ckw-accent);color:var(--ckw-accent-ink);border-radius:4px;padding:0 5px;font-size:10px;font-weight:700;text-transform:uppercase;vertical-align:1px}
|
|
92
|
-
.ckw-time{color:var(--ckw-fg3);font-size:12px;margin-left:6px}
|
|
93
|
-
.ckw-sr{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}
|
|
94
|
-
/* Floating widget */
|
|
95
|
-
.ckw-fab{position:fixed;z-index:2147483000;bottom:20px;display:inline-flex;align-items:center;gap:8px;height:40px;padding:0 16px;border-radius:999px;border:0;background:var(--ckw-accent);color:var(--ckw-accent-ink);font-weight:600;font-size:14px;box-shadow:var(--ckw-shadow)}
|
|
96
|
-
.ckw-fab[data-pos=bottom-right],.ckw-pop[data-pos=bottom-right]{right:20px}
|
|
97
|
-
.ckw-fab[data-pos=bottom-left],.ckw-pop[data-pos=bottom-left]{left:20px}
|
|
98
|
-
.ckw-pop{position:fixed;z-index:2147483001;bottom:70px;width:380px;max-width:calc(100vw - 24px);max-height:min(560px,calc(100vh - 90px));display:flex;flex-direction:column;background:var(--ckw-bg);border:1px solid var(--ckw-line);border-radius:12px;box-shadow:var(--ckw-shadow);overflow:hidden}
|
|
99
|
-
.ckw-pop-head{display:flex;align-items:center;justify-content:space-between;padding:10px 12px;border-bottom:1px solid var(--ckw-line);font-weight:600}
|
|
100
|
-
.ckw-pop-body{padding:12px;overflow-y:auto;flex:1}
|
|
101
|
-
.ckw-pop-foot{padding:8px 12px;border-top:1px solid var(--ckw-line);display:flex;justify-content:space-between;align-items:center;font-size:13px}
|
|
102
|
-
.ckw-pop-foot a{color:var(--ckw-accent);text-decoration:none;font-weight:500}
|
|
103
|
-
.ckw-pop .ckw-list{border:0;border-radius:0}
|
|
104
|
-
.ckw-pop .ckw-row{padding:8px 0}
|
|
105
|
-
.ckw-pop .ckw-form{border:0;padding:0;margin:12px 0 0}
|
|
106
|
-
@media (max-width:520px){.ckw-pop{left:0!important;right:0!important;bottom:0;width:100%;max-width:100%;border-radius:12px 12px 0 0;max-height:85vh}.ckw-fab{bottom:14px}.ckw-fab[data-pos=bottom-right]{right:14px}.ckw-fab[data-pos=bottom-left]{left:14px}}
|
|
107
|
-
/* Survey */
|
|
108
|
-
.ckw-survey{position:fixed;z-index:2147483000;left:20px;bottom:20px;width:360px;max-width:calc(100vw - 24px);background:var(--ckw-bg);border:1px solid var(--ckw-line);border-radius:12px;box-shadow:var(--ckw-shadow);padding:14px;animation:ckw-in .2s ease-out}
|
|
109
|
-
@keyframes ckw-in{from{opacity:0;transform:translateY(8px)}}
|
|
110
|
-
@media (max-width:520px){.ckw-survey{left:0;right:0;bottom:0;width:100%;max-width:100%;border-radius:12px 12px 0 0}}
|
|
111
|
-
.ckw-sv-top{display:flex;justify-content:space-between;align-items:center;margin-bottom:8px}
|
|
112
|
-
.ckw-dots{display:flex;gap:4px}
|
|
113
|
-
.ckw-dot{width:6px;height:6px;border-radius:50%;background:var(--ckw-bg3)}
|
|
114
|
-
.ckw-dot[data-on=true]{background:var(--ckw-accent)}
|
|
115
|
-
.ckw-q{font-weight:600;font-size:15px;margin:0 0 2px;border:0;padding:0}
|
|
116
|
-
.ckw-root .ckw-q:focus-visible{outline:none}
|
|
117
|
-
.ckw-qd{color:var(--ckw-fg2);font-size:13px;margin:0 0 10px}
|
|
118
|
-
.ckw-scale{display:flex;gap:4px;flex-wrap:wrap}
|
|
119
|
-
.ckw-num{flex:1 1 0;min-width:26px;height:34px;border:1px solid var(--ckw-line);background:var(--ckw-bg);border-radius:8px;font-size:13px;font-weight:600;padding:0}
|
|
120
|
-
.ckw-num:hover{border-color:var(--ckw-accent)}
|
|
121
|
-
.ckw-num[aria-pressed=true]{background:var(--ckw-accent);color:var(--ckw-accent-ink);border-color:var(--ckw-accent)}
|
|
122
|
-
.ckw-root .ckw-star{background:none;border:0;padding:2px;color:var(--ckw-bg3)}
|
|
123
|
-
.ckw-root .ckw-star[data-on=true]{color:#f5a524}
|
|
124
|
-
.ckw-star svg{width:28px;height:28px}
|
|
125
|
-
.ckw-lh{display:flex;justify-content:space-between;color:var(--ckw-fg3);font-size:11px;margin-top:4px}
|
|
126
|
-
.ckw-opts{display:flex;flex-direction:column;gap:6px}
|
|
127
|
-
.ckw-opt{display:flex;gap:8px;align-items:center;border:1px solid var(--ckw-line);border-radius:8px;padding:7px 10px;background:var(--ckw-bg);cursor:pointer}
|
|
128
|
-
.ckw-opt:has(input:checked){border-color:var(--ckw-accent);background:color-mix(in srgb,var(--ckw-accent) 8%,transparent)}
|
|
129
|
-
.ckw-opt input{accent-color:var(--ckw-accent)}
|
|
130
|
-
.ckw-sv-foot{display:flex;justify-content:space-between;align-items:center;gap:8px;margin-top:12px}
|
|
131
|
-
.ckw-thanks{text-align:center;padding:14px 0;display:flex;flex-direction:column;align-items:center;gap:8px}
|
|
132
|
-
.ckw-tick{width:32px;height:32px;border-radius:50%;background:var(--ckw-accent);color:var(--ckw-accent-ink);display:flex;align-items:center;justify-content:center}
|
|
133
|
-
`;
|
|
5
|
+
import { injectStyles } from "./styles-css.js";
|
|
6
|
+
import { CSS } from "./styles-css.js";
|
|
134
7
|
var useStyles = () => {
|
|
135
8
|
useEffect(() => {
|
|
136
|
-
|
|
137
|
-
const el = document.createElement("style");
|
|
138
|
-
el.id = STYLE_ID;
|
|
139
|
-
el.textContent = CSS;
|
|
140
|
-
document.head.appendChild(el);
|
|
9
|
+
injectStyles();
|
|
141
10
|
}, []);
|
|
142
11
|
};
|
|
143
12
|
export {
|
package/dist/styles.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/styles.ts"],"sourcesContent":["\"use client\";\n\nimport { useEffect } from \"react\";\n\nconst STYLE_ID = \"ckw-styles\";\n\n/** The one stylesheet for every Cockpit widget. Everything is scoped under `.ckw-root` and prefixed `ckw-`. */\nexport const CSS = `\n.ckw-root{--ckw-accent:#3f76ff;--ckw-accent-ink:#fff;--ckw-bg:#fff;--ckw-bg2:#f7f7f8;--ckw-bg3:#eeeff1;--ckw-fg:#1c1d20;--ckw-fg2:#5d6068;--ckw-fg3:#8b8e96;--ckw-line:#e4e5e8;--ckw-danger:#d92d20;--ckw-shadow:0 8px 30px rgba(16,18,24,.16);\nfont-size:14px;line-height:1.45;font-family:inherit;color:var(--ckw-fg);box-sizing:border-box;-webkit-font-smoothing:antialiased}\n.ckw-root[data-theme=dark]{--ckw-bg:#17181b;--ckw-bg2:#1f2024;--ckw-bg3:#292a30;--ckw-fg:#f1f2f4;--ckw-fg2:#b0b3ba;--ckw-fg3:#7e818a;--ckw-line:#2e2f35;--ckw-shadow:0 8px 30px rgba(0,0,0,.5)}\n@media (prefers-color-scheme:dark){.ckw-root[data-theme=auto]{--ckw-bg:#17181b;--ckw-bg2:#1f2024;--ckw-bg3:#292a30;--ckw-fg:#f1f2f4;--ckw-fg2:#b0b3ba;--ckw-fg3:#7e818a;--ckw-line:#2e2f35;--ckw-shadow:0 8px 30px rgba(0,0,0,.5)}}\n.ckw-root *,.ckw-root *::before,.ckw-root *::after{box-sizing:border-box}\n.ckw-root button,.ckw-root input,.ckw-root select,.ckw-root textarea{font:inherit;color:inherit;margin:0}\n.ckw-root button{cursor:pointer}\n.ckw-root :focus-visible{outline:2px solid var(--ckw-accent);outline-offset:2px}\n.ckw-board{width:100%;max-width:760px;margin:0 auto;background:var(--ckw-bg);min-width:0}\n.ckw-head{display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap;margin-bottom:12px}\n.ckw-title{font-size:20px;font-weight:600;margin:0;letter-spacing:-.01em}\n.ckw-sub{color:var(--ckw-fg2);margin:2px 0 0;font-size:13px}\n.ckw-btn{display:inline-flex;align-items:center;justify-content:center;gap:6px;height:32px;padding:0 12px;border-radius:8px;border:1px solid var(--ckw-line);background:var(--ckw-bg);font-weight:500;font-size:13px;white-space:nowrap}\n.ckw-btn:hover{background:var(--ckw-bg2)}\n.ckw-btn[disabled]{opacity:.55;cursor:not-allowed}\n.ckw-btn-primary{background:var(--ckw-accent);border-color:var(--ckw-accent);color:var(--ckw-accent-ink)}\n.ckw-btn-primary:hover{background:var(--ckw-accent);filter:brightness(1.08)}\n.ckw-btn-ghost{border-color:transparent;background:transparent;color:var(--ckw-fg2)}\n.ckw-icon{width:16px;height:16px;flex:none;display:block}\n.ckw-tabs{display:flex;gap:4px;border-bottom:1px solid var(--ckw-line);margin-bottom:12px;overflow-x:auto}\n.ckw-tab{background:none;border:0;border-bottom:2px solid transparent;padding:8px 10px;margin-bottom:-1px;color:var(--ckw-fg2);font-weight:500;font-size:13px;white-space:nowrap}\n.ckw-tab[aria-selected=true]{color:var(--ckw-fg);border-bottom-color:var(--ckw-accent)}\n.ckw-tools{display:flex;gap:8px;flex-wrap:wrap;align-items:center;margin-bottom:10px}\n.ckw-input,.ckw-select,.ckw-textarea{width:100%;border:1px solid var(--ckw-line);border-radius:8px;background:var(--ckw-bg);padding:7px 10px;font-size:14px;min-height:34px}\n.ckw-input::placeholder,.ckw-textarea::placeholder{color:var(--ckw-fg3)}\n.ckw-textarea{resize:vertical;min-height:72px}\n.ckw-search{flex:1 1 160px;min-width:0}\n.ckw-seg{display:inline-flex;border:1px solid var(--ckw-line);border-radius:8px;overflow:hidden}\n.ckw-seg button{border:0;background:var(--ckw-bg);padding:0 10px;height:32px;font-size:13px;color:var(--ckw-fg2)}\n.ckw-seg button[aria-pressed=true]{background:var(--ckw-bg3);color:var(--ckw-fg);font-weight:500}\n.ckw-chips{display:flex;gap:6px;flex-wrap:wrap;margin-bottom:10px}\n.ckw-chip{border:1px solid var(--ckw-line);background:var(--ckw-bg);border-radius:999px;padding:3px 10px;font-size:12px;color:var(--ckw-fg2)}\n.ckw-chip[aria-pressed=true]{background:var(--ckw-fg);color:var(--ckw-bg);border-color:var(--ckw-fg)}\n.ckw-list{list-style:none;margin:0;padding:0;border:1px solid var(--ckw-line);border-radius:8px;overflow:hidden}\n.ckw-list>li+li{border-top:1px solid var(--ckw-line)}\n.ckw-row{display:flex;gap:12px;align-items:flex-start;padding:10px 12px;background:var(--ckw-bg)}\n.ckw-row:hover{background:var(--ckw-bg2)}\n.ckw-vote{flex:none;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:0;width:44px;min-height:48px;border:1px solid var(--ckw-line);border-radius:8px;background:var(--ckw-bg);font-size:13px;font-weight:600;font-variant-numeric:tabular-nums;padding:4px 0;color:var(--ckw-fg2)}\n.ckw-vote:hover{border-color:var(--ckw-accent);color:var(--ckw-accent)}\n.ckw-vote[aria-pressed=true]{background:var(--ckw-accent);border-color:var(--ckw-accent);color:var(--ckw-accent-ink)}\n.ckw-vote-sm{width:auto;min-height:0;flex-direction:row;gap:4px;padding:2px 8px}\n.ckw-main{flex:1;min-width:0;text-align:left}\n.ckw-link{display:block;width:100%;text-align:left;background:none;border:0;padding:0;font-weight:600;font-size:14px;color:var(--ckw-fg);overflow-wrap:anywhere}\n.ckw-link:hover{color:var(--ckw-accent)}\n.ckw-excerpt{margin:2px 0 0;color:var(--ckw-fg2);font-size:13px;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;overflow-wrap:anywhere}\n.ckw-meta{display:flex;gap:8px;align-items:center;margin-top:6px;color:var(--ckw-fg3);font-size:12px;flex-wrap:wrap}\n.ckw-pill{display:inline-flex;align-items:center;border-radius:999px;padding:1px 8px;font-size:11px;font-weight:600;background:var(--ckw-bg3);color:var(--ckw-fg2)}\n.ckw-pill[data-s=planned]{background:rgba(63,118,255,.14);color:#3f76ff}\n.ckw-pill[data-s=progress]{background:rgba(245,158,11,.16);color:#b45309}\n.ckw-pill[data-s=shipped]{background:rgba(22,163,74,.15);color:#15803d}\n.ckw-root[data-theme=dark] .ckw-pill[data-s=progress]{color:#fbbf24}\n.ckw-root[data-theme=dark] .ckw-pill[data-s=shipped]{color:#4ade80}\n@media (prefers-color-scheme:dark){.ckw-root[data-theme=auto] .ckw-pill[data-s=progress]{color:#fbbf24}.ckw-root[data-theme=auto] .ckw-pill[data-s=shipped]{color:#4ade80}}\n.ckw-stat{display:inline-flex;align-items:center;gap:4px}\n.ckw-empty{border:1px dashed var(--ckw-line);border-radius:8px;padding:28px 16px;text-align:center;color:var(--ckw-fg2)}\n.ckw-error{border:1px solid color-mix(in srgb,var(--ckw-danger) 40%,transparent);background:color-mix(in srgb,var(--ckw-danger) 8%,transparent);color:var(--ckw-danger);border-radius:8px;padding:8px 10px;font-size:13px;display:flex;gap:8px;align-items:center;justify-content:space-between;margin-bottom:10px}\n.ckw-skel{height:68px;border-radius:8px;background:var(--ckw-bg2);animation:ckw-sh 1.2s ease-in-out infinite;margin-bottom:6px}\n@keyframes ckw-sh{50%{opacity:.5}}\n@media (prefers-reduced-motion:reduce){.ckw-skel{animation:none}.ckw-root *{transition:none!important}}\n.ckw-form{display:flex;flex-direction:column;gap:10px;border:1px solid var(--ckw-line);border-radius:8px;padding:12px;margin-bottom:12px;background:var(--ckw-bg)}\n.ckw-field{display:flex;flex-direction:column;gap:4px}\n.ckw-label{font-size:12px;font-weight:600;color:var(--ckw-fg2)}\n.ckw-actions{display:flex;gap:8px;justify-content:flex-end}\n.ckw-dupes{border:1px solid var(--ckw-line);border-radius:8px;background:var(--ckw-bg2);padding:8px 10px;font-size:13px}\n.ckw-dupes p{margin:0 0 4px;color:var(--ckw-fg2);font-size:12px}\n.ckw-dupe{display:flex;gap:8px;align-items:center;justify-content:space-between;padding:3px 0}\n.ckw-dupe span{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n.ckw-cols{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:12px}\n@media (max-width:640px){.ckw-cols{grid-template-columns:1fr}}\n.ckw-col h3{font-size:12px;text-transform:uppercase;letter-spacing:.04em;color:var(--ckw-fg2);margin:0 0 8px;display:flex;gap:6px;align-items:center}\n.ckw-card{border:1px solid var(--ckw-line);border-radius:8px;padding:10px;margin-bottom:8px;background:var(--ckw-bg)}\n.ckw-card .ckw-link{margin-bottom:6px}\n.ckw-entry{padding:12px 0;border-bottom:1px solid var(--ckw-line)}\n.ckw-entry time{font-size:12px;color:var(--ckw-fg3)}\n.ckw-entry h3{font-size:15px;margin:2px 0 4px}\n.ckw-entry p{margin:0;color:var(--ckw-fg2);white-space:pre-wrap;overflow-wrap:anywhere}\n.ckw-back{margin-bottom:8px;padding-left:4px}\n.ckw-detail-head{display:flex;gap:12px;align-items:flex-start}\n.ckw-detail-head h2{margin:0 0 4px;font-size:18px;overflow-wrap:anywhere}\n.ckw-body{white-space:pre-wrap;overflow-wrap:anywhere;color:var(--ckw-fg2);margin:12px 0}\n.ckw-h{font-size:13px;font-weight:600;margin:16px 0 8px}\n.ckw-comment{padding:8px 0;border-top:1px solid var(--ckw-line)}\n.ckw-comment b{font-size:13px}\n.ckw-comment p{margin:2px 0 0;white-space:pre-wrap;overflow-wrap:anywhere}\n.ckw-team{margin-left:6px;background:var(--ckw-accent);color:var(--ckw-accent-ink);border-radius:4px;padding:0 5px;font-size:10px;font-weight:700;text-transform:uppercase;vertical-align:1px}\n.ckw-time{color:var(--ckw-fg3);font-size:12px;margin-left:6px}\n.ckw-sr{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}\n/* Floating widget */\n.ckw-fab{position:fixed;z-index:2147483000;bottom:20px;display:inline-flex;align-items:center;gap:8px;height:40px;padding:0 16px;border-radius:999px;border:0;background:var(--ckw-accent);color:var(--ckw-accent-ink);font-weight:600;font-size:14px;box-shadow:var(--ckw-shadow)}\n.ckw-fab[data-pos=bottom-right],.ckw-pop[data-pos=bottom-right]{right:20px}\n.ckw-fab[data-pos=bottom-left],.ckw-pop[data-pos=bottom-left]{left:20px}\n.ckw-pop{position:fixed;z-index:2147483001;bottom:70px;width:380px;max-width:calc(100vw - 24px);max-height:min(560px,calc(100vh - 90px));display:flex;flex-direction:column;background:var(--ckw-bg);border:1px solid var(--ckw-line);border-radius:12px;box-shadow:var(--ckw-shadow);overflow:hidden}\n.ckw-pop-head{display:flex;align-items:center;justify-content:space-between;padding:10px 12px;border-bottom:1px solid var(--ckw-line);font-weight:600}\n.ckw-pop-body{padding:12px;overflow-y:auto;flex:1}\n.ckw-pop-foot{padding:8px 12px;border-top:1px solid var(--ckw-line);display:flex;justify-content:space-between;align-items:center;font-size:13px}\n.ckw-pop-foot a{color:var(--ckw-accent);text-decoration:none;font-weight:500}\n.ckw-pop .ckw-list{border:0;border-radius:0}\n.ckw-pop .ckw-row{padding:8px 0}\n.ckw-pop .ckw-form{border:0;padding:0;margin:12px 0 0}\n@media (max-width:520px){.ckw-pop{left:0!important;right:0!important;bottom:0;width:100%;max-width:100%;border-radius:12px 12px 0 0;max-height:85vh}.ckw-fab{bottom:14px}.ckw-fab[data-pos=bottom-right]{right:14px}.ckw-fab[data-pos=bottom-left]{left:14px}}\n/* Survey */\n.ckw-survey{position:fixed;z-index:2147483000;left:20px;bottom:20px;width:360px;max-width:calc(100vw - 24px);background:var(--ckw-bg);border:1px solid var(--ckw-line);border-radius:12px;box-shadow:var(--ckw-shadow);padding:14px;animation:ckw-in .2s ease-out}\n@keyframes ckw-in{from{opacity:0;transform:translateY(8px)}}\n@media (max-width:520px){.ckw-survey{left:0;right:0;bottom:0;width:100%;max-width:100%;border-radius:12px 12px 0 0}}\n.ckw-sv-top{display:flex;justify-content:space-between;align-items:center;margin-bottom:8px}\n.ckw-dots{display:flex;gap:4px}\n.ckw-dot{width:6px;height:6px;border-radius:50%;background:var(--ckw-bg3)}\n.ckw-dot[data-on=true]{background:var(--ckw-accent)}\n.ckw-q{font-weight:600;font-size:15px;margin:0 0 2px;border:0;padding:0}\n.ckw-root .ckw-q:focus-visible{outline:none}\n.ckw-qd{color:var(--ckw-fg2);font-size:13px;margin:0 0 10px}\n.ckw-scale{display:flex;gap:4px;flex-wrap:wrap}\n.ckw-num{flex:1 1 0;min-width:26px;height:34px;border:1px solid var(--ckw-line);background:var(--ckw-bg);border-radius:8px;font-size:13px;font-weight:600;padding:0}\n.ckw-num:hover{border-color:var(--ckw-accent)}\n.ckw-num[aria-pressed=true]{background:var(--ckw-accent);color:var(--ckw-accent-ink);border-color:var(--ckw-accent)}\n.ckw-root .ckw-star{background:none;border:0;padding:2px;color:var(--ckw-bg3)}\n.ckw-root .ckw-star[data-on=true]{color:#f5a524}\n.ckw-star svg{width:28px;height:28px}\n.ckw-lh{display:flex;justify-content:space-between;color:var(--ckw-fg3);font-size:11px;margin-top:4px}\n.ckw-opts{display:flex;flex-direction:column;gap:6px}\n.ckw-opt{display:flex;gap:8px;align-items:center;border:1px solid var(--ckw-line);border-radius:8px;padding:7px 10px;background:var(--ckw-bg);cursor:pointer}\n.ckw-opt:has(input:checked){border-color:var(--ckw-accent);background:color-mix(in srgb,var(--ckw-accent) 8%,transparent)}\n.ckw-opt input{accent-color:var(--ckw-accent)}\n.ckw-sv-foot{display:flex;justify-content:space-between;align-items:center;gap:8px;margin-top:12px}\n.ckw-thanks{text-align:center;padding:14px 0;display:flex;flex-direction:column;align-items:center;gap:8px}\n.ckw-tick{width:32px;height:32px;border-radius:50%;background:var(--ckw-accent);color:var(--ckw-accent-ink);display:flex;align-items:center;justify-content:center}\n`;\n\n/** Puts the stylesheet into the page once, however many widgets mount. */\nexport const useStyles = () => {\n useEffect(() => {\n if (document.getElementById(STYLE_ID)) return;\n const el = document.createElement(\"style\");\n el.id = STYLE_ID;\n el.textContent = CSS;\n document.head.appendChild(el);\n }, []);\n};\n"],"mappings":";;;AAEA,SAAS,iBAAiB;AAE1B,IAAM,WAAW;AAGV,IAAM,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAkIZ,IAAM,YAAY,MAAM;AAC3B,YAAU,MAAM;AACZ,QAAI,SAAS,eAAe,QAAQ,EAAG;AACvC,UAAM,KAAK,SAAS,cAAc,OAAO;AACzC,OAAG,KAAK;AACR,OAAG,cAAc;AACjB,aAAS,KAAK,YAAY,EAAE;AAAA,EAChC,GAAG,CAAC,CAAC;AACT;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/styles.ts"],"sourcesContent":["\"use client\";\n\nimport { useEffect } from \"react\";\nimport { injectStyles } from \"./styles-css\";\n\nexport { CSS } from \"./styles-css\";\n\n/** Puts the stylesheet into the page once, however many widgets mount. */\nexport const useStyles = () => {\n useEffect(() => {\n injectStyles();\n }, []);\n};\n"],"mappings":";;;AAEA,SAAS,iBAAiB;AAC1B,SAAS,oBAAoB;AAE7B,SAAS,WAAW;AAGb,IAAM,YAAY,MAAM;AAC3B,YAAU,MAAM;AACZ,iBAAa;AAAA,EACjB,GAAG,CAAC,CAAC;AACT;","names":[]}
|
package/dist/ui.d.ts
CHANGED
|
@@ -13,6 +13,9 @@ export declare const Plus: () => import("react").JSX.Element;
|
|
|
13
13
|
export declare const Cross: () => import("react").JSX.Element;
|
|
14
14
|
export declare const Check: () => import("react").JSX.Element;
|
|
15
15
|
export declare const Chat: () => import("react").JSX.Element;
|
|
16
|
+
export declare const Search: () => import("react").JSX.Element;
|
|
17
|
+
export declare const Sun: () => import("react").JSX.Element;
|
|
18
|
+
export declare const Moon: () => import("react").JSX.Element;
|
|
16
19
|
export declare const Star: () => import("react").JSX.Element;
|
|
17
20
|
export declare const StatusPill: ({ status }: {
|
|
18
21
|
status: PostStatus;
|
package/dist/ui.js
CHANGED
|
@@ -15,6 +15,15 @@ var Plus = () => /* @__PURE__ */ jsx(Svg, { children: /* @__PURE__ */ jsx("path"
|
|
|
15
15
|
var Cross = () => /* @__PURE__ */ jsx(Svg, { children: /* @__PURE__ */ jsx("path", { d: "m4 4 8 8M12 4l-8 8" }) });
|
|
16
16
|
var Check = () => /* @__PURE__ */ jsx(Svg, { children: /* @__PURE__ */ jsx("path", { d: "m3 8.5 3.2 3.2L13 4.8" }) });
|
|
17
17
|
var Chat = () => /* @__PURE__ */ jsx(Svg, { children: /* @__PURE__ */ jsx("path", { d: "M2.5 4.5a2 2 0 0 1 2-2h7a2 2 0 0 1 2 2v4.5a2 2 0 0 1-2 2H7l-3 2.5V11a2 2 0 0 1-1.5-2z" }) });
|
|
18
|
+
var Search = () => /* @__PURE__ */ jsxs(Svg, { children: [
|
|
19
|
+
/* @__PURE__ */ jsx("circle", { cx: "7", cy: "7", r: "4.5" }),
|
|
20
|
+
/* @__PURE__ */ jsx("path", { d: "m10.5 10.5 3 3" })
|
|
21
|
+
] });
|
|
22
|
+
var Sun = () => /* @__PURE__ */ jsxs(Svg, { children: [
|
|
23
|
+
/* @__PURE__ */ jsx("circle", { cx: "8", cy: "8", r: "3" }),
|
|
24
|
+
/* @__PURE__ */ jsx("path", { d: "M8 1.5v1.5M8 13v1.5M1.5 8H3M13 8h1.5M3.4 3.4l1 1M11.6 11.6l1 1M3.4 12.6l1-1M11.6 4.4l1-1" })
|
|
25
|
+
] });
|
|
26
|
+
var Moon = () => /* @__PURE__ */ jsx(Svg, { children: /* @__PURE__ */ jsx("path", { d: "M13.5 9.5A5.5 5.5 0 0 1 6.5 2.5a5.5 5.5 0 1 0 7 7z" }) });
|
|
18
27
|
var Star = () => /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "currentColor", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { d: "m12 2.8 2.8 5.8 6.4.9-4.6 4.5 1.1 6.3L12 17.2l-5.7 3.1 1.1-6.3L2.8 9.5l6.4-.9z" }) });
|
|
19
28
|
var StatusPill = ({ status }) => /* @__PURE__ */ jsx("span", { className: "ckw-pill", "data-s": status, children: STATUS_LABEL[status] ?? status });
|
|
20
29
|
var VoteButton = ({ post, onVote, small }) => /* @__PURE__ */ jsxs(
|
|
@@ -65,10 +74,13 @@ export {
|
|
|
65
74
|
Check,
|
|
66
75
|
ChevronUp,
|
|
67
76
|
Cross,
|
|
77
|
+
Moon,
|
|
68
78
|
Plus,
|
|
69
79
|
Root,
|
|
80
|
+
Search,
|
|
70
81
|
Star,
|
|
71
82
|
StatusPill,
|
|
83
|
+
Sun,
|
|
72
84
|
VoteButton,
|
|
73
85
|
similarPosts,
|
|
74
86
|
timeAgo,
|
package/dist/ui.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/ui.tsx"],"sourcesContent":["\"use client\";\n\nimport { type ReactNode, useEffect, useRef } from \"react\";\nimport { type FeedbackPost, type PostStatus, STATUS_LABEL } from \"./api\";\nimport { useStyles } from \"./styles\";\n\nexport type Theme = \"light\" | \"dark\" | \"auto\";\n\n/** The scoped wrapper every widget renders inside. Carries the accent and the theme. */\nexport const Root = ({ theme = \"auto\", accent = \"#3f76ff\", className, children }: { theme?: Theme; accent?: string; className?: string; children: ReactNode }) => {\n useStyles();\n return (\n <div className={`ckw-root${className ? ` ${className}` : \"\"}`} data-theme={theme} style={{ [\"--ckw-accent\" as string]: accent }}>\n {children}\n </div>\n );\n};\n\nconst Svg = ({ children, size = 16 }: { children: ReactNode; size?: number }) => (\n <svg className=\"ckw-icon\" width={size} height={size} viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.8\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\">\n {children}\n </svg>\n);\n\nexport const ChevronUp = () => (\n <Svg>\n <path d=\"M3.5 10 8 5.5 12.5 10\" />\n </Svg>\n);\nexport const Plus = () => (\n <Svg>\n <path d=\"M8 3v10M3 8h10\" />\n </Svg>\n);\nexport const Cross = () => (\n <Svg>\n <path d=\"m4 4 8 8M12 4l-8 8\" />\n </Svg>\n);\nexport const Check = () => (\n <Svg>\n <path d=\"m3 8.5 3.2 3.2L13 4.8\" />\n </Svg>\n);\nexport const Chat = () => (\n <Svg>\n <path d=\"M2.5 4.5a2 2 0 0 1 2-2h7a2 2 0 0 1 2 2v4.5a2 2 0 0 1-2 2H7l-3 2.5V11a2 2 0 0 1-1.5-2z\" />\n </Svg>\n);\nexport const Star = () => (\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" aria-hidden=\"true\">\n <path d=\"m12 2.8 2.8 5.8 6.4.9-4.6 4.5 1.1 6.3L12 17.2l-5.7 3.1 1.1-6.3L2.8 9.5l6.4-.9z\" />\n </svg>\n);\n\nexport const StatusPill = ({ status }: { status: PostStatus }) => (\n <span className=\"ckw-pill\" data-s={status}>\n {STATUS_LABEL[status] ?? status}\n </span>\n);\n\nexport const VoteButton = ({ post, onVote, small }: { post: FeedbackPost; onVote: (p: FeedbackPost) => void; small?: boolean }) => (\n <button\n type=\"button\"\n className={`ckw-vote${small ? \" ckw-vote-sm\" : \"\"}`}\n aria-pressed={post.voted}\n aria-label={`${post.voted ? \"Remove your vote from\" : \"Upvote\"} ${post.title}. ${post.votes} votes`}\n onClick={() => onVote(post)}\n >\n <ChevronUp />\n <span>{post.votes}</span>\n </button>\n);\n\nexport const timeAgo = (iso: string) => {\n const t = new Date(iso).getTime();\n if (Number.isNaN(t)) return \"\";\n const d = Math.max(0, Date.now() - t) / 1000;\n if (d < 60) return \"just now\";\n if (d < 3600) return `${Math.floor(d / 60)}m ago`;\n if (d < 86400) return `${Math.floor(d / 3600)}h ago`;\n if (d < 86400 * 30) return `${Math.floor(d / 86400)}d ago`;\n return new Date(iso).toLocaleDateString(undefined, { month: \"short\", day: \"numeric\", year: \"numeric\" });\n};\n\n/** Calls `onClose` on Esc while mounted. */\nexport const useEscape = (onClose: () => void) => {\n const ref = useRef(onClose);\n ref.current = onClose;\n useEffect(() => {\n const h = (e: KeyboardEvent) => e.key === \"Escape\" && ref.current();\n document.addEventListener(\"keydown\", h);\n return () => document.removeEventListener(\"keydown\", h);\n }, []);\n};\n\n/** Words of a title, lowercased, without filler. */\nconst words = (s: string) =>\n s\n .toLowerCase()\n .split(/[^a-z0-9]+/)\n .filter((w) => w.length > 2 && ![\"the\", \"and\", \"for\", \"with\", \"add\", \"can\", \"please\", \"want\", \"would\", \"our\", \"you\", \"have\"].includes(w));\n\n/** Up to three existing posts that share words with what the visitor is typing. */\nexport const similarPosts = (title: string, posts: FeedbackPost[]) => {\n const mine = words(title);\n if (mine.length === 0 || title.trim().length < 4) return [];\n return posts\n .map((p) => {\n const theirs = new Set(words(`${p.title} ${p.body}`.slice(0, 300)));\n const hit = mine.filter((w) => theirs.has(w) || [...theirs].some((t) => t.startsWith(w) || w.startsWith(t))).length;\n return { p, score: hit / mine.length };\n })\n .filter((x) => x.score >= 0.5)\n .sort((a, b) => b.score - a.score || b.p.votes - a.p.votes)\n .slice(0, 3)\n .map((x) => x.p);\n};\n"],"mappings":";;;AAEA,SAAyB,WAAW,cAAc;AAClD,SAA6C,oBAAoB;AACjE,SAAS,iBAAiB;AAQlB,
|
|
1
|
+
{"version":3,"sources":["../src/ui.tsx"],"sourcesContent":["\"use client\";\n\nimport { type ReactNode, useEffect, useRef } from \"react\";\nimport { type FeedbackPost, type PostStatus, STATUS_LABEL } from \"./api\";\nimport { useStyles } from \"./styles\";\n\nexport type Theme = \"light\" | \"dark\" | \"auto\";\n\n/** The scoped wrapper every widget renders inside. Carries the accent and the theme. */\nexport const Root = ({ theme = \"auto\", accent = \"#3f76ff\", className, children }: { theme?: Theme; accent?: string; className?: string; children: ReactNode }) => {\n useStyles();\n return (\n <div className={`ckw-root${className ? ` ${className}` : \"\"}`} data-theme={theme} style={{ [\"--ckw-accent\" as string]: accent }}>\n {children}\n </div>\n );\n};\n\nconst Svg = ({ children, size = 16 }: { children: ReactNode; size?: number }) => (\n <svg className=\"ckw-icon\" width={size} height={size} viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\" strokeWidth=\"1.8\" strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\">\n {children}\n </svg>\n);\n\nexport const ChevronUp = () => (\n <Svg>\n <path d=\"M3.5 10 8 5.5 12.5 10\" />\n </Svg>\n);\nexport const Plus = () => (\n <Svg>\n <path d=\"M8 3v10M3 8h10\" />\n </Svg>\n);\nexport const Cross = () => (\n <Svg>\n <path d=\"m4 4 8 8M12 4l-8 8\" />\n </Svg>\n);\nexport const Check = () => (\n <Svg>\n <path d=\"m3 8.5 3.2 3.2L13 4.8\" />\n </Svg>\n);\nexport const Chat = () => (\n <Svg>\n <path d=\"M2.5 4.5a2 2 0 0 1 2-2h7a2 2 0 0 1 2 2v4.5a2 2 0 0 1-2 2H7l-3 2.5V11a2 2 0 0 1-1.5-2z\" />\n </Svg>\n);\nexport const Search = () => (\n <Svg>\n <circle cx=\"7\" cy=\"7\" r=\"4.5\" />\n <path d=\"m10.5 10.5 3 3\" />\n </Svg>\n);\nexport const Sun = () => (\n <Svg>\n <circle cx=\"8\" cy=\"8\" r=\"3\" />\n <path d=\"M8 1.5v1.5M8 13v1.5M1.5 8H3M13 8h1.5M3.4 3.4l1 1M11.6 11.6l1 1M3.4 12.6l1-1M11.6 4.4l1-1\" />\n </Svg>\n);\nexport const Moon = () => (\n <Svg>\n <path d=\"M13.5 9.5A5.5 5.5 0 0 1 6.5 2.5a5.5 5.5 0 1 0 7 7z\" />\n </Svg>\n);\nexport const Star = () => (\n <svg viewBox=\"0 0 24 24\" fill=\"currentColor\" aria-hidden=\"true\">\n <path d=\"m12 2.8 2.8 5.8 6.4.9-4.6 4.5 1.1 6.3L12 17.2l-5.7 3.1 1.1-6.3L2.8 9.5l6.4-.9z\" />\n </svg>\n);\n\nexport const StatusPill = ({ status }: { status: PostStatus }) => (\n <span className=\"ckw-pill\" data-s={status}>\n {STATUS_LABEL[status] ?? status}\n </span>\n);\n\nexport const VoteButton = ({ post, onVote, small }: { post: FeedbackPost; onVote: (p: FeedbackPost) => void; small?: boolean }) => (\n <button\n type=\"button\"\n className={`ckw-vote${small ? \" ckw-vote-sm\" : \"\"}`}\n aria-pressed={post.voted}\n aria-label={`${post.voted ? \"Remove your vote from\" : \"Upvote\"} ${post.title}. ${post.votes} votes`}\n onClick={() => onVote(post)}\n >\n <ChevronUp />\n <span>{post.votes}</span>\n </button>\n);\n\nexport const timeAgo = (iso: string) => {\n const t = new Date(iso).getTime();\n if (Number.isNaN(t)) return \"\";\n const d = Math.max(0, Date.now() - t) / 1000;\n if (d < 60) return \"just now\";\n if (d < 3600) return `${Math.floor(d / 60)}m ago`;\n if (d < 86400) return `${Math.floor(d / 3600)}h ago`;\n if (d < 86400 * 30) return `${Math.floor(d / 86400)}d ago`;\n return new Date(iso).toLocaleDateString(undefined, { month: \"short\", day: \"numeric\", year: \"numeric\" });\n};\n\n/** Calls `onClose` on Esc while mounted. */\nexport const useEscape = (onClose: () => void) => {\n const ref = useRef(onClose);\n ref.current = onClose;\n useEffect(() => {\n const h = (e: KeyboardEvent) => e.key === \"Escape\" && ref.current();\n document.addEventListener(\"keydown\", h);\n return () => document.removeEventListener(\"keydown\", h);\n }, []);\n};\n\n/** Words of a title, lowercased, without filler. */\nconst words = (s: string) =>\n s\n .toLowerCase()\n .split(/[^a-z0-9]+/)\n .filter((w) => w.length > 2 && ![\"the\", \"and\", \"for\", \"with\", \"add\", \"can\", \"please\", \"want\", \"would\", \"our\", \"you\", \"have\"].includes(w));\n\n/** Up to three existing posts that share words with what the visitor is typing. */\nexport const similarPosts = (title: string, posts: FeedbackPost[]) => {\n const mine = words(title);\n if (mine.length === 0 || title.trim().length < 4) return [];\n return posts\n .map((p) => {\n const theirs = new Set(words(`${p.title} ${p.body}`.slice(0, 300)));\n const hit = mine.filter((w) => theirs.has(w) || [...theirs].some((t) => t.startsWith(w) || w.startsWith(t))).length;\n return { p, score: hit / mine.length };\n })\n .filter((x) => x.score >= 0.5)\n .sort((a, b) => b.score - a.score || b.p.votes - a.p.votes)\n .slice(0, 3)\n .map((x) => x.p);\n};\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mrrocket/sdk",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "MRRocket SDK: page views, events, heatmap clicks, session recordings, A/B tests, feature flags, error tracking, feedback board and
|
|
3
|
+
"version": "0.9.0",
|
|
4
|
+
"description": "MRRocket SDK: page views, events, heatmap clicks, session recordings, A/B tests, feature flags, error tracking, feedback board, surveys, a chat messenger, a cancel flow, onboarding tours and checklists, in-app messages, push notifications and redirect tests that your MRRocket agents can run and read. Next.js (@mrrocket/sdk/next), React Native and Expo (@mrrocket/sdk/react-native), and a script tag for any website.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"nextjs",
|
|
7
7
|
"analytics",
|
|
@@ -92,15 +92,19 @@
|
|
|
92
92
|
"@rrweb/record": "2.1.6"
|
|
93
93
|
},
|
|
94
94
|
"peerDependencies": {
|
|
95
|
-
"@react-native-async-storage/async-storage": ">=1.17",
|
|
96
95
|
"expo-application": ">=5",
|
|
96
|
+
"expo-constants": ">=14",
|
|
97
97
|
"expo-device": ">=5",
|
|
98
|
+
"expo-haptics": ">=12",
|
|
98
99
|
"expo-localization": ">=14",
|
|
100
|
+
"expo-notifications": ">=0.20",
|
|
99
101
|
"expo-router": ">=3",
|
|
100
102
|
"next": ">=15",
|
|
101
103
|
"react": ">=18",
|
|
102
104
|
"react-dom": ">=18",
|
|
103
|
-
"react-native": ">=0.72"
|
|
105
|
+
"react-native": ">=0.72",
|
|
106
|
+
"@react-native-async-storage/async-storage": ">=1.17",
|
|
107
|
+
"react-native-view-shot": ">=3.8"
|
|
104
108
|
},
|
|
105
109
|
"peerDependenciesMeta": {
|
|
106
110
|
"@react-native-async-storage/async-storage": {
|
|
@@ -112,9 +116,15 @@
|
|
|
112
116
|
"expo-device": {
|
|
113
117
|
"optional": true
|
|
114
118
|
},
|
|
119
|
+
"expo-constants": {
|
|
120
|
+
"optional": true
|
|
121
|
+
},
|
|
115
122
|
"expo-localization": {
|
|
116
123
|
"optional": true
|
|
117
124
|
},
|
|
125
|
+
"expo-notifications": {
|
|
126
|
+
"optional": true
|
|
127
|
+
},
|
|
118
128
|
"expo-router": {
|
|
119
129
|
"optional": true
|
|
120
130
|
},
|
|
@@ -126,6 +136,12 @@
|
|
|
126
136
|
},
|
|
127
137
|
"react-native": {
|
|
128
138
|
"optional": true
|
|
139
|
+
},
|
|
140
|
+
"expo-haptics": {
|
|
141
|
+
"optional": true
|
|
142
|
+
},
|
|
143
|
+
"react-native-view-shot": {
|
|
144
|
+
"optional": true
|
|
129
145
|
}
|
|
130
146
|
},
|
|
131
147
|
"devDependencies": {
|