@wix/web5-core 1.56.0 → 1.56.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/package.json +4 -3
- package/src/components/placement/PlacementResponseRenderer.css +269 -0
- package/src/components/ui/Disclaimer.css +35 -0
- package/src/components/ui/FeedbackBar.css +267 -0
- package/src/components/ui/PlacementLoader.css +101 -0
- package/src/components/ui/PromptEntryEmptyState.css +172 -0
- package/src/components/ui/SearchSection.css +538 -0
- package/src/components/ui/SectionSkeleton.css +109 -0
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wix/web5-core",
|
|
3
3
|
"license": "MIT",
|
|
4
|
-
"version": "1.56.
|
|
4
|
+
"version": "1.56.1",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "tsachis",
|
|
7
7
|
"email": "tsachis@wix.com"
|
|
@@ -14,7 +14,8 @@
|
|
|
14
14
|
"dist/cjs",
|
|
15
15
|
"dist/esm",
|
|
16
16
|
"dist/types",
|
|
17
|
-
"src/styles"
|
|
17
|
+
"src/styles",
|
|
18
|
+
"src/components/**/*.css"
|
|
18
19
|
],
|
|
19
20
|
"scripts": {
|
|
20
21
|
"build": "yoshi-library build && node scripts/fix-esm-extensions.js",
|
|
@@ -99,5 +100,5 @@
|
|
|
99
100
|
"wallaby": {
|
|
100
101
|
"autoDetect": true
|
|
101
102
|
},
|
|
102
|
-
"falconPackageHash": "
|
|
103
|
+
"falconPackageHash": "ddcfd2461f54a7f6bce7c9799d570b3aa2f85da1923cca6e4afb6bb4"
|
|
103
104
|
}
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
/* PlacementResponseRenderer — placement card chrome (DL #097 —
|
|
2
|
+
Figma 128:5251 framing / 128:5258 conversation).
|
|
3
|
+
Renders the streamed answer as a warm card with a FormAI eyebrow and a
|
|
4
|
+
gradient highlight ring (accent → transparent, top-left → bottom-right)
|
|
5
|
+
that holds while the answer streams, spins twice once it settles, and then
|
|
6
|
+
stays put. The conversation variant additionally shows the user's question
|
|
7
|
+
as a chip.
|
|
8
|
+
Re-skin via the `--w5-placement-*` tokens below.
|
|
9
|
+
The loading skeleton's styles live in `../ui/PlacementLoader.css`. */
|
|
10
|
+
|
|
11
|
+
/* Outer host-page spacing — matches the loader's `--w5-placement-spacing` so
|
|
12
|
+
the gap to surrounding content doesn't change at swap time. */
|
|
13
|
+
[data-w5-placement-renderer] {
|
|
14
|
+
margin-block: var(--w5-placement-spacing, 24px);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/* The loader→content swap is height-animated by the PlacementSmoothHeight
|
|
18
|
+
wrapper (`.w5-placement__body` below); this fade-in covers the paint swap
|
|
19
|
+
itself so the card doesn't pop in while the height glides. Plays once per
|
|
20
|
+
renderer mount (so again after each re-submit). */
|
|
21
|
+
[data-w5-placement-renderer] {
|
|
22
|
+
animation: w5-placement-content-in 240ms ease-out both;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
@keyframes w5-placement-content-in {
|
|
26
|
+
from {
|
|
27
|
+
opacity: 0;
|
|
28
|
+
}
|
|
29
|
+
to {
|
|
30
|
+
opacity: 1;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
[data-w5-placement-renderer].w5-placement {
|
|
35
|
+
box-sizing: border-box;
|
|
36
|
+
padding: var(--w5-placement-card-padding, 30px);
|
|
37
|
+
border-radius: var(--w5-placement-card-radius, 4px);
|
|
38
|
+
background: var(--w5-placement-card-bg, #f1f0ee);
|
|
39
|
+
/* Section components inside the answer use `bg-background`
|
|
40
|
+
(= var(--color-background), white), which would paint a white block over
|
|
41
|
+
the card. Re-point that token within the placement so those sections
|
|
42
|
+
inherit the card colour instead — one shared background across the whole
|
|
43
|
+
placement. Change --w5-placement-card-bg to re-theme card + sections. */
|
|
44
|
+
--color-background: var(--w5-placement-card-bg, #f1f0ee);
|
|
45
|
+
/* Reserve the border box so the conversation highlight ring (the
|
|
46
|
+
`::before` gradient below) doesn't shift layout when it fades in/out. */
|
|
47
|
+
border: 2px solid transparent;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/* Height smoothing for the whole placement slot: PlacementSmoothHeight
|
|
51
|
+
(mounted around the loader/content swap in embed-placement) measures the
|
|
52
|
+
current child (ResizeObserver) and sets an explicit `height` here, so the
|
|
53
|
+
loader→content swap and each streamed section appending animate instead
|
|
54
|
+
of snapping. Until the first measurement lands there's no inline height
|
|
55
|
+
and the box sizes naturally. */
|
|
56
|
+
.w5-placement__body {
|
|
57
|
+
overflow: clip;
|
|
58
|
+
transition: height var(--w5-placement-grow-duration, 350ms) ease-out;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/* flow-root so children's top/bottom margins can't collapse out of the
|
|
62
|
+
measured inner box (they'd be clipped by the wrapper otherwise). */
|
|
63
|
+
.w5-placement__body-inner {
|
|
64
|
+
display: flow-root;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/* Height clamp + "Show more" (DL #113) — Google-AI-Overview style. Opt-in via
|
|
68
|
+
the slot's `data-clamp` attribute; the renderer adds `--clamped` to the card
|
|
69
|
+
ROOT and caps it directly (no inner wrapper), so the answer sections stay
|
|
70
|
+
direct children of the placement root — clients lay them out with
|
|
71
|
+
`:has(> …)` direct-child grids (feature-com's search-overview two-column
|
|
72
|
+
layout) that a wrapper would break. The cap is also what
|
|
73
|
+
`PlacementSmoothHeight` then measures, so the slot animates to the capped
|
|
74
|
+
height rather than the full content. */
|
|
75
|
+
.w5-placement--clamped {
|
|
76
|
+
position: relative;
|
|
77
|
+
max-height: var(--w5-placement-clamp-height, 220px);
|
|
78
|
+
overflow: hidden;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/* The variant highlight ring is a `::before` at `inset: -2px` (outside the
|
|
82
|
+
padding box) — `overflow: hidden` above would clip it to a stub. Drop it on
|
|
83
|
+
clamped cards; the clamp + fade is its own treatment. */
|
|
84
|
+
.w5-placement--clamped::before {
|
|
85
|
+
content: none;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/* Fade the cut-off bottom edge to the card background (a wash, like Google —
|
|
89
|
+
not a mask that makes text vanish). Rendered only when the content overflows
|
|
90
|
+
(the renderer omits it otherwise), pinned to the bottom of the capped root. */
|
|
91
|
+
.w5-placement__fade {
|
|
92
|
+
position: absolute;
|
|
93
|
+
inset-inline: 0;
|
|
94
|
+
bottom: 0;
|
|
95
|
+
height: var(--w5-placement-fade-height, 96px);
|
|
96
|
+
background: linear-gradient(
|
|
97
|
+
to bottom,
|
|
98
|
+
transparent,
|
|
99
|
+
var(--w5-placement-card-bg, #f1f0ee)
|
|
100
|
+
);
|
|
101
|
+
pointer-events: none;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/* "Show more" pill, pinned over the fade. Re-skins via the shared
|
|
105
|
+
`--w5-placement-*` tokens. */
|
|
106
|
+
.w5-placement__show-more {
|
|
107
|
+
position: absolute;
|
|
108
|
+
bottom: 14px;
|
|
109
|
+
left: 50%;
|
|
110
|
+
transform: translateX(-50%);
|
|
111
|
+
display: inline-flex;
|
|
112
|
+
align-items: center;
|
|
113
|
+
gap: 6px;
|
|
114
|
+
padding: 8px 18px;
|
|
115
|
+
border-radius: 999px;
|
|
116
|
+
border: 1px solid var(--w5-placement-show-more-border, #d8d5cf);
|
|
117
|
+
background: var(--w5-placement-show-more-bg, #fff);
|
|
118
|
+
color: var(--w5-placement-show-more-color, #000);
|
|
119
|
+
font-size: 14px;
|
|
120
|
+
line-height: 15px;
|
|
121
|
+
font-weight: 500;
|
|
122
|
+
text-decoration: none;
|
|
123
|
+
cursor: pointer;
|
|
124
|
+
white-space: nowrap;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
.w5-placement__show-more:hover {
|
|
128
|
+
background: var(--w5-placement-show-more-bg-hover, #f6f5f3);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
.w5-placement__show-more:focus-visible {
|
|
132
|
+
outline: 2px solid var(--w5-placement-accent, #ef1b28);
|
|
133
|
+
outline-offset: 2px;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
.w5-placement__show-more-icon {
|
|
137
|
+
flex: none;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
.w5-placement__eyebrow {
|
|
141
|
+
display: flex;
|
|
142
|
+
align-items: center;
|
|
143
|
+
gap: 10px;
|
|
144
|
+
margin-bottom: 20px;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
.w5-placement__eyebrow-icon {
|
|
148
|
+
flex: none;
|
|
149
|
+
color: var(--w5-placement-accent, #ef1b28);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
.w5-placement__eyebrow-label {
|
|
153
|
+
font-size: 14px;
|
|
154
|
+
line-height: 15px;
|
|
155
|
+
font-weight: 500;
|
|
156
|
+
color: var(--w5-placement-eyebrow-color, #000);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/* The user's question (conversation variant). */
|
|
160
|
+
.w5-placement__query {
|
|
161
|
+
display: inline-block;
|
|
162
|
+
margin: 0 0 20px;
|
|
163
|
+
padding: 7px 10px;
|
|
164
|
+
border-radius: 3px;
|
|
165
|
+
background: var(--w5-placement-query-bg, #e2dfd9);
|
|
166
|
+
font-size: 14px;
|
|
167
|
+
line-height: 15px;
|
|
168
|
+
color: var(--w5-placement-query-color, #000);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/* Placement highlight (conversation + informational): a gradient ring — fully
|
|
172
|
+
opaque accent at the top-left corner fading to transparent toward the
|
|
173
|
+
bottom-right. A solid `border-color` can't render a gradient, so the ring
|
|
174
|
+
is a masked pseudo-element: the gradient paints the whole box, and the
|
|
175
|
+
mask punches out the padding box so only the 2px border area remains.
|
|
176
|
+
The ring shows as soon as the placement starts to render, holds for the
|
|
177
|
+
whole streamed render (the `--streaming` modifier below); once the answer
|
|
178
|
+
settles the modifier drops and the animation plays — the gradient spins
|
|
179
|
+
two full counter-clockwise turns, then the ring stays in place. Replays
|
|
180
|
+
after each re-submit since the renderer remounts via the loader. */
|
|
181
|
+
.w5-placement--conversation,
|
|
182
|
+
.w5-placement--informational {
|
|
183
|
+
position: relative;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/* Registered so the gradient angle interpolates in the keyframes below.
|
|
187
|
+
Browsers without `@property` (Firefox < 128) apply custom-property
|
|
188
|
+
keyframes discretely — harmless here, since -585deg ≡ 135deg (mod 360°)
|
|
189
|
+
the jump is invisible and only the hold + fade-out remains. */
|
|
190
|
+
@property --w5-placement-highlight-angle {
|
|
191
|
+
syntax: '<angle>';
|
|
192
|
+
inherits: false;
|
|
193
|
+
initial-value: 135deg;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
.w5-placement--conversation::before,
|
|
197
|
+
.w5-placement--informational::before {
|
|
198
|
+
content: '';
|
|
199
|
+
position: absolute;
|
|
200
|
+
/* Cover the reserved 2px transparent border (absolute positioning is
|
|
201
|
+
relative to the padding box, which excludes it). */
|
|
202
|
+
inset: -2px;
|
|
203
|
+
padding: 2px;
|
|
204
|
+
/* Outer radius of the card's border box: card radius + border width. */
|
|
205
|
+
border-radius: calc(var(--w5-placement-card-radius, 4px) + 2px);
|
|
206
|
+
background: linear-gradient(
|
|
207
|
+
var(--w5-placement-highlight-angle, 135deg),
|
|
208
|
+
var(--w5-placement-accent, #ef1b28),
|
|
209
|
+
transparent
|
|
210
|
+
);
|
|
211
|
+
/* Keep only the ring: padding-box ⊖ full box. */
|
|
212
|
+
-webkit-mask:
|
|
213
|
+
linear-gradient(#fff 0 0) content-box,
|
|
214
|
+
linear-gradient(#fff 0 0);
|
|
215
|
+
-webkit-mask-composite: xor;
|
|
216
|
+
mask:
|
|
217
|
+
linear-gradient(#fff 0 0) content-box,
|
|
218
|
+
linear-gradient(#fff 0 0);
|
|
219
|
+
mask-composite: exclude;
|
|
220
|
+
pointer-events: none;
|
|
221
|
+
/* ~9.4s default for the 2.5 counter-clockwise turns (same angular speed as
|
|
222
|
+
the original 2 turns in 7.5s); the ring then holds its final state
|
|
223
|
+
(`both` fill mode) and stays visible. */
|
|
224
|
+
animation: w5-placement-highlight
|
|
225
|
+
var(--w5-placement-highlight-duration, 9375ms) linear both;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/* Still streaming: hold the ring fully visible; the spin only starts
|
|
229
|
+
when this class is removed (answer settled) and the animation kicks in. */
|
|
230
|
+
.w5-placement--conversation.w5-placement--streaming::before,
|
|
231
|
+
.w5-placement--informational.w5-placement--streaming::before {
|
|
232
|
+
animation: none;
|
|
233
|
+
opacity: 1;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
@keyframes w5-placement-highlight {
|
|
237
|
+
/* Two and a half counter-clockwise turns (135° → -765° ≡ 315°) at constant
|
|
238
|
+
speed, so the accent settles on the opposite side (bottom-right); the
|
|
239
|
+
ring stays fully visible throughout and after. */
|
|
240
|
+
0% {
|
|
241
|
+
--w5-placement-highlight-angle: 135deg;
|
|
242
|
+
opacity: 1;
|
|
243
|
+
}
|
|
244
|
+
100% {
|
|
245
|
+
--w5-placement-highlight-angle: -765deg;
|
|
246
|
+
opacity: 1;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
@media (prefers-reduced-motion: reduce) {
|
|
251
|
+
/* No spin — show the ring statically in its settled position
|
|
252
|
+
(accent at the bottom-right). */
|
|
253
|
+
.w5-placement--conversation::before,
|
|
254
|
+
.w5-placement--informational::before,
|
|
255
|
+
.w5-placement--conversation.w5-placement--streaming::before,
|
|
256
|
+
.w5-placement--informational.w5-placement--streaming::before {
|
|
257
|
+
animation: none;
|
|
258
|
+
opacity: 1;
|
|
259
|
+
--w5-placement-highlight-angle: 315deg;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
.w5-placement__body {
|
|
263
|
+
transition: none;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
[data-w5-placement-renderer] {
|
|
267
|
+
animation: none;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/* "AI can make mistakes. Learn more" footer. Mounted by the host app
|
|
2
|
+
alongside the FeedbackBar; clients can override the whole component via
|
|
3
|
+
the DisclaimerComponent UI slot.
|
|
4
|
+
|
|
5
|
+
Typography defaults mirror `.web5-feedback-bar` so a single client-side
|
|
6
|
+
override (`--web5-feedback-bar-color`) re-skins both together. The
|
|
7
|
+
disclaimer-specific vars stay as escape hatches when divergence is
|
|
8
|
+
needed. */
|
|
9
|
+
|
|
10
|
+
.web5-disclaimer {
|
|
11
|
+
margin: 0;
|
|
12
|
+
font-size: var(
|
|
13
|
+
--web5-disclaimer-font-size,
|
|
14
|
+
var(--web5-feedback-bar-font-size, 13px)
|
|
15
|
+
);
|
|
16
|
+
font-weight: 400;
|
|
17
|
+
line-height: normal;
|
|
18
|
+
color: var(
|
|
19
|
+
--web5-disclaimer-color,
|
|
20
|
+
var(--web5-feedback-bar-color, var(--web5-feedback-label-color, #6b7280))
|
|
21
|
+
);
|
|
22
|
+
text-align: var(--web5-disclaimer-text-align, left);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.web5-disclaimer__link {
|
|
26
|
+
color: inherit;
|
|
27
|
+
text-decoration: underline;
|
|
28
|
+
text-decoration-skip-ink: none;
|
|
29
|
+
cursor: pointer;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
.web5-disclaimer__link:hover,
|
|
33
|
+
.web5-disclaimer__link:focus-visible {
|
|
34
|
+
color: var(--web5-disclaimer-link-hover-color, inherit);
|
|
35
|
+
}
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
/* "Was this helpful?" bar + popover. Mounted by the host app inside the
|
|
2
|
+
sections container; clients can override the whole component via the
|
|
3
|
+
FeedbackBarComponent UI slot. */
|
|
4
|
+
|
|
5
|
+
.web5-feedback-bar {
|
|
6
|
+
display: flex;
|
|
7
|
+
align-items: center;
|
|
8
|
+
justify-content: flex-start;
|
|
9
|
+
gap: 12px;
|
|
10
|
+
width: fit-content;
|
|
11
|
+
/* Negative top margin pulls the bar up into the previous section's bottom
|
|
12
|
+
padding so it visually sits inside that section's color band (matches
|
|
13
|
+
Figma — bar at the bottom of the NextSteps purple gradient) without
|
|
14
|
+
changing its DOM position. Tune via --web5-feedback-margin-top. */
|
|
15
|
+
margin: var(--web5-feedback-margin-top, -4rem) 0
|
|
16
|
+
var(--web5-feedback-margin-bottom, 1.5rem) 0;
|
|
17
|
+
font-size: var(--web5-feedback-bar-font-size, 13px);
|
|
18
|
+
font-weight: 400;
|
|
19
|
+
line-height: normal;
|
|
20
|
+
/* Bar-scoped label color falls back to the shared muted color so popover
|
|
21
|
+
elements (title-hint, close button) stay readable on white when Circana
|
|
22
|
+
re-skins the bar text to light. */
|
|
23
|
+
color: var(
|
|
24
|
+
--web5-feedback-bar-color,
|
|
25
|
+
var(--web5-feedback-label-color, #6b7280)
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.web5-feedback-label {
|
|
30
|
+
margin: 0;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.web5-feedback-thumb {
|
|
34
|
+
position: relative;
|
|
35
|
+
width: 32px;
|
|
36
|
+
height: 32px;
|
|
37
|
+
border-radius: 50%;
|
|
38
|
+
border: 0;
|
|
39
|
+
background: transparent;
|
|
40
|
+
color: var(--web5-feedback-thumb-color, #2b2b2b);
|
|
41
|
+
display: inline-flex;
|
|
42
|
+
align-items: center;
|
|
43
|
+
justify-content: center;
|
|
44
|
+
cursor: pointer;
|
|
45
|
+
transition:
|
|
46
|
+
background 0.12s,
|
|
47
|
+
color 0.12s;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/* Hover tooltip — pill above the thumb. Scoped to bar thumbs only; the
|
|
51
|
+
popover header thumbs are sentiment switchers and don't need tooltips. */
|
|
52
|
+
.web5-feedback-bar .web5-feedback-thumb[data-tooltip]::after {
|
|
53
|
+
content: attr(data-tooltip);
|
|
54
|
+
position: absolute;
|
|
55
|
+
bottom: calc(100% + 8px);
|
|
56
|
+
left: 50%;
|
|
57
|
+
transform: translateX(-50%);
|
|
58
|
+
padding: 8px 16px;
|
|
59
|
+
background: var(--web5-feedback-tooltip-bg, #1f1f1f);
|
|
60
|
+
color: var(--web5-feedback-tooltip-color, #fff);
|
|
61
|
+
border-radius: 999px;
|
|
62
|
+
font-size: 14px;
|
|
63
|
+
font-weight: 500;
|
|
64
|
+
line-height: 1;
|
|
65
|
+
white-space: nowrap;
|
|
66
|
+
opacity: 0;
|
|
67
|
+
pointer-events: none;
|
|
68
|
+
transition: opacity 0.12s;
|
|
69
|
+
z-index: 50;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.web5-feedback-bar .web5-feedback-thumb[data-tooltip]:hover::after,
|
|
73
|
+
.web5-feedback-bar .web5-feedback-thumb[data-tooltip]:focus-visible::after {
|
|
74
|
+
opacity: 1;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.web5-feedback-thumb:hover {
|
|
78
|
+
background: var(--web5-feedback-thumb-hover-bg, rgba(0, 0, 0, 0.06));
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.web5-feedback-thumb--active {
|
|
82
|
+
background: var(--web5-feedback-accent, #1a1422);
|
|
83
|
+
color: #fff;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.web5-feedback-thumb--active:hover {
|
|
87
|
+
background: var(--web5-feedback-accent-hover, #2a2236);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/* Bar-only overrides — the bar may sit on a colored band (e.g. NextSteps'
|
|
91
|
+
purple gradient) and need light icons/hover, while the popover thumbs
|
|
92
|
+
always sit on white and stay dark. Selector path stops at the bar's own
|
|
93
|
+
thumbs-row to avoid leaking into the popover header thumbs. */
|
|
94
|
+
.web5-feedback-bar > .web5-feedback-thumbs-row > .web5-feedback-thumb {
|
|
95
|
+
color: var(
|
|
96
|
+
--web5-feedback-bar-thumb-color,
|
|
97
|
+
var(--web5-feedback-thumb-color, #2b2b2b)
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.web5-feedback-bar > .web5-feedback-thumbs-row > .web5-feedback-thumb:hover {
|
|
102
|
+
background: var(
|
|
103
|
+
--web5-feedback-bar-thumb-hover-bg,
|
|
104
|
+
var(--web5-feedback-thumb-hover-bg, rgba(0, 0, 0, 0.06))
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/* Dim the rest of the page while the popover is open. */
|
|
109
|
+
.web5-feedback-backdrop {
|
|
110
|
+
position: fixed;
|
|
111
|
+
inset: 0;
|
|
112
|
+
background: rgba(0, 0, 0, 0.4);
|
|
113
|
+
z-index: 65;
|
|
114
|
+
animation: web5-feedback-backdrop-in 0.18s ease both;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
@keyframes web5-feedback-backdrop-in {
|
|
118
|
+
from {
|
|
119
|
+
opacity: 0;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/* Centered on the viewport rather than anchored to the bar — so the form
|
|
124
|
+
reads as a focused modal regardless of where the bar sits on the page. */
|
|
125
|
+
.web5-feedback-popover {
|
|
126
|
+
position: fixed;
|
|
127
|
+
top: 50%;
|
|
128
|
+
left: 50%;
|
|
129
|
+
transform: translate(-50%, -50%);
|
|
130
|
+
width: min(574px, 92vw);
|
|
131
|
+
z-index: 70;
|
|
132
|
+
background: #fff;
|
|
133
|
+
border: 1px solid rgba(0, 0, 0, 0.06);
|
|
134
|
+
border-radius: 14px;
|
|
135
|
+
padding: 30px;
|
|
136
|
+
display: flex;
|
|
137
|
+
flex-direction: column;
|
|
138
|
+
gap: 25px;
|
|
139
|
+
box-shadow: 0 24px 48px -12px rgba(20, 14, 32, 0.25),
|
|
140
|
+
0 8px 16px -8px rgba(20, 14, 32, 0.12);
|
|
141
|
+
animation: web5-feedback-pop-in 0.18s ease both;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
@keyframes web5-feedback-pop-in {
|
|
145
|
+
from {
|
|
146
|
+
opacity: 0;
|
|
147
|
+
transform: translate(-50%, calc(-50% + 8px));
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
.web5-feedback-head {
|
|
152
|
+
display: flex;
|
|
153
|
+
flex-direction: column;
|
|
154
|
+
gap: 15px;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
.web5-feedback-thumbs-row {
|
|
158
|
+
display: flex;
|
|
159
|
+
gap: 0;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
.web5-feedback-title {
|
|
163
|
+
margin: 0;
|
|
164
|
+
font-size: 15px;
|
|
165
|
+
font-weight: 600;
|
|
166
|
+
color: var(--web5-feedback-title-color, #2b2b2b);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
.web5-feedback-title-hint {
|
|
170
|
+
font-weight: 400;
|
|
171
|
+
color: var(--web5-feedback-label-color, #6b7280);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
.web5-feedback-close {
|
|
175
|
+
position: absolute;
|
|
176
|
+
top: 24px;
|
|
177
|
+
right: 24px;
|
|
178
|
+
width: 24px;
|
|
179
|
+
height: 24px;
|
|
180
|
+
border-radius: 50%;
|
|
181
|
+
border: 0;
|
|
182
|
+
background: transparent;
|
|
183
|
+
color: var(--web5-feedback-label-color, #6b7280);
|
|
184
|
+
cursor: pointer;
|
|
185
|
+
display: inline-flex;
|
|
186
|
+
align-items: center;
|
|
187
|
+
justify-content: center;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
.web5-feedback-close:hover {
|
|
191
|
+
background: rgba(0, 0, 0, 0.06);
|
|
192
|
+
color: var(--web5-feedback-title-color, #2b2b2b);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
.web5-feedback-chips {
|
|
196
|
+
display: flex;
|
|
197
|
+
gap: 13px;
|
|
198
|
+
flex-wrap: wrap;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
.web5-feedback-chip {
|
|
202
|
+
display: inline-flex;
|
|
203
|
+
align-items: center;
|
|
204
|
+
padding: 8px 15px;
|
|
205
|
+
height: 30px;
|
|
206
|
+
border-radius: 999px;
|
|
207
|
+
border: 1px solid rgba(0, 0, 0, 0.12);
|
|
208
|
+
background: #fff;
|
|
209
|
+
color: var(--web5-feedback-chip-color, #2b2b2b);
|
|
210
|
+
font-size: 13px;
|
|
211
|
+
cursor: pointer;
|
|
212
|
+
transition:
|
|
213
|
+
background 0.12s,
|
|
214
|
+
border-color 0.12s,
|
|
215
|
+
color 0.12s;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/* Hover: neutral fill, default border — no accent tint. */
|
|
219
|
+
.web5-feedback-chip:hover {
|
|
220
|
+
background: var(--web5-feedback-chip-hover-bg, rgba(0, 0, 0, 0.04));
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/* Selected: accent-colored border, subtle fill, default text color
|
|
224
|
+
(matches Figma — the chip label stays dark, only the outline changes). */
|
|
225
|
+
.web5-feedback-chip.web5-feedback-chip--selected,
|
|
226
|
+
.web5-feedback-chip.web5-feedback-chip--selected:hover {
|
|
227
|
+
background: var(--web5-feedback-chip-selected-bg, rgba(0, 0, 0, 0.04));
|
|
228
|
+
border-color: var(--web5-feedback-accent, #1a1422);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
.web5-feedback-textarea {
|
|
232
|
+
width: 100%;
|
|
233
|
+
min-height: 100px;
|
|
234
|
+
padding: 15px;
|
|
235
|
+
border-radius: 10px;
|
|
236
|
+
border: 1px solid rgba(0, 0, 0, 0.12);
|
|
237
|
+
background: #fff;
|
|
238
|
+
font: 14px/1.4 inherit;
|
|
239
|
+
color: var(--web5-feedback-title-color, #2b2b2b);
|
|
240
|
+
resize: vertical;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
.web5-feedback-textarea::placeholder {
|
|
244
|
+
color: var(--web5-feedback-placeholder-color, #7a838a);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
.web5-feedback-submit {
|
|
248
|
+
width: 100%;
|
|
249
|
+
height: 38px;
|
|
250
|
+
border-radius: 999px;
|
|
251
|
+
border: 0;
|
|
252
|
+
background: var(--web5-feedback-accent, #1a1422);
|
|
253
|
+
color: #fff;
|
|
254
|
+
font-size: 14px;
|
|
255
|
+
font-weight: 500;
|
|
256
|
+
cursor: pointer;
|
|
257
|
+
transition: background 0.12s;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
.web5-feedback-submit:hover {
|
|
261
|
+
background: var(--web5-feedback-accent-hover, #2a2236);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
.web5-feedback-submit:disabled {
|
|
265
|
+
background: var(--web5-feedback-accent-disabled, rgba(26, 20, 34, 0.45));
|
|
266
|
+
cursor: not-allowed;
|
|
267
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/* PlacementLoader — placement loading skeleton.
|
|
2
|
+
Rendered before the streamed response arrives. Client packages can re-skin
|
|
3
|
+
via the `--w5-placement-loader-*` tokens below without touching the markup.
|
|
4
|
+
Defaults mirror the canonical wireframe: a soft-bordered rounded container
|
|
5
|
+
with two stub text lines and a larger content block, all using a very
|
|
6
|
+
light accent-tinted skeleton wash.
|
|
7
|
+
The rendered placement's card chrome lives in
|
|
8
|
+
`../placement/PlacementResponseRenderer.css`. */
|
|
9
|
+
|
|
10
|
+
/* Wrapper around the loader. Drives the entrance animation: the slot starts
|
|
11
|
+
empty, the wrapper expands from a 0-height grid row to its natural row,
|
|
12
|
+
smoothly pushing surrounding host content down instead of popping in. The
|
|
13
|
+
margin-block on either side gives breathing room from neighbouring blocks
|
|
14
|
+
on the host page and animates in alongside the height for a coherent
|
|
15
|
+
reveal. Clients can re-skin the spacing via `--w5-placement-spacing`.
|
|
16
|
+
The loader→content swap itself is height-animated by the
|
|
17
|
+
PlacementSmoothHeight wrapper (see `../placement/PlacementResponseRenderer.css`). */
|
|
18
|
+
.w5-placement--loading {
|
|
19
|
+
display: grid;
|
|
20
|
+
grid-template-rows: 1fr;
|
|
21
|
+
margin-block: var(--w5-placement-spacing, 24px);
|
|
22
|
+
animation: w5-placement-loader-reveal 420ms ease-out both;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.w5-placement--loading > * {
|
|
26
|
+
min-height: 0;
|
|
27
|
+
overflow: hidden;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
@keyframes w5-placement-loader-reveal {
|
|
31
|
+
from {
|
|
32
|
+
grid-template-rows: 0fr;
|
|
33
|
+
margin-block: 0;
|
|
34
|
+
opacity: 0;
|
|
35
|
+
}
|
|
36
|
+
to {
|
|
37
|
+
grid-template-rows: 1fr;
|
|
38
|
+
margin-block: var(--w5-placement-spacing, 24px);
|
|
39
|
+
opacity: 1;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.w5-placement-loader {
|
|
44
|
+
display: flex;
|
|
45
|
+
flex-direction: column;
|
|
46
|
+
gap: var(--w5-placement-loader-gap, 24px);
|
|
47
|
+
padding: var(--w5-placement-loader-padding, 20px 24px);
|
|
48
|
+
border: var(--w5-placement-loader-border, 1px solid rgb(226 232 240));
|
|
49
|
+
border-radius: var(--w5-placement-loader-radius, 12px);
|
|
50
|
+
background: var(--w5-placement-loader-bg, #fff);
|
|
51
|
+
width: 100%;
|
|
52
|
+
box-sizing: border-box;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.w5-placement-loader__lines {
|
|
56
|
+
display: flex;
|
|
57
|
+
flex-direction: column;
|
|
58
|
+
gap: var(--w5-placement-loader-line-gap, 10px);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.w5-placement-loader__line,
|
|
62
|
+
.w5-placement-loader__block {
|
|
63
|
+
display: block;
|
|
64
|
+
/* Very light tint of the placement accent (oklch(0.6 0.24 26.24)) —
|
|
65
|
+
same hue, lightness raised and chroma dropped for a skeleton wash. */
|
|
66
|
+
background: var(--w5-placement-loader-skeleton, oklch(0.95 0.04 26.24));
|
|
67
|
+
border-radius: var(--w5-placement-loader-skeleton-radius, 6px);
|
|
68
|
+
animation: w5-placement-loader-pulse 1.4s ease-in-out infinite;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
.w5-placement-loader__line {
|
|
72
|
+
height: var(--w5-placement-loader-line-height, 14px);
|
|
73
|
+
width: 100%;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.w5-placement-loader__line--short {
|
|
77
|
+
width: var(--w5-placement-loader-line-short-width, 70%);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.w5-placement-loader__block {
|
|
81
|
+
height: var(--w5-placement-loader-block-height, 120px);
|
|
82
|
+
width: 100%;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
@keyframes w5-placement-loader-pulse {
|
|
86
|
+
0%,
|
|
87
|
+
100% {
|
|
88
|
+
opacity: 1;
|
|
89
|
+
}
|
|
90
|
+
50% {
|
|
91
|
+
opacity: 0.55;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
@media (prefers-reduced-motion: reduce) {
|
|
96
|
+
.w5-placement--loading,
|
|
97
|
+
.w5-placement-loader__line,
|
|
98
|
+
.w5-placement-loader__block {
|
|
99
|
+
animation: none;
|
|
100
|
+
}
|
|
101
|
+
}
|