@helpway/react 0.17.0 → 0.17.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +9 -1
- package/dist/index.js +1572 -770
- package/dist/index.js.map +1 -1
- package/package.json +4 -3
- package/src/themed/styles.css +344 -81
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@helpway/react",
|
|
3
|
-
"version": "0.17.
|
|
3
|
+
"version": "0.17.2",
|
|
4
4
|
"description": "Official React SDK for Helpway — drop-in AI chat support widget with headless hooks for custom UIs.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"helpway",
|
|
@@ -43,8 +43,9 @@
|
|
|
43
43
|
"test": "bun test",
|
|
44
44
|
"sync:icons": "bun scripts/sync-icons.ts",
|
|
45
45
|
"prepublishOnly": "bun run build",
|
|
46
|
-
"prepack": "bun run build && bun scripts/apply-publish-config.ts",
|
|
47
|
-
"postpack": "bun scripts/apply-publish-config.ts --restore"
|
|
46
|
+
"prepack": "bun scripts/sync-icons.ts --check && bun run build && bun scripts/apply-publish-config.ts",
|
|
47
|
+
"postpack": "bun scripts/apply-publish-config.ts --restore",
|
|
48
|
+
"check:icons": "bun scripts/sync-icons.ts --check"
|
|
48
49
|
},
|
|
49
50
|
"//": "publishConfig swaps main/types/exports to the built dist on publish. Workspace consumers get raw src (fast HMR, no build step); npm consumers get compiled dist with .d.ts. Standard monorepo pattern.",
|
|
50
51
|
"dependencies": {
|
package/src/themed/styles.css
CHANGED
|
@@ -41,6 +41,20 @@
|
|
|
41
41
|
padding: 0;
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
+
/* Text takes its colour from the widget, not from the page.
|
|
45
|
+
Outside the script embed's shadow root the widget is ordinary DOM, and a
|
|
46
|
+
host stylesheet's prose rules reach in: Carna's `p strong { color:
|
|
47
|
+
var(--ink-1) }` drew every bold word of an answer in near-black on the
|
|
48
|
+
landing's blue panel (Ali, 2026-10-12: "renklerde sorunlar var"). The
|
|
49
|
+
widget never set a colour on these elements — it expected them to inherit —
|
|
50
|
+
so anything the page said won.
|
|
51
|
+
`:where()` keeps this at one class of specificity: it beats a host's
|
|
52
|
+
element rules (`strong`, `p strong`, `.x`-less prose) and still loses to
|
|
53
|
+
every widget rule that follows, so no component colour changes. */
|
|
54
|
+
.hw-widget :where(p, li, strong, b, em, i, u, s, small, a, code, pre, blockquote, h1, h2, h3, h4, h5, h6) {
|
|
55
|
+
color: inherit;
|
|
56
|
+
}
|
|
57
|
+
|
|
44
58
|
/* ── Tokens ──────────────────────────────────────
|
|
45
59
|
Wrapped in :where() so the default token block has zero specificity.
|
|
46
60
|
That way `applyTheme()` (which writes inline styles onto the host
|
|
@@ -370,6 +384,48 @@
|
|
|
370
384
|
height: min(800px, calc(100vh - 112px));
|
|
371
385
|
}
|
|
372
386
|
|
|
387
|
+
/* The mobile SDK's sheet (widget.js mobile mode, #268): the native sheet IS
|
|
388
|
+
the window, at every width. An iPad's page sheet is wider than the 480px
|
|
389
|
+
phone breakpoint, and without this the floating panel would sit in a
|
|
390
|
+
corner of it. No open animation either — the sheet already slid up, and
|
|
391
|
+
a second slide inside it reads as the app stuttering. :host only matches
|
|
392
|
+
inside the embed's shadow root, so @helpway/react consumers never see it. */
|
|
393
|
+
:host([data-hw-mode="mobile"]) .hw-window,
|
|
394
|
+
:host([data-hw-mode="mobile"]) .hw-window--reading {
|
|
395
|
+
position: fixed;
|
|
396
|
+
inset: 0;
|
|
397
|
+
width: 100%;
|
|
398
|
+
height: var(--hw-visible-height, 100%);
|
|
399
|
+
border-radius: 0;
|
|
400
|
+
box-shadow: none;
|
|
401
|
+
animation: none;
|
|
402
|
+
}
|
|
403
|
+
/* The bubble is the launcher, and the app's own Help row is the launcher
|
|
404
|
+
here. hideLauncher does not remove it (it only stops click-outside from
|
|
405
|
+
closing the panel), so without this a black × sat over the send button. */
|
|
406
|
+
/* The hero is a gradient (background-image), so its computed
|
|
407
|
+
background-color was transparent and the SDK could not tell the native
|
|
408
|
+
sheet what colour sits under iOS's grabber. The gradient's own top-left
|
|
409
|
+
stop, as a solid underneath it: invisible here, measurable there
|
|
410
|
+
(widget-embed mobile-chrome.ts). */
|
|
411
|
+
:host([data-hw-mode="mobile"]) .hw-hero {
|
|
412
|
+
background-color: color-mix(in srgb, var(--hw-primary) 60%, black);
|
|
413
|
+
}
|
|
414
|
+
:host([data-hw-mode="mobile"]) .hw-bubble {
|
|
415
|
+
display: none;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
/* Keyboard open (default-widget.tsx sets data-hw-keyboard from
|
|
419
|
+
visualViewport). The home-indicator inset is under the keyboard, so
|
|
420
|
+
padding for it leaves an empty band between composer and keys; and the
|
|
421
|
+
"Powered by" line costs a row the conversation needs more. */
|
|
422
|
+
.hw-window[data-hw-keyboard] .hw-composer {
|
|
423
|
+
padding-bottom: 8px;
|
|
424
|
+
}
|
|
425
|
+
.hw-window[data-hw-keyboard] .hw-powered {
|
|
426
|
+
display: none;
|
|
427
|
+
}
|
|
428
|
+
|
|
373
429
|
@keyframes hw-window-open {
|
|
374
430
|
from {
|
|
375
431
|
opacity: 0;
|
|
@@ -1241,6 +1297,14 @@
|
|
|
1241
1297
|
min-width: 0;
|
|
1242
1298
|
scrollbar-color: rgba(0, 0, 0, 0.2) transparent;
|
|
1243
1299
|
scrollbar-width: thin;
|
|
1300
|
+
/* The header has no rule under it and shares the thread's ground, so a
|
|
1301
|
+
message scrolled half out of view was cut along a line nobody could see
|
|
1302
|
+
and looked broken rather than scrolled. The last 12px dissolve instead.
|
|
1303
|
+
12, because the list's own top padding is 16: at rest the first message
|
|
1304
|
+
starts below the fade and is untouched. (The docked placement has had
|
|
1305
|
+
this since it was built, at 16px.) */
|
|
1306
|
+
-webkit-mask-image: linear-gradient(180deg, transparent 0, #000 12px);
|
|
1307
|
+
mask-image: linear-gradient(180deg, transparent 0, #000 12px);
|
|
1244
1308
|
}
|
|
1245
1309
|
|
|
1246
1310
|
.hw-messages::-webkit-scrollbar {
|
|
@@ -1603,6 +1667,10 @@
|
|
|
1603
1667
|
color: inherit;
|
|
1604
1668
|
margin-top: 6px;
|
|
1605
1669
|
transition: background 0.15s;
|
|
1670
|
+
/* A card you can hit with a thumb, even when it is a title and nothing else. */
|
|
1671
|
+
min-height: 44px;
|
|
1672
|
+
max-width: 100%;
|
|
1673
|
+
text-align: start;
|
|
1606
1674
|
}
|
|
1607
1675
|
|
|
1608
1676
|
.hw-link-preview:hover {
|
|
@@ -1634,9 +1702,29 @@
|
|
|
1634
1702
|
}
|
|
1635
1703
|
|
|
1636
1704
|
.hw-link-preview-favicon {
|
|
1637
|
-
width:
|
|
1638
|
-
height:
|
|
1639
|
-
|
|
1705
|
+
width: 14px;
|
|
1706
|
+
height: 14px;
|
|
1707
|
+
flex: 0 0 14px;
|
|
1708
|
+
border-radius: 3px;
|
|
1709
|
+
}
|
|
1710
|
+
/* On glass the site's mark is somebody else's colour on ours: Carna's blue
|
|
1711
|
+
knot on the blue panel was a smudge. A small white chip under it, the way a
|
|
1712
|
+
browser tab holds a favicon. White and not a token on purpose: a favicon is
|
|
1713
|
+
drawn for a light ground, whatever the panel around it is. */
|
|
1714
|
+
.hw-widget[data-hw-placement="docked"] .hw-link-preview-favicon {
|
|
1715
|
+
box-sizing: content-box;
|
|
1716
|
+
padding: 2px;
|
|
1717
|
+
background: #ffffff;
|
|
1718
|
+
}
|
|
1719
|
+
|
|
1720
|
+
.hw-link-preview-host {
|
|
1721
|
+
/* A hostname reads left to right in every language. It WRAPS and is never
|
|
1722
|
+
cut here: the end of a host is what says whose site it is, and an
|
|
1723
|
+
ellipsis there would hide it (link-preview.ts shortens it from the start). */
|
|
1724
|
+
direction: ltr;
|
|
1725
|
+
min-width: 0;
|
|
1726
|
+
overflow-wrap: anywhere;
|
|
1727
|
+
word-break: break-all;
|
|
1640
1728
|
}
|
|
1641
1729
|
|
|
1642
1730
|
.hw-link-preview-title {
|
|
@@ -1652,6 +1740,8 @@
|
|
|
1652
1740
|
-webkit-line-clamp: 2;
|
|
1653
1741
|
-webkit-box-orient: vertical;
|
|
1654
1742
|
overflow: hidden;
|
|
1743
|
+
/* A title with no spaces (a URL, a hash) breaks instead of widening the card. */
|
|
1744
|
+
overflow-wrap: anywhere;
|
|
1655
1745
|
}
|
|
1656
1746
|
|
|
1657
1747
|
.hw-link-preview-desc {
|
|
@@ -1662,9 +1752,15 @@
|
|
|
1662
1752
|
-webkit-line-clamp: 2;
|
|
1663
1753
|
-webkit-box-orient: vertical;
|
|
1664
1754
|
overflow: hidden;
|
|
1755
|
+
overflow-wrap: anywhere;
|
|
1665
1756
|
}
|
|
1666
1757
|
|
|
1667
1758
|
.hw-link-preview-url {
|
|
1759
|
+
/* The site, first: a small mark and the host on one quiet line. */
|
|
1760
|
+
display: flex;
|
|
1761
|
+
align-items: center;
|
|
1762
|
+
gap: 6px;
|
|
1763
|
+
min-width: 0;
|
|
1668
1764
|
font-size: 11px;
|
|
1669
1765
|
/* --hw-text-muted is referenced in seven rules and defined in none, so every
|
|
1670
1766
|
one of them silently falls back to a hardcoded grey and stops following
|
|
@@ -2540,22 +2636,6 @@
|
|
|
2540
2636
|
color: var(--hw-text-2);
|
|
2541
2637
|
}
|
|
2542
2638
|
|
|
2543
|
-
/* ════════════════════════════════════════════════
|
|
2544
|
-
RESOLVED BANNER
|
|
2545
|
-
════════════════════════════════════════════════ */
|
|
2546
|
-
|
|
2547
|
-
.hw-resolved-banner {
|
|
2548
|
-
display: flex;
|
|
2549
|
-
align-items: center;
|
|
2550
|
-
justify-content: center;
|
|
2551
|
-
padding: 12px 16px;
|
|
2552
|
-
border-top: 1px solid var(--hw-border);
|
|
2553
|
-
background: var(--hw-bg-subtle);
|
|
2554
|
-
color: var(--hw-text-2);
|
|
2555
|
-
font-size: 13px;
|
|
2556
|
-
flex-shrink: 0;
|
|
2557
|
-
}
|
|
2558
|
-
|
|
2559
2639
|
/* ════════════════════════════════════════════════
|
|
2560
2640
|
NEW CONVERSATION FORM
|
|
2561
2641
|
════════════════════════════════════════════════ */
|
|
@@ -2687,6 +2767,16 @@
|
|
|
2687
2767
|
.hw-powered {
|
|
2688
2768
|
padding-bottom: calc(5px + env(safe-area-inset-bottom, 0px));
|
|
2689
2769
|
}
|
|
2770
|
+
/* The inset belongs to whatever is LAST in the window. With "Powered by"
|
|
2771
|
+
under the composer (or the tabs), both were padding for the same home
|
|
2772
|
+
indicator — the empty band above "Powered by" in Ali's simulator run of
|
|
2773
|
+
the mobile SDK. The line carries it; what sits above it does not. */
|
|
2774
|
+
.hw-window:has(.hw-powered) .hw-composer {
|
|
2775
|
+
padding-bottom: 8px;
|
|
2776
|
+
}
|
|
2777
|
+
.hw-window:has(.hw-powered) .hw-tabs {
|
|
2778
|
+
padding-bottom: 0;
|
|
2779
|
+
}
|
|
2690
2780
|
|
|
2691
2781
|
/* Touch targets */
|
|
2692
2782
|
.hw-header-close,
|
|
@@ -3978,6 +4068,31 @@
|
|
|
3978
4068
|
currentColor, so it inherits the row's measured ink instead of carrying a
|
|
3979
4069
|
second colour decision. The 3/4 arc uses `transparent` rather than color-mix:
|
|
3980
4070
|
this bundle runs on whatever browser a customer's visitor brought. */
|
|
4071
|
+
/* The one action of the "lost" state. Text-weight, not a pill: the band stays
|
|
4072
|
+
a band. Underlined so it reads as pressable without a colour of its own —
|
|
4073
|
+
it takes the panel's ink, which holds on glass and on any brand surface. */
|
|
4074
|
+
.hw-disconnect-retry {
|
|
4075
|
+
flex: none;
|
|
4076
|
+
padding: 2px 4px;
|
|
4077
|
+
margin: -2px 0;
|
|
4078
|
+
border: 0;
|
|
4079
|
+
border-radius: 4px;
|
|
4080
|
+
background: none;
|
|
4081
|
+
color: var(--hw-text);
|
|
4082
|
+
font: inherit;
|
|
4083
|
+
font-weight: 600;
|
|
4084
|
+
text-decoration: underline;
|
|
4085
|
+
text-underline-offset: 2px;
|
|
4086
|
+
cursor: pointer;
|
|
4087
|
+
}
|
|
4088
|
+
.hw-disconnect-retry:hover {
|
|
4089
|
+
text-decoration-thickness: 2px;
|
|
4090
|
+
}
|
|
4091
|
+
.hw-disconnect-retry:focus-visible {
|
|
4092
|
+
outline: 2px solid var(--hw-text);
|
|
4093
|
+
outline-offset: 1px;
|
|
4094
|
+
}
|
|
4095
|
+
|
|
3981
4096
|
.hw-disconnect-spinner {
|
|
3982
4097
|
width: 9px;
|
|
3983
4098
|
height: 9px;
|
|
@@ -4094,94 +4209,98 @@
|
|
|
4094
4209
|
}
|
|
4095
4210
|
|
|
4096
4211
|
/* ════════════════════════════════════════════════
|
|
4097
|
-
RESOLVED CONVERSATION —
|
|
4212
|
+
RESOLVED CONVERSATION — STATUS + RATING
|
|
4213
|
+
One status row, then the rating on a single line. Every colour is a
|
|
4214
|
+
token: the block has no tone of its own, and the brand colour only
|
|
4215
|
+
edges the pressed option — it never sits behind or under the text, so
|
|
4216
|
+
contrast does not depend on what the customer picked.
|
|
4217
|
+
(DESIGN-DECISIONS rule/widget-resolved-block)
|
|
4098
4218
|
════════════════════════════════════════════════ */
|
|
4099
4219
|
|
|
4100
4220
|
.hw-resolved {
|
|
4101
4221
|
display: flex;
|
|
4102
4222
|
flex-direction: column;
|
|
4103
|
-
|
|
4104
|
-
|
|
4105
|
-
padding: 16px 20px;
|
|
4223
|
+
gap: 8px;
|
|
4224
|
+
padding: 10px 14px;
|
|
4106
4225
|
border-top: 1px solid var(--hw-border);
|
|
4107
4226
|
flex-shrink: 0;
|
|
4108
4227
|
}
|
|
4109
4228
|
|
|
4110
|
-
.hw-resolved-
|
|
4111
|
-
font-size: 13px;
|
|
4112
|
-
color: var(--hw-text-3);
|
|
4113
|
-
font-weight: 500;
|
|
4114
|
-
}
|
|
4115
|
-
|
|
4116
|
-
.hw-resolved-actions {
|
|
4229
|
+
.hw-resolved-status {
|
|
4117
4230
|
display: flex;
|
|
4118
|
-
|
|
4119
|
-
|
|
4120
|
-
|
|
4121
|
-
|
|
4122
|
-
padding: 6px 16px;
|
|
4123
|
-
border: 1px solid var(--hw-border-md);
|
|
4124
|
-
border-radius: 8px;
|
|
4125
|
-
background: var(--hw-bg);
|
|
4231
|
+
align-items: center;
|
|
4232
|
+
gap: 6px;
|
|
4233
|
+
font-size: 12.5px;
|
|
4234
|
+
font-weight: 550;
|
|
4126
4235
|
color: var(--hw-text);
|
|
4127
|
-
font-size: 13px;
|
|
4128
|
-
font-weight: 500;
|
|
4129
|
-
cursor: pointer;
|
|
4130
|
-
transition: background 0.15s;
|
|
4131
4236
|
}
|
|
4132
4237
|
|
|
4133
|
-
.hw-resolved-
|
|
4134
|
-
|
|
4238
|
+
.hw-resolved-status svg {
|
|
4239
|
+
flex: none;
|
|
4240
|
+
color: var(--hw-text-2);
|
|
4135
4241
|
}
|
|
4136
4242
|
|
|
4137
|
-
/* CSAT Rating */
|
|
4138
4243
|
.hw-csat {
|
|
4139
4244
|
display: flex;
|
|
4140
|
-
flex-direction: column;
|
|
4141
4245
|
align-items: center;
|
|
4142
|
-
|
|
4246
|
+
justify-content: space-between;
|
|
4247
|
+
flex-wrap: wrap;
|
|
4248
|
+
gap: 6px 10px;
|
|
4143
4249
|
}
|
|
4144
4250
|
|
|
4145
|
-
|
|
4251
|
+
/* text-2, not text-3: at 12px text-3 is under 4.5:1 on both surfaces (the
|
|
4252
|
+
same measurement as .hw-msg-meta). */
|
|
4253
|
+
.hw-csat-label,
|
|
4254
|
+
.hw-csat-error {
|
|
4146
4255
|
font-size: 12px;
|
|
4147
|
-
color: var(--hw-text-
|
|
4256
|
+
color: var(--hw-text-2);
|
|
4257
|
+
}
|
|
4258
|
+
|
|
4259
|
+
.hw-csat-error {
|
|
4260
|
+
color: var(--hw-text);
|
|
4148
4261
|
}
|
|
4149
4262
|
|
|
4150
4263
|
.hw-csat-buttons {
|
|
4151
4264
|
display: flex;
|
|
4152
|
-
gap:
|
|
4265
|
+
gap: 6px;
|
|
4153
4266
|
}
|
|
4154
4267
|
|
|
4155
4268
|
.hw-csat-btn {
|
|
4156
|
-
|
|
4157
|
-
|
|
4269
|
+
display: inline-flex;
|
|
4270
|
+
align-items: center;
|
|
4271
|
+
gap: 5px;
|
|
4272
|
+
height: 30px;
|
|
4273
|
+
padding: 0 11px;
|
|
4158
4274
|
border: 1px solid var(--hw-border-md);
|
|
4159
|
-
border-radius:
|
|
4275
|
+
border-radius: 999px;
|
|
4160
4276
|
background: var(--hw-bg);
|
|
4277
|
+
color: var(--hw-text);
|
|
4278
|
+
font: inherit;
|
|
4279
|
+
font-size: 12px;
|
|
4280
|
+
font-weight: 550;
|
|
4161
4281
|
cursor: pointer;
|
|
4162
|
-
|
|
4163
|
-
align-items: center;
|
|
4164
|
-
justify-content: center;
|
|
4165
|
-
font-size: 18px;
|
|
4166
|
-
transition: transform 0.15s, border-color 0.15s, background 0.15s;
|
|
4282
|
+
transition: background 0.15s, border-color 0.15s;
|
|
4167
4283
|
}
|
|
4168
4284
|
|
|
4169
|
-
.hw-csat-btn
|
|
4170
|
-
|
|
4171
|
-
border-color: var(--hw-text-3);
|
|
4285
|
+
.hw-csat-btn svg {
|
|
4286
|
+
flex: none;
|
|
4172
4287
|
}
|
|
4173
4288
|
|
|
4174
|
-
.hw-csat-btn
|
|
4175
|
-
border-color: var(--hw-primary);
|
|
4289
|
+
.hw-csat-btn:hover {
|
|
4176
4290
|
background: var(--hw-bg-hover);
|
|
4177
|
-
transform: scale(1.15);
|
|
4178
4291
|
}
|
|
4179
4292
|
|
|
4180
|
-
.hw-csat-
|
|
4181
|
-
|
|
4182
|
-
|
|
4183
|
-
|
|
4184
|
-
|
|
4293
|
+
.hw-csat-btn:focus-visible {
|
|
4294
|
+
outline: 2px solid var(--hw-text);
|
|
4295
|
+
outline-offset: 2px;
|
|
4296
|
+
}
|
|
4297
|
+
|
|
4298
|
+
/* The answer, kept. Pressed and read-only: the server takes one rating. */
|
|
4299
|
+
.hw-csat-btn[aria-pressed="true"] {
|
|
4300
|
+
background: var(--hw-bg-hover);
|
|
4301
|
+
border-color: var(--hw-brand, var(--hw-primary));
|
|
4302
|
+
box-shadow: inset 0 0 0 1px var(--hw-brand, var(--hw-primary));
|
|
4303
|
+
cursor: default;
|
|
4185
4304
|
}
|
|
4186
4305
|
|
|
4187
4306
|
/* ════════════════════════════════════════════════
|
|
@@ -4542,16 +4661,6 @@
|
|
|
4542
4661
|
color: #f87171;
|
|
4543
4662
|
}
|
|
4544
4663
|
|
|
4545
|
-
.hw-resolved {
|
|
4546
|
-
border-color: var(--hw-border);
|
|
4547
|
-
}
|
|
4548
|
-
|
|
4549
|
-
.hw-resolved-reopen,
|
|
4550
|
-
.hw-csat-btn {
|
|
4551
|
-
background: var(--hw-bg-hover);
|
|
4552
|
-
border-color: var(--hw-border-md);
|
|
4553
|
-
color: var(--hw-text);
|
|
4554
|
-
}
|
|
4555
4664
|
|
|
4556
4665
|
.hw-hover-preview {
|
|
4557
4666
|
background: #1c1c1e;
|
|
@@ -5696,18 +5805,30 @@
|
|
|
5696
5805
|
|
|
5697
5806
|
/* Sources. A numbered row per entry rather than a card — the answer is the
|
|
5698
5807
|
content, these are the receipts, and receipts should be quiet. */
|
|
5699
|
-
|
|
5808
|
+
/* Attached to the answer they belong to. They sat 8px under the bubble and
|
|
5809
|
+
10px in, so the number lined up with neither the bubble's edge nor its
|
|
5810
|
+
text, and the row read as a separate thing floating above the name line
|
|
5811
|
+
(Ali, 2026-10-12). 4px under it now, and the number starts where the
|
|
5812
|
+
bubble's text starts: 14px in, the bubble's own padding. */
|
|
5813
|
+
.hw-sources { display: flex; flex-direction: column; gap: 2px; margin-top: 4px; }
|
|
5700
5814
|
.hw-source {
|
|
5701
5815
|
display: flex;
|
|
5702
5816
|
align-items: center;
|
|
5703
5817
|
gap: 9px;
|
|
5704
|
-
padding:
|
|
5818
|
+
padding: 5px 14px;
|
|
5705
5819
|
border-radius: 9px;
|
|
5706
5820
|
background: transparent;
|
|
5707
5821
|
color: var(--hw-text);
|
|
5708
5822
|
text-decoration: none;
|
|
5709
5823
|
transition: background 0.15s;
|
|
5710
5824
|
}
|
|
5825
|
+
/* In the docked placement an answer has no bubble and its text starts at the
|
|
5826
|
+
column's edge, so the number does too. The hover ground still gets its 8px
|
|
5827
|
+
of air: it is pulled out by the same amount it is padded. */
|
|
5828
|
+
.hw-widget[data-hw-placement="docked"] .hw-source {
|
|
5829
|
+
margin-inline: -8px;
|
|
5830
|
+
padding-inline: 8px;
|
|
5831
|
+
}
|
|
5711
5832
|
a.hw-source { cursor: pointer; }
|
|
5712
5833
|
a.hw-source:hover { background: var(--hw-bg-hover); }
|
|
5713
5834
|
.hw-source-n {
|
|
@@ -5732,3 +5853,145 @@ a.hw-source:hover { background: var(--hw-bg-hover); }
|
|
|
5732
5853
|
text-overflow: ellipsis;
|
|
5733
5854
|
white-space: nowrap;
|
|
5734
5855
|
}
|
|
5856
|
+
|
|
5857
|
+
/* ── Docked, brand surface ─────────────────────────────────────────────────
|
|
5858
|
+
`theme.dockSurface: "brand"`: the panel, the bar under it and the reply
|
|
5859
|
+
preview are filled with the customer's colour instead of neutral glass.
|
|
5860
|
+
|
|
5861
|
+
Everything here is built from four values that `applyTheme` writes on the
|
|
5862
|
+
host from the brand colour (widget-core dock-ink.ts): the tint, the ink
|
|
5863
|
+
chosen for it, the shade (the far end from the ink) and the quiet inks. Two
|
|
5864
|
+
rules, and both are tested there for 4,096 colours:
|
|
5865
|
+
|
|
5866
|
+
- text is the ink, and the ink clears 4.5:1 on the tint;
|
|
5867
|
+
- the surface only moves toward the SHADE, never toward the ink, so the
|
|
5868
|
+
tint itself is the worst ground any text meets.
|
|
5869
|
+
|
|
5870
|
+
That second rule is why the light patch at the top right is the tint and
|
|
5871
|
+
the rest settles away from it. A patch lifted toward white under white
|
|
5872
|
+
text is how body copy fell to 2.9:1 on the first brand panel.
|
|
5873
|
+
|
|
5874
|
+
The fallbacks (white ink on --hw-primary) are what the panel does when the
|
|
5875
|
+
colour could not be read: a named colour, oklch(), a var(). */
|
|
5876
|
+
.hw-widget[data-hw-placement="docked"][data-hw-dock-surface="brand"] {
|
|
5877
|
+
--hw-dock-tint: var(--hw-primary);
|
|
5878
|
+
--hw-dock-ink: #ffffff;
|
|
5879
|
+
--hw-dock-shade: #000000;
|
|
5880
|
+
--hw-dock-wash: var(--hw-dock-shade);
|
|
5881
|
+
--hw-dock-ink-2: color-mix(in srgb, var(--hw-dock-ink) 86%, var(--hw-dock-tint));
|
|
5882
|
+
--hw-dock-ink-3: color-mix(in srgb, var(--hw-dock-ink) 78%, var(--hw-dock-tint));
|
|
5883
|
+
--hw-dock-ink-4: color-mix(in srgb, var(--hw-dock-ink) 60%, var(--hw-dock-tint));
|
|
5884
|
+
--hw-dock-pill-bg: var(--hw-dock-tint);
|
|
5885
|
+
--hw-dock-pill-fg: var(--hw-dock-ink);
|
|
5886
|
+
--hw-dock-pill-border: color-mix(in srgb, var(--hw-dock-ink) 30%, transparent);
|
|
5887
|
+
}
|
|
5888
|
+
.hw-widget[data-hw-placement="docked"][data-hw-dock-surface="brand"] :is(.hw-window, .hw-dock-bar, .hw-preview) {
|
|
5889
|
+
--hw-text: var(--hw-dock-ink);
|
|
5890
|
+
--hw-text-1: var(--hw-dock-ink);
|
|
5891
|
+
--hw-text-2: var(--hw-dock-ink-2);
|
|
5892
|
+
--hw-text-3: var(--hw-dock-ink-3);
|
|
5893
|
+
--hw-text-4: var(--hw-dock-ink-4);
|
|
5894
|
+
--hw-text-muted: var(--hw-dock-ink-2);
|
|
5895
|
+
--hw-bg: color-mix(in srgb, var(--hw-dock-wash) 12%, transparent);
|
|
5896
|
+
--hw-bg-subtle: transparent;
|
|
5897
|
+
--hw-bg-hover: color-mix(in srgb, var(--hw-dock-wash) 18%, transparent);
|
|
5898
|
+
--hw-border: color-mix(in srgb, var(--hw-dock-ink) 22%, transparent);
|
|
5899
|
+
--hw-border-md: color-mix(in srgb, var(--hw-dock-ink) 34%, transparent);
|
|
5900
|
+
--hw-focus-border: color-mix(in srgb, var(--hw-dock-ink) 60%, transparent);
|
|
5901
|
+
--hw-focus-ring: color-mix(in srgb, var(--hw-dock-ink) 18%, transparent);
|
|
5902
|
+
/* The agent's bubble (the token is misnamed) is unboxed in this placement;
|
|
5903
|
+
where it does show, it is a wash, with the ink on it. */
|
|
5904
|
+
--hw-visitor-bubble-bg: color-mix(in srgb, var(--hw-dock-wash) 14%, transparent);
|
|
5905
|
+
--hw-visitor-bubble-text: var(--hw-dock-ink);
|
|
5906
|
+
/* A solid object on the brand surface is the inverse pair: ink ground,
|
|
5907
|
+
brand-coloured text. Same two colours as the body text, same ratio. */
|
|
5908
|
+
--hw-primary: var(--hw-dock-ink);
|
|
5909
|
+
--hw-primary-hover: var(--hw-dock-ink);
|
|
5910
|
+
--hw-brand: var(--hw-dock-ink);
|
|
5911
|
+
--hw-on-brand: var(--hw-dock-tint);
|
|
5912
|
+
--hw-dock-surface: transparent;
|
|
5913
|
+
--hw-dock-on-surface: var(--hw-dock-ink);
|
|
5914
|
+
color: var(--hw-dock-ink);
|
|
5915
|
+
background:
|
|
5916
|
+
radial-gradient(70% 60% at 86% 8%, var(--hw-dock-tint), transparent 64%),
|
|
5917
|
+
linear-gradient(
|
|
5918
|
+
165deg,
|
|
5919
|
+
color-mix(in srgb, var(--hw-dock-shade) 12%, var(--hw-dock-tint)) 0%,
|
|
5920
|
+
color-mix(in srgb, var(--hw-dock-shade) 30%, var(--hw-dock-tint)) 100%
|
|
5921
|
+
);
|
|
5922
|
+
backdrop-filter: none;
|
|
5923
|
+
-webkit-backdrop-filter: none;
|
|
5924
|
+
box-shadow:
|
|
5925
|
+
0 24px 60px -20px rgba(12, 11, 10, 0.5),
|
|
5926
|
+
inset 0 0 0 1px color-mix(in srgb, var(--hw-dock-ink) 16%, transparent);
|
|
5927
|
+
}
|
|
5928
|
+
/* The visitor's own message. A 16%-white pill on the panel measured 1.49:1
|
|
5929
|
+
against it — it was nearly not there. It is the solid object of the thread. */
|
|
5930
|
+
.hw-widget[data-hw-placement="docked"][data-hw-dock-surface="brand"] .hw-msg--visitor .hw-msg-bubble {
|
|
5931
|
+
background: var(--hw-dock-ink);
|
|
5932
|
+
color: var(--hw-dock-tint);
|
|
5933
|
+
}
|
|
5934
|
+
.hw-widget[data-hw-placement="docked"][data-hw-dock-surface="brand"] .hw-msg--visitor .hw-msg-bubble a,
|
|
5935
|
+
.hw-widget[data-hw-placement="docked"][data-hw-dock-surface="brand"] .hw-msg--visitor .hw-msg-bubble a:hover {
|
|
5936
|
+
color: inherit;
|
|
5937
|
+
}
|
|
5938
|
+
.hw-widget[data-hw-placement="docked"][data-hw-dock-surface="brand"]
|
|
5939
|
+
:is(
|
|
5940
|
+
.hw-dock-send:not(:disabled),
|
|
5941
|
+
.hw-quick-reply-btn,
|
|
5942
|
+
.hw-quick-reply-btn:hover:not(:disabled),
|
|
5943
|
+
.hw-email-card-submit,
|
|
5944
|
+
.hw-offer,
|
|
5945
|
+
.hw-offer:hover
|
|
5946
|
+
) {
|
|
5947
|
+
background: var(--hw-dock-ink);
|
|
5948
|
+
color: var(--hw-dock-tint);
|
|
5949
|
+
}
|
|
5950
|
+
/* Places the glass block wrote white by hand. They take the ink. */
|
|
5951
|
+
.hw-widget[data-hw-placement="docked"][data-hw-dock-surface="brand"]
|
|
5952
|
+
:is(
|
|
5953
|
+
.hw-preview-body,
|
|
5954
|
+
.hw-header-close:hover,
|
|
5955
|
+
.hw-header-menu-btn:hover,
|
|
5956
|
+
.hw-preview-close:hover,
|
|
5957
|
+
.hw-quick-reply-btn[data-tapped="true"]
|
|
5958
|
+
) {
|
|
5959
|
+
color: var(--hw-dock-ink);
|
|
5960
|
+
}
|
|
5961
|
+
.hw-widget[data-hw-placement="docked"][data-hw-dock-surface="brand"] :is(.hw-preview-close, .hw-preview-footer) {
|
|
5962
|
+
color: var(--hw-dock-ink-2);
|
|
5963
|
+
}
|
|
5964
|
+
.hw-widget[data-hw-placement="docked"][data-hw-dock-surface="brand"] .hw-quick-reply-btn[data-tapped="true"] {
|
|
5965
|
+
background: color-mix(in srgb, var(--hw-dock-wash) 22%, transparent);
|
|
5966
|
+
}
|
|
5967
|
+
.hw-widget[data-hw-placement="docked"][data-hw-dock-surface="brand"] .hw-window :focus-visible {
|
|
5968
|
+
outline-color: var(--hw-dock-ink);
|
|
5969
|
+
}
|
|
5970
|
+
/* Code and the email row sat on a black wash. Under dark ink that is the
|
|
5971
|
+
wrong direction; the shade is always the right one. */
|
|
5972
|
+
.hw-widget[data-hw-placement="docked"][data-hw-dock-surface="brand"] .hw-msg-bubble :is(pre, code),
|
|
5973
|
+
.hw-widget[data-hw-placement="docked"][data-hw-dock-surface="brand"] .hw-email-card-row {
|
|
5974
|
+
background: color-mix(in srgb, var(--hw-dock-shade) 26%, transparent);
|
|
5975
|
+
}
|
|
5976
|
+
.hw-widget[data-hw-placement="docked"][data-hw-dock-surface="brand"] .hw-header-menu {
|
|
5977
|
+
background: color-mix(in srgb, var(--hw-dock-shade) 34%, var(--hw-dock-tint));
|
|
5978
|
+
color: var(--hw-dock-ink);
|
|
5979
|
+
}
|
|
5980
|
+
/* Initials are a solid object too. A 12%-white disc with white letters is a
|
|
5981
|
+
faint ring on a brand colour, and nothing at all on a light one. */
|
|
5982
|
+
.hw-widget[data-hw-placement="docked"][data-hw-dock-surface="brand"] :is(.hw-header-bot-icon--team, .hw-event-avatar) {
|
|
5983
|
+
background: var(--hw-dock-ink);
|
|
5984
|
+
color: var(--hw-dock-tint);
|
|
5985
|
+
}
|
|
5986
|
+
/* The bar's placeholder is an instruction ("Reply to reopen…"), so it is
|
|
5987
|
+
held to the text floor, not to the 45% a hint gets on glass. */
|
|
5988
|
+
.hw-widget[data-hw-placement="docked"][data-hw-dock-surface="brand"] .hw-dock-input::placeholder {
|
|
5989
|
+
color: var(--hw-dock-ink-3);
|
|
5990
|
+
}
|
|
5991
|
+
.hw-widget[data-hw-placement="docked"][data-hw-dock-surface="brand"] .hw-typing-dot {
|
|
5992
|
+
background: var(--hw-dock-ink-2);
|
|
5993
|
+
}
|
|
5994
|
+
.hw-widget[data-hw-placement="docked"][data-hw-dock-surface="brand"] .hw-disconnect {
|
|
5995
|
+
background: color-mix(in srgb, var(--hw-dock-shade) 16%, transparent);
|
|
5996
|
+
color: var(--hw-dock-ink-2);
|
|
5997
|
+
}
|